signalk-p2p-plugin 0.3.0 → 0.4.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/CHANGELOG.md +20 -0
- package/README.md +41 -14
- package/deploy/README.md +20 -2
- package/deploy/policy.json +30 -0
- package/dist/advanced-config.d.ts +11 -0
- package/dist/advanced-config.d.ts.map +1 -0
- package/dist/advanced-config.js +40 -0
- package/dist/advanced-config.js.map +1 -0
- package/dist/api.d.ts +14 -1
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +41 -3
- package/dist/api.js.map +1 -1
- package/dist/config.d.ts +5 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +12 -273
- package/dist/config.js.map +1 -1
- package/dist/data/envelope.d.ts.map +1 -1
- package/dist/data/envelope.js +2 -0
- package/dist/data/envelope.js.map +1 -1
- package/dist/data/types.d.ts +1 -1
- package/dist/data/types.d.ts.map +1 -1
- package/dist/groups/control.d.ts +8 -0
- package/dist/groups/control.d.ts.map +1 -1
- package/dist/groups/control.js +30 -0
- package/dist/groups/control.js.map +1 -1
- package/dist/groups/manager.d.ts +2 -0
- package/dist/groups/manager.d.ts.map +1 -1
- package/dist/groups/manager.js +28 -1
- package/dist/groups/manager.js.map +1 -1
- package/dist/groups/types.d.ts +12 -0
- package/dist/groups/types.d.ts.map +1 -1
- package/dist/groups/types.js +23 -0
- package/dist/groups/types.js.map +1 -1
- package/dist/live/relay.d.ts +3 -0
- package/dist/live/relay.d.ts.map +1 -1
- package/dist/live/relay.js +11 -0
- package/dist/live/relay.js.map +1 -1
- package/dist/peer/cli.js +16 -0
- package/dist/peer/cli.js.map +1 -1
- package/dist/peer/config.d.ts +3 -0
- package/dist/peer/config.d.ts.map +1 -1
- package/dist/peer/config.js +5 -0
- package/dist/peer/config.js.map +1 -1
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +136 -46
- package/dist/plugin.js.map +1 -1
- package/dist/policy/operator.d.ts +13 -0
- package/dist/policy/operator.d.ts.map +1 -0
- package/dist/policy/operator.js +53 -0
- package/dist/policy/operator.js.map +1 -0
- package/dist/policy/policy.d.ts +49 -0
- package/dist/policy/policy.d.ts.map +1 -0
- package/dist/policy/policy.js +147 -0
- package/dist/policy/policy.js.map +1 -0
- package/docs/plans/README.md +2 -2
- package/docs/plans/architecture.md +2 -2
- package/docs/plans/networks.md +35 -7
- package/docs/plans/peer-node.md +7 -2
- package/docs/plans/shared-data.md +4 -3
- package/package.json +3 -2
- package/policy/default.json +30 -0
- package/policy/operator.pub +2 -0
- package/public/index.html +268 -68
package/public/index.html
CHANGED
|
@@ -40,6 +40,32 @@
|
|
|
40
40
|
.network-card input[type="checkbox"] {
|
|
41
41
|
accent-color: #0fb9e9;
|
|
42
42
|
}
|
|
43
|
+
.sharing-wrap {
|
|
44
|
+
overflow-x: auto;
|
|
45
|
+
margin-top: 0.5rem;
|
|
46
|
+
}
|
|
47
|
+
.sharing-table {
|
|
48
|
+
width: 100%;
|
|
49
|
+
border-collapse: collapse;
|
|
50
|
+
}
|
|
51
|
+
.sharing-table th,
|
|
52
|
+
.sharing-table td {
|
|
53
|
+
padding: 0.4rem 0.5rem;
|
|
54
|
+
border-bottom: 1px solid #172a45;
|
|
55
|
+
text-align: left;
|
|
56
|
+
vertical-align: top;
|
|
57
|
+
}
|
|
58
|
+
.sharing-table th {
|
|
59
|
+
color: #9fb3c8;
|
|
60
|
+
font-size: 0.8rem;
|
|
61
|
+
text-transform: uppercase;
|
|
62
|
+
letter-spacing: 0.04em;
|
|
63
|
+
white-space: nowrap;
|
|
64
|
+
}
|
|
65
|
+
.sharing-table td small {
|
|
66
|
+
color: #9fb3c8;
|
|
67
|
+
display: block;
|
|
68
|
+
}
|
|
43
69
|
section {
|
|
44
70
|
margin: 1.25rem 0;
|
|
45
71
|
}
|
|
@@ -75,6 +101,25 @@
|
|
|
75
101
|
button:hover {
|
|
76
102
|
background: #7dd3fc;
|
|
77
103
|
}
|
|
104
|
+
details {
|
|
105
|
+
margin: 1rem 0;
|
|
106
|
+
}
|
|
107
|
+
summary {
|
|
108
|
+
cursor: pointer;
|
|
109
|
+
color: #9fb3c8;
|
|
110
|
+
font-weight: 600;
|
|
111
|
+
}
|
|
112
|
+
input[type="number"],
|
|
113
|
+
select {
|
|
114
|
+
background: #101f38;
|
|
115
|
+
color: #e8eef8;
|
|
116
|
+
border: 1px solid #27405f;
|
|
117
|
+
border-radius: 0.35rem;
|
|
118
|
+
padding: 0.2rem 0.35rem;
|
|
119
|
+
}
|
|
120
|
+
input[type="number"] {
|
|
121
|
+
width: 5.5rem;
|
|
122
|
+
}
|
|
78
123
|
textarea {
|
|
79
124
|
width: 100%;
|
|
80
125
|
min-height: 4rem;
|
|
@@ -103,15 +148,18 @@
|
|
|
103
148
|
<h1>Signal K P2P</h1>
|
|
104
149
|
<div id="message"></div>
|
|
105
150
|
|
|
106
|
-
<
|
|
107
|
-
<
|
|
108
|
-
<
|
|
109
|
-
|
|
151
|
+
<details>
|
|
152
|
+
<summary>Advanced</summary>
|
|
153
|
+
<section>
|
|
154
|
+
<h2>Identity</h2>
|
|
155
|
+
<div id="identity">loading…</div>
|
|
156
|
+
</section>
|
|
110
157
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
158
|
+
<section>
|
|
159
|
+
<h2>Claims</h2>
|
|
160
|
+
<div id="claims"></div>
|
|
161
|
+
</section>
|
|
162
|
+
</details>
|
|
115
163
|
|
|
116
164
|
<section>
|
|
117
165
|
<h2>Groups & networks</h2>
|
|
@@ -122,7 +170,6 @@
|
|
|
122
170
|
<button onclick="createGroup()">Create group</button>
|
|
123
171
|
<button onclick="invite()">Create invite</button>
|
|
124
172
|
<button onclick="joinGroup()">Join with token</button>
|
|
125
|
-
<button onclick="setThreshold()">Set threshold</button>
|
|
126
173
|
</div>
|
|
127
174
|
<textarea
|
|
128
175
|
id="token"
|
|
@@ -130,12 +177,12 @@
|
|
|
130
177
|
></textarea>
|
|
131
178
|
</section>
|
|
132
179
|
|
|
133
|
-
<section>
|
|
180
|
+
<section id="requests-section">
|
|
134
181
|
<h2>Join requests</h2>
|
|
135
182
|
<div id="requests"></div>
|
|
136
183
|
</section>
|
|
137
184
|
|
|
138
|
-
<section>
|
|
185
|
+
<section id="proposals-section">
|
|
139
186
|
<h2>Pending proposals</h2>
|
|
140
187
|
<div id="proposals"></div>
|
|
141
188
|
</section>
|
|
@@ -212,7 +259,13 @@
|
|
|
212
259
|
call("/sharing"),
|
|
213
260
|
]);
|
|
214
261
|
renderIdentity(results[0], results[1]);
|
|
215
|
-
|
|
262
|
+
renderSharing(
|
|
263
|
+
results[0],
|
|
264
|
+
results[6],
|
|
265
|
+
(results[3].groups || []).filter(function (group) {
|
|
266
|
+
return !group.removed;
|
|
267
|
+
}),
|
|
268
|
+
);
|
|
216
269
|
renderClaims(results[2].claims || []);
|
|
217
270
|
renderGroups(results[3].groups || []);
|
|
218
271
|
renderRequests(results[4].requests || []);
|
|
@@ -244,6 +297,27 @@
|
|
|
244
297
|
);
|
|
245
298
|
root.appendChild(text("h3", "Status"));
|
|
246
299
|
root.appendChild(identityRow("Version", status.version));
|
|
300
|
+
if (status.policy) {
|
|
301
|
+
root.appendChild(
|
|
302
|
+
identityRow(
|
|
303
|
+
"Network policy",
|
|
304
|
+
"v" +
|
|
305
|
+
status.policy.version +
|
|
306
|
+
" · issued " +
|
|
307
|
+
new Date(status.policy.issuedAt * 1000)
|
|
308
|
+
.toISOString()
|
|
309
|
+
.slice(0, 10),
|
|
310
|
+
),
|
|
311
|
+
);
|
|
312
|
+
if (status.policy.operator) {
|
|
313
|
+
root.appendChild(
|
|
314
|
+
identityRow(
|
|
315
|
+
"Policy operator",
|
|
316
|
+
status.policy.operator.slice(0, 16) + "…",
|
|
317
|
+
),
|
|
318
|
+
);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
247
321
|
root.appendChild(identityRow("Started", status.started ? "yes" : "no"));
|
|
248
322
|
root.appendChild(identityRow("Peers", status.peers));
|
|
249
323
|
root.appendChild(identityRow("Injected vessels", status.injected));
|
|
@@ -278,13 +352,28 @@
|
|
|
278
352
|
}
|
|
279
353
|
}
|
|
280
354
|
|
|
281
|
-
function
|
|
355
|
+
function sharingCheckbox(checked, onchange, disabled) {
|
|
356
|
+
var cell = document.createElement("td");
|
|
357
|
+
var input = document.createElement("input");
|
|
358
|
+
input.type = "checkbox";
|
|
359
|
+
input.checked = !!checked;
|
|
360
|
+
input.disabled = Boolean(disabled);
|
|
361
|
+
input.onchange = function () {
|
|
362
|
+
onchange(input.checked);
|
|
363
|
+
};
|
|
364
|
+
cell.appendChild(input);
|
|
365
|
+
return cell;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
function renderSharing(status, sharing, groups) {
|
|
282
369
|
clear("public-network");
|
|
283
370
|
var root = document.getElementById("public-network");
|
|
284
371
|
root.className = "network-card";
|
|
285
372
|
status = status || {};
|
|
286
373
|
sharing = sharing || {};
|
|
374
|
+
groups = groups || [];
|
|
287
375
|
var network = sharing.network;
|
|
376
|
+
var publicEnabled = Boolean(network && network.enabled);
|
|
288
377
|
root.appendChild(
|
|
289
378
|
identityRow(
|
|
290
379
|
"Public network",
|
|
@@ -293,52 +382,121 @@
|
|
|
293
382
|
);
|
|
294
383
|
if (network) {
|
|
295
384
|
root.appendChild(
|
|
296
|
-
identityRow(
|
|
297
|
-
"Status",
|
|
298
|
-
(network.enabled ? "enabled" : "disabled") +
|
|
299
|
-
" · " +
|
|
300
|
-
(network.consent || "opt-out"),
|
|
301
|
-
),
|
|
385
|
+
identityRow("Status", network.enabled ? "enabled" : "disabled"),
|
|
302
386
|
);
|
|
387
|
+
var consentRow = document.createElement("div");
|
|
388
|
+
consentRow.className = "row";
|
|
389
|
+
consentRow.appendChild(text("code", "Sharing"));
|
|
390
|
+
var consent = document.createElement("select");
|
|
391
|
+
[
|
|
392
|
+
["receive-only", "Receive only (don't share my vessel)"],
|
|
393
|
+
["underway-gated", "Share only while underway"],
|
|
394
|
+
["coarse-position", "Share an approximate position"],
|
|
395
|
+
["opt-out", "Share my vessel"],
|
|
396
|
+
].forEach(function (entry) {
|
|
397
|
+
var option = document.createElement("option");
|
|
398
|
+
option.value = entry[0];
|
|
399
|
+
option.textContent = entry[1];
|
|
400
|
+
consent.appendChild(option);
|
|
401
|
+
});
|
|
402
|
+
consent.value = network.consent || "receive-only";
|
|
403
|
+
consent.onchange = function () {
|
|
404
|
+
setConsent(consent.value);
|
|
405
|
+
};
|
|
406
|
+
consentRow.appendChild(consent);
|
|
407
|
+
root.appendChild(consentRow);
|
|
303
408
|
}
|
|
304
409
|
root.appendChild(identityRow("Peers", status.peers));
|
|
305
|
-
|
|
410
|
+
|
|
411
|
+
var wrap = document.createElement("div");
|
|
412
|
+
wrap.className = "sharing-wrap";
|
|
413
|
+
var table = document.createElement("table");
|
|
414
|
+
table.className = "sharing-table";
|
|
415
|
+
|
|
416
|
+
var head = document.createElement("tr");
|
|
417
|
+
head.appendChild(text("th", "Data set"));
|
|
418
|
+
head.appendChild(text("th", "Public"));
|
|
419
|
+
groups.forEach(function (group) {
|
|
420
|
+
var th = text("th", group.name || group.id.slice(0, 8));
|
|
421
|
+
th.title = group.id;
|
|
422
|
+
head.appendChild(th);
|
|
423
|
+
});
|
|
424
|
+
table.appendChild(head);
|
|
425
|
+
|
|
426
|
+
(sharing.dataSets || []).forEach(function (set) {
|
|
427
|
+
var row = document.createElement("tr");
|
|
428
|
+
var name = document.createElement("td");
|
|
429
|
+
name.appendChild(text("code", set.title));
|
|
430
|
+
name.appendChild(text("small", set.description));
|
|
431
|
+
row.appendChild(name);
|
|
432
|
+
row.appendChild(
|
|
433
|
+
sharingCheckbox(
|
|
434
|
+
set.public,
|
|
435
|
+
function (checked) {
|
|
436
|
+
setSharing(set.id, { public: checked });
|
|
437
|
+
},
|
|
438
|
+
!publicEnabled,
|
|
439
|
+
),
|
|
440
|
+
);
|
|
441
|
+
groups.forEach(function (group) {
|
|
442
|
+
var checked =
|
|
443
|
+
set.groups === "all" ||
|
|
444
|
+
(Array.isArray(set.groups) && set.groups.indexOf(group.id) >= 0);
|
|
445
|
+
row.appendChild(
|
|
446
|
+
sharingCheckbox(checked, function (value) {
|
|
447
|
+
var current =
|
|
448
|
+
set.groups === "all"
|
|
449
|
+
? groups.map(function (entry) {
|
|
450
|
+
return entry.id;
|
|
451
|
+
})
|
|
452
|
+
: set.groups.slice();
|
|
453
|
+
if (value && current.indexOf(group.id) < 0) {
|
|
454
|
+
current.push(group.id);
|
|
455
|
+
}
|
|
456
|
+
if (!value) {
|
|
457
|
+
current = current.filter(function (id) {
|
|
458
|
+
return id !== group.id;
|
|
459
|
+
});
|
|
460
|
+
}
|
|
461
|
+
setSharing(set.id, { groups: current });
|
|
462
|
+
}),
|
|
463
|
+
);
|
|
464
|
+
});
|
|
465
|
+
table.appendChild(row);
|
|
466
|
+
});
|
|
467
|
+
|
|
468
|
+
wrap.appendChild(table);
|
|
469
|
+
root.appendChild(wrap);
|
|
470
|
+
if (!groups.length) {
|
|
306
471
|
root.appendChild(
|
|
307
|
-
|
|
308
|
-
"
|
|
309
|
-
|
|
310
|
-
" (capacity " +
|
|
311
|
-
status.electedPeer.capacity +
|
|
312
|
-
")",
|
|
472
|
+
text(
|
|
473
|
+
"p",
|
|
474
|
+
"No private groups yet. Create or join one to add group columns.",
|
|
313
475
|
),
|
|
314
476
|
);
|
|
315
477
|
}
|
|
316
|
-
(sharing.dataSets || []).forEach(function (set) {
|
|
317
|
-
var label = document.createElement("label");
|
|
318
|
-
label.className = "row";
|
|
319
|
-
var input = document.createElement("input");
|
|
320
|
-
input.type = "checkbox";
|
|
321
|
-
input.checked = !!set.public;
|
|
322
|
-
input.disabled = !(network && network.enabled);
|
|
323
|
-
input.onchange = function () {
|
|
324
|
-
setPublic(set.id, input.checked);
|
|
325
|
-
};
|
|
326
|
-
label.appendChild(input);
|
|
327
|
-
label.appendChild(text("code", set.title));
|
|
328
|
-
label.appendChild(text("span", set.description));
|
|
329
|
-
root.appendChild(label);
|
|
330
|
-
});
|
|
331
478
|
root.appendChild(
|
|
332
479
|
text(
|
|
333
480
|
"p",
|
|
334
|
-
"
|
|
481
|
+
"Check a group column to share that data set with that group. Public membership is open. Changes apply immediately.",
|
|
335
482
|
),
|
|
336
483
|
);
|
|
337
484
|
}
|
|
338
485
|
|
|
339
|
-
async function
|
|
486
|
+
async function setConsent(consent) {
|
|
340
487
|
try {
|
|
341
|
-
await call("/
|
|
488
|
+
await call("/network/consent", { consent: consent });
|
|
489
|
+
say("", false);
|
|
490
|
+
return refresh();
|
|
491
|
+
} catch (error) {
|
|
492
|
+
say(String(error), true);
|
|
493
|
+
return refresh();
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
async function setSharing(dataSet, update) {
|
|
498
|
+
try {
|
|
499
|
+
await call("/sharing", Object.assign({ dataSet: dataSet }, update));
|
|
342
500
|
say("", false);
|
|
343
501
|
return refresh();
|
|
344
502
|
} catch (error) {
|
|
@@ -404,8 +562,6 @@
|
|
|
404
562
|
text(
|
|
405
563
|
"span",
|
|
406
564
|
group.role +
|
|
407
|
-
" · epoch " +
|
|
408
|
-
group.epoch +
|
|
409
565
|
" · " +
|
|
410
566
|
group.members +
|
|
411
567
|
" member(s)" +
|
|
@@ -415,22 +571,24 @@
|
|
|
415
571
|
: ""),
|
|
416
572
|
),
|
|
417
573
|
);
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
574
|
+
if (group.role === "owner" || group.role === "admin") {
|
|
575
|
+
row.appendChild(
|
|
576
|
+
button(
|
|
577
|
+
"Remove",
|
|
578
|
+
action(function () {
|
|
579
|
+
return removeMember(group.id);
|
|
580
|
+
}),
|
|
581
|
+
),
|
|
582
|
+
);
|
|
583
|
+
row.appendChild(
|
|
584
|
+
button(
|
|
585
|
+
"Promote",
|
|
586
|
+
action(function () {
|
|
587
|
+
return promoteMember(group.id);
|
|
588
|
+
}),
|
|
589
|
+
),
|
|
590
|
+
);
|
|
591
|
+
}
|
|
434
592
|
row.appendChild(
|
|
435
593
|
button(
|
|
436
594
|
"Leave",
|
|
@@ -440,10 +598,47 @@
|
|
|
440
598
|
),
|
|
441
599
|
);
|
|
442
600
|
root.appendChild(row);
|
|
601
|
+
|
|
602
|
+
if (!group.removed && group.role !== "viewer") {
|
|
603
|
+
var rateRow = document.createElement("div");
|
|
604
|
+
rateRow.className = "row";
|
|
605
|
+
rateRow.appendChild(text("code", "Publish rate"));
|
|
606
|
+
var input = document.createElement("input");
|
|
607
|
+
input.type = "number";
|
|
608
|
+
input.min = "0.01";
|
|
609
|
+
input.max = String(group.rateCapHz);
|
|
610
|
+
input.step = "0.01";
|
|
611
|
+
input.value = String(group.publishRateHz);
|
|
612
|
+
rateRow.appendChild(input);
|
|
613
|
+
rateRow.appendChild(
|
|
614
|
+
text("span", "/ " + group.rateCapHz + " Hz maximum"),
|
|
615
|
+
);
|
|
616
|
+
rateRow.appendChild(
|
|
617
|
+
button(
|
|
618
|
+
"Set",
|
|
619
|
+
action(function () {
|
|
620
|
+
return setGroupRate(group.id, Number(input.value));
|
|
621
|
+
}),
|
|
622
|
+
),
|
|
623
|
+
);
|
|
624
|
+
if (group.role === "owner" || group.role === "admin") {
|
|
625
|
+
rateRow.appendChild(
|
|
626
|
+
button(
|
|
627
|
+
"Set cap",
|
|
628
|
+
action(function () {
|
|
629
|
+
return setGroupRateCap(group.id);
|
|
630
|
+
}),
|
|
631
|
+
),
|
|
632
|
+
);
|
|
633
|
+
}
|
|
634
|
+
root.appendChild(rateRow);
|
|
635
|
+
}
|
|
443
636
|
});
|
|
444
637
|
}
|
|
445
638
|
|
|
446
639
|
function renderRequests(requests) {
|
|
640
|
+
document.getElementById("requests-section").style.display =
|
|
641
|
+
requests.length ? "" : "none";
|
|
447
642
|
clear("requests");
|
|
448
643
|
var root = document.getElementById("requests");
|
|
449
644
|
if (!requests.length) {
|
|
@@ -477,6 +672,8 @@
|
|
|
477
672
|
}
|
|
478
673
|
|
|
479
674
|
function renderProposals(proposals) {
|
|
675
|
+
document.getElementById("proposals-section").style.display =
|
|
676
|
+
proposals.length ? "" : "none";
|
|
480
677
|
clear("proposals");
|
|
481
678
|
var root = document.getElementById("proposals");
|
|
482
679
|
if (!proposals.length) {
|
|
@@ -600,13 +797,16 @@
|
|
|
600
797
|
await call("/groups/leave", { groupId: groupId });
|
|
601
798
|
}
|
|
602
799
|
|
|
603
|
-
async function
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
800
|
+
async function setGroupRate(groupId, rateHz) {
|
|
801
|
+
await call("/groups/rate", { groupId: groupId, rateHz: rateHz });
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
async function setGroupRateCap(groupId) {
|
|
805
|
+
var value = prompt("Group publish rate cap (Hz)", "1");
|
|
806
|
+
if (value === null) return;
|
|
807
|
+
await call("/groups/rate-cap", {
|
|
608
808
|
groupId: groupId,
|
|
609
|
-
|
|
809
|
+
rateHz: Number(value),
|
|
610
810
|
});
|
|
611
811
|
}
|
|
612
812
|
|