mirror of
https://github.com/ShaYmez/allmon2-last-heard.git
synced 2024-11-23 08:28:38 -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
|
||||
storage/*
|
||||
|
102
app.js
102
app.js
@ -1,19 +1,18 @@
|
||||
Vue.component('lt-startstop', {
|
||||
template: '<button class="pure-button pure-button-primary" @click="toggleTail" :class="{ \'button-error\': buttonState }">' +
|
||||
'{{ buttonState ? "Stop" : "Start" }} Tail</button>',
|
||||
Vue.component('lt-node-link', {
|
||||
template: `<a :href='uri' target="_blank">{{ node }}</a>`,
|
||||
props: ['node', 'type'],
|
||||
data() {
|
||||
return {
|
||||
buttonState: false
|
||||
uri: '',
|
||||
urlMap: {
|
||||
0: '#',
|
||||
1: 'http://stats.allstarlink.org/nodeinfo.cgi?node=',
|
||||
2: 'http://www.irlp.net/status/index.php?nodeid='
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.toggleTail();
|
||||
},
|
||||
methods: {
|
||||
toggleTail() {
|
||||
this.buttonState = !this.buttonState;
|
||||
this.$emit('click', this.buttonState);
|
||||
}
|
||||
this.uri = this.urlMap[this.type] + this.node;
|
||||
}
|
||||
});
|
||||
|
||||
@ -25,9 +24,13 @@ let App = new Vue({
|
||||
intervalTimer: null,
|
||||
fetchEvery: 2000,
|
||||
// uri = 'http://www3.winsystem.org/monitor/ajax-logtail.php'
|
||||
uri: 'testdata.txt',
|
||||
uri: 'fetchData.php',
|
||||
lastData: null,
|
||||
logs: [],
|
||||
nodes: {
|
||||
1: [],
|
||||
2: []
|
||||
},
|
||||
nodeTypeLabels: {
|
||||
0: 'Unknown',
|
||||
1: 'Allstar',
|
||||
@ -39,9 +42,12 @@ let App = new Vue({
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.toggleTail();
|
||||
},
|
||||
methods: {
|
||||
toggleTail(state) {
|
||||
this.enabled = state;
|
||||
toggleTail() {
|
||||
this.enabled = !this.enabled;
|
||||
|
||||
if (this.enabled) {
|
||||
this.start();
|
||||
@ -63,29 +69,42 @@ let App = new Vue({
|
||||
},
|
||||
|
||||
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.parseLogData();
|
||||
});
|
||||
},
|
||||
|
||||
parseLogData() {
|
||||
this.logs = [];
|
||||
let rows = this.lastData.split("\n").reverse();
|
||||
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 '';
|
||||
}
|
||||
},
|
||||
|
||||
rows.forEach((v) => {
|
||||
parseLogData() {
|
||||
let rows = this.lastData.split("\n");
|
||||
|
||||
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]+))?/);
|
||||
if (!match) return;
|
||||
|
||||
let type = this.getNodeType(match[2]);
|
||||
|
||||
this.addEntry(
|
||||
{
|
||||
node: match[3],
|
||||
via: match[4],
|
||||
type: type,
|
||||
typeLabel: this.getNodeTypeLabel(type),
|
||||
desc: this.fetchNodeInfo(match[3], type),
|
||||
dateTime: match[1],
|
||||
info: this.fetchNodeInfo(match[3], type),
|
||||
dateTime: moment(match[1], "MMM DD hh:mm:ss"),
|
||||
}
|
||||
);
|
||||
});
|
||||
@ -100,22 +119,41 @@ let App = new Vue({
|
||||
},
|
||||
|
||||
fetchNodeInfo(node, type) {
|
||||
return type === 1 ? this.fetchNodeInfoAllstar(node)
|
||||
: (type === 2 ? this.fetchNodeInfoIRLP(node) : null);
|
||||
},
|
||||
if (type === 0) return;
|
||||
|
||||
fetchNodeInfoAllstar(node) {
|
||||
let info;
|
||||
return info;
|
||||
},
|
||||
// Bind it and recurse, fetch it again
|
||||
// if (typeof this.nodes[type][node] === "undefined") {
|
||||
// this.nodes[type][node] = null;
|
||||
// return this.fetchNodeInfo(node, type);
|
||||
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) {
|
||||
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 {
|
||||
padding: 1em;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.text-center {
|
||||
@ -16,7 +17,32 @@
|
||||
}
|
||||
|
||||
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%;
|
||||
}
|
||||
|
||||
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 */
|
||||
|
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="text-center">
|
||||
<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 class="content-wrapper">
|
||||
<div class="content">
|
||||
<table class="pure-table logs">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Node #</th>
|
||||
<th>Via Node</th>
|
||||
<th>Node#</th>
|
||||
<th>Via</th>
|
||||
<th>Type</th>
|
||||
<th>Description</th>
|
||||
<th>Date/Time</th>
|
||||
<th>When</th>
|
||||
<th class="desc">Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody v-cloak>
|
||||
<tr v-for="row in logs">
|
||||
<td>{{ row.node }}</td>
|
||||
<td>{{ row.via }}</td>
|
||||
<td><lt-node-link :node="row.node" :type="row.type" /></td>
|
||||
<td><lt-node-link :node="row.via" :type="row.type" /></td>
|
||||
<td>{{ row.typeLabel }}</td>
|
||||
<td>{{ fetchNodeInfo(row.node) }}</td>
|
||||
<td>{{ row.dateTime }}</td>
|
||||
<td class="when">{{ row.dateTime.format('hh:mm:ss MM/DD/YY') }}</td>
|
||||
<td>
|
||||
{{ getNodeInfo(row.node, row.type) }}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</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/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="app.js" type="text/javascript"></script>
|
||||
</body>
|
||||
|
Loading…
Reference in New Issue
Block a user