UNPKG

signalk-server

Version:

An implementation of a [Signal K](http://signalk.org) server for boats.

133 lines (132 loc) 4.88 kB
"use strict"; /* 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}`); }); } } }; }