syndicate-js/packages/core/src/transport/relay.ts

90 lines
2.9 KiB
TypeScript
Raw Normal View History

2021-12-01 16:24:29 +00:00
/// SPDX-License-Identifier: GPL-3.0-or-later
2024-02-03 14:59:22 +00:00
/// SPDX-FileCopyrightText: Copyright © 2016-2024 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
2021-12-01 16:13:00 +00:00
import { Assertion, Facet, Ref, Turn } from '../runtime/actor.js';
import { BytesLike, Decoder, encode, Embedded, stringify, underlying } from '@preserves/core';
2021-12-01 16:13:00 +00:00
import * as IO from '../gen/protocol.js';
import { wireRefEmbeddedType } from './protocol.js';
import { WireRef } from '../gen/sturdy.js';
import { LayerBoundary } from './membrane.js';
2021-12-01 16:13:00 +00:00
2023-05-28 09:18:29 +00:00
const FLUSH = Symbol.for('flush');
2021-12-01 16:13:00 +00:00
export type PacketWriter = (bs: Uint8Array) => void;
export interface RelayOptions {
packetWriter: PacketWriter;
setup(r: Relay): void;
2021-12-01 16:13:00 +00:00
debug?: boolean;
trustPeer?: boolean;
2021-12-12 22:54:35 +00:00
initialOid?: IO.Oid;
initialRef?: Ref;
nextLocalOid?: IO.Oid;
2021-12-01 16:13:00 +00:00
}
export class Relay extends LayerBoundary {
2021-12-01 16:13:00 +00:00
readonly facet: Facet;
2023-05-28 09:18:29 +00:00
readonly selfRef: Ref;
2021-12-01 16:13:00 +00:00
readonly w: PacketWriter;
2021-12-12 22:54:35 +00:00
readonly peer: Ref | null;
pendingTurn: IO.Turn<Embedded<WireRef>> = [];
2021-12-01 16:13:00 +00:00
debug: boolean;
readonly decoder = new Decoder(void 0, {
includeAnnotations: false,
embeddedDecode: wireRefEmbeddedType,
});
constructor(options: RelayOptions) {
super(options.trustPeer, options.nextLocalOid);
this.facet = Turn.activeFacet;
2023-05-28 09:18:29 +00:00
this.selfRef = Turn.ref(this);
2021-12-01 16:13:00 +00:00
this.w = options.packetWriter;
this.debug = options.debug ?? false;
this.facet.preventInertCheck();
options.setup(this);
2021-12-12 22:54:35 +00:00
if (options.initialRef !== void 0) {
this.rewriteRefOut(options.initialRef, false, []);
}
this.peer = (options.initialOid !== void 0)
? this.rewriteRefIn(new Embedded<WireRef>(WireRef.mine(options.initialOid)), [])
2021-12-12 22:54:35 +00:00
: null;
2021-12-01 16:13:00 +00:00
}
2023-05-28 09:18:29 +00:00
message(body: Assertion) {
if (body === FLUSH) {
if (this.debug) console.log('OUT', stringify(IO.fromTurn(this.pendingTurn)));
2023-05-28 09:18:29 +00:00
this.w(underlying(encode(IO.fromTurn(this.pendingTurn), {
canonical: true,
embeddedEncode: wireRefEmbeddedType,
})));
this.pendingTurn = [];
}
}
send(remoteOid: IO.Oid, m: IO.Event<Embedded<WireRef>>): void {
2021-12-01 16:13:00 +00:00
if (this.pendingTurn.length === 0) {
2023-05-28 09:18:29 +00:00
Turn.active.message(this.selfRef, FLUSH);
2021-12-01 16:13:00 +00:00
}
this.pendingTurn.push(IO.TurnEvent({ oid: remoteOid, event: m }));
}
accept(bs: BytesLike): void {
this.facet.turn(() => {
2021-12-01 16:13:00 +00:00
this.decoder.write(bs);
while (true) {
const rawPacket = this.decoder.try_next();
if (rawPacket === void 0) break;
const wirePacket = IO.toPacket(rawPacket);
if (wirePacket === void 0) throw new Error("Bad IO.Packet");
if (this.debug) console.log('IN', stringify(rawPacket));
this.proxyPacket(wirePacket);
2021-12-01 16:13:00 +00:00
}
});
}
}