syndicate-js/packages/ws-relay/src/index.ts

74 lines
3.4 KiB
TypeScript

/// SPDX-License-Identifier: GPL-3.0-or-later
/// SPDX-FileCopyrightText: Copyright © 2016-2023 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
import { QuasiValue as Q, Ref, Relay, Turn, Supervisor, SupervisorRestartPolicy, Observe, Schemas, assertionFacetObserver, isEmbedded } from "@syndicate-lang/core";
import * as G from "./gen/ws";
export * from "./gen/ws";
export function boot(ds: Ref, debug: boolean = false) {
spawn named 'wsRelay' {
at ds {
during Observe({ "pattern": :pattern G.Resolved({
"addr": \$addrPatValue,
"sturdyref": \$sturdyRefPatValue,
"resolved": \Q.bind(),
}) }) => {
const addr = Q.drop_lit(addrPatValue, G.toRelayAddress);
const sturdyref = Q.drop_lit(sturdyRefPatValue, Schemas.sturdy.toSturdyRef);
if (addr && sturdyref) {
assert G.ViaRelay({
"addr": addr,
"assertion": Schemas.gatekeeper.fromResolve(Schemas.gatekeeper.Resolve({
"sturdyref": sturdyref,
"observer": create assertionFacetObserver(e => {
if (isEmbedded(e)) {
assert G.fromResolved(G.Resolved({
"addr": addr,
"sturdyref": sturdyref,
"resolved": e.embeddedValue,
}));
}
}),
})),
});
}
}
during G.ViaRelay({ "addr": $addrValue }) => spawn named ['wsRelay', addrValue] {
let counter = 0;
new Supervisor({
restartPolicy: SupervisorRestartPolicy.ALWAYS,
}, () => ['wsRelay', addrValue, counter++], () => {
const addr = G.toRelayAddress(addrValue);
if (addr !== void 0) {
stop on message G.ForceRelayDisconnect(addrValue);
const facet = Turn.activeFacet;
const ws = new WebSocket(addr.url);
ws.binaryType = 'arraybuffer';
ws.onclose = () => facet.turn(() => { stop {} });
ws.onerror = () => facet.turn(() =>
Turn.active.crash(new Error("WebSocket error")));
ws.onopen = () => facet.turn(() => {
const relay = new Relay.Relay({
debug,
trustPeer: true,
packetWriter: bs => ws.send(bs),
setup(r: Relay.Relay) {
ws.onmessage = e => facet.turn(() =>
r.accept(new Uint8Array(e.data)));
},
initialOid: 0,
});
during G.ViaRelay({ "addr": addrValue, "assertion": $a }) => {
at relay.peer! {
assert a;
}
}
});
}
});
}
}
}
}