UNPKG

signalk-server

Version:

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

161 lines (159 loc) 7.1 kB
"use strict"; /* * Copyright 2014-2015 Fabian Tollenaar <fabian@starting-point.nl> * * 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. */ const { createDebug } = require('../debug'); const debug = createDebug('signalk-server:interfaces:rest'); const express = require('express'); const { getMetadata } = require('@signalk/signalk-schema'); const ports = require('../ports'); const iso8601rexexp = /^(-?(?:[1-9][0-9]*)?[0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9])T(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])(\.[0-9]+)?Z$/; module.exports = function (app) { 'use strict'; const pathPrefix = '/signalk'; const versionPrefix = '/v1'; const apiPathPrefix = pathPrefix + versionPrefix + '/api/'; const streamPath = pathPrefix + versionPrefix + '/stream'; const KNOWN_OTHER_PATH_PREFIXES = ['resources']; return { start: function () { app.use('/', express.static(__dirname + '/../../public')); app.get(apiPathPrefix + '*', function (req, res, next) { let path = String(req.path).replace(apiPathPrefix, ''); if (path === 'self') { return res.json(`vessels.${app.selfId}`); } path = path.length > 0 ? path.replace(/\/$/, '').split('/') : []; if (KNOWN_OTHER_PATH_PREFIXES.indexOf(path[0]) >= 0) { next(); return; } if (path.length > 4 && path[path.length - 1] === 'meta') { let meta = getMetadata(path.slice(0, path.length - 1).join('.')); if (meta) { res.json(meta); return; } } if (path.length > 5 && path[path.length - 2] === 'meta') { let meta = getMetadata(path.slice(0, path.length - 2).join('.')); let value = meta && meta[path[path.length - 1]]; if (value) { res.json(value); return; } } path = path.map((p) => (p === 'self' ? app.selfId : p)); function sendResult(last, aPath) { if (last) { for (const i in aPath) { const p = aPath[i]; if (typeof last[p] !== 'undefined') { last = last[p]; } else { next(); return; } } } else { next(); return; } return res.json(last); } if (path[0] && path[0] === 'snapshot') { if (!req.query.time) { res.status(400).send('Snapshot api requires time query parameter'); } else { if (!iso8601rexexp.test(req.query.time)) { res .status(400) .send('Time query parameter must be a valid ISO 8601 UTC time value like 2018-12-11T18:40:03.246'); } else if (!app.historyProvider) { res.status(501).send('No history provider'); } else { const realPath = path.slice(1); app.historyProvider.getHistory(new Date(req.query.time), realPath, (deltas) => { if (deltas.length === 0) { res.status(404).send('No data found for the given time'); return; } const last = app.deltaCache.buildFullFromDeltas(req.skPrincipal, deltas); sendResult(last, realPath); }); } } } else { let last; if (app.securityStrategy.anyACLs()) { last = app.deltaCache.buildFull(req.skPrincipal, path); } else { last = app.signalk.retrieve(); } sendResult(last, path); } }); app.get(pathPrefix, function (req, res) { const host = req.headers.host; const splitHost = host.split(':'); let httpProtocol = 'http://'; let wsProtocol = 'ws://'; if (app.config.settings.ssl || (req.headers['x-forwarded-proto'] && req.headers['x-forwarded-proto'] === 'https')) { httpProtocol = 'https://'; wsProtocol = 'wss://'; } const services = { version: getVersion(), 'signalk-http': httpProtocol + host + apiPathPrefix, 'signalk-ws': wsProtocol + host + streamPath }; if (app.interfaces.tcp && app.interfaces.tcp.data) { services['signalk-tcp'] = `tcp://${splitHost[0]}:${app.interfaces.tcp.data.port}`; } res.json({ endpoints: { v1: services }, server: { id: 'signalk-server-node', version: app.config.version } }); }); if (app.historyProvider && app.historyProvider.registerHistoryApiRoute) { debug('Adding history api route'); const historyApiRouter = express.Router(); app.historyProvider.registerHistoryApiRoute(historyApiRouter); app.use(pathPrefix + versionPrefix + '/history', historyApiRouter); } }, mdns: { name: app.config.settings.ssl ? '_signalk-https' : '_signalk-http', type: 'tcp', port: ports.getExternalPort(app) } }; }; // @ts-ignore const getVersion = () => require('../../package.json').version;