/// SPDX-License-Identifier: GPL-3.0-or-later /// SPDX-FileCopyrightText: Copyright © 2016-2023 Tony Garnock-Jones 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; } } }); } }); } } } }