Compare commits
15 Commits
a05656efff
...
dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
02e8a102d3
|
|||
|
27fda231ea
|
|||
|
|
1a70eb6aa5 | ||
|
|
bf4d7fd3ee | ||
|
fb0fb2e508
|
|||
|
2175a55a61
|
|||
|
e620f2532d
|
|||
| b2981fd54f | |||
| 4aae8d743c | |||
|
90115079a3
|
|||
| d5de48350c | |||
| 21af41467e | |||
| c60764fa66 | |||
| d928d93d25 | |||
|
fdcb58493a
|
33
Dockerfile
Normal file
33
Dockerfile
Normal file
@@ -0,0 +1,33 @@
|
||||
# use the official Bun image
|
||||
# see all versions at https://hub.docker.com/r/oven/bun/tags
|
||||
FROM oven/bun:1 as base
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
# install dependencies into temp directory
|
||||
# this will cache them and speed up future builds
|
||||
FROM base AS install
|
||||
RUN mkdir -p /temp/dev
|
||||
COPY package.json bun.lockb /temp/dev/
|
||||
RUN cd /temp/dev && bun install --frozen-lockfile
|
||||
|
||||
# install with --production (exclude devDependencies)
|
||||
RUN mkdir -p /temp/prod
|
||||
COPY package.json bun.lockb /temp/prod/
|
||||
RUN cd /temp/prod && bun install --frozen-lockfile --production
|
||||
|
||||
# copy node_modules from temp directory
|
||||
# then copy all (non-ignored) project files into the image
|
||||
FROM base AS prerelease
|
||||
COPY --from=install /temp/dev/node_modules node_modules
|
||||
COPY . .
|
||||
|
||||
# copy production dependencies and source code into final image
|
||||
FROM base AS release
|
||||
COPY --from=install /temp/prod/node_modules node_modules
|
||||
COPY --from=prerelease /usr/src/app/mqtt.js .
|
||||
COPY --from=prerelease /usr/src/app/package.json .
|
||||
COPY --from=prerelease /usr/src/app/index.html .
|
||||
|
||||
# run the app
|
||||
USER bun
|
||||
ENTRYPOINT [ "bun", "run", "mqtt.js" ]
|
||||
@@ -10,6 +10,6 @@
|
||||
7. Point browser to localhost:8000
|
||||
8. Enjoy streaming
|
||||
|
||||
# Prequisites:
|
||||
# Prerequisites:
|
||||
* MQTT Server (`apt install mosquitto` or docker-mosquitto)
|
||||
* MQTT-Streaming at wavelog enabled (`config.php`-switch: `$config['mqtt_server']='your_mosquitto_server';`)
|
||||
* MQTT-Streaming at wavelog enabled (`config.php`-switch: `$config['mqtt_server']='your_mosquitto_server';`)
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
const config = {
|
||||
mqttserver: {
|
||||
host: "mqtt://[your mqtt-server here]"
|
||||
}
|
||||
mqttserver: {
|
||||
host: "mqtt://[your mqtt-server here]"
|
||||
},
|
||||
prefix: "",
|
||||
whitelist_url: "https://laber",
|
||||
whitelist_enabled: false,
|
||||
webport: 8000,
|
||||
webbind:"0.0.0.0"
|
||||
};
|
||||
|
||||
module.exports = config;
|
||||
|
||||
11
docker-compose.yaml
Normal file
11
docker-compose.yaml
Normal file
@@ -0,0 +1,11 @@
|
||||
version: '3'
|
||||
services:
|
||||
liveqso:
|
||||
build:
|
||||
dockerfile: ./Dockerfile
|
||||
container_name: liveqso
|
||||
ports:
|
||||
- 8098:8000 # Exposed port - see WEBPORT above
|
||||
volumes:
|
||||
- ./config.js:/usr/src/app/config.js:U
|
||||
restart: unless-stopped
|
||||
109
index.html
109
index.html
@@ -1,10 +1,9 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<base href="/">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<script src="/jquery/jquery.min.js"></script>
|
||||
<script src="/socket.io/socket.io.js"></script>
|
||||
<style type="text/css" rel="stylesheet">
|
||||
<style type="text/css">
|
||||
#mqtt{ border: 1px solid #444; overflow-x:hidden; overflow-y:auto; background-color:#333; color: #EEE; text-shadow:#000 0 0 2px; height: 400px; padding: 10px; font-size:12px; line-height:20px;}
|
||||
.monospace{font-family: Monaco,"Bitstream Vera Sans Mono","Lucida Console",Terminal,monospace;}
|
||||
.selection::selection , .selection *::selection{background: #EEE;color:#000;border-color:#000; text-shadow:#fff 0 0 2px;}
|
||||
@@ -46,66 +45,68 @@
|
||||
</tbody>
|
||||
</table>
|
||||
<script type="text/javascript">
|
||||
const base = document.querySelector('base');
|
||||
if (base) {
|
||||
base.href = window.location.pathname;
|
||||
}
|
||||
document.write(`<script src="${base.href}/jquery/jquery.min.js"><\/script>`);
|
||||
document.write(`<script src="${base.href}/socket.io/socket.io.js"><\/script>`);
|
||||
</script>
|
||||
<script type="text/javascript" defer>
|
||||
(function() {
|
||||
const queryString = window.location.search;
|
||||
const urlParams = new URLSearchParams(queryString);
|
||||
const filter = urlParams.get('call') || '';
|
||||
const tableBody = document.getElementById('messagesTable').querySelector('tbody');
|
||||
var lines = 0;
|
||||
var buffer = $('#mqtt');
|
||||
var socket = io.connect("/"); // http://localhost:8000");
|
||||
var socket = io.connect({ path: window.location.pathname+"/socket.io" }); // http://localhost:8000");
|
||||
socket.on('connect', function() {
|
||||
console.log('Connected to:', socket.host);
|
||||
});
|
||||
console.log('Connected to:', socket.host);
|
||||
});
|
||||
socket.on('mqtt', function(message) {
|
||||
try {
|
||||
showit=JSON.stringify(message);
|
||||
} catch {};
|
||||
const row = document.createElement('tr');
|
||||
const timestampCell = document.createElement('td');
|
||||
const CellCall = document.createElement('td');
|
||||
const CellGrid = document.createElement('td');
|
||||
const CellStationCall = document.createElement('td');
|
||||
const CellStationGrid = document.createElement('td');
|
||||
const CellBand = document.createElement('td');
|
||||
const CellQRG = document.createElement('td');
|
||||
const CellMode = document.createElement('td');
|
||||
const CellRSTR = document.createElement('td');
|
||||
const CellRSTS = document.createElement('td');
|
||||
if ((filter == '') || (filter == message.station_call)) {
|
||||
const row = document.createElement('tr');
|
||||
const timestampCell = document.createElement('td');
|
||||
const CellCall = document.createElement('td');
|
||||
const CellGrid = document.createElement('td');
|
||||
const CellStationCall = document.createElement('td');
|
||||
const CellStationGrid = document.createElement('td');
|
||||
const CellBand = document.createElement('td');
|
||||
const CellQRG = document.createElement('td');
|
||||
const CellMode = document.createElement('td');
|
||||
const CellRSTR = document.createElement('td');
|
||||
const CellRSTS = document.createElement('td');
|
||||
|
||||
CellCall.textContent = message.call;
|
||||
CellGrid.textContent = message.grid;
|
||||
CellStationCall.textContent = message.station_call;
|
||||
CellStationGrid.textContent = message.station_grid;
|
||||
CellBand.textContent = message.band;
|
||||
CellQRG.textContent = message.qrg;
|
||||
CellMode.textContent = message.mode;
|
||||
CellRSTR.textContent = message.RST_RCVD;
|
||||
CellRSTS.textContent = message.RST_SENT;
|
||||
timestampCell.textContent = tsclean(message.qso_time);
|
||||
CellCall.textContent = message.call;
|
||||
CellGrid.textContent = message.grid;
|
||||
CellStationCall.textContent = message.station_call;
|
||||
CellStationGrid.textContent = message.station_grid;
|
||||
CellBand.textContent = message.band;
|
||||
CellQRG.textContent = message.qrg;
|
||||
CellMode.textContent = message.mode;
|
||||
CellRSTR.textContent = message.RST_RCVD;
|
||||
CellRSTS.textContent = message.RST_SENT;
|
||||
timestampCell.textContent = tsclean(message.qso_time);
|
||||
|
||||
row.appendChild(timestampCell);
|
||||
row.appendChild(CellStationCall);
|
||||
row.appendChild(CellStationGrid);
|
||||
row.appendChild(CellCall);
|
||||
row.appendChild(CellGrid);
|
||||
row.appendChild(CellBand);
|
||||
row.appendChild(CellQRG);
|
||||
row.appendChild(CellMode);
|
||||
row.appendChild(CellRSTR);
|
||||
row.appendChild(CellRSTS);
|
||||
row.classList.add('new-row');
|
||||
tableBody.insertBefore(row, tableBody.firstChild);
|
||||
setTimeout(() => {
|
||||
row.classList.remove('new-row');
|
||||
}, 1500);
|
||||
|
||||
});
|
||||
|
||||
/*
|
||||
$( "#i_topic" ).change(function() {
|
||||
socket.emit("wishtopic",this.value);
|
||||
$('#mqtt').empty();
|
||||
});
|
||||
*/
|
||||
row.appendChild(timestampCell);
|
||||
row.appendChild(CellStationCall);
|
||||
row.appendChild(CellStationGrid);
|
||||
row.appendChild(CellCall);
|
||||
row.appendChild(CellGrid);
|
||||
row.appendChild(CellBand);
|
||||
row.appendChild(CellQRG);
|
||||
row.appendChild(CellMode);
|
||||
row.appendChild(CellRSTR);
|
||||
row.appendChild(CellRSTS);
|
||||
row.classList.add('new-row');
|
||||
tableBody.insertBefore(row, tableBody.firstChild);
|
||||
setTimeout(() => {
|
||||
row.classList.remove('new-row');
|
||||
}, 1500);
|
||||
}
|
||||
|
||||
});
|
||||
})();
|
||||
function tsclean(timestamp) {
|
||||
const parts = timestamp.split(':');
|
||||
|
||||
64
mqtt.js
64
mqtt.js
@@ -6,12 +6,13 @@ const path = require('path');
|
||||
const express = require('express');
|
||||
const app = express(); // http-express framework laden (macht routing, etc.)
|
||||
const http = require('http').Server(app); // http-server module laden
|
||||
const io = require('socket.io')(http); // socket.io einbinden
|
||||
const io = require('socket.io')(http, {path: `${config.prefix}/socket.io`,}); // socket.io einbinden
|
||||
var whitelist=[];
|
||||
|
||||
app.use('/jquery', express.static(path.join(__dirname, 'node_modules', 'jquery', 'dist')));
|
||||
app.use(config.prefix+'/jquery', express.static(path.join(__dirname, 'node_modules', 'jquery', 'dist')));
|
||||
|
||||
app.get('/', (req, res) => { // Routing fuer index.html
|
||||
res.sendFile(__dirname + '/index.html'); // index.html rauspusten
|
||||
app.get(config.prefix+'/', (req, res) => {
|
||||
res.sendFile(__dirname + '/index.html');
|
||||
});
|
||||
|
||||
const mqttC=mqtt.connect(mqttserver);
|
||||
@@ -40,21 +41,25 @@ mqttC.on('message', function (topic, message) { // Handler, wenn mqtt-message ko
|
||||
} else {
|
||||
msg.content=message.toString(); // Ist nix json? dann ab in "content" damit
|
||||
}
|
||||
if (topic.startsWith('wavelog/qso/logged')) {
|
||||
tobrowser=parse_qso_msg(msg.content);
|
||||
if (tobrowser.qso_time) {
|
||||
tobrowser.qso_age=dinmin(tobrowser.qso_time);
|
||||
if (tobrowser.qso_age<=10) {
|
||||
io.emit("mqtt",tobrowser); // und raus an den Browser (nur fuer DIESES Socket, nicht fuer alle Clients) damit
|
||||
if (!(config.whitelist_enabled) || (whitelist.whitelist.includes(msg.content.user_name))) {
|
||||
if (topic.startsWith('wavelog/qso/logged')) {
|
||||
tobrowser=parse_qso_msg(msg.content);
|
||||
if (tobrowser.qso_time) {
|
||||
tobrowser.qso_age=dinmin(tobrowser.qso_time);
|
||||
if (tobrowser.qso_age<=10) {
|
||||
io.emit("mqtt",tobrowser); // und raus an den Browser (nur fuer DIESES Socket, nicht fuer alle Clients) damit
|
||||
}
|
||||
} else {
|
||||
console.log("No Timestamp!");
|
||||
}
|
||||
console.log(topic+' / QSO from: '+tobrowser.station_call+' with '+tobrowser.call+' in Mode: '+tobrowser.mode+' at '+tobrowser.qso_time);
|
||||
} else {
|
||||
console.log("No Timestamp!");
|
||||
tobrowser=parse_cat_msg(topic,msg.content);
|
||||
// io.emit("cat",tobrowser); // und raus an den Browser (nur fuer DIESES Socket, nicht fuer alle Clients) damit
|
||||
console.log(topic+' / CAT for User '+tobrowser.user_id+' ('+msg.content.user_name+') at '+tobrowser.qrg+' in Mode '+tobrowser.mode);
|
||||
}
|
||||
console.log(topic+' / QSO from: '+tobrowser.station_call+' with '+tobrowser.call+' in Mode: '+tobrowser.mode+' at '+tobrowser.qso_time);
|
||||
} else {
|
||||
tobrowser=parse_cat_msg(topic,msg.content);
|
||||
// io.emit("cat",tobrowser); // und raus an den Browser (nur fuer DIESES Socket, nicht fuer alle Clients) damit
|
||||
console.log(topic+' / CAT for User '+tobrowser.user_id+' at '+tobrowser.qrg+' in Mode '+tobrowser.mode);
|
||||
console.log(msg.content.user_name+' not in Whitelist');
|
||||
}
|
||||
});
|
||||
|
||||
@@ -75,6 +80,21 @@ function parse_cat_msg(topic,msg) {
|
||||
return retmsg;
|
||||
}
|
||||
|
||||
async function getWhitelist() {
|
||||
if (config.whitelist_enabled) {
|
||||
try {
|
||||
const response = await fetch(config.whitelist_url);
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! Status: ${response.status}`);
|
||||
}
|
||||
const data = await response.json();
|
||||
whitelist = data;
|
||||
} catch (error) {
|
||||
console.error('Error fetching JSON data:', error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function parse_qso_msg(msg) {
|
||||
let retmsg={};
|
||||
retmsg.call=msg.COL_CALL;
|
||||
@@ -91,9 +111,15 @@ function parse_qso_msg(msg) {
|
||||
}
|
||||
|
||||
const dinmin = (timestamp) => {
|
||||
return Math.floor((Date.now() - new Date(timestamp).getTime()) / 60000);
|
||||
return Math.floor((Date.now() - new Date(timestamp).getTime()) / 60000);
|
||||
}
|
||||
|
||||
http.listen(8000,'127.0.0.1', () => { // Webserver starten
|
||||
console.log(`Socket.IO server running at http://localhost:8000/`); // debug
|
||||
});
|
||||
function startup() {
|
||||
getWhitelist();
|
||||
http.listen(config.webport,config.webbind, () => { // Webserver starten
|
||||
console.log(`Socket.IO server running at http://${config.webbind}:${config.webport}`); // debug
|
||||
});
|
||||
const intervalID = setInterval(getWhitelist,5*60*1000);
|
||||
}
|
||||
|
||||
startup();
|
||||
|
||||
Reference in New Issue
Block a user