novy-syndicate/src/protocol.ts

78 lines
2.5 KiB
TypeScript
Raw Normal View History

2021-03-04 18:54:12 +00:00
import { Handle, Ref } from './actor.js';
import { Attenuation, Pattern, Template } from './rewrite.js';
2021-03-02 08:50:23 +00:00
import { Record, Value } from 'preserves';
export const _Assert = Symbol.for('assert');
export const _Retract = Symbol.for('retract');
export const _Message = Symbol.for('message');
export const _Sync = Symbol.for('sync');
2021-03-03 14:45:35 +00:00
function mk<T extends object>() {
return {
Assert: Record.makeConstructor<{assertion: Value<T>, handle: Handle}, T>()(
_Assert, ['assertion', 'handle']),
Retract: Record.makeConstructor<{handle: Handle}, T>()(
_Retract, ['handle']),
Message: Record.makeConstructor<{body: Value<T>}, T>()(
_Message, ['body']),
Sync: Record.makeConstructor<{peer: T}, T>()(
_Sync, ['peer']),
};
}
export type EntityMessage<T extends object> =
| Record<typeof _Assert, [Value<T>, Handle], T>
| Record<typeof _Retract, [Handle], T>
| Record<typeof _Message, [Value<T>], T>
| Record<typeof _Sync, [T], T>;
2021-03-02 08:50:23 +00:00
2021-03-03 14:45:35 +00:00
export type TurnMessage<T extends object> = Array<[Oid, EntityMessage<T>]>;
2021-03-02 08:50:23 +00:00
export type Oid = number;
2021-03-03 14:45:35 +00:00
export type WireSymbol = { oid: Oid, ref: Ref, count: number };
export type WireRef =
| { loc: "mine", oid: Oid }
| { loc: "your", oid: Oid, attenuation: EncodedAttenuation };
export const IO = mk<WireRef>();
export function myRef(oid: Oid): WireRef & { loc: "mine" } {
return { loc: 'mine', oid };
}
export function yourRef(oid: Oid, attenuation: EncodedAttenuation): WireRef & { loc: "your" } {
return { loc: 'your', oid, attenuation };
}
export type EncodedAttenuation = Array<Array<[Value<WireRef>, Value<WireRef>]>>;
export function encodeAttenuation(a: Attenuation | undefined): EncodedAttenuation {
if (a === void 0) return [];
return a.map(s => s.map(({pattern, template}) => [
pattern as Value<WireRef>,
template as Value<WireRef>,
]));
}
export function decodeAttenuation(v: Array<Value<WireRef>>): Attenuation {
function complain(): never {
throw new Error(
`Received invalid attenuation ${v.asPreservesText()} from peer`);
}
if (v.length === 0) return [];
return v.map(s => {
if (!Array.isArray(s)) complain();
return s.map(e => {
if (!(Array.isArray(e) && e.length === 2)) complain();
// TODO: check structure of pattern and template
return {
pattern: e[0] as Pattern,
template: e[1] as Template,
};
});
});
}