signalk-server
Version:
An implementation of a [Signal K](http://signalk.org) server for boats.
133 lines (132 loc) • 4.88 kB
JavaScript
;
/* eslint-disable @typescript-eslint/no-explicit-any */
/*
* Copyright 2015 Teppo Kurki <teppo.kurki@iki.fi>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const net_1 = require("net");
const split_1 = __importDefault(require("split"));
const debug_1 = require("../debug");
const types_1 = require("../types");
const debug = (0, debug_1.createDebug)('signalk-server:interfaces:tcp:signalk');
module.exports = (app) => {
'use strict';
let idSequence = 0;
let server;
const port = Number(process.env.TCPSTREAMPORT) || 8375;
const api = new types_1.Interface();
api.start = () => {
if (!app.securityStrategy.allowReadOnly()) {
debug('Not starting tcp interface because readOnly is false');
return;
}
debug('Starting tcp interface');
server = (0, net_1.createServer)((socket) => {
socket.id = idSequence++;
socket.name = socket.remoteAddress + ':' + socket.remotePort;
debug('Connected:' + socket.id + ' ' + socket.name);
socket.on('error', (err) => {
debug('Error:' + err + ' ' + socket.id + ' ' + socket.name);
});
socket.on('close', (hadError) => {
debug('Close:' + hadError + ' ' + socket.id + ' ' + socket.name);
});
const unsubscibes = [];
socket
.pipe((0, split_1.default)((s) => {
if (s.length > 0) {
try {
return JSON.parse(s);
}
catch (e) {
console.log(e.message);
}
}
}))
.on('data', socketMessageHandler(app, socket, unsubscibes))
.on('error', (err) => {
console.error(err);
});
socket.on('end', () => {
unsubscibes.forEach((f) => f());
debug('Ended:' + socket.id + ' ' + socket.name);
});
socket.write(JSON.stringify(app.getHello()) + '\r\n');
});
server.on('listening', () => debug('Signal K tcp server listening on ' + port));
server.on('error', (e) => {
console.error(`Signal K tcp server error: ${e.message}`);
});
if (process.env.TCPSTREAMADDRESS) {
debug('Binding to ' + process.env.TCPSTREAMADDRESS);
server.listen(port, process.env.TCPSTREAMADDRESS);
}
else {
server.listen(port);
}
return {
port
};
};
api.stop = () => {
if (server) {
server.close();
server = null;
}
};
api.mdns = {
name: '_signalk-tcp',
type: 'tcp',
port
};
return api;
};
function socketMessageHandler(app, socket, unsubscribes) {
let lastUpdateErrorLogged = 0;
return (msg) => {
if (msg.updates) {
if (app.securityStrategy.isDummy()) {
app.handleMessage('tcp', msg);
}
else {
if (Date.now() - lastUpdateErrorLogged > 60 * 1000) {
console.error(`Security is enabled, deltas over tcp ignored`);
lastUpdateErrorLogged = Date.now();
}
}
}
else if (msg.subscribe) {
debug.enabled && debug(`subscribe:${JSON.stringify(msg)}`);
app.subscriptionmanager.subscribe(msg, unsubscribes, (err) => {
console.error(`Subscribe failed:${err}`);
}, (aMsg) => socket.write(`${JSON.stringify(aMsg)}\r\n`));
}
else if (msg.unsubscribe) {
debug.enabled && debug(`unsubscribe:${JSON.stringify(msg)}`);
try {
app.subscriptionmanager.unsubscribe(msg, unsubscribes);
}
catch (e) {
console.error(e.message);
socket.write(JSON.stringify(e.message));
socket.end(() => {
console.error(`Closed ${socket.name}`);
});
}
}
};
}