signalk-edge-link 1.0.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +212 -468
- package/lib/CircularBuffer.js +33 -35
- package/lib/bin/edge-link-cli.js +373 -0
- package/lib/bonding.js +740 -0
- package/lib/config-io.js +141 -0
- package/lib/config-watcher.js +251 -0
- package/lib/congestion.js +223 -0
- package/lib/connection-config.js +357 -0
- package/lib/constants.js +85 -65
- package/lib/crypto.js +271 -98
- package/lib/index.js +699 -0
- package/lib/instance.js +911 -0
- package/lib/metrics-publisher.js +264 -0
- package/lib/metrics.js +311 -229
- package/lib/monitoring.js +572 -0
- package/lib/packet-capture.js +290 -0
- package/lib/packet.js +467 -0
- package/lib/pathDictionary.js +456 -483
- package/lib/pipeline-factory.js +36 -0
- package/lib/pipeline-utils.js +134 -0
- package/lib/pipeline-v2-client.js +799 -0
- package/lib/pipeline-v2-server.js +803 -0
- package/lib/pipeline.js +268 -285
- package/lib/prometheus.js +197 -0
- package/lib/retransmit-queue.js +246 -0
- package/lib/routes/config-validation.js +40 -0
- package/lib/routes/config.js +280 -0
- package/lib/routes/connections.js +467 -0
- package/lib/routes/control.js +179 -0
- package/lib/routes/metrics.js +126 -0
- package/lib/routes/monitoring.js +353 -0
- package/lib/routes/types.js +2 -0
- package/lib/routes.js +538 -393
- package/lib/scripts/migrate-config.js +74 -0
- package/lib/sequence.js +227 -0
- package/lib/types.js +2 -0
- package/package.json +161 -75
- package/public/11.413e152fbef6e7dfd2f8.js +2 -0
- package/public/11.413e152fbef6e7dfd2f8.js.map +1 -0
- package/public/277.509a7bfc11fac344f433.js +9 -0
- package/public/277.509a7bfc11fac344f433.js.map +1 -0
- package/public/540.70a0bc6aadb412703390.js +3 -0
- package/public/540.70a0bc6aadb412703390.js.map +1 -0
- package/public/index.html +1 -1
- package/public/main.3576323fe7e587bd7c5e.js +2 -0
- package/public/main.3576323fe7e587bd7c5e.js.map +1 -0
- package/public/{main.5d54244033b773c1441a.css → main.e2b9c98749816ac2e285.css} +478 -1
- package/public/main.e2b9c98749816ac2e285.css.map +1 -0
- package/public/remoteEntry.js +1 -1
- package/public/remoteEntry.js.map +1 -1
- package/schemas/config.schema.json +104 -0
- package/.github/dependabot.yml +0 -11
- package/.prettierignore +0 -13
- package/doc/dataconnectorconcept.jpg +0 -0
- package/doc/datarate.jpg +0 -0
- package/index.js +0 -642
- package/public/277.bd457fe42516968eea57.js +0 -15
- package/public/277.bd457fe42516968eea57.js.map +0 -1
- package/public/540.d28b9c447a7de79d8bcd.js +0 -3
- package/public/540.d28b9c447a7de79d8bcd.js.map +0 -1
- package/public/831.35ab14aec7975c4cb7c1.js +0 -3
- package/public/831.35ab14aec7975c4cb7c1.js.LICENSE.txt +0 -1
- package/public/831.35ab14aec7975c4cb7c1.js.map +0 -1
- package/public/main.285dd2e6a0c82d8d73a7.js +0 -3
- package/public/main.285dd2e6a0c82d8d73a7.js.LICENSE.txt +0 -1
- package/public/main.285dd2e6a0c82d8d73a7.js.map +0 -1
- package/public/main.5d54244033b773c1441a.css.map +0 -1
- /package/public/{277.bd457fe42516968eea57.js.LICENSE.txt → 277.509a7bfc11fac344f433.js.LICENSE.txt} +0 -0
- /package/public/{540.d28b9c447a7de79d8bcd.js.LICENSE.txt → 540.70a0bc6aadb412703390.js.LICENSE.txt} +0 -0
package/README.md
CHANGED
|
@@ -1,538 +1,282 @@
|
|
|
1
1
|
# Signal K Edge Link
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
[
|
|
44
|
-
|
|
45
|
-
---
|
|
46
|
-
|
|
47
|
-
## Overview
|
|
48
|
-
|
|
49
|
-
Signal K Edge Link is a Signal K Node Server plugin that enables real-time data sharing between vessels or shore stations over UDP. It combines AES-256-GCM authenticated encryption with Brotli compression to deliver secure, bandwidth-efficient transmission — achieving up to **97% bandwidth reduction** compared to raw data.
|
|
50
|
-
|
|
51
|
-
**Key capabilities:**
|
|
52
|
-
|
|
53
|
-
| Feature | Description |
|
|
54
|
-
|---------|-------------|
|
|
55
|
-
| Encrypted transport | AES-256-GCM authenticated encryption with per-message unique IV |
|
|
56
|
-
| Brotli compression | Quality-10 compression with 85–97% reduction on typical data |
|
|
57
|
-
| Binary protocol | Zero JSON overhead in the wire format |
|
|
58
|
-
| Path dictionary | 170+ Signal K paths mapped to numeric IDs (10–20% savings) |
|
|
59
|
-
| MessagePack | Optional binary serialization (15–25% additional savings) |
|
|
60
|
-
| Smart batching | Adaptive packet sizing that prevents UDP fragmentation |
|
|
61
|
-
| Sentence filtering | Exclude NMEA sentences (GSV, GSA, etc.) to reduce bandwidth |
|
|
62
|
-
| Network monitoring | TCP ping with RTT measurement published to Signal K |
|
|
63
|
-
| Web dashboard | Real-time bandwidth, compression, and path analytics |
|
|
64
|
-
| Hot-reload config | Configuration files reload automatically on change |
|
|
65
|
-
|
|
66
|
-
---
|
|
67
|
-
|
|
68
|
-
## Getting Started
|
|
69
|
-
|
|
70
|
-
### Installation
|
|
71
|
-
|
|
72
|
-
```bash
|
|
73
|
-
cd ~/.signalk/node_modules/
|
|
74
|
-
git clone https://github.com/KEGustafsson/signalk-edge-link.git
|
|
75
|
-
cd signalk-edge-link
|
|
76
|
-
npm install
|
|
77
|
-
npm run build
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
Restart your Signal K server after installation.
|
|
81
|
-
|
|
82
|
-
### Quick Start
|
|
83
|
-
|
|
84
|
-
1. Open **Admin UI → Plugin Config → Signal K Edge Link**
|
|
85
|
-
2. Choose an operation mode:
|
|
86
|
-
- **Server** — receives data from remote clients
|
|
87
|
-
- **Client** — sends data to a remote server
|
|
88
|
-
3. Set the **UDP port** (must match between client and server)
|
|
89
|
-
4. Enter a **32-character encryption key** (must be identical on both ends)
|
|
90
|
-
5. For client mode, enter the **server IP address**
|
|
91
|
-
6. Enable the plugin and verify data flow in the web dashboard
|
|
92
|
-
|
|
93
|
-
> **Tip:** Start with the default settings. Enable path dictionary and MessagePack later for additional bandwidth savings.
|
|
94
|
-
|
|
95
|
-
---
|
|
96
|
-
|
|
97
|
-
## Configuration
|
|
98
|
-
|
|
99
|
-
The plugin provides a custom React-based configuration UI that dynamically adapts to the selected operation mode, showing only relevant settings.
|
|
100
|
-
|
|
101
|
-
**Access:** Admin UI → Plugin Config → Signal K Edge Link
|
|
102
|
-
|
|
103
|
-
### Server Mode (Receiver)
|
|
104
|
-
|
|
105
|
-
| Setting | Description |
|
|
106
|
-
|---------|-------------|
|
|
107
|
-
| Operation Mode | Server/Client selector |
|
|
108
|
-
| UDP Port | Port to listen on (1024–65535) |
|
|
109
|
-
| Encryption Key | 32-character secret key |
|
|
110
|
-
| MessagePack | Enable binary serialization |
|
|
111
|
-
| Path Dictionary | Enable path encoding |
|
|
112
|
-
|
|
113
|
-
### Client Mode (Sender)
|
|
114
|
-
|
|
115
|
-
| Setting | Description |
|
|
116
|
-
|---------|-------------|
|
|
117
|
-
| Operation Mode | Server/Client selector |
|
|
118
|
-
| UDP Port | Port to send to |
|
|
119
|
-
| Encryption Key | 32-character secret key (must match server) |
|
|
120
|
-
| Destination Address | Server IP or hostname |
|
|
121
|
-
| Heartbeat Interval | Keep-alive message frequency (seconds) |
|
|
122
|
-
| Connectivity Test Target | Address to ping for network monitoring |
|
|
123
|
-
| Connectivity Test Port | Port to test (80, 443, etc.) |
|
|
124
|
-
| Check Interval | How often to test connectivity (minutes) |
|
|
125
|
-
| MessagePack | Enable binary serialization |
|
|
126
|
-
| Path Dictionary | Enable path encoding |
|
|
127
|
-
|
|
128
|
-
Additional client settings are available in the web dashboard:
|
|
129
|
-
- **Delta timer** — collection interval (100–10000 ms)
|
|
130
|
-
- **Subscription paths** — Signal K paths to transmit
|
|
131
|
-
- **Sentence filter** — NMEA sentences to exclude (e.g., `GSV, GSA, VTG`)
|
|
132
|
-
|
|
133
|
-
### Web Dashboard
|
|
134
|
-
|
|
135
|
-
**Access:** `http://[signalk-server]:3000/plugins/signalk-edge-link`
|
|
136
|
-
|
|
137
|
-
The dashboard provides real-time monitoring and configuration controls.
|
|
138
|
-
|
|
139
|
-
**Client mode:**
|
|
140
|
-
- Delta timer and subscription management
|
|
141
|
-
- Sentence filter configuration
|
|
142
|
-
- Upload/download bandwidth with compression ratio
|
|
143
|
-
- Bandwidth savings display (actual bytes saved)
|
|
144
|
-
- Path analytics with per-path data volume breakdown
|
|
145
|
-
- Performance metrics (errors, uptime, deltas sent)
|
|
146
|
-
- Rate history chart (last 150 seconds)
|
|
147
|
-
|
|
148
|
-
**Server mode:**
|
|
149
|
-
- Download bandwidth and packet rate
|
|
150
|
-
- Bandwidth savings display
|
|
151
|
-
- Incoming path analytics
|
|
152
|
-
- Performance metrics (deltas received, errors)
|
|
153
|
-
- Compression effectiveness tracking
|
|
154
|
-
|
|
155
|
-
### Configuration Files
|
|
156
|
-
|
|
157
|
-
These JSON files are stored in the plugin data directory and support hot-reload — changes take effect automatically without restarting.
|
|
158
|
-
|
|
159
|
-
| File | Purpose | Default |
|
|
160
|
-
|------|---------|---------|
|
|
161
|
-
| `delta_timer.json` | Collection interval in ms | `{"deltaTimer": 1000}` |
|
|
162
|
-
| `subscription.json` | Signal K paths to subscribe | `{"context": "*", "subscribe": [...]}` |
|
|
163
|
-
| `sentence_filter.json` | NMEA sentences to exclude | `{"sentences": []}` |
|
|
164
|
-
|
|
165
|
-
### API Endpoints
|
|
166
|
-
|
|
167
|
-
All endpoints are rate-limited to 20 requests per minute per IP.
|
|
168
|
-
|
|
169
|
-
| Method | Endpoint | Description |
|
|
170
|
-
|--------|----------|-------------|
|
|
171
|
-
| GET | `/plugins/signalk-edge-link/config/:filename` | Read a configuration file |
|
|
172
|
-
| POST | `/plugins/signalk-edge-link/config/:filename` | Update a configuration file |
|
|
173
|
-
| GET | `/plugins/signalk-edge-link/metrics` | Real-time statistics and performance data |
|
|
174
|
-
| GET | `/plugins/signalk-edge-link/paths` | Path dictionary information |
|
|
175
|
-
| GET | `/plugins/signalk-edge-link/plugin-config` | Current plugin configuration |
|
|
176
|
-
| POST | `/plugins/signalk-edge-link/plugin-config` | Update plugin configuration |
|
|
177
|
-
| GET | `/plugins/signalk-edge-link/plugin-schema` | Plugin schema definition |
|
|
178
|
-
|
|
179
|
-
---
|
|
180
|
-
|
|
181
|
-
## Network Monitoring
|
|
182
|
-
|
|
183
|
-
In client mode, the plugin measures **Round Trip Time (RTT)** using TCP ping to monitor connectivity and latency.
|
|
184
|
-
|
|
185
|
-
**How it works:**
|
|
186
|
-
1. TCP ping is sent to the configured test address and port at the configured interval
|
|
187
|
-
2. RTT is published to local Signal K at `networking.modem.rtt` (value in seconds)
|
|
188
|
-
3. If subscribed, RTT data is transmitted to the remote server with other data
|
|
189
|
-
|
|
190
|
-
**To enable RTT transmission:** Add `networking.modem.rtt` to your subscription paths.
|
|
191
|
-
|
|
192
|
-
**Use cases:**
|
|
193
|
-
- Monitor cellular or satellite modem latency
|
|
194
|
-
- Track connection quality over time
|
|
195
|
-
- Trigger alerts on high latency
|
|
196
|
-
- Analyze network performance trends
|
|
197
|
-
|
|
198
|
-
---
|
|
199
|
-
|
|
200
|
-
## Performance
|
|
201
|
-
|
|
202
|
-
### Bandwidth Comparison
|
|
203
|
-
|
|
204
|
-

|
|
205
|
-
|
|
206
|
-
| Mode | Bandwidth | Reduction vs. WebSocket |
|
|
207
|
-
|------|-----------|------------------------|
|
|
208
|
-
| 1000 ms collection | ~44.1 kb/s | ~70% |
|
|
209
|
-
| 100 ms collection | ~107.7 kb/s | ~28% |
|
|
210
|
-
| WebSocket real-time | ~149.5 kb/s | — |
|
|
211
|
-
|
|
212
|
-
Typical compression results on Signal K data:
|
|
213
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/signalk-edge-link)
|
|
4
|
+
[](LICENSE)
|
|
5
|
+
[](https://nodejs.org)
|
|
6
|
+
|
|
7
|
+
Signal K Edge Link is a Signal K plugin that transfers vessel deltas between Signal K servers over encrypted UDP.
|
|
8
|
+
|
|
9
|
+
It is designed for links where latency, packet loss, and bandwidth usage matter (cellular, satellite, and other unstable WAN paths).
|
|
10
|
+
|
|
11
|
+

|
|
12
|
+
|
|
13
|
+
## Why use it?
|
|
14
|
+
|
|
15
|
+
- **Secure transport** using AES-256-GCM
|
|
16
|
+
- **Bandwidth optimization** with Brotli compression (plus optional MessagePack and path dictionary)
|
|
17
|
+
- **Two operating modes**:
|
|
18
|
+
- **Client**: subscribes to local deltas and sends packets
|
|
19
|
+
- **Server**: receives packets, decrypts, and forwards to local Signal K
|
|
20
|
+
- **Protocol v2/v3 features** for difficult links:
|
|
21
|
+
- ACK/NAK-based reliability
|
|
22
|
+
- congestion control
|
|
23
|
+
- optional primary/backup bonding
|
|
24
|
+
- monitoring and alerting endpoints
|
|
25
|
+
- **Multi-connection support** on one Signal K instance
|
|
26
|
+
|
|
27
|
+
## How data flows
|
|
28
|
+
|
|
29
|
+
```text
|
|
30
|
+
Client Signal K
|
|
31
|
+
-> subscribe + batch deltas
|
|
32
|
+
-> optional path dictionary + MessagePack
|
|
33
|
+
-> Brotli compress
|
|
34
|
+
-> AES-256-GCM encrypt
|
|
35
|
+
-> UDP send
|
|
36
|
+
|
|
37
|
+
Server Signal K
|
|
38
|
+
<- UDP receive
|
|
39
|
+
<- AES-256-GCM decrypt
|
|
40
|
+
<- Brotli decompress
|
|
41
|
+
<- optional MessagePack + path decode
|
|
42
|
+
<- inject into local Signal K
|
|
214
43
|
```
|
|
215
|
-
Original: 19,293 bytes → Encrypted + Compressed: 622 bytes (96.78% reduction)
|
|
216
|
-
```
|
|
217
|
-
|
|
218
|
-
### Smart Batching
|
|
219
|
-
|
|
220
|
-
The plugin uses adaptive smart batching to keep UDP packets under the MTU limit (1400 bytes), preventing fragmentation that can cause data loss.
|
|
221
|
-
|
|
222
|
-
1. **Rolling average** — tracks bytes-per-delta using exponential smoothing
|
|
223
|
-
2. **Dynamic batch sizing** — calculates optimal deltas per packet based on recent sizes
|
|
224
|
-
3. **Early send trigger** — sends immediately when a batch reaches the predicted size limit
|
|
225
|
-
4. **Self-learning** — continuously adapts as data patterns change
|
|
226
|
-
|
|
227
|
-
```
|
|
228
|
-
Example: Initial estimate 5 deltas/batch → After learning: 11 deltas/batch
|
|
229
|
-
All packets stay well under 1400 bytes
|
|
230
|
-
```
|
|
231
|
-
|
|
232
|
-
### Optimization Tips
|
|
233
44
|
|
|
234
|
-
|
|
45
|
+
## Requirements
|
|
235
46
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
5. **Review subscriptions** — subscribe only to paths you need
|
|
47
|
+
- Two Signal K instances (source and destination)
|
|
48
|
+
- UDP reachability from client to server on your chosen port
|
|
49
|
+
- Shared encryption key on both ends (32-character ASCII, 64-character hex, or 44-character base64)
|
|
50
|
+
- Node.js 16+ (if installing from source: dev dependencies including TypeScript are installed automatically via `npm install`)
|
|
241
51
|
|
|
242
|
-
|
|
52
|
+
## Installation
|
|
243
53
|
|
|
244
|
-
|
|
54
|
+
### Option A: Signal K Plugin Manager
|
|
245
55
|
|
|
246
|
-
|
|
56
|
+
Install **Signal K Edge Link** from your Signal K plugin catalog.
|
|
247
57
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
| Property | Detail |
|
|
251
|
-
|----------|--------|
|
|
252
|
-
| Algorithm | AES-256-GCM |
|
|
253
|
-
| IV | 12 bytes, unique per message |
|
|
254
|
-
| Auth tag | 16 bytes, tamper detection |
|
|
255
|
-
| Wire format | `[IV (12 bytes)][Encrypted Data][Auth Tag (16 bytes)]` |
|
|
256
|
-
| Overhead | 28 bytes per packet |
|
|
257
|
-
|
|
258
|
-
**Security features:**
|
|
259
|
-
- Tamper detection — any modification causes decryption failure
|
|
260
|
-
- Rate-limited API endpoints (20 req/min/IP)
|
|
261
|
-
- Input validation on all parameters
|
|
262
|
-
- Key entropy checking — rejects weak keys
|
|
263
|
-
- XSS protection in the web UI
|
|
264
|
-
- Stateless UDP — no session state to compromise
|
|
265
|
-
|
|
266
|
-
### Secret Key Requirements
|
|
267
|
-
|
|
268
|
-
- Exactly **32 characters** (256 bits)
|
|
269
|
-
- Minimum **8 unique characters**
|
|
270
|
-
- Must match on both client and server
|
|
271
|
-
|
|
272
|
-
Generate a secure key:
|
|
58
|
+
### Option B: Manual install from source
|
|
273
59
|
|
|
274
60
|
```bash
|
|
275
|
-
|
|
61
|
+
cd ~/.signalk/node_modules
|
|
62
|
+
git clone https://github.com/KEGustafsson/signalk-edge-link.git
|
|
63
|
+
cd signalk-edge-link
|
|
64
|
+
npm install
|
|
65
|
+
npm run build
|
|
276
66
|
```
|
|
277
67
|
|
|
278
|
-
|
|
279
|
-
```
|
|
280
|
-
Abc123!@#XYZ456$%^uvw789&*()pqr0
|
|
281
|
-
K9#mP2$nQ7@rS4%tU6^vW8*xY3!zA5&
|
|
282
|
-
abcdefgh12345678901234567890abcd
|
|
283
|
-
```
|
|
68
|
+
Restart Signal K after installation.
|
|
284
69
|
|
|
285
|
-
|
|
286
|
-
```
|
|
287
|
-
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa # All same character
|
|
288
|
-
abababababababababababababababab # Insufficient diversity
|
|
289
|
-
MySecretKey123 # Too short
|
|
290
|
-
```
|
|
70
|
+
## Quick start
|
|
291
71
|
|
|
292
|
-
###
|
|
72
|
+
### 1) Configure the destination (Server mode)
|
|
293
73
|
|
|
294
|
-
|
|
295
|
-
2. Never commit keys to version control
|
|
296
|
-
3. Rotate keys periodically (every 6–12 months)
|
|
297
|
-
4. Monitor logs for decryption failures (may indicate attacks or key mismatch)
|
|
298
|
-
5. Restrict UDP access with firewall rules to known IP addresses
|
|
299
|
-
6. Test configuration in a safe environment before production deployment
|
|
74
|
+
In Signal K Admin UI:
|
|
300
75
|
|
|
301
|
-
|
|
76
|
+
1. Open `Server -> Plugin Config -> Signal K Edge Link`
|
|
77
|
+
2. Click **Add Server**
|
|
78
|
+
3. Set:
|
|
79
|
+
- `Connection Name` (for example `shore-server`)
|
|
80
|
+
- `UDP Port` (default `4446`)
|
|
81
|
+
- `Encryption Key` (same shared secret used by client)
|
|
82
|
+
- `Protocol Version` (`3` recommended for new deployments; use `2` only for compatibility with an existing v2 peer)
|
|
83
|
+
4. Save
|
|
302
84
|
|
|
303
|
-
|
|
85
|
+
### 2) Configure the source (Client mode)
|
|
304
86
|
|
|
305
|
-
|
|
87
|
+
On the sending Signal K instance:
|
|
306
88
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
-
|
|
89
|
+
1. Open `Server -> Plugin Config -> Signal K Edge Link`
|
|
90
|
+
2. Click **Add Client**
|
|
91
|
+
3. Set:
|
|
92
|
+
- `Connection Name` (for example `vessel-client`)
|
|
93
|
+
- `Server Address` (destination host/IP)
|
|
94
|
+
- `UDP Port` (must match server)
|
|
95
|
+
- `Encryption Key` (must match server)
|
|
96
|
+
- `Protocol Version` (`3` recommended for new deployments; use `2` only for compatibility with an existing v2 peer)
|
|
97
|
+
4. Save
|
|
311
98
|
|
|
312
|
-
###
|
|
99
|
+
### 3) Verify traffic
|
|
313
100
|
|
|
314
|
-
|
|
315
|
-
- Verify `public/` directory exists with built files
|
|
316
|
-
- Clear browser cache and refresh
|
|
101
|
+
Open the runtime UI:
|
|
317
102
|
|
|
318
|
-
|
|
103
|
+
`http://<signalk-host>:3000/plugins/signalk-edge-link/`
|
|
319
104
|
|
|
320
|
-
|
|
321
|
-
1. Confirm encryption keys match on both ends
|
|
322
|
-
2. Verify UDP port and destination address
|
|
323
|
-
3. Check firewall allows UDP traffic on the configured port
|
|
324
|
-
4. Confirm subscription paths are valid Signal K paths
|
|
325
|
-
5. Verify delta timer is running (check metrics in web dashboard)
|
|
105
|
+
Check that:
|
|
326
106
|
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
3. Check Signal K logs for decryption errors
|
|
331
|
-
4. Verify client is sending data (check client metrics)
|
|
107
|
+
- client `Deltas Sent` increases
|
|
108
|
+
- server `Deltas Received` increases
|
|
109
|
+
- encryption/decryption errors remain stable at zero
|
|
332
110
|
|
|
333
|
-
|
|
111
|
+
## Protocol version guidance
|
|
334
112
|
|
|
335
|
-
|
|
|
336
|
-
|
|
337
|
-
|
|
|
338
|
-
|
|
|
339
|
-
|
|
|
113
|
+
| Version | Use when | Notes |
|
|
114
|
+
| ------- | --------------------------------------------------------- | --------------------------------------------------------------------------- |
|
|
115
|
+
| v1 | stable local links, simplest setup | lower overhead, no ACK/NAK reliability layer |
|
|
116
|
+
| v2 | packet loss, variable latency, WAN links | adds retransmission, congestion control, bonding, richer monitoring |
|
|
117
|
+
| v3 | same use cases as v2 when both peers can upgrade together | keeps v2 features and authenticates ACK/NAK/HEARTBEAT/HELLO control packets |
|
|
340
118
|
|
|
341
|
-
|
|
119
|
+
For unstable links, start with **v3** when both peers support it; fall back to **v2** only when you need compatibility with an already deployed v2 peer.
|
|
342
120
|
|
|
343
|
-
|
|
344
|
-
- Enable path dictionary and MessagePack
|
|
345
|
-
- Filter unnecessary NMEA sentences
|
|
346
|
-
- Check network latency with the ping monitor
|
|
347
|
-
- Monitor CPU usage (Brotli compression at quality 10 is CPU-intensive)
|
|
121
|
+
## Runtime UI and API
|
|
348
122
|
|
|
349
|
-
|
|
123
|
+
- Runtime UI: `/plugins/signalk-edge-link/`
|
|
124
|
+
- API base path: `/plugins/signalk-edge-link`
|
|
125
|
+
- Default API rate limit: **120 requests/minute/IP**
|
|
350
126
|
|
|
351
|
-
|
|
352
|
-
- Connection monitor status and ping results
|
|
353
|
-
- Configuration file changes (automatic reload)
|
|
354
|
-
- Delta transmission statistics
|
|
355
|
-
- Compression ratios and packet sizes
|
|
356
|
-
- Error messages with full context
|
|
127
|
+
Most used endpoints:
|
|
357
128
|
|
|
358
|
-
|
|
129
|
+
- `GET /metrics`
|
|
130
|
+
- `GET /network-metrics`
|
|
131
|
+
- `GET /monitoring/alerts`
|
|
132
|
+
- `GET /connections`
|
|
133
|
+
- `GET /instances`
|
|
134
|
+
- `GET /instances/:id`
|
|
135
|
+
- `GET /connections/:id/metrics`
|
|
136
|
+
- `GET /connections/:id/network-metrics`
|
|
137
|
+
- `GET /bonding`
|
|
138
|
+
- `POST /bonding`
|
|
359
139
|
|
|
360
|
-
|
|
140
|
+
For full endpoint details, use `docs/api-reference.md
|
|
361
141
|
|
|
362
|
-
|
|
142
|
+
## Configuration model (summary)
|
|
363
143
|
|
|
364
|
-
|
|
144
|
+
Configuration is an array of independent connections:
|
|
365
145
|
|
|
146
|
+
```json
|
|
147
|
+
{
|
|
148
|
+
"connections": [
|
|
149
|
+
{
|
|
150
|
+
"name": "shore-server",
|
|
151
|
+
"serverType": "server",
|
|
152
|
+
"udpPort": 4446,
|
|
153
|
+
"secretKey": "<32-byte key>",
|
|
154
|
+
"protocolVersion": 3
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
"name": "sat-client",
|
|
158
|
+
"serverType": "client",
|
|
159
|
+
"udpPort": 4447,
|
|
160
|
+
"udpAddress": "10.0.0.1",
|
|
161
|
+
"secretKey": "<32-byte key>",
|
|
162
|
+
"protocolVersion": 3
|
|
163
|
+
}
|
|
164
|
+
]
|
|
165
|
+
}
|
|
366
166
|
```
|
|
367
|
-
Client (Sender):
|
|
368
|
-
Signal K Deltas → Filter → [Path Encode] → [MessagePack] → Brotli → AES-256-GCM → UDP
|
|
369
167
|
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
168
|
+
- Each connection runs independently.
|
|
169
|
+
- Legacy single-object config is auto-normalized to one connection.
|
|
170
|
+
- Client runtime JSON files (`delta_timer.json`, `subscription.json`, `sentence_filter.json`) are stored per connection and can be edited via API.
|
|
373
171
|
|
|
374
|
-
|
|
172
|
+
For complete setting definitions and ranges, use `docs/configuration-reference.md`.
|
|
375
173
|
|
|
376
|
-
|
|
377
|
-
|--------|---------------|
|
|
378
|
-
| `index.js` | Plugin entry point, shared state, file watchers, lifecycle |
|
|
379
|
-
| `lib/constants.js` | Shared constants and batch size calculation |
|
|
380
|
-
| `lib/CircularBuffer.js` | Fixed-size circular buffer for O(1) metrics history |
|
|
381
|
-
| `lib/crypto.js` | AES-256-GCM encryption and decryption |
|
|
382
|
-
| `lib/metrics.js` | Bandwidth tracking, path analytics, error recording |
|
|
383
|
-
| `lib/pathDictionary.js` | Signal K path encoding (170+ paths) |
|
|
384
|
-
| `lib/pipeline.js` | Compress → encrypt → send / receive → decrypt → decompress |
|
|
385
|
-
| `lib/routes.js` | HTTP route handlers, rate limiting, config file I/O |
|
|
174
|
+
Schema and migration helpers:
|
|
386
175
|
|
|
387
|
-
|
|
176
|
+
- `schemas/config.schema.json` (machine-readable config schema)
|
|
177
|
+
- `src/scripts/migrate-config.ts` (convert legacy flat config to `connections[]`)
|
|
178
|
+
- `npm run migrate:config -- <input.json> [output.json]`
|
|
388
179
|
|
|
389
|
-
|
|
180
|
+
## Security notes
|
|
390
181
|
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
├── lib/
|
|
395
|
-
│ ├── CircularBuffer.js # Fixed-size circular buffer
|
|
396
|
-
│ ├── constants.js # Shared constants and utilities
|
|
397
|
-
│ ├── crypto.js # AES-256-GCM encryption module
|
|
398
|
-
│ ├── metrics.js # Metrics, bandwidth, path analytics
|
|
399
|
-
│ ├── pathDictionary.js # Signal K path encoding (170+ paths)
|
|
400
|
-
│ ├── pipeline.js # Pack/unpack pipeline (compress, encrypt, UDP)
|
|
401
|
-
│ └── routes.js # HTTP routes and rate limiting
|
|
402
|
-
├── src/
|
|
403
|
-
│ ├── webapp/
|
|
404
|
-
│ │ ├── index.js # Web dashboard (vanilla JS)
|
|
405
|
-
│ │ └── styles.css
|
|
406
|
-
│ └── components/
|
|
407
|
-
│ └── PluginConfigurationPanel.jsx # React config panel
|
|
408
|
-
├── __tests__/ # 209 tests across 9 files
|
|
409
|
-
│ ├── crypto.test.js
|
|
410
|
-
│ ├── pathDictionary.test.js
|
|
411
|
-
│ ├── compression.test.js
|
|
412
|
-
│ ├── full-pipeline.test.js
|
|
413
|
-
│ ├── smartBatching.test.js
|
|
414
|
-
│ ├── config.test.js
|
|
415
|
-
│ ├── index.test.js
|
|
416
|
-
│ ├── webapp.test.js
|
|
417
|
-
│ └── integration-pipe.test.js
|
|
418
|
-
└── public/ # Built UI files (generated)
|
|
419
|
-
```
|
|
182
|
+
- Uses AES-256-GCM authenticated encryption.
|
|
183
|
+
- Keys must match exactly and can be entered as 32-character ASCII, 64-character hex, or 44-character base64.
|
|
184
|
+
- Restrict UDP ingress to trusted source addresses whenever possible.
|
|
420
185
|
|
|
421
|
-
|
|
186
|
+
Example key generation:
|
|
422
187
|
|
|
423
188
|
```bash
|
|
424
|
-
|
|
425
|
-
npm run build # Production build
|
|
426
|
-
npm test # Run all 209 tests
|
|
427
|
-
npm run test:watch # Run tests in watch mode
|
|
428
|
-
npm run test:coverage # Generate coverage report
|
|
429
|
-
npm run lint # Check code style
|
|
430
|
-
npm run lint:fix # Auto-fix linting issues
|
|
431
|
-
npm run format # Format code with Prettier
|
|
189
|
+
openssl rand -hex 32
|
|
432
190
|
```
|
|
433
191
|
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
The test suite covers all critical paths with 209 tests across 9 files:
|
|
437
|
-
|
|
438
|
-
| Test file | Scope |
|
|
439
|
-
|-----------|-------|
|
|
440
|
-
| `crypto.test.js` | Encryption, decryption, key validation |
|
|
441
|
-
| `pathDictionary.test.js` | Path encoding and decoding |
|
|
442
|
-
| `compression.test.js` | Brotli compression effectiveness |
|
|
443
|
-
| `full-pipeline.test.js` | End-to-end compression + encryption round-trip |
|
|
444
|
-
| `smartBatching.test.js` | Rolling average, batch limits, size verification |
|
|
445
|
-
| `config.test.js` | Configuration file creation, loading, hot-reload |
|
|
446
|
-
| `index.test.js` | Plugin lifecycle, schema validation |
|
|
447
|
-
| `webapp.test.js` | Web UI metrics and API endpoints |
|
|
448
|
-
| `integration-pipe.test.js` | Full input → backend → frontend data flow |
|
|
192
|
+
## Troubleshooting
|
|
449
193
|
|
|
450
|
-
|
|
194
|
+
Common checks:
|
|
451
195
|
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
npm test -- --coverage
|
|
456
|
-
```
|
|
196
|
+
- Verify `udpAddress`, `udpPort`, and `secretKey` match both ends.
|
|
197
|
+
- Confirm server UDP port is reachable and not already in use.
|
|
198
|
+
- If link quality is poor, switch to `protocolVersion: 3` when both peers can upgrade together, or `2` if you must stay compatible with an existing v2 peer.
|
|
457
199
|
|
|
458
|
-
|
|
200
|
+
For issue-oriented diagnostics, use `docs/troubleshooting.md`.
|
|
459
201
|
|
|
460
|
-
|
|
202
|
+
## Developer commands
|
|
461
203
|
|
|
462
|
-
```
|
|
463
|
-
|
|
464
|
-
|
|
204
|
+
```bash
|
|
205
|
+
npm run build
|
|
206
|
+
npm run dev
|
|
207
|
+
npm test
|
|
208
|
+
npm run test:v2
|
|
209
|
+
npm run test:integration
|
|
210
|
+
npm run lint
|
|
211
|
+
npm run lint:fix
|
|
212
|
+
npm run cli -- help
|
|
213
|
+
npm run cli -- instances list --token=$EDGE_LINK_TOKEN --state=running --limit=10 --page=1 --format=table
|
|
214
|
+
npm run cli -- instances show alpha --token=$EDGE_LINK_TOKEN --format=table
|
|
215
|
+
npm run cli -- instances create --config ./new-instance.json --token=$EDGE_LINK_TOKEN
|
|
216
|
+
npm run cli -- instances update alpha --patch '{"udpAddress":"10.0.0.2"}' --token=$EDGE_LINK_TOKEN
|
|
217
|
+
npm run cli -- instances delete alpha --token=$EDGE_LINK_TOKEN
|
|
218
|
+
npm run cli -- bonding status --token=$EDGE_LINK_TOKEN --format=table
|
|
219
|
+
npm run cli -- bonding update --patch '{"failoverThreshold":300}' --token=$EDGE_LINK_TOKEN
|
|
220
|
+
npm run cli -- status --token=$EDGE_LINK_TOKEN --format=table
|
|
465
221
|
```
|
|
466
222
|
|
|
467
|
-
|
|
223
|
+
## Management API security
|
|
468
224
|
|
|
469
|
-
|
|
470
|
-
Client side:
|
|
471
|
-
JSON.stringify(delta) → Serialization
|
|
472
|
-
→ [pathDictionary.encode()] → Optional: numeric path IDs
|
|
473
|
-
→ [msgpack.encode()] → Optional: binary format
|
|
474
|
-
→ brotli.compress(quality=10) → Maximum compression
|
|
475
|
-
→ encryptBinary(key) → AES-256-GCM
|
|
476
|
-
→ UDP send
|
|
477
|
-
|
|
478
|
-
Server side:
|
|
479
|
-
UDP receive
|
|
480
|
-
→ decryptBinary(key) → Verify + decrypt
|
|
481
|
-
→ brotli.decompress()
|
|
482
|
-
→ [msgpack.decode()]
|
|
483
|
-
→ [pathDictionary.decode()]
|
|
484
|
-
→ JSON.parse()
|
|
485
|
-
→ Signal K handleMessage()
|
|
486
|
-
```
|
|
225
|
+
Set `managementApiToken` in plugin options (or the environment variable `SIGNALK_EDGE_LINK_MANAGEMENT_TOKEN`). Protected routes include:
|
|
487
226
|
|
|
488
|
-
|
|
227
|
+
- `/instances`, `/bonding`, `/status`, `/plugin-config`
|
|
228
|
+
- `/config/*`, `/connections/:id/config/*`
|
|
229
|
+
- `/connections/:id/metrics`, `/connections/:id/network-metrics`
|
|
230
|
+
- `/connections/:id/bonding`, `/connections/:id/congestion`
|
|
231
|
+
- `/connections/:id/monitoring/*`, `/monitoring/alerts`
|
|
232
|
+
- `/capture/*`, `/delta-timer`
|
|
489
233
|
|
|
490
|
-
|
|
491
|
-
|----------|-------|---------|
|
|
492
|
-
| Safety margin | 85% | Target 85% of MTU (1190 bytes effective) |
|
|
493
|
-
| Smoothing factor | 0.2 | Rolling average weight (20% new, 80% old) |
|
|
494
|
-
| Initial estimate | 200 bytes | Starting bytes-per-delta assumption |
|
|
495
|
-
| Min deltas | 1 | Always send at least 1 delta |
|
|
496
|
-
| Max deltas | 50 | Cap to prevent excessive batching latency |
|
|
234
|
+
Send the token as either:
|
|
497
235
|
|
|
498
|
-
|
|
236
|
+
- `X-Edge-Link-Token: <token>`
|
|
237
|
+
- `Authorization: Bearer <token>`
|
|
499
238
|
|
|
500
|
-
|
|
501
|
-
|--------|-------|
|
|
502
|
-
| Compression ratio | 85–97% on typical Signal K data |
|
|
503
|
-
| Packet latency | 20–30 ms (serialize → compress → encrypt) |
|
|
504
|
-
| Throughput | 10–100 Hz update rates |
|
|
505
|
-
| Memory | Constant O(1) with circular buffers |
|
|
239
|
+
CLI commands support `--token=<token>` or the `SIGNALK_EDGE_LINK_MANAGEMENT_TOKEN` environment variable.
|
|
506
240
|
|
|
507
|
-
|
|
241
|
+
## Web UI token injection
|
|
508
242
|
|
|
509
|
-
|
|
510
|
-
2. Create a feature branch: `git checkout -b feature/name`
|
|
511
|
-
3. Make changes and add tests
|
|
512
|
-
4. Run `npm test` and `npm run lint` (all must pass)
|
|
513
|
-
5. Run `npm run build` (must succeed)
|
|
514
|
-
6. Commit with clear messages using conventional format
|
|
515
|
-
7. Submit a pull request
|
|
243
|
+
Management pages automatically attach auth headers when a token is available. Token sources are checked in this order:
|
|
516
244
|
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
- Code formatted with Prettier
|
|
521
|
-
- Test coverage for new features
|
|
522
|
-
- README updated if adding features
|
|
245
|
+
1. `window.__EDGE_LINK_AUTH__.token` — injected global (preferred for server-side injection)
|
|
246
|
+
2. URL query parameter `?edgeLinkToken=<token>`
|
|
247
|
+
3. `localStorage.setItem("signalkEdgeLinkManagementToken", "<token>")`
|
|
523
248
|
|
|
524
|
-
|
|
249
|
+
The UI sends both `X-Edge-Link-Token` and `Authorization: Bearer <token>` by default. Override with:
|
|
525
250
|
|
|
251
|
+
```javascript
|
|
252
|
+
window.__EDGE_LINK_AUTH__ = {
|
|
253
|
+
token: "<token>",
|
|
254
|
+
queryParam: "edgeLinkToken",
|
|
255
|
+
localStorageKey: "signalkEdgeLinkManagementToken",
|
|
256
|
+
headerMode: "both" // "both" | "authorization" | "x-edge-link-token"
|
|
257
|
+
};
|
|
526
258
|
```
|
|
527
|
-
type: description
|
|
528
259
|
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
260
|
+
## Documentation map
|
|
261
|
+
|
|
262
|
+
- `docs/README.md` (documentation index)
|
|
263
|
+
- `docs/architecture-overview.md` (system architecture and lifecycle)
|
|
264
|
+
- `docs/configuration-reference.md` (settings and defaults)
|
|
265
|
+
- `docs/api-reference.md
|
|
266
|
+
- `docs/protocol-v2.md` (reliable protocol operational overview)
|
|
267
|
+
- `docs/protocol-v3-spec.md` (authenticated control-plane details)
|
|
268
|
+
- `docs/bonding.md` (bonding concepts and API usage)
|
|
269
|
+
- `docs/congestion-control.md` (congestion-control behavior and tuning)
|
|
270
|
+
- `docs/metrics.md` (metrics and monitoring reference)
|
|
271
|
+
- `docs/management-tools.md` (instance/bonding API + CLI operations)
|
|
272
|
+
- `docs/security.md` (security guidance and deployment hardening)
|
|
273
|
+
- `docs/performance-tuning.md` (deployment tuning recommendations by hardware profile)
|
|
274
|
+
- `samples/` (example JSON configurations for minimal/dev/v2-bonding setups)
|
|
275
|
+
- `grafana/dashboards/edge-link.json` (starter Grafana dashboard)
|
|
276
|
+
- `schemas/config.schema.json` (unified plugin config schema)
|
|
277
|
+
- `src/scripts/migrate-config.ts` (legacy config migration utility)
|
|
278
|
+
- `src/bin/edge-link-cli.ts` (CLI wrapper for migration and instance/bonding management)
|
|
533
279
|
|
|
534
280
|
## License
|
|
535
281
|
|
|
536
|
-
MIT
|
|
537
|
-
|
|
538
|
-
See [LICENSE](LICENSE) file for details.
|
|
282
|
+
MIT. See `LICENSE`.
|