UNPKG

signalk-server

Version:

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

119 lines 4.02 kB
"use strict"; // // Filters delta updates targeting the self vessel context. Static identity // data (name, mmsi, design dimensions, GPS antenna offsets, callsignVhf) is // configured at the server level and must not be overwritten by deltas from // other providers; the only exception is the special `defaults` $source that // carries the server-level base data itself. // // The hot path is `filterStaticSelfData` -> `filterSelfDataKP`, called for // every value of every self-context delta. // Object.defineProperty(exports, "__esModule", { value: true }); exports.filterStaticSelfData = filterStaticSelfData; const ROOT_VESSEL_FILTERED_KEYS = new Set(['name', 'mmsi']); const SELF_DATA_FILTERED_PATHS = new Set([ 'design.aisShipType', 'design.beam', 'design.length', 'design.draft', 'sensors.gps.fromBow', 'sensors.gps.fromCenter' ]); const COMMUNICATION_FILTERED_KEYS = new Set([ 'callsignVhf' ]); function isRecord(v) { return v !== null && typeof v === 'object'; } function omitKeys(obj, exclude) { const res = {}; for (const k of Object.keys(obj)) { if (!exclude.has(k)) { res[k] = obj[k]; } } return res; } // Probe the small filter Set against the (typically larger) input object // rather than enumerating the input's keys. function hasAnyKey(obj, keys) { for (const k of keys) { if (k in obj) { return true; } } return false; } // Accepts Partial<Delta> because the upstream input pipeline produces deltas // with optional fields and patches them in place; see handleMessage in // src/index.ts. function filterStaticSelfData(delta, selfContext) { if (delta.context !== selfContext || !delta.updates) { return delta; } const keptUpdates = []; for (const update of delta.updates) { if (!('values' in update) || update['$source'] === 'defaults') { keptUpdates.push(update); continue; } const kept = []; for (const pathValue of update.values) { const nvp = filterSelfDataKP(pathValue); if (nvp) { kept.push(nvp); } } if (kept.length === 0) { // Every value was filtered out. Keep the update only if it still // carries a meta payload; otherwise drop it so empty husk updates // don't flow downstream. if ('meta' in update) { delete update.values; keptUpdates.push(update); } } else { update.values = kept; keptUpdates.push(update); } } delta.updates = keptUpdates; return delta; } function filterSelfDataKP(pathValue) { // Path '' carries the vessel root: filter top-level identity keys plus the // communication subobject's callsignVhf. if (pathValue.path === '') { if (!isRecord(pathValue.value)) { // Malformed self-root payload (null, primitive). Pass through unchanged // rather than throwing so co-batched valid updates are not lost. return pathValue; } let value = pathValue.value; if (hasAnyKey(value, ROOT_VESSEL_FILTERED_KEYS)) { value = omitKeys(value, ROOT_VESSEL_FILTERED_KEYS); pathValue.value = value; } const comm = value.communication; if (isRecord(comm) && hasAnyKey(comm, COMMUNICATION_FILTERED_KEYS)) { const filtered = omitKeys(comm, COMMUNICATION_FILTERED_KEYS); if (Object.keys(filtered).length === 0) { delete value.communication; } else { value.communication = filtered; } } if (Object.keys(value).length === 0) { return null; } return pathValue; } if (SELF_DATA_FILTERED_PATHS.has(pathValue.path)) { return null; } return pathValue; } //# sourceMappingURL=staticDataFilter.js.map