mirror of https://github.com/q191201771/lal.git
Add lal Web UI using http api
parent
6dff63cbfd
commit
61a7c2e128
@ -0,0 +1,565 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>lal</title>
|
||||
<style>
|
||||
body {
|
||||
background-color: #5e5e5e;
|
||||
color: #dadada;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
table {
|
||||
margin: auto;
|
||||
width: 80%;
|
||||
background-color: #25252b;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
th {
|
||||
color: #fff;
|
||||
line-height: 1.4;
|
||||
background-color: #19191d;
|
||||
}
|
||||
|
||||
tbody>tr:nth-child(even) {
|
||||
background-color: #29292e;
|
||||
}
|
||||
|
||||
tbody>tr:hover {
|
||||
background-color: #442727;
|
||||
}
|
||||
|
||||
td {
|
||||
color: #ccc;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
td:hover {
|
||||
background-color: #813737;
|
||||
color: #fff;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #dadada;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<section>
|
||||
<h1>Server Info</h1>
|
||||
<table>
|
||||
<tr>
|
||||
<th>Server ID</th>
|
||||
<td>{{.ServerID}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Git Tag</th>
|
||||
<td>{{.GitTag}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Git Commit Log</th>
|
||||
<td>{{.GitCommitLog}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Git Status</th>
|
||||
<td>{{.GitStatus}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Build Time</th>
|
||||
<td>{{.BuildTime}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Go Version</th>
|
||||
<td>{{.GoVersion}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Runtime</th>
|
||||
<td>{{.runtime}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>lal Version</th>
|
||||
<td>{{.LalVersion}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>API Version</th>
|
||||
<td>{{.ApiVersion}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Notify Version</th>
|
||||
<td>{{.NotifyVersion}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Start Time</th>
|
||||
<td>{{.StartTime}}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</section>
|
||||
|
||||
<section id="allGroupSection">
|
||||
<h1>All Group</h1>
|
||||
<div>
|
||||
Sort:
|
||||
<select id="selAllGroupSortCol">
|
||||
<option value="name">Name</option>
|
||||
<option value="start">Pub StartTime</option>
|
||||
</select>
|
||||
<input type="radio" name="rbAllGroupSort" value="asc" checked> ASC
|
||||
<input type="radio" name="rbAllGroupSort" value="desc"> DESC
|
||||
</div>
|
||||
<div>
|
||||
<input type="checkbox" id="chkAllGroupAuto" onclick="onCheckBoxAllGroupAutoClick();"> Auto
|
||||
<input type="number" id="txtAllGroupInterval" value="1" min="1" onchange="onChangeTxtAllGroupInterval();">s
|
||||
<button id="btnAllGroupRefresh" onclick="requestAllGroup();">Refresh</button>
|
||||
</div>
|
||||
<div>
|
||||
Update Time: <label id="lblAllGroupUpdateTime"></label>
|
||||
</div><br>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th rowspan="3">#</th>
|
||||
<th colspan="2">Name</th>
|
||||
<th colspan="3">Video</th>
|
||||
<th>Audio</th>
|
||||
<th colspan="7">Pub</th>
|
||||
<th rowspan="3">Subs</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th rowspan="2">App</th>
|
||||
<th rowspan="2">Stream</th>
|
||||
<th rowspan="2">Codec</th>
|
||||
<th rowspan="2">Width</th>
|
||||
<th rowspan="2">Height</th>
|
||||
<th rowspan="2">Codec</th>
|
||||
<th rowspan="2">Session ID</th>
|
||||
<th rowspan="2">Remote Addr</th>
|
||||
<th rowspan="2">Start Time</th>
|
||||
<th colspan="2">Read</th>
|
||||
<th colspan="2">Write</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Bytes Sum</th>
|
||||
<th>Bitrate</th>
|
||||
<th>Bytes Sum</th>
|
||||
<th>Bitrate</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="allGroupTable"></tbody>
|
||||
</table>
|
||||
</section>
|
||||
|
||||
<section id="groupSection" style="display: none;">
|
||||
<h1 id="groupName">Group</h1>
|
||||
<a href="javascript:GroupClose()">Back</a>
|
||||
<div>
|
||||
<input type="checkbox" id="chkGroupAuto" onclick="onCheckBoxGroupAutoClick();"> Auto
|
||||
<input type="number" id="txtGroupInterval" value="1" min="1" onchange="onChangeTxtGroupInterval();">s
|
||||
<button id="btnGroupRefresh" onclick="requestGroup();">Refresh</button>
|
||||
</div>
|
||||
<div>
|
||||
Update Time: <label id="lblGroupUpdateTime"></label>
|
||||
</div>
|
||||
<h4>Group Info</h4>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th colspan="2">Name</th>
|
||||
<th colspan="3">Video</th>
|
||||
<th>Audio</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>App Name</th>
|
||||
<th>Stream Name</th>
|
||||
<th>Video Codec</th>
|
||||
<th>Video Width</th>
|
||||
<th>Video Height</th>
|
||||
<th>Audio Codec</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="groupInfoTable"></tbody>
|
||||
</table>
|
||||
|
||||
<h4>Pub</h4>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th rowspan="2">Session ID</th>
|
||||
<th rowspan="2">Remote Addr</th>
|
||||
<th rowspan="2">Start Time</th>
|
||||
<th colspan="2">Read</th>
|
||||
<th colspan="2">Write</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Bytes Sum</th>
|
||||
<th>Bitrate</th>
|
||||
<th>Bytes Sum</th>
|
||||
<th>Bitrate</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="groupPubTable"></tbody>
|
||||
</table>
|
||||
|
||||
<h4>Pull</h4>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th rowspan="2">Session ID</th>
|
||||
<th rowspan="2">Protocol</th>
|
||||
<th rowspan="2">Remote Addr</th>
|
||||
<th rowspan="2">Start Time</th>
|
||||
<th colspan="2">Read</th>
|
||||
<th colspan="2">Write</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Bytes Sum</th>
|
||||
<th>Bitrate</th>
|
||||
<th>Bytes Sum</th>
|
||||
<th>Bitrate</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="groupPullTable"></tbody>
|
||||
</table>
|
||||
|
||||
<h4>Subs</h4>
|
||||
<div>
|
||||
Sort:
|
||||
<input type="radio" name="rbSubSort" value="asc" checked> ASC
|
||||
<input type="radio" name="rbSubSort" value="desc"> DESC
|
||||
</div>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th rowspan="2">#</th>
|
||||
<th rowspan="2">Session ID</th>
|
||||
<th rowspan="2">Protocol</th>
|
||||
<th rowspan="2">Remote Addr</th>
|
||||
<th rowspan="2">Start Time</th>
|
||||
<th colspan="2">Read</th>
|
||||
<th colspan="2">Write</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Bytes Sum</th>
|
||||
<th>Bitrate</th>
|
||||
<th>Bytes Sum</th>
|
||||
<th>Bitrate</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="groupSubTable"></tbody>
|
||||
</table>
|
||||
</section>
|
||||
|
||||
<footer>
|
||||
<hr>lal
|
||||
</footer>
|
||||
|
||||
<script>
|
||||
const allGroupSection = document.getElementById("allGroupSection");
|
||||
const selAllGroupSortCol = document.getElementById("selAllGroupSortCol");
|
||||
const rbAllGroupSort = document.getElementsByName("rbAllGroupSort");
|
||||
const chkAllGroupAuto = document.getElementById("chkAllGroupAuto");
|
||||
const btnAllGroupRefresh = document.getElementById("btnAllGroupRefresh");
|
||||
const txtAllGroupInterval = document.getElementById("txtAllGroupInterval");
|
||||
const lblAllGroupUpdateTime = document.getElementById("lblAllGroupUpdateTime");
|
||||
const allGroupTable = document.getElementById("allGroupTable");
|
||||
let allGroupTimer;
|
||||
|
||||
const groupSection = document.getElementById("groupSection");
|
||||
const groupName = document.getElementById("groupName");
|
||||
const chkGroupAuto = document.getElementById("chkGroupAuto");
|
||||
const btnGroupRefresh = document.getElementById("btnGroupRefresh");
|
||||
const txtGroupInterval = document.getElementById("txtGroupInterval");
|
||||
const lblGroupUpdateTime = document.getElementById("lblGroupUpdateTime");
|
||||
const groupInfoTable = document.getElementById("groupInfoTable");
|
||||
const groupPubTable = document.getElementById("groupPubTable");
|
||||
const groupPullTable = document.getElementById("groupPullTable");
|
||||
const rbSubSort = document.getElementsByName("rbSubSort");
|
||||
const groupSubTable = document.getElementById("groupSubTable");
|
||||
let groupTimer;
|
||||
|
||||
init();
|
||||
|
||||
function init() {
|
||||
const params = new URLSearchParams(location.search);
|
||||
let sort = params.get("sort");
|
||||
if(sort == "start") {
|
||||
selAllGroupSortCol.value = "start";
|
||||
}
|
||||
let isDesc = params.get("desc");
|
||||
if(isDesc == 1) {
|
||||
for(let index = 0; index < rbAllGroupSort.length; index++) {
|
||||
if(rbAllGroupSort[index].value == "desc") {
|
||||
rbAllGroupSort[index].checked = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
let interval = params.get("interval");
|
||||
if(interval > 0) {
|
||||
txtAllGroupInterval.value = interval;
|
||||
}
|
||||
let isAuto = params.get("auto");
|
||||
if(isAuto == 1) {
|
||||
chkAllGroupAuto.checked = true;
|
||||
onCheckBoxAllGroupAutoClick();
|
||||
return;
|
||||
}
|
||||
requestAllGroup();
|
||||
}
|
||||
|
||||
function StartAllGroupTimer() {
|
||||
let interval = txtAllGroupInterval.value * 1000;
|
||||
btnAllGroupRefresh.disabled = "disabled";
|
||||
allGroupTimer = setInterval(requestAllGroup, interval);
|
||||
}
|
||||
|
||||
function StopAllGroupTimer() {
|
||||
btnAllGroupRefresh.disabled = false;
|
||||
clearInterval(allGroupTimer);
|
||||
}
|
||||
|
||||
function onCheckBoxAllGroupAutoClick() {
|
||||
if(chkAllGroupAuto.checked) {
|
||||
requestAllGroup();
|
||||
StartAllGroupTimer();
|
||||
} else {
|
||||
StopAllGroupTimer();
|
||||
}
|
||||
}
|
||||
|
||||
function onChangeTxtAllGroupInterval() {
|
||||
if(chkAllGroupAuto.checked) {
|
||||
StopAllGroupTimer();
|
||||
StartAllGroupTimer();
|
||||
}
|
||||
}
|
||||
|
||||
function httpAsync(url, method, callback) {
|
||||
const xmlHttp = new XMLHttpRequest();
|
||||
xmlHttp.onreadystatechange = function() {
|
||||
if(xmlHttp.readyState == 4)
|
||||
callback(xmlHttp.status, xmlHttp.responseText);
|
||||
}
|
||||
xmlHttp.open(method, url, true);
|
||||
xmlHttp.send(null);
|
||||
}
|
||||
|
||||
function allGroupSort(a, b) {
|
||||
const sortCol = selAllGroupSortCol.options[selAllGroupSortCol.selectedIndex].value;
|
||||
let isDesc = false;
|
||||
for(let index = 0; index < rbAllGroupSort.length; index++) {
|
||||
if(rbAllGroupSort[index].checked) {
|
||||
if(rbAllGroupSort[index].value == "desc") {
|
||||
isDesc = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
let data1 = sortCol == "name" ? a["app_name"] : a["pub"]["start_time"];
|
||||
let data2 = sortCol == "name" ? b["app_name"] : b["pub"]["start_time"];
|
||||
if(data1 == data2) {
|
||||
data1 = a["stream_name"];
|
||||
data2 = b["stream_name"];
|
||||
}
|
||||
if(isDesc) {
|
||||
let tmp = data1;
|
||||
data1 = data2;
|
||||
data2 = tmp;
|
||||
}
|
||||
return data1 < data2 ? -1 : 1
|
||||
}
|
||||
|
||||
function requestAllGroup() {
|
||||
httpAsync("/api/stat/all_group", "GET", function(code, resp) {
|
||||
if(code == 200) {
|
||||
const obj = JSON.parse(resp);
|
||||
obj["data"]["groups"].sort(allGroupSort);
|
||||
for(let index = allGroupTable.rows.length; index > 0; index--) {
|
||||
allGroupTable.deleteRow(-1);
|
||||
}
|
||||
|
||||
for(let i=0;i<obj["data"]["groups"].length;i++) {
|
||||
const group = obj["data"]["groups"][i];
|
||||
const newRow = allGroupTable.insertRow();
|
||||
newRow.insertCell(0).innerText = i + 1;
|
||||
newRow.insertCell(1).innerText = group["app_name"];
|
||||
newRow.insertCell(2).innerText = group["stream_name"];
|
||||
newRow.insertCell(3).innerText = group["video_codec"];
|
||||
newRow.insertCell(4).innerText = group["video_width"];
|
||||
newRow.insertCell(5).innerText = group["video_height"];
|
||||
newRow.insertCell(6).innerText = group["audio_codec"];
|
||||
newRow.insertCell(7).innerText = group["pub"]["session_id"];
|
||||
newRow.insertCell(8).innerText = group["pub"]["remote_addr"];
|
||||
newRow.insertCell(9).innerText = group["pub"]["start_time"];
|
||||
newRow.insertCell(10).innerText = group["pub"]["read_bytes_sum"];
|
||||
newRow.insertCell(11).innerText = group["pub"]["read_bitrate_kbits"];
|
||||
newRow.insertCell(12).innerText = group["pub"]["wrote_bytes_sum"];
|
||||
newRow.insertCell(13).innerText = group["pub"]["write_bitrate_kbits"];
|
||||
let subsCnt = 0;
|
||||
if(group["subs"]) {
|
||||
subsCnt = group["subs"].length;
|
||||
}
|
||||
newRow.insertCell(14).innerText = subsCnt;
|
||||
newRow.addEventListener("click", function() {GroupOpen(group["stream_name"]);});
|
||||
}
|
||||
lblAllGroupUpdateTime.innerText = (new Date().toString());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function GroupOpen(streamName) {
|
||||
txtGroupInterval.value = txtAllGroupInterval.value;
|
||||
chkGroupAuto.checked = chkAllGroupAuto.checked;
|
||||
for(let i = 0; i < rbAllGroupSort.length; i++) {
|
||||
if(rbAllGroupSort[i].checked) {
|
||||
for(let j = 0; j < rbSubSort.length; j++) {
|
||||
if(rbSubSort[j].value == rbAllGroupSort[i].value) {
|
||||
rbSubSort[j].checked = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
StopAllGroupTimer();
|
||||
groupName.innerText = streamName;
|
||||
allGroupSection.style.display = "none";
|
||||
groupSection.style.display = "block";
|
||||
if(chkGroupAuto.checked) {
|
||||
onCheckBoxGroupAutoClick();
|
||||
return;
|
||||
}
|
||||
requestGroup();
|
||||
}
|
||||
|
||||
function GroupClose() {
|
||||
txtAllGroupInterval.value = txtGroupInterval.value;
|
||||
chkAllGroupAuto.checked = chkGroupAuto.checked;
|
||||
for(let i = 0; i < rbSubSort.length; i++) {
|
||||
if(rbSubSort[i].checked) {
|
||||
for(let j = 0; j < rbAllGroupSort.length; j++) {
|
||||
if(rbAllGroupSort[j].value == rbSubSort[i].value) {
|
||||
rbAllGroupSort[j].checked = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
StopGroupTimer();
|
||||
onCheckBoxAllGroupAutoClick();
|
||||
allGroupSection.style.display = "block";
|
||||
groupSection.style.display = "none";
|
||||
}
|
||||
|
||||
function onCheckBoxGroupAutoClick() {
|
||||
if(chkGroupAuto.checked) {
|
||||
requestGroup();
|
||||
StartGroupTimer();
|
||||
} else {
|
||||
StopGroupTimer();
|
||||
}
|
||||
}
|
||||
|
||||
function onChangeTxtGroupInterval() {
|
||||
if(chkGroupAuto.checked) {
|
||||
StopGroupTimer();
|
||||
StartGroupTimer();
|
||||
}
|
||||
}
|
||||
|
||||
function StartGroupTimer() {
|
||||
let interval = txtGroupInterval.value * 1000;
|
||||
btnGroupRefresh.disabled = "disabled";
|
||||
groupTimer = setInterval(requestGroup, interval);
|
||||
}
|
||||
|
||||
function StopGroupTimer() {
|
||||
btnGroupRefresh.disabled = false;
|
||||
clearInterval(groupTimer);
|
||||
}
|
||||
|
||||
function subSort(a, b) {
|
||||
let isDesc = false;
|
||||
for(let index = 0; index < rbSubSort.length; index++) {
|
||||
if(rbSubSort[index].checked) {
|
||||
if(rbSubSort[index].value == "desc") {
|
||||
isDesc = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
let data1 = isDesc ? b["session_id"] : a["session_id"];
|
||||
let data2 = isDesc ? a["session_id"] : b["session_id"];
|
||||
return data1 < data2 ? -1 : 1
|
||||
}
|
||||
|
||||
function requestGroup() {
|
||||
httpAsync("/api/stat/group?stream_name="+groupName.innerText, "GET", function(code, resp) {
|
||||
if(code == 200) {
|
||||
const obj = JSON.parse(resp);
|
||||
for(let index = groupInfoTable.rows.length; index > 0; index--) {
|
||||
groupInfoTable.deleteRow(-1);
|
||||
}
|
||||
for(let index = groupPubTable.rows.length; index > 0; index--) {
|
||||
groupPubTable.deleteRow(-1);
|
||||
}
|
||||
for(let index = groupPullTable.rows.length; index > 0; index--) {
|
||||
groupPullTable.deleteRow(-1);
|
||||
}
|
||||
for(let index = groupSubTable.rows.length; index > 0; index--) {
|
||||
groupSubTable.deleteRow(-1);
|
||||
}
|
||||
|
||||
if(obj["error_code"] > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const infoRow = groupInfoTable.insertRow();
|
||||
infoRow.insertCell(0).innerText = obj["data"]["app_name"];
|
||||
infoRow.insertCell(1).innerText = obj["data"]["stream_name"];
|
||||
infoRow.insertCell(2).innerText = obj["data"]["video_codec"];
|
||||
infoRow.insertCell(3).innerText = obj["data"]["video_width"];
|
||||
infoRow.insertCell(4).innerText = obj["data"]["video_height"];
|
||||
infoRow.insertCell(5).innerText = obj["data"]["audio_codec"];
|
||||
|
||||
const pubRow = groupPubTable.insertRow();
|
||||
pubRow.insertCell(0).innerText = obj["data"]["pub"]["session_id"];
|
||||
pubRow.insertCell(1).innerText = obj["data"]["pub"]["remote_addr"];
|
||||
pubRow.insertCell(2).innerText = obj["data"]["pub"]["start_time"];
|
||||
pubRow.insertCell(3).innerText = obj["data"]["pub"]["read_bytes_sum"];
|
||||
pubRow.insertCell(4).innerText = obj["data"]["pub"]["read_bitrate_kbits"];
|
||||
pubRow.insertCell(5).innerText = obj["data"]["pub"]["wrote_bytes_sum"];
|
||||
pubRow.insertCell(6).innerText = obj["data"]["pub"]["write_bitrate_kbits"];
|
||||
|
||||
const pullRow = groupPullTable.insertRow();
|
||||
pullRow.insertCell(0).innerText = obj["data"]["pull"]["session_id"];
|
||||
pullRow.insertCell(1).innerText = obj["data"]["pull"]["protocol"];
|
||||
pullRow.insertCell(2).innerText = obj["data"]["pull"]["remote_addr"];
|
||||
pullRow.insertCell(3).innerText = obj["data"]["pull"]["start_time"];
|
||||
pullRow.insertCell(4).innerText = obj["data"]["pull"]["read_bytes_sum"];
|
||||
pullRow.insertCell(5).innerText = obj["data"]["pull"]["read_bitrate_kbits"];
|
||||
pullRow.insertCell(6).innerText = obj["data"]["pull"]["wrote_bytes_sum"];
|
||||
pullRow.insertCell(7).innerText = obj["data"]["pull"]["write_bitrate_kbits"];
|
||||
|
||||
if(obj["data"]["subs"]) {
|
||||
obj["data"]["subs"].sort(subSort);
|
||||
for(let i = 0; i < obj["data"]["subs"].length; i++) {
|
||||
const sub = obj["data"]["subs"][i];
|
||||
const subRow = groupSubTable.insertRow();
|
||||
subRow.insertCell(0).innerText = i + 1;
|
||||
subRow.insertCell(1).innerText = sub["session_id"];
|
||||
subRow.insertCell(2).innerText = sub["protocol"];
|
||||
subRow.insertCell(3).innerText = sub["remote_addr"];
|
||||
subRow.insertCell(4).innerText = sub["start_time"];
|
||||
subRow.insertCell(5).innerText = sub["read_bytes_sum"];
|
||||
subRow.insertCell(6).innerText = sub["read_bitrate_kbits"];
|
||||
subRow.insertCell(7).innerText = sub["wrote_bytes_sum"];
|
||||
subRow.insertCell(8).innerText = sub["write_bitrate_kbits"];
|
||||
}
|
||||
}
|
||||
lblGroupUpdateTime.innerText = (new Date().toString());
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue