signalk-edge-link 2.4.1 → 2.5.1
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/LICENSE +21 -21
- package/README.md +283 -283
- package/lib/bin/edge-link-cli.js +23 -23
- package/lib/config-watcher.js +49 -36
- package/lib/connection-config.js +49 -4
- package/lib/crypto.js +11 -5
- package/lib/index.js +21 -3
- package/lib/instance.js +71 -6
- package/lib/pipeline-v2-client.js +16 -8
- package/lib/prometheus.js +31 -0
- package/lib/routes/config.js +46 -16
- package/lib/routes/connections.js +2 -1
- package/lib/routes/metrics.js +9 -5
- package/lib/routes/monitoring.js +82 -3
- package/lib/routes.js +134 -16
- package/lib/shared/connection-schema.js +49 -24
- package/lib/values-snapshot.js +152 -0
- package/package.json +165 -164
- package/public/{277.99e19dcb5b778c964ace.js → 277.d365356803e61762acb0.js} +3 -3
- package/public/277.d365356803e61762acb0.js.map +1 -0
- package/public/982.8b63f75cddc5341d56cb.js +2 -0
- package/public/982.8b63f75cddc5341d56cb.js.map +1 -0
- package/public/main.0b6f5e3267731da945f0.js.map +1 -1
- package/public/main.2ae3dd54effad689f0da.css.map +1 -1
- package/public/remoteEntry.js +1 -1
- package/public/remoteEntry.js.map +1 -1
- package/public/277.99e19dcb5b778c964ace.js.map +0 -1
- package/public/982.cc4f5aca99be921e0171.js +0 -2
- package/public/982.cc4f5aca99be921e0171.js.map +0 -1
- /package/public/{277.99e19dcb5b778c964ace.js.LICENSE.txt → 277.d365356803e61762acb0.js.LICENSE.txt} +0 -0
package/LICENSE
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2024-2026 Karl-Erik Gustafsson
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024-2026 Karl-Erik Gustafsson
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,283 +1,283 @@
|
|
|
1
|
-
# Signal K Edge Link
|
|
2
|
-
|
|
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
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
## Requirements
|
|
46
|
-
|
|
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`)
|
|
51
|
-
|
|
52
|
-
## Installation
|
|
53
|
-
|
|
54
|
-
### Option A: Signal K Plugin Manager
|
|
55
|
-
|
|
56
|
-
Install **Signal K Edge Link** from your Signal K plugin catalog.
|
|
57
|
-
|
|
58
|
-
### Option B: Manual install from source
|
|
59
|
-
|
|
60
|
-
```bash
|
|
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
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
Restart Signal K after installation.
|
|
69
|
-
|
|
70
|
-
## Quick start
|
|
71
|
-
|
|
72
|
-
### 1) Configure the destination (Server mode)
|
|
73
|
-
|
|
74
|
-
In Signal K Admin UI:
|
|
75
|
-
|
|
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
|
|
84
|
-
|
|
85
|
-
### 2) Configure the source (Client mode)
|
|
86
|
-
|
|
87
|
-
On the sending Signal K instance:
|
|
88
|
-
|
|
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
|
|
98
|
-
|
|
99
|
-
### 3) Verify traffic
|
|
100
|
-
|
|
101
|
-
Open the runtime UI:
|
|
102
|
-
|
|
103
|
-
`http://<signalk-host>:3000/plugins/signalk-edge-link/`
|
|
104
|
-
|
|
105
|
-
Check that:
|
|
106
|
-
|
|
107
|
-
- client `Deltas Sent` increases
|
|
108
|
-
- server `Deltas Received` increases
|
|
109
|
-
- encryption/decryption errors remain stable at zero
|
|
110
|
-
|
|
111
|
-
## Protocol version guidance
|
|
112
|
-
|
|
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 |
|
|
118
|
-
|
|
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.
|
|
120
|
-
|
|
121
|
-
## Runtime UI and API
|
|
122
|
-
|
|
123
|
-
- Runtime UI: `/plugins/signalk-edge-link/`
|
|
124
|
-
- API base path: `/plugins/signalk-edge-link`
|
|
125
|
-
- Default API rate limit: **120 requests/minute/IP**
|
|
126
|
-
|
|
127
|
-
Most used endpoints:
|
|
128
|
-
|
|
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`
|
|
139
|
-
|
|
140
|
-
For full endpoint details, use `docs/api-reference.md
|
|
141
|
-
|
|
142
|
-
## Configuration model (summary)
|
|
143
|
-
|
|
144
|
-
Configuration is an array of independent connections:
|
|
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
|
-
}
|
|
166
|
-
```
|
|
167
|
-
|
|
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.
|
|
171
|
-
|
|
172
|
-
For complete setting definitions and ranges, use `docs/configuration-reference.md`.
|
|
173
|
-
|
|
174
|
-
Schema and migration helpers:
|
|
175
|
-
|
|
176
|
-
- The runtime schema is defined inline as `plugin.schema` in `src/index.ts`
|
|
177
|
-
and served to the Signal K admin UI. `docs/configuration-reference.md` is
|
|
178
|
-
the authoritative human-readable reference.
|
|
179
|
-
- `src/scripts/migrate-config.ts` (convert legacy flat config to `connections[]`)
|
|
180
|
-
- `npm run migrate:config -- <input.json> [output.json]`
|
|
181
|
-
|
|
182
|
-
## Security notes
|
|
183
|
-
|
|
184
|
-
- Uses AES-256-GCM authenticated encryption.
|
|
185
|
-
- Keys must match exactly and can be entered as 32-character ASCII, 64-character hex, or 44-character base64.
|
|
186
|
-
- Restrict UDP ingress to trusted source addresses whenever possible.
|
|
187
|
-
|
|
188
|
-
Example key generation:
|
|
189
|
-
|
|
190
|
-
```bash
|
|
191
|
-
openssl rand -hex 32
|
|
192
|
-
```
|
|
193
|
-
|
|
194
|
-
## Troubleshooting
|
|
195
|
-
|
|
196
|
-
Common checks:
|
|
197
|
-
|
|
198
|
-
- Verify `udpAddress`, `udpPort`, and `secretKey` match both ends.
|
|
199
|
-
- Confirm server UDP port is reachable and not already in use.
|
|
200
|
-
- 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.
|
|
201
|
-
|
|
202
|
-
For issue-oriented diagnostics, use `docs/troubleshooting.md`.
|
|
203
|
-
|
|
204
|
-
## Developer commands
|
|
205
|
-
|
|
206
|
-
```bash
|
|
207
|
-
npm run build
|
|
208
|
-
npm run dev
|
|
209
|
-
npm test
|
|
210
|
-
npm run test:v2
|
|
211
|
-
npm run test:integration
|
|
212
|
-
npm run lint
|
|
213
|
-
npm run lint:fix
|
|
214
|
-
npm run cli -- help
|
|
215
|
-
npm run cli -- instances list --token=$EDGE_LINK_TOKEN --state=running --limit=10 --page=1 --format=table
|
|
216
|
-
npm run cli -- instances show alpha --token=$EDGE_LINK_TOKEN --format=table
|
|
217
|
-
npm run cli -- instances create --config ./new-instance.json --token=$EDGE_LINK_TOKEN
|
|
218
|
-
npm run cli -- instances update alpha --patch '{"udpAddress":"10.0.0.2"}' --token=$EDGE_LINK_TOKEN
|
|
219
|
-
npm run cli -- instances delete alpha --token=$EDGE_LINK_TOKEN
|
|
220
|
-
npm run cli -- bonding status --token=$EDGE_LINK_TOKEN --format=table
|
|
221
|
-
npm run cli -- bonding update --patch '{"failoverThreshold":300}' --token=$EDGE_LINK_TOKEN
|
|
222
|
-
npm run cli -- status --token=$EDGE_LINK_TOKEN --format=table
|
|
223
|
-
```
|
|
224
|
-
|
|
225
|
-
## Management API security
|
|
226
|
-
|
|
227
|
-
Set `managementApiToken` in plugin options (or the environment variable `SIGNALK_EDGE_LINK_MANAGEMENT_TOKEN`). Protected routes include:
|
|
228
|
-
|
|
229
|
-
- `/instances`, `/bonding`, `/status`, `/plugin-config`
|
|
230
|
-
- `/config/*`, `/connections/:id/config/*`
|
|
231
|
-
- `/connections/:id/metrics`, `/connections/:id/network-metrics`
|
|
232
|
-
- `/connections/:id/bonding`, `/connections/:id/congestion`
|
|
233
|
-
- `/connections/:id/monitoring/*`, `/monitoring/alerts`
|
|
234
|
-
- `/capture/*`, `/delta-timer`
|
|
235
|
-
|
|
236
|
-
Send the token as either:
|
|
237
|
-
|
|
238
|
-
- `X-Edge-Link-Token: <token>`
|
|
239
|
-
- `Authorization: Bearer <token>`
|
|
240
|
-
|
|
241
|
-
CLI commands support `--token=<token>` or the `SIGNALK_EDGE_LINK_MANAGEMENT_TOKEN` environment variable.
|
|
242
|
-
|
|
243
|
-
## Web UI token injection
|
|
244
|
-
|
|
245
|
-
Management pages automatically attach auth headers when a token is available. Token sources are checked in this order:
|
|
246
|
-
|
|
247
|
-
1. `window.__EDGE_LINK_AUTH__.token` — injected global (preferred for server-side injection)
|
|
248
|
-
2. URL query parameter `?edgeLinkToken=<token>`
|
|
249
|
-
3. `localStorage.setItem("signalkEdgeLinkManagementToken", "<token>")`
|
|
250
|
-
|
|
251
|
-
The UI sends both `X-Edge-Link-Token` and `Authorization: Bearer <token>` by default. Override with:
|
|
252
|
-
|
|
253
|
-
```javascript
|
|
254
|
-
window.__EDGE_LINK_AUTH__ = {
|
|
255
|
-
token: "<token>",
|
|
256
|
-
queryParam: "edgeLinkToken",
|
|
257
|
-
localStorageKey: "signalkEdgeLinkManagementToken",
|
|
258
|
-
headerMode: "both" // "both" | "authorization" | "x-edge-link-token"
|
|
259
|
-
};
|
|
260
|
-
```
|
|
261
|
-
|
|
262
|
-
## Documentation map
|
|
263
|
-
|
|
264
|
-
- `docs/README.md` (documentation index)
|
|
265
|
-
- `docs/architecture-overview.md` (system architecture and lifecycle)
|
|
266
|
-
- `docs/configuration-reference.md` (settings and defaults)
|
|
267
|
-
- `docs/api-reference.md
|
|
268
|
-
- `docs/protocol-v2.md` (reliable protocol operational overview)
|
|
269
|
-
- `docs/protocol-v3-spec.md` (authenticated control-plane details)
|
|
270
|
-
- `docs/bonding.md` (bonding concepts and API usage)
|
|
271
|
-
- `docs/congestion-control.md` (congestion-control behavior and tuning)
|
|
272
|
-
- `docs/metrics.md` (metrics and monitoring reference)
|
|
273
|
-
- `docs/management-tools.md` (instance/bonding API + CLI operations)
|
|
274
|
-
- `docs/security.md` (security guidance and deployment hardening)
|
|
275
|
-
- `docs/performance-tuning.md` (deployment tuning recommendations by hardware profile)
|
|
276
|
-
- `samples/` (example JSON configurations for minimal/dev/v2-bonding setups)
|
|
277
|
-
- `grafana/dashboards/edge-link.json` (starter Grafana dashboard)
|
|
278
|
-
- `src/scripts/migrate-config.ts` (legacy config migration utility)
|
|
279
|
-
- `src/bin/edge-link-cli.ts` (CLI wrapper for migration and instance/bonding management)
|
|
280
|
-
|
|
281
|
-
## License
|
|
282
|
-
|
|
283
|
-
MIT. See `LICENSE`.
|
|
1
|
+
# Signal K Edge Link
|
|
2
|
+
|
|
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
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Requirements
|
|
46
|
+
|
|
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`)
|
|
51
|
+
|
|
52
|
+
## Installation
|
|
53
|
+
|
|
54
|
+
### Option A: Signal K Plugin Manager
|
|
55
|
+
|
|
56
|
+
Install **Signal K Edge Link** from your Signal K plugin catalog.
|
|
57
|
+
|
|
58
|
+
### Option B: Manual install from source
|
|
59
|
+
|
|
60
|
+
```bash
|
|
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
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Restart Signal K after installation.
|
|
69
|
+
|
|
70
|
+
## Quick start
|
|
71
|
+
|
|
72
|
+
### 1) Configure the destination (Server mode)
|
|
73
|
+
|
|
74
|
+
In Signal K Admin UI:
|
|
75
|
+
|
|
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
|
|
84
|
+
|
|
85
|
+
### 2) Configure the source (Client mode)
|
|
86
|
+
|
|
87
|
+
On the sending Signal K instance:
|
|
88
|
+
|
|
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
|
|
98
|
+
|
|
99
|
+
### 3) Verify traffic
|
|
100
|
+
|
|
101
|
+
Open the runtime UI:
|
|
102
|
+
|
|
103
|
+
`http://<signalk-host>:3000/plugins/signalk-edge-link/`
|
|
104
|
+
|
|
105
|
+
Check that:
|
|
106
|
+
|
|
107
|
+
- client `Deltas Sent` increases
|
|
108
|
+
- server `Deltas Received` increases
|
|
109
|
+
- encryption/decryption errors remain stable at zero
|
|
110
|
+
|
|
111
|
+
## Protocol version guidance
|
|
112
|
+
|
|
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 |
|
|
118
|
+
|
|
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.
|
|
120
|
+
|
|
121
|
+
## Runtime UI and API
|
|
122
|
+
|
|
123
|
+
- Runtime UI: `/plugins/signalk-edge-link/`
|
|
124
|
+
- API base path: `/plugins/signalk-edge-link`
|
|
125
|
+
- Default API rate limit: **120 requests/minute/IP**
|
|
126
|
+
|
|
127
|
+
Most used endpoints:
|
|
128
|
+
|
|
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`
|
|
139
|
+
|
|
140
|
+
For full endpoint details, use `docs/api-reference.md
|
|
141
|
+
|
|
142
|
+
## Configuration model (summary)
|
|
143
|
+
|
|
144
|
+
Configuration is an array of independent connections:
|
|
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
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
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.
|
|
171
|
+
|
|
172
|
+
For complete setting definitions and ranges, use `docs/configuration-reference.md`.
|
|
173
|
+
|
|
174
|
+
Schema and migration helpers:
|
|
175
|
+
|
|
176
|
+
- The runtime schema is defined inline as `plugin.schema` in `src/index.ts`
|
|
177
|
+
and served to the Signal K admin UI. `docs/configuration-reference.md` is
|
|
178
|
+
the authoritative human-readable reference.
|
|
179
|
+
- `src/scripts/migrate-config.ts` (convert legacy flat config to `connections[]`)
|
|
180
|
+
- `npm run migrate:config -- <input.json> [output.json]`
|
|
181
|
+
|
|
182
|
+
## Security notes
|
|
183
|
+
|
|
184
|
+
- Uses AES-256-GCM authenticated encryption.
|
|
185
|
+
- Keys must match exactly and can be entered as 32-character ASCII, 64-character hex, or 44-character base64.
|
|
186
|
+
- Restrict UDP ingress to trusted source addresses whenever possible.
|
|
187
|
+
|
|
188
|
+
Example key generation:
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
openssl rand -hex 32
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
## Troubleshooting
|
|
195
|
+
|
|
196
|
+
Common checks:
|
|
197
|
+
|
|
198
|
+
- Verify `udpAddress`, `udpPort`, and `secretKey` match both ends.
|
|
199
|
+
- Confirm server UDP port is reachable and not already in use.
|
|
200
|
+
- 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.
|
|
201
|
+
|
|
202
|
+
For issue-oriented diagnostics, use `docs/troubleshooting.md`.
|
|
203
|
+
|
|
204
|
+
## Developer commands
|
|
205
|
+
|
|
206
|
+
```bash
|
|
207
|
+
npm run build
|
|
208
|
+
npm run dev
|
|
209
|
+
npm test
|
|
210
|
+
npm run test:v2
|
|
211
|
+
npm run test:integration
|
|
212
|
+
npm run lint
|
|
213
|
+
npm run lint:fix
|
|
214
|
+
npm run cli -- help
|
|
215
|
+
npm run cli -- instances list --token=$EDGE_LINK_TOKEN --state=running --limit=10 --page=1 --format=table
|
|
216
|
+
npm run cli -- instances show alpha --token=$EDGE_LINK_TOKEN --format=table
|
|
217
|
+
npm run cli -- instances create --config ./new-instance.json --token=$EDGE_LINK_TOKEN
|
|
218
|
+
npm run cli -- instances update alpha --patch '{"udpAddress":"10.0.0.2"}' --token=$EDGE_LINK_TOKEN
|
|
219
|
+
npm run cli -- instances delete alpha --token=$EDGE_LINK_TOKEN
|
|
220
|
+
npm run cli -- bonding status --token=$EDGE_LINK_TOKEN --format=table
|
|
221
|
+
npm run cli -- bonding update --patch '{"failoverThreshold":300}' --token=$EDGE_LINK_TOKEN
|
|
222
|
+
npm run cli -- status --token=$EDGE_LINK_TOKEN --format=table
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
## Management API security
|
|
226
|
+
|
|
227
|
+
Set `managementApiToken` in plugin options (or the environment variable `SIGNALK_EDGE_LINK_MANAGEMENT_TOKEN`). Protected routes include:
|
|
228
|
+
|
|
229
|
+
- `/instances`, `/bonding`, `/status`, `/plugin-config`
|
|
230
|
+
- `/config/*`, `/connections/:id/config/*`
|
|
231
|
+
- `/connections/:id/metrics`, `/connections/:id/network-metrics`
|
|
232
|
+
- `/connections/:id/bonding`, `/connections/:id/congestion`
|
|
233
|
+
- `/connections/:id/monitoring/*`, `/monitoring/alerts`
|
|
234
|
+
- `/capture/*`, `/delta-timer`
|
|
235
|
+
|
|
236
|
+
Send the token as either:
|
|
237
|
+
|
|
238
|
+
- `X-Edge-Link-Token: <token>`
|
|
239
|
+
- `Authorization: Bearer <token>`
|
|
240
|
+
|
|
241
|
+
CLI commands support `--token=<token>` or the `SIGNALK_EDGE_LINK_MANAGEMENT_TOKEN` environment variable.
|
|
242
|
+
|
|
243
|
+
## Web UI token injection
|
|
244
|
+
|
|
245
|
+
Management pages automatically attach auth headers when a token is available. Token sources are checked in this order:
|
|
246
|
+
|
|
247
|
+
1. `window.__EDGE_LINK_AUTH__.token` — injected global (preferred for server-side injection)
|
|
248
|
+
2. URL query parameter `?edgeLinkToken=<token>`
|
|
249
|
+
3. `localStorage.setItem("signalkEdgeLinkManagementToken", "<token>")`
|
|
250
|
+
|
|
251
|
+
The UI sends both `X-Edge-Link-Token` and `Authorization: Bearer <token>` by default. Override with:
|
|
252
|
+
|
|
253
|
+
```javascript
|
|
254
|
+
window.__EDGE_LINK_AUTH__ = {
|
|
255
|
+
token: "<token>",
|
|
256
|
+
queryParam: "edgeLinkToken",
|
|
257
|
+
localStorageKey: "signalkEdgeLinkManagementToken",
|
|
258
|
+
headerMode: "both" // "both" | "authorization" | "x-edge-link-token"
|
|
259
|
+
};
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
## Documentation map
|
|
263
|
+
|
|
264
|
+
- `docs/README.md` (documentation index)
|
|
265
|
+
- `docs/architecture-overview.md` (system architecture and lifecycle)
|
|
266
|
+
- `docs/configuration-reference.md` (settings and defaults)
|
|
267
|
+
- `docs/api-reference.md
|
|
268
|
+
- `docs/protocol-v2.md` (reliable protocol operational overview)
|
|
269
|
+
- `docs/protocol-v3-spec.md` (authenticated control-plane details)
|
|
270
|
+
- `docs/bonding.md` (bonding concepts and API usage)
|
|
271
|
+
- `docs/congestion-control.md` (congestion-control behavior and tuning)
|
|
272
|
+
- `docs/metrics.md` (metrics and monitoring reference)
|
|
273
|
+
- `docs/management-tools.md` (instance/bonding API + CLI operations)
|
|
274
|
+
- `docs/security.md` (security guidance and deployment hardening)
|
|
275
|
+
- `docs/performance-tuning.md` (deployment tuning recommendations by hardware profile)
|
|
276
|
+
- `samples/` (example JSON configurations for minimal/dev/v2-bonding setups)
|
|
277
|
+
- `grafana/dashboards/edge-link.json` (starter Grafana dashboard)
|
|
278
|
+
- `src/scripts/migrate-config.ts` (legacy config migration utility)
|
|
279
|
+
- `src/bin/edge-link-cli.ts` (CLI wrapper for migration and instance/bonding management)
|
|
280
|
+
|
|
281
|
+
## License
|
|
282
|
+
|
|
283
|
+
MIT. See `LICENSE`.
|
package/lib/bin/edge-link-cli.js
CHANGED
|
@@ -16,29 +16,29 @@ const node_https_1 = __importDefault(require("node:https"));
|
|
|
16
16
|
const node_url_1 = require("node:url");
|
|
17
17
|
const migrate_config_1 = require("../scripts/migrate-config");
|
|
18
18
|
function printHelp() {
|
|
19
|
-
console.log(`Signal K Edge Link CLI
|
|
20
|
-
|
|
21
|
-
Usage:
|
|
22
|
-
edge-link-cli migrate-config <input.json> [output.json]
|
|
23
|
-
edge-link-cli instances list [--baseUrl=<url>] [--token=<token>] [--state=<value>] [--limit=<n>] [--page=<n>] [--format=json|table]
|
|
24
|
-
edge-link-cli instances show <id> [--baseUrl=<url>] [--token=<token>] [--format=json|table]
|
|
25
|
-
edge-link-cli instances create --config <path.json> [--baseUrl=<url>] [--token=<token>]
|
|
26
|
-
edge-link-cli instances update <id> --patch '{"key":"value"}' [--baseUrl=<url>] [--token=<token>]
|
|
27
|
-
edge-link-cli instances delete <id> [--baseUrl=<url>] [--token=<token>]
|
|
28
|
-
edge-link-cli bonding status [--baseUrl=<url>] [--token=<token>] [--format=json|table]
|
|
29
|
-
edge-link-cli bonding update --patch '{"failoverThreshold":300}' [--baseUrl=<url>] [--token=<token>]
|
|
30
|
-
edge-link-cli status [--baseUrl=<url>] [--token=<token>] [--format=json|table]
|
|
31
|
-
|
|
32
|
-
Commands:
|
|
33
|
-
migrate-config Convert legacy flat plugin config to connections[] format
|
|
34
|
-
instances list Print instance summaries from GET /instances
|
|
35
|
-
instances show Print one instance from GET /instances/:id
|
|
36
|
-
instances create Create a new instance via POST /instances
|
|
37
|
-
instances update Update an instance via PUT /instances/:id
|
|
38
|
-
instances delete Delete an instance via DELETE /instances/:id
|
|
39
|
-
bonding status Print bonding summary from GET /bonding
|
|
40
|
-
bonding update Update bonding settings via POST /bonding
|
|
41
|
-
status Print aggregated status from GET /status
|
|
19
|
+
console.log(`Signal K Edge Link CLI
|
|
20
|
+
|
|
21
|
+
Usage:
|
|
22
|
+
edge-link-cli migrate-config <input.json> [output.json]
|
|
23
|
+
edge-link-cli instances list [--baseUrl=<url>] [--token=<token>] [--state=<value>] [--limit=<n>] [--page=<n>] [--format=json|table]
|
|
24
|
+
edge-link-cli instances show <id> [--baseUrl=<url>] [--token=<token>] [--format=json|table]
|
|
25
|
+
edge-link-cli instances create --config <path.json> [--baseUrl=<url>] [--token=<token>]
|
|
26
|
+
edge-link-cli instances update <id> --patch '{"key":"value"}' [--baseUrl=<url>] [--token=<token>]
|
|
27
|
+
edge-link-cli instances delete <id> [--baseUrl=<url>] [--token=<token>]
|
|
28
|
+
edge-link-cli bonding status [--baseUrl=<url>] [--token=<token>] [--format=json|table]
|
|
29
|
+
edge-link-cli bonding update --patch '{"failoverThreshold":300}' [--baseUrl=<url>] [--token=<token>]
|
|
30
|
+
edge-link-cli status [--baseUrl=<url>] [--token=<token>] [--format=json|table]
|
|
31
|
+
|
|
32
|
+
Commands:
|
|
33
|
+
migrate-config Convert legacy flat plugin config to connections[] format
|
|
34
|
+
instances list Print instance summaries from GET /instances
|
|
35
|
+
instances show Print one instance from GET /instances/:id
|
|
36
|
+
instances create Create a new instance via POST /instances
|
|
37
|
+
instances update Update an instance via PUT /instances/:id
|
|
38
|
+
instances delete Delete an instance via DELETE /instances/:id
|
|
39
|
+
bonding status Print bonding summary from GET /bonding
|
|
40
|
+
bonding update Update bonding settings via POST /bonding
|
|
41
|
+
status Print aggregated status from GET /status
|
|
42
42
|
`);
|
|
43
43
|
}
|
|
44
44
|
function getArgValue(args, flag, fallback = null) {
|