diff --git a/src/relay.ts b/src/relay.ts index 626e67b..b6d958e 100644 --- a/src/relay.ts +++ b/src/relay.ts @@ -1,5 +1,5 @@ import { Actor, Assertion, attenuate, Entity, Handle, Ref, Turn } from './actor.js'; -import { Bytes, canonicalString, decode, encode, FlexMap, IdentityMap, mapPointers, underlying, Value } from 'preserves'; +import { BytesLike, canonicalString, Decoder, encode, FlexMap, IdentityMap, mapPointers, underlying, Value } from 'preserves'; import { EncodedAttenuation, EntityMessage, @@ -146,6 +146,30 @@ export class Relay { debug: boolean; trustPeer: boolean; + readonly decoder = new Decoder(void 0, { + includeAnnotations: false, + decodePointer: v => { + function complain(): never { + throw new Error( + `Received invalid object reference ${v.asPreservesText()} from peer`); + } + if (!(Array.isArray(v) && v.length >= 2 && typeof v[1] === 'number')) { + complain(); + } + const oid = v[1] as Oid; + switch (v[0]) { + case 0: + if (v.length > 2) complain(); + return myRef(oid); + case 1: + // TODO: check EncodedAttenuation + return yourRef(oid, v.slice(2) as EncodedAttenuation); + default: + complain(); + } + }, + }); + constructor(t: Turn, options: RelayOptions) { this.actor = t.actor; this.w = options.packetWriter; @@ -255,37 +279,19 @@ export class Relay { return this.exported.byOid.get(localOid)?.ref ?? INERT_REF; } - accept(bs0: Uint8Array): void { + accept(bs: BytesLike): void { Turn.for(this.actor, t => { - const bs = Bytes.from(bs0); - const wireTurn = decode(bs, { - decodePointer: v => { - function complain(): never { - throw new Error( - `Received invalid object reference ${v.asPreservesText()} from peer`); - } - if (!(Array.isArray(v) && v.length >= 2 && typeof v[1] === 'number')) { - complain(); - } - const oid = v[1] as Oid; - switch (v[0]) { - case 0: - if (v.length > 2) complain(); - return myRef(oid); - case 1: - // TODO: check EncodedAttenuation - return yourRef(oid, v.slice(2) as EncodedAttenuation); - default: - complain(); - } - }, - }) as TurnMessage; - // ^ TODO: deep check that v is a TurnMessage - if (this.debug) console.log('IN', wireTurn.asPreservesText()); - wireTurn.forEach(v => { - const [localOid, m] = v; - this.handle(t, this.lookupLocal(localOid), m); - }); + this.decoder.write(bs); + while (true) { + const wireTurn = this.decoder.try_next() as (TurnMessage | undefined); + if (wireTurn === void 0) break; + // TODO: deep check that wireTurn really is a TurnMessage + if (this.debug) console.log('IN', wireTurn.asPreservesText()); + wireTurn.forEach(v => { + const [localOid, m] = v; + this.handle(t, this.lookupLocal(localOid), m); + }); + } }); }