compose.yml für dockge dazu
This commit is contained in:
17
Dockerfile
Normal file
17
Dockerfile
Normal file
@@ -0,0 +1,17 @@
|
||||
FROM node:20-alpine
|
||||
|
||||
WORKDIR /opt/app
|
||||
|
||||
RUN apk add --no-cache tzdata
|
||||
ENV TZ=Europe/Berlin
|
||||
ENV NODE_ENV=production
|
||||
|
||||
COPY package*.json ./
|
||||
RUN npm ci --omit=dev
|
||||
|
||||
COPY . .
|
||||
|
||||
EXPOSE 3011
|
||||
|
||||
CMD ["npm", "start"]
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
FROM node:9-alpine
|
||||
|
||||
WORKDIR /opt/app
|
||||
ADD . /opt/app
|
||||
|
||||
RUN apk add --no-cache tzdata
|
||||
ENV TZ Europe/Berlin
|
||||
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
|
||||
|
||||
RUN touch cmds.sh \
|
||||
&& echo 'npm start' >>cmds.sh
|
||||
|
||||
EXPOSE 3011
|
||||
|
||||
CMD sh ./cmds.sh
|
||||
|
||||
36
compose.yml
Normal file
36
compose.yml
Normal file
@@ -0,0 +1,36 @@
|
||||
# Docker Compose für Production Server mit Traefik
|
||||
services:
|
||||
laufschrift:
|
||||
image: docker.citysensor.de/laufschrift:latest
|
||||
container_name: laufschrift
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- NODE_ENV=production
|
||||
- MQTTHOST=${MQTTHOST:-localhost}
|
||||
- MQTTPORT=${MQTTPORT:-1883}
|
||||
- MQTTUSR=${MQTTUSR:-}
|
||||
- MQTTPWD=${MQTTPWD:-}
|
||||
- TOPIC=${TOPIC:-sonoff}
|
||||
- SWITCH_API_TOKEN=${SWITCH_API_TOKEN:-}
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- traefik.http.routers.laufschrift.entrypoints=http
|
||||
- traefik.http.routers.laufschrift.rule=Host(`laufschrift.fuerst-stuttgart.de`)
|
||||
- traefik.http.middlewares.laufschrift-https-redirect.redirectscheme.scheme=https
|
||||
- traefik.http.routers.laufschrift.middlewares=laufschrift-https-redirect
|
||||
- traefik.http.routers.laufschrift-secure.entrypoints=https
|
||||
- traefik.http.routers.laufschrift-secure.rule=Host(`laufschrift.fuerst-stuttgart.de`)
|
||||
- traefik.http.routers.laufschrift-secure.tls=true
|
||||
- traefik.http.routers.laufschrift-secure.tls.certresolver=letsencrypt
|
||||
- traefik.http.routers.laufschrift-secure.service=laufschrift
|
||||
- traefik.http.services.laufschrift.loadbalancer.server.port=3000
|
||||
networks:
|
||||
- proxy
|
||||
- gitea-internal
|
||||
networks:
|
||||
proxy:
|
||||
name: dockge_default
|
||||
external: true
|
||||
gitea-internal:
|
||||
name: gitea_gitea-internal
|
||||
external: true
|
||||
66
deploy.sh
Executable file
66
deploy.sh
Executable file
@@ -0,0 +1,66 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Deploy Script für laufschrift
|
||||
# Baut das Docker Image und lädt es zu docker.citysensor.de hoch
|
||||
|
||||
set -e
|
||||
|
||||
# Konfiguration
|
||||
REGISTRY="docker.citysensor.de"
|
||||
IMAGE_NAME="laufschrift"
|
||||
TAG="${TAG:-$(date +%Y%m%d%H%M)}" # default Datum
|
||||
FULL_IMAGE="${REGISTRY}/${IMAGE_NAME}:${TAG}"
|
||||
|
||||
# Build-Datum
|
||||
BUILD_DATE=$(date +%d.%m.%Y)
|
||||
|
||||
echo "=========================================="
|
||||
echo "Laufschrift Deploy Script"
|
||||
echo "=========================================="
|
||||
echo "Registry: ${REGISTRY}"
|
||||
echo "Image: ${IMAGE_NAME}"
|
||||
echo "Tag: ${TAG}"
|
||||
echo "Build-Datum: ${BUILD_DATE}"
|
||||
echo "=========================================="
|
||||
echo ""
|
||||
|
||||
# 1. Login zur Registry (falls noch nicht eingeloggt)
|
||||
echo ">>> Login zu ${REGISTRY}..."
|
||||
docker login "${REGISTRY}"
|
||||
echo ""
|
||||
|
||||
# 2. Multiplatform Builder einrichten (docker-container driver erforderlich)
|
||||
echo ">>> Richte Multiplatform Builder ein..."
|
||||
if ! docker buildx inspect multiplatform-builder &>/dev/null; then
|
||||
docker buildx create --name multiplatform-builder --driver docker-container --bootstrap
|
||||
fi
|
||||
docker buildx use multiplatform-builder
|
||||
echo ""
|
||||
|
||||
# 3. Docker Image bauen und pushen (Multiplatform)
|
||||
echo ">>> Baue Multiplatform Docker Image und pushe zu Registry..."
|
||||
docker buildx build \
|
||||
--platform linux/amd64,linux/arm64 \
|
||||
--build-arg BUILD_DATE="${BUILD_DATE}" \
|
||||
-t "${FULL_IMAGE}" \
|
||||
--push \
|
||||
.
|
||||
|
||||
# 4. Keep :latest in sync for simple rollbacks and manual usage.
|
||||
echo ">>> Tagge das image zusätzlich als :latest ..."
|
||||
docker buildx imagetools create \
|
||||
-t "${REGISTRY}/${IMAGE_NAME}:latest" \
|
||||
"${FULL_IMAGE}"
|
||||
|
||||
|
||||
echo ">>> Build und Push erfolgreich!"
|
||||
|
||||
echo ""
|
||||
echo "=========================================="
|
||||
echo "✓ Deploy erfolgreich abgeschlossen!"
|
||||
echo "=========================================="
|
||||
echo ""
|
||||
echo "Auf dem Server ausführen:"
|
||||
echo " docker pull ${FULL_IMAGE}"
|
||||
echo " docker-compose -f docker-compose.prod.yml up -d"
|
||||
echo ""
|
||||
60
deploy_citysensor.sh
Executable file
60
deploy_citysensor.sh
Executable file
@@ -0,0 +1,60 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# Deploys laufschrift to docker.citysensor.de by:
|
||||
# 1) building and pushing a multi-platform image
|
||||
# 2) syncing compose/env files to the remote host
|
||||
# 3) pulling and restarting the service remotely
|
||||
|
||||
REMOTE_HOST="${REMOTE_HOST:-docker.citysensor.de}"
|
||||
REMOTE_USER="${REMOTE_USER:-rxf}"
|
||||
REMOTE_PORT="${REMOTE_PORT:-22022}"
|
||||
REMOTE_DIR="${REMOTE_DIR:-/opt/laufschrift}"
|
||||
|
||||
IMAGE_REPO="${IMAGE_REPO:-gitea.fuerst-stuttgart.de/admin/laufschrift}"
|
||||
IMAGE_TAG="${IMAGE_TAG:-$(date +%Y%m%d%H%M)}"
|
||||
PLATFORMS="${PLATFORMS:-linux/amd64,linux/arm64}"
|
||||
|
||||
DEPLOY_ENV_FILE="${DEPLOY_ENV_FILE:-.env}"
|
||||
BUILD_PUSH="${BUILD_PUSH:-1}"
|
||||
|
||||
FULL_IMAGE="${IMAGE_REPO}:${IMAGE_TAG}"
|
||||
REMOTE="${REMOTE_USER}@${REMOTE_HOST}"
|
||||
|
||||
if [[ ! -f "docker-compose.yml" ]]; then
|
||||
echo "ERROR: docker-compose.yml not found in current directory."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! -f "${DEPLOY_ENV_FILE}" ]]; then
|
||||
echo "ERROR: ${DEPLOY_ENV_FILE} not found."
|
||||
echo " Create it first, e.g. from .env.example"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "${BUILD_PUSH}" == "1" ]]; then
|
||||
echo "==> Building and pushing multi-platform image: ${FULL_IMAGE}"
|
||||
docker buildx build \
|
||||
--platform "${PLATFORMS}" \
|
||||
-f Dockerfile_laufschrift \
|
||||
-t "${FULL_IMAGE}" \
|
||||
--push \
|
||||
.
|
||||
|
||||
# Keep :latest in sync for simple rollbacks and manual usage.
|
||||
docker buildx imagetools create \
|
||||
-t "${IMAGE_REPO}:latest" \
|
||||
"${FULL_IMAGE}"
|
||||
fi
|
||||
|
||||
echo "==> Syncing compose and env to ${REMOTE}:${REMOTE_DIR}"
|
||||
ssh -p "${REMOTE_PORT}" "${REMOTE}" "mkdir -p '${REMOTE_DIR}'"
|
||||
scp -P "${REMOTE_PORT}" docker-compose.yml "${REMOTE}:${REMOTE_DIR}/docker-compose.yml"
|
||||
scp -P "${REMOTE_PORT}" "${DEPLOY_ENV_FILE}" "${REMOTE}:${REMOTE_DIR}/.env"
|
||||
|
||||
echo "==> Deploying ${FULL_IMAGE} on ${REMOTE_HOST}"
|
||||
ssh -p "${REMOTE_PORT}" "${REMOTE}" "cd '${REMOTE_DIR}' && IMAGE='${FULL_IMAGE}' docker compose pull app && IMAGE='${FULL_IMAGE}' docker compose up -d --no-build --remove-orphans"
|
||||
|
||||
echo "==> Deployment finished"
|
||||
echo " Host: ${REMOTE_HOST}"
|
||||
echo " Image: ${FULL_IMAGE}"
|
||||
20
docker-compose.yml
Normal file
20
docker-compose.yml
Normal file
@@ -0,0 +1,20 @@
|
||||
|
||||
services:
|
||||
app:
|
||||
image: docker.citysensor.de/laufschrift:latest
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
platforms:
|
||||
- linux/amd64
|
||||
- linux/arm64
|
||||
ports:
|
||||
- "3011:3011"
|
||||
environment:
|
||||
MQTTHOST: ${MQTTHOST:-localhost}
|
||||
MQTTPORT: ${MQTTPORT:-1883}
|
||||
MQTTUSR: ${MQTTUSR:-}
|
||||
MQTTPWD: ${MQTTPWD:-}
|
||||
TOPIC: ${TOPIC:-sonoff}
|
||||
SWITCH_API_TOKEN: ${SWITCH_API_TOKEN:-}
|
||||
restart: unless-stopped
|
||||
2787
package-lock.json
generated
2787
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
21
package.json
21
package.json
@@ -1,19 +1,18 @@
|
||||
{
|
||||
"name": "laufschrift",
|
||||
"version": "0.0.0",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"start": "node ./bin/www >>/var/log/laufschrift.log 2>&1"
|
||||
"start": "node ./bin/www"
|
||||
},
|
||||
"dependencies": {
|
||||
"await-fs": "^1.0.0",
|
||||
"cookie-parser": "~1.4.3",
|
||||
"debug": "~2.6.9",
|
||||
"express": "~4.16.0",
|
||||
"http-errors": "~1.6.2",
|
||||
"moment": "^2.24.0",
|
||||
"morgan": "~1.9.0",
|
||||
"mqtt": "^2.18.8",
|
||||
"pug": "^2.0.3"
|
||||
"cookie-parser": "^1.4.7",
|
||||
"debug": "^4.4.3",
|
||||
"express": "^4.22.1",
|
||||
"http-errors": "^2.0.1",
|
||||
"moment": "^2.30.1",
|
||||
"morgan": "^1.10.1",
|
||||
"mqtt": "^5.15.0",
|
||||
"pug": "^3.0.3"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,10 +5,16 @@ $(document).ready(function() {
|
||||
console.log("Es geht los");
|
||||
|
||||
const URL = "switch/";
|
||||
const checktime = 5000000; // alle 30sec Zustand prüfen
|
||||
|
||||
const POLL_INTERVAL_MS = 1000;
|
||||
const queryToken = new URLSearchParams(window.location.search).get('token');
|
||||
const storedToken = localStorage.getItem('switchApiToken');
|
||||
const API_TOKEN = queryToken || storedToken || '';
|
||||
let interval = null;
|
||||
let status = "";
|
||||
let tr;
|
||||
|
||||
if (queryToken) {
|
||||
localStorage.setItem('switchApiToken', queryToken);
|
||||
}
|
||||
|
||||
|
||||
$('#versn').html("V " + VERSION + ' ' + VDATE); // Vesion anzeigen
|
||||
@@ -19,13 +25,13 @@ $(document).ready(function() {
|
||||
// sendCommand(URL,"PowerOnState%200"); // OFF bei Power ON
|
||||
// sendCommand(URL,"PulseTime%20"+(brenndauer+100)); // Brenndauer einstellen
|
||||
|
||||
let interval = setInterval(sendTimedCommand, 1000); // alle Sekunde pollen
|
||||
startPolling();
|
||||
|
||||
document.addEventListener('visibilitychange', function (event) {
|
||||
if (!document.hidden) {
|
||||
interval = setInterval(sendTimedCommand, 1000);
|
||||
startPolling();
|
||||
} else {
|
||||
clearTimeout(interval); // The page is hidden.
|
||||
stopPolling();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -33,8 +39,7 @@ $(document).ready(function() {
|
||||
sendCommand(URL, "get_status")
|
||||
|
||||
$("#schalter").click(function () {
|
||||
let message;
|
||||
if (status == 'ON') {
|
||||
if (status === 'ON') {
|
||||
console.log("Sende OFF")
|
||||
sendCommand(URL, "switch_off")
|
||||
} else {
|
||||
@@ -45,18 +50,36 @@ $(document).ready(function() {
|
||||
|
||||
function sendCommand(url, cmnd) {
|
||||
console.log("sendCommand", cmnd);
|
||||
const p = new Promise((resolve, reject) => {
|
||||
$.getJSON(url + cmnd, function (data, err) { // AJAX Call
|
||||
if (err != 'success') {
|
||||
reject(err);
|
||||
alert("Fehler <br />" + err); // if error, show it
|
||||
} else {
|
||||
let endpoint = url + cmnd;
|
||||
if (API_TOKEN) {
|
||||
endpoint += '?token=' + encodeURIComponent(API_TOKEN);
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
$.getJSON(endpoint)
|
||||
.done(function (data) {
|
||||
console.log("gekommen: ", data);
|
||||
resolve(data);
|
||||
})
|
||||
.fail(function (_jqXHR, textStatus, errorThrown) {
|
||||
const msg = errorThrown || textStatus || "Unbekannter Fehler";
|
||||
reject(msg);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function startPolling() {
|
||||
if (interval !== null) {
|
||||
clearInterval(interval);
|
||||
}
|
||||
interval = setInterval(sendTimedCommand, POLL_INTERVAL_MS);
|
||||
}
|
||||
|
||||
function stopPolling() {
|
||||
if (interval !== null) {
|
||||
clearInterval(interval);
|
||||
interval = null;
|
||||
}
|
||||
});
|
||||
});
|
||||
return p;
|
||||
}
|
||||
|
||||
function sendTimedCommand() {
|
||||
@@ -65,13 +88,12 @@ $(document).ready(function() {
|
||||
.then(data => {
|
||||
// console.log("Timed Status= ", st);
|
||||
status = data.relais;
|
||||
if (status != 'pending') {
|
||||
clearTimeout(tr);
|
||||
if (status == 'ON') {
|
||||
if (status !== 'pending') {
|
||||
if (status === 'ON') {
|
||||
$('#schalter').html('Laufschrift <b>AUS</b> schalten');
|
||||
$('#status').text('EIN');
|
||||
$('#laufzeile').addClass('machrot');
|
||||
if(data.offtime != undefined) {
|
||||
if (data.offtime !== undefined) {
|
||||
$('#auszeit').text(data.offtime);
|
||||
$('#auszeile').show();
|
||||
}
|
||||
@@ -82,6 +104,9 @@ $(document).ready(function() {
|
||||
$('#auszeile').hide();
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
console.log('Statusabfrage fehlgeschlagen:', err);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
235
routes/switch.js
235
routes/switch.js
@@ -1,118 +1,169 @@
|
||||
var express = require('express');
|
||||
let router = express.Router();
|
||||
let mqtt = require('mqtt');
|
||||
let moment = require('moment');
|
||||
const fs = require('await-fs');
|
||||
var router = express.Router();
|
||||
var mqtt = require('mqtt');
|
||||
var moment = require('moment');
|
||||
var fs = require('fs/promises');
|
||||
var crypto = require('crypto');
|
||||
|
||||
var DEFAULT_BRENNDAUER = 300;
|
||||
var brenndauer = DEFAULT_BRENNDAUER;
|
||||
|
||||
const configName = "config.json"
|
||||
var MQTTHOST = process.env.MQTTHOST || 'localhost';
|
||||
var MQTTPORT = process.env.MQTTPORT || 1883;
|
||||
var MQTTUSR = process.env.MQTTUSR || '';
|
||||
var MQTTPWD = process.env.MQTTPWD || '';
|
||||
var TOPIC = process.env.TOPIC || 'sonoff';
|
||||
var SWITCH_API_TOKEN = process.env.SWITCH_API_TOKEN || '';
|
||||
|
||||
var switchOffTimer;
|
||||
var state = {
|
||||
connect: 'disconnected',
|
||||
relais: 'UNKNOWN',
|
||||
offtime: undefined,
|
||||
lastError: undefined
|
||||
};
|
||||
|
||||
let brenndauer = 300; // 20sec Relais ON
|
||||
var client = mqtt.connect('mqtt://' + MQTTHOST + ':' + MQTTPORT, {
|
||||
username: MQTTUSR,
|
||||
password: MQTTPWD
|
||||
});
|
||||
|
||||
// MQTT:
|
||||
let MQTTHOST = process.env.MQTTHOST;
|
||||
let MQTTPORT = process.env.MQTTPORT;
|
||||
let MQTTUSR = process.env.MQTTUSR;
|
||||
let MQTTPWD = process.env.MQTTPWD;
|
||||
let TOPIC=process.env.TOPIC;
|
||||
|
||||
|
||||
if (MQTTHOST === undefined) { MQTTHOST = 'localhost';}
|
||||
if (MQTTPORT === undefined) { MQTTPORT = 1883;}
|
||||
if (MQTTUSR === undefined) { MQTTUSR = "";}
|
||||
if (MQTTPWD === undefined) { MQTTPWD = "";}
|
||||
if (TOPIC === undefined) { TOPIC = "sonoff";}
|
||||
|
||||
/*
|
||||
if (MQTTHOST === undefined) { MQTTHOST = 'laufschrift.rexfue.de';}
|
||||
if (MQTTPORT === undefined) { MQTTPORT = 1883;}
|
||||
if (MQTTUSR === undefined) { MQTTUSR = "stwLauf";}
|
||||
if (MQTTPWD === undefined) { MQTTPWD = "37CrNcgP";}
|
||||
*/
|
||||
// console.log("H",MQTTHOST," P",MQTTPORT," U",MQTTUSR," p",MQTTPWD);
|
||||
|
||||
let tio;
|
||||
let connected = false;
|
||||
let relais = 'MIST';
|
||||
let client = mqtt.connect("mqtt://" + MQTTHOST + ":" + MQTTPORT,{username: MQTTUSR, password: MQTTPWD});
|
||||
let offtime = "";
|
||||
let retur = {};
|
||||
|
||||
console.log("Start: ", moment().format("YYYY-MM-DD HH:mm"));
|
||||
console.log('Start: ', moment().format('YYYY-MM-DD HH:mm'));
|
||||
|
||||
client.on('connect', function() {
|
||||
connected = true;
|
||||
retur.connect = 'connected';
|
||||
client.subscribe('stat/'+TOPIC+'/POWER');
|
||||
})
|
||||
|
||||
client.on('message',function(topix,message) {
|
||||
relais = message.toString();
|
||||
console.log("Status = ",relais);
|
||||
if (relais == 'OFF') {
|
||||
delete retur.offtime;
|
||||
state.connect = 'connected';
|
||||
state.lastError = undefined;
|
||||
client.subscribe('stat/' + TOPIC + '/POWER', function(err) {
|
||||
if (err) {
|
||||
state.lastError = 'subscribe failed: ' + err.message;
|
||||
}
|
||||
retur.relais = relais;
|
||||
});
|
||||
});
|
||||
|
||||
client.on('reconnect', function(){
|
||||
retur.connect = 'reconnect';
|
||||
client.on('reconnect', function() {
|
||||
state.connect = 'reconnect';
|
||||
});
|
||||
|
||||
client.on('offline', function() {
|
||||
state.connect = 'offline';
|
||||
});
|
||||
|
||||
// Konfig einlesen und entsprechende Variablen einstellen
|
||||
(async () => {
|
||||
try{
|
||||
let json = await fs.readFile('config/config.json','utf8')
|
||||
js = JSON.parse(json);
|
||||
if(js.brenndauer != undefined) {
|
||||
brenndauer = js.brenndauer;
|
||||
client.on('error', function(err) {
|
||||
state.lastError = err.message;
|
||||
});
|
||||
|
||||
client.on('message', function(_topic, message) {
|
||||
state.relais = message.toString();
|
||||
if (state.relais === 'OFF') {
|
||||
state.offtime = undefined;
|
||||
}
|
||||
console.log(brenndauer);
|
||||
}catch(err){
|
||||
console.log(err)
|
||||
}
|
||||
})()
|
||||
|
||||
|
||||
// beim start mal den Zustand abfragen
|
||||
doPublish("");
|
||||
});
|
||||
|
||||
function getResponse() {
|
||||
return {
|
||||
connect: state.connect,
|
||||
relais: state.relais,
|
||||
offtime: state.offtime,
|
||||
lastError: state.lastError
|
||||
};
|
||||
}
|
||||
|
||||
function doPublish(payload) {
|
||||
// retur.relais='pending';
|
||||
client.publish('cmnd/'+TOPIC+'/Power',payload);
|
||||
if (payload == 'On') {
|
||||
offtime = moment().add(brenndauer, 's').format("HH.mm");
|
||||
tio = setTimeout(doPublish, brenndauer * 1000, "Off");
|
||||
retur.offtime = offtime;
|
||||
} else if (payload == 'Off') {
|
||||
clearTimeout(tio);
|
||||
client.publish('cmnd/' + TOPIC + '/Power', payload, function(err) {
|
||||
if (err) {
|
||||
state.lastError = err.message;
|
||||
}
|
||||
});
|
||||
|
||||
if (payload === 'On') {
|
||||
clearTimeout(switchOffTimer);
|
||||
state.offtime = moment().add(brenndauer, 's').format('HH.mm');
|
||||
switchOffTimer = setTimeout(doPublish, brenndauer * 1000, 'Off');
|
||||
} else if (payload === 'Off') {
|
||||
clearTimeout(switchOffTimer);
|
||||
state.offtime = undefined;
|
||||
}
|
||||
}
|
||||
// end MQTT
|
||||
|
||||
/* GET switch data */
|
||||
router.get('/:cmd', function(req, res, next) {
|
||||
let cmd = req.params.cmd;
|
||||
let wert = req.query.wert;
|
||||
|
||||
if (cmd == 'get_status') {
|
||||
doPublish("");
|
||||
} else if (cmd == 'switch_on') {
|
||||
doPublish("On");
|
||||
} else if (cmd == 'switch_off') {
|
||||
doPublish("Off");
|
||||
} else if (cmd == 'check') {
|
||||
|
||||
} else {
|
||||
retur = { error: "invalid command"};
|
||||
res.json(retur);
|
||||
// Read optional runtime config.
|
||||
(async function loadConfig() {
|
||||
try {
|
||||
var json = await fs.readFile('config/config.json', 'utf8');
|
||||
var cfg = JSON.parse(json);
|
||||
if (cfg.brenndauer !== undefined) {
|
||||
brenndauer = Number(cfg.brenndauer) || DEFAULT_BRENNDAUER;
|
||||
}
|
||||
console.log("return: ",retur)
|
||||
res.json(retur);
|
||||
} catch (err) {
|
||||
state.lastError = 'config load failed: ' + err.message;
|
||||
}
|
||||
})();
|
||||
|
||||
// Query initial state once at startup.
|
||||
doPublish('');
|
||||
|
||||
function timingSafeEqualString(a, b) {
|
||||
var aBuf = Buffer.from(String(a));
|
||||
var bBuf = Buffer.from(String(b));
|
||||
if (aBuf.length !== bBuf.length) {
|
||||
return false;
|
||||
}
|
||||
return crypto.timingSafeEqual(aBuf, bBuf);
|
||||
}
|
||||
|
||||
function extractRequestToken(req) {
|
||||
var authHeader = req.get('authorization') || '';
|
||||
if (authHeader.startsWith('Bearer ')) {
|
||||
return authHeader.slice(7).trim();
|
||||
}
|
||||
|
||||
var apiKeyHeader = req.get('x-api-key');
|
||||
if (apiKeyHeader) {
|
||||
return apiKeyHeader;
|
||||
}
|
||||
|
||||
if (typeof req.query.token === 'string') {
|
||||
return req.query.token;
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
router.use(function(req, res, next) {
|
||||
if (!SWITCH_API_TOKEN) {
|
||||
return next();
|
||||
}
|
||||
|
||||
var providedToken = extractRequestToken(req);
|
||||
if (!providedToken || !timingSafeEqualString(providedToken, SWITCH_API_TOKEN)) {
|
||||
return res.status(401).json({ error: 'unauthorized' });
|
||||
}
|
||||
|
||||
return next();
|
||||
});
|
||||
|
||||
router.get('/:cmd', function(req, res) {
|
||||
var cmd = req.params.cmd;
|
||||
|
||||
if (cmd === 'get_status') {
|
||||
doPublish('');
|
||||
return res.json(getResponse());
|
||||
}
|
||||
|
||||
if (cmd === 'switch_on') {
|
||||
doPublish('On');
|
||||
return res.json(getResponse());
|
||||
}
|
||||
|
||||
if (cmd === 'switch_off') {
|
||||
doPublish('Off');
|
||||
return res.json(getResponse());
|
||||
}
|
||||
|
||||
if (cmd === 'check') {
|
||||
return res.json(getResponse());
|
||||
}
|
||||
|
||||
return res.status(400).json({ error: 'invalid command' });
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
|
||||
Reference in New Issue
Block a user