Compare commits

...

14 Commits

Author SHA1 Message Date
02e8a102d3 Missing Files 2025-04-11 18:40:29 +02:00
27fda231ea lockb 2025-04-11 18:20:54 +02:00
Joerg (DJ7NT)
1a70eb6aa5 Update Dockerfile 2025-04-11 18:19:19 +02:00
Joerg (DJ7NT)
bf4d7fd3ee Update Dockerfile 2025-04-11 18:18:27 +02:00
fb0fb2e508 Dockerizing... 2025-04-11 18:08:31 +02:00
2175a55a61 Added prefix, port, host 2025-04-11 17:39:53 +02:00
e620f2532d Merge remote-tracking branch 'int/dev' into dev 2025-04-11 14:45:44 +02:00
b2981fd54f In JS/Browser Filtering on own call 2025-04-11 12:45:11 +00:00
4aae8d743c Friendly debuggng/verbosity at console 2025-04-11 12:24:59 +00:00
90115079a3 Merge remote-tracking branch 'int/dev' into dev 2025-04-11 12:35:31 +02:00
d5de48350c Config-item for it 2025-04-11 08:36:46 +00:00
21af41467e Glonal en/disabling of whitelist 2025-04-11 08:36:24 +00:00
fdcb58493a Typo 2025-04-10 10:51:54 +02:00
a05656efff Documentation 2025-04-10 10:42:17 +02:00
7 changed files with 128 additions and 72 deletions

33
Dockerfile Normal file
View 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" ]

View File

@@ -2,10 +2,14 @@
# Install:
1. git clone it
2. you need nodeJS / npm or bun
2. you need nodeJS / npm or [bun](https://bun.sh/docs/installation)
3. `npm install` or `bun i`
4. rename config.js.sample to config.js
5. adjust config.js to your local MQTT-Broker
6. ` node ./mqtt.js` or `bun ./mqtt.js`
7. Point browser to localhost:8000
8. Enjoy streaming
# Prerequisites:
* MQTT Server (`apt install mosquitto` or docker-mosquitto)
* MQTT-Streaming at wavelog enabled (`config.php`-switch: `$config['mqtt_server']='your_mosquitto_server';`)

BIN
bun.lockb Executable file

Binary file not shown.

View File

@@ -2,7 +2,11 @@ const config = {
mqttserver: {
host: "mqtt://[your mqtt-server here]"
},
whitelist_url: "https://laber"
prefix: "",
whitelist_url: "https://laber",
whitelist_enabled: false,
webport: 8000,
webbind:"0.0.0.0"
};
module.exports = config;

11
docker-compose.yaml Normal file
View 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

View File

@@ -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(':');

35
mqtt.js
View File

@@ -6,13 +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);
@@ -41,7 +41,7 @@ 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 (whitelist.whitelist.includes(msg.content.user_name)) {
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) {
@@ -56,7 +56,7 @@ mqttC.on('message', function (topic, message) { // Handler, wenn mqtt-message ko
} 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(topic+' / CAT for User '+tobrowser.user_id+' ('+msg.content.user_name+') at '+tobrowser.qrg+' in Mode '+tobrowser.mode);
}
} else {
console.log(msg.content.user_name+' not in Whitelist');
@@ -81,15 +81,17 @@ function parse_cat_msg(topic,msg) {
}
async function getWhitelist() {
try {
const response = await fetch(config.whitelist_url);
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
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);
}
const data = await response.json();
whitelist = data;
} catch (error) {
console.error('Error fetching JSON data:', error);
}
}
@@ -114,9 +116,10 @@ const dinmin = (timestamp) => {
function startup() {
getWhitelist();
http.listen(8000,'127.0.0.1', () => { // Webserver starten
console.log(`Socket.IO server running at http://localhost:8000/`); // debug
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();