mirror of
https://github.com/ShaYmez/allmon2-last-heard.git
synced 2024-11-27 02:09:19 -05:00
Create server-side stuff
This commit is contained in:
parent
b61ef71cdb
commit
6bcd05dc8a
1
.gitignore
vendored
1
.gitignore
vendored
@ -1 +1,2 @@
|
|||||||
yarn-error.log
|
yarn-error.log
|
||||||
|
storage/*
|
||||||
|
106
app.js
106
app.js
@ -1,19 +1,18 @@
|
|||||||
Vue.component('lt-startstop', {
|
Vue.component('lt-node-link', {
|
||||||
template: '<button class="pure-button pure-button-primary" @click="toggleTail" :class="{ \'button-error\': buttonState }">' +
|
template: `<a :href='uri' target="_blank">{{ node }}</a>`,
|
||||||
'{{ buttonState ? "Stop" : "Start" }} Tail</button>',
|
props: ['node', 'type'],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
buttonState: false
|
uri: '',
|
||||||
|
urlMap: {
|
||||||
|
0: '#',
|
||||||
|
1: 'http://stats.allstarlink.org/nodeinfo.cgi?node=',
|
||||||
|
2: 'http://www.irlp.net/status/index.php?nodeid='
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.toggleTail();
|
this.uri = this.urlMap[this.type] + this.node;
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
toggleTail() {
|
|
||||||
this.buttonState = !this.buttonState;
|
|
||||||
this.$emit('click', this.buttonState);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -25,9 +24,13 @@ let App = new Vue({
|
|||||||
intervalTimer: null,
|
intervalTimer: null,
|
||||||
fetchEvery: 2000,
|
fetchEvery: 2000,
|
||||||
// uri = 'http://www3.winsystem.org/monitor/ajax-logtail.php'
|
// uri = 'http://www3.winsystem.org/monitor/ajax-logtail.php'
|
||||||
uri: 'testdata.txt',
|
uri: 'fetchData.php',
|
||||||
lastData: null,
|
lastData: null,
|
||||||
logs: [],
|
logs: [],
|
||||||
|
nodes: {
|
||||||
|
1: [],
|
||||||
|
2: []
|
||||||
|
},
|
||||||
nodeTypeLabels: {
|
nodeTypeLabels: {
|
||||||
0: 'Unknown',
|
0: 'Unknown',
|
||||||
1: 'Allstar',
|
1: 'Allstar',
|
||||||
@ -39,9 +42,12 @@ let App = new Vue({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
mounted() {
|
||||||
|
this.toggleTail();
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
toggleTail(state) {
|
toggleTail() {
|
||||||
this.enabled = state;
|
this.enabled = !this.enabled;
|
||||||
|
|
||||||
if (this.enabled) {
|
if (this.enabled) {
|
||||||
this.start();
|
this.start();
|
||||||
@ -63,29 +69,42 @@ let App = new Vue({
|
|||||||
},
|
},
|
||||||
|
|
||||||
fetchLog() {
|
fetchLog() {
|
||||||
axios.get(this.uri).then(({data}) => {
|
// Force re-render component so it updates callsigns & node info
|
||||||
|
this.$forceUpdate();
|
||||||
|
|
||||||
|
axios.get(this.uri + '?cmd=log').then(({data}) => {
|
||||||
this.lastData = data;
|
this.lastData = data;
|
||||||
this.parseLogData();
|
this.parseLogData();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getNodeInfo(node, type) {
|
||||||
|
if (typeof this.nodes[type][node] !== "undefined") {
|
||||||
|
let info = this.nodes[type][node];
|
||||||
|
if (typeof info.callsign === "undefined") return;
|
||||||
|
return `${info.callsign} ${info.desc} ${info.location}`;
|
||||||
|
} else {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
parseLogData() {
|
parseLogData() {
|
||||||
this.logs = [];
|
let rows = this.lastData.split("\n");
|
||||||
let rows = this.lastData.split("\n").reverse();
|
|
||||||
|
|
||||||
rows.forEach((v) => {
|
rows.forEach(async (v) => {
|
||||||
let match = v.match(/([A-Za-z]+ [0-9]+ [0-9]+\:[0-9]+\:[0-9]+) (rpt|stn)([A-Za-z0-9]+) .*? (?:\[(?:via) ([0-9]+))?/);
|
let match = v.match(/([A-Za-z]+ [0-9]+ [0-9]+\:[0-9]+\:[0-9]+) (rpt|stn)([A-Za-z0-9]+) .*? (?:\[(?:via) ([0-9]+))?/);
|
||||||
if (!match) return;
|
if (!match) return;
|
||||||
|
|
||||||
let type = this.getNodeType(match[2]);
|
let type = this.getNodeType(match[2]);
|
||||||
|
|
||||||
this.addEntry(
|
this.addEntry(
|
||||||
{
|
{
|
||||||
node: match[3],
|
node: match[3],
|
||||||
via: match[4],
|
via: match[4],
|
||||||
type: type,
|
type: type,
|
||||||
typeLabel: this.getNodeTypeLabel(type),
|
typeLabel: this.getNodeTypeLabel(type),
|
||||||
desc: this.fetchNodeInfo(match[3], type),
|
info: this.fetchNodeInfo(match[3], type),
|
||||||
dateTime: match[1],
|
dateTime: moment(match[1], "MMM DD hh:mm:ss"),
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@ -100,22 +119,41 @@ let App = new Vue({
|
|||||||
},
|
},
|
||||||
|
|
||||||
fetchNodeInfo(node, type) {
|
fetchNodeInfo(node, type) {
|
||||||
return type === 1 ? this.fetchNodeInfoAllstar(node)
|
if (type === 0) return;
|
||||||
: (type === 2 ? this.fetchNodeInfoIRLP(node) : null);
|
|
||||||
},
|
// Bind it and recurse, fetch it again
|
||||||
|
// if (typeof this.nodes[type][node] === "undefined") {
|
||||||
fetchNodeInfoAllstar(node) {
|
// this.nodes[type][node] = null;
|
||||||
let info;
|
// return this.fetchNodeInfo(node, type);
|
||||||
return info;
|
if (this.nodes[type][node]) {
|
||||||
},
|
// Don't even call fetchNode**
|
||||||
|
return this.nodes[type][node];
|
||||||
fetchNodeInfoIRLP(node) {
|
}
|
||||||
let info;
|
|
||||||
return info;
|
axios.get(this.uri + '?cmd=node&type='+type+'&node='+node).then(({data}) => {
|
||||||
|
this.nodes[type][node] = data;
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
addEntry(log) {
|
addEntry(log) {
|
||||||
this.logs.push(log);
|
// Generate unique ID for this entry
|
||||||
|
log.uniqId = (log.node + log.dateTime.unix()).hashCode();
|
||||||
|
if (!_.findWhere(this.logs, { uniqId: log.uniqId })) {
|
||||||
|
this.logs.unshift(log);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
String.prototype.hashCode = function() {
|
||||||
|
let hash = 0;
|
||||||
|
if (this.length === 0) {
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
for (var i = 0; i < this.length; i++) {
|
||||||
|
let char = this.charCodeAt(i);
|
||||||
|
hash = ((hash<<5)-hash)+char;
|
||||||
|
hash = hash & hash; // Convert to 32bit integer
|
||||||
|
}
|
||||||
|
return Math.abs(hash);
|
||||||
|
};
|
@ -1,5 +1,6 @@
|
|||||||
.header {
|
.header {
|
||||||
padding: 1em;
|
padding: 1em;
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.text-center {
|
.text-center {
|
||||||
@ -16,9 +17,34 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
table.logs {
|
table.logs {
|
||||||
|
width: 85%;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 64em) {
|
||||||
|
table.logs {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
table.logs th {
|
||||||
|
background-color: #3e6eb6;
|
||||||
|
color: #fff;
|
||||||
|
width: 1%;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.logs th.desc {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
table.logs tbody tr:nth-child(even){
|
||||||
|
background-color: #cbcbcb;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.logs tr td.when{
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
/* We want to give the content area some more padding */
|
/* We want to give the content area some more padding */
|
||||||
.content {
|
.content {
|
||||||
padding: 1em 1em 3em;
|
padding: 1em 1em 3em;
|
||||||
|
99
fetchData.php
Normal file
99
fetchData.php
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
$cmd = $_GET['cmd'] ?? null;
|
||||||
|
$node = intval($_GET['node'] ?? null);
|
||||||
|
$type = intval($_GET['type'] ?? null);
|
||||||
|
|
||||||
|
if ($cmd === "log" || $cmd == "logText") {
|
||||||
|
$data = file_get_contents("http://www3.winsystem.org/monitor/ajax-logtail.php");
|
||||||
|
|
||||||
|
// Just output the raw data
|
||||||
|
if ($cmd === "log") {
|
||||||
|
echo $data;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else if ($cmd === "node") {
|
||||||
|
if (empty($node)) return;
|
||||||
|
|
||||||
|
if ($type === 1) {
|
||||||
|
$info = fetchNodeInfoAllstar($node);
|
||||||
|
} else if ($type === 2) {
|
||||||
|
$info = fetchNodeInfoIRLP($node);
|
||||||
|
}
|
||||||
|
|
||||||
|
echo json_encode($info, JSON_UNESCAPED_SLASHES);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
function fetchNodeInfoAllstar($node) {
|
||||||
|
$db = fetchAllStarDb();
|
||||||
|
|
||||||
|
if (empty($node)) return [];
|
||||||
|
|
||||||
|
$db = explode("\n", $db);
|
||||||
|
foreach ($db as $row) {
|
||||||
|
$row = explode("|", $row);
|
||||||
|
if (intval($row[0]) !== $node) continue;
|
||||||
|
|
||||||
|
return [
|
||||||
|
'node' => $node,
|
||||||
|
'callsign' => $row[1],
|
||||||
|
'desc' => $row[2],
|
||||||
|
'location' => $row[3]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
'node' => $node
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
function fetchNodeInfoIRLP($node) {
|
||||||
|
$db = fetchIRLPDb();
|
||||||
|
$db = explode("\n", $db);
|
||||||
|
|
||||||
|
foreach ($db as $row) {
|
||||||
|
$line = str_getcsv($row, "\t");
|
||||||
|
|
||||||
|
if ($line[0] != $node) continue;
|
||||||
|
|
||||||
|
return [
|
||||||
|
'node' => $node,
|
||||||
|
'callsign' => $line[1],
|
||||||
|
'desc' => $line[15],
|
||||||
|
'location' => "{$line[2]}, {$line[3]}"
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
'node' => $node,
|
||||||
|
'callsign' => $node,
|
||||||
|
'desc' => '',
|
||||||
|
'location' => ''
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
function fetchAllStarDb() {
|
||||||
|
$dbFile = __DIR__.'/storage/allstar.txt';
|
||||||
|
if (!file_exists($dbFile)) {
|
||||||
|
$db = file_get_contents("http://allmondb.allstarlink.org");
|
||||||
|
file_put_contents($dbFile, $db);
|
||||||
|
return $db;
|
||||||
|
}
|
||||||
|
|
||||||
|
return file_get_contents($dbFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
function fetchIRLPDb() {
|
||||||
|
$dbFile = __DIR__.'/storage/irlp.txt';
|
||||||
|
|
||||||
|
if (!file_exists($dbFile)) {
|
||||||
|
$db = file_get_contents("http://status.irlp.net/nohtmlstatus.txt.zip");
|
||||||
|
file_put_contents("${dbFile}.zip", $db);
|
||||||
|
shell_exec("/usr/bin/unzip -p ${dbFile}.zip > ${dbFile}");
|
||||||
|
}
|
||||||
|
|
||||||
|
return file_get_contents($dbFile);
|
||||||
|
}
|
||||||
|
|
24
index.html
24
index.html
@ -14,29 +14,32 @@
|
|||||||
<div class="header">
|
<div class="header">
|
||||||
<div class="text-center">
|
<div class="text-center">
|
||||||
<h1>WIN System Log Tail</h1>
|
<h1>WIN System Log Tail</h1>
|
||||||
<lt-startstop @click="toggleTail"/>
|
<button v-cloak class="pure-button pure-button-primary" @click="toggleTail" :class="{ 'button-error': enabled }">
|
||||||
|
{{ enabled ? "Stop" : "Start" }} Tail
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="content-wrapper">
|
<div class="content-wrapper">
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<table class="pure-table logs">
|
<table class="pure-table logs">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Node #</th>
|
<th>Node#</th>
|
||||||
<th>Via Node</th>
|
<th>Via</th>
|
||||||
<th>Type</th>
|
<th>Type</th>
|
||||||
<th>Description</th>
|
<th>When</th>
|
||||||
<th>Date/Time</th>
|
<th class="desc">Description</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody v-cloak>
|
<tbody v-cloak>
|
||||||
<tr v-for="row in logs">
|
<tr v-for="row in logs">
|
||||||
<td>{{ row.node }}</td>
|
<td><lt-node-link :node="row.node" :type="row.type" /></td>
|
||||||
<td>{{ row.via }}</td>
|
<td><lt-node-link :node="row.via" :type="row.type" /></td>
|
||||||
<td>{{ row.typeLabel }}</td>
|
<td>{{ row.typeLabel }}</td>
|
||||||
<td>{{ fetchNodeInfo(row.node) }}</td>
|
<td class="when">{{ row.dateTime.format('hh:mm:ss MM/DD/YY') }}</td>
|
||||||
<td>{{ row.dateTime }}</td>
|
<td>
|
||||||
|
{{ getNodeInfo(row.node, row.type) }}
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
@ -46,6 +49,7 @@
|
|||||||
|
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.10.2/underscore-min.js"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.10.2/underscore-min.js"></script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.19.2/axios.min.js"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.19.2/axios.min.js"></script>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.27.0/moment.min.js"></script>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
|
||||||
<script src="app.js" type="text/javascript"></script>
|
<script src="app.js" type="text/javascript"></script>
|
||||||
</body>
|
</body>
|
||||||
|
Loading…
Reference in New Issue
Block a user