@agoric/network
Advanced tools
Comparing version 0.1.1-dev-c731c8c.0 to 0.1.1-dev-c74c628.0
export * from './network.js'; | ||
export * from './shapes.js'; | ||
export { prepareRouter, prepareRouterProtocol } from './router.js'; | ||
export * from './multiaddr.js'; | ||
export * from './bytes.js'; |
{ | ||
"name": "@agoric/network", | ||
"version": "0.1.1-dev-c731c8c.0+c731c8c", | ||
"version": "0.1.1-dev-c74c628.0+c74c628", | ||
"description": "Agoric's network protocol API", | ||
@@ -24,18 +24,18 @@ "type": "module", | ||
"dependencies": { | ||
"@agoric/assert": "0.6.1-dev-c731c8c.0+c731c8c", | ||
"@agoric/internal": "0.3.3-dev-c731c8c.0+c731c8c", | ||
"@agoric/store": "0.9.3-dev-c731c8c.0+c731c8c", | ||
"@agoric/vat-data": "0.5.3-dev-c731c8c.0+c731c8c", | ||
"@endo/base64": "^1.0.2", | ||
"@endo/far": "^1.0.4", | ||
"@endo/patterns": "^1.1.0", | ||
"@endo/promise-kit": "^1.0.4" | ||
"@agoric/assert": "0.6.1-dev-c74c628.0+c74c628", | ||
"@agoric/internal": "0.3.3-dev-c74c628.0+c74c628", | ||
"@agoric/store": "0.9.3-dev-c74c628.0+c74c628", | ||
"@agoric/vat-data": "0.5.3-dev-c74c628.0+c74c628", | ||
"@endo/base64": "^1.0.4", | ||
"@endo/far": "^1.1.1", | ||
"@endo/patterns": "^1.3.1", | ||
"@endo/promise-kit": "^1.1.1" | ||
}, | ||
"devDependencies": { | ||
"@agoric/swingset-liveslots": "0.10.3-dev-c731c8c.0+c731c8c", | ||
"@agoric/swingset-vat": "0.32.3-dev-c731c8c.0+c731c8c", | ||
"@agoric/zone": "0.2.3-dev-c731c8c.0+c731c8c", | ||
"@endo/bundle-source": "^3.1.0", | ||
"@agoric/swingset-liveslots": "0.10.3-dev-c74c628.0+c74c628", | ||
"@agoric/swingset-vat": "0.32.3-dev-c74c628.0+c74c628", | ||
"@agoric/zone": "0.2.3-dev-c74c628.0+c74c628", | ||
"@endo/bundle-source": "^3.2.2", | ||
"ava": "^5.3.0", | ||
"c8": "^7.13.0" | ||
"c8": "^9.1.0" | ||
}, | ||
@@ -59,3 +59,3 @@ "exports": { | ||
"engines": { | ||
"node": ">=14.15.0" | ||
"node": "^18.12 || ^20.9" | ||
}, | ||
@@ -73,5 +73,5 @@ "ava": { | ||
"typeCoverage": { | ||
"atLeast": 76.57 | ||
"atLeast": 89.74 | ||
}, | ||
"gitHead": "c731c8cc815d9cbc814a79a7e53936d672d67a9b" | ||
"gitHead": "c74c62863bb9de77e66f8d909058804912e72528" | ||
} |
/** | ||
* Convert some data to bytes. | ||
* Convert a Uint8Array or other sequence of octets to a string representation | ||
* that `@endo/marshal` accepts as Passable. | ||
* | ||
* @param {Data} data | ||
* @param {ByteSource} byteSource | ||
* @returns {Bytes} | ||
*/ | ||
export function toBytes(data: Data): Bytes; | ||
export function toBytes(byteSource: ByteSource): Bytes; | ||
/** | ||
@@ -18,8 +19,8 @@ * Convert bytes to a String. | ||
* | ||
* @param {Data} data | ||
* @param {ByteSource} byteSource | ||
* @returns {string} base64 encoding | ||
*/ | ||
export function dataToBase64(data: Data): string; | ||
export function dataToBase64(byteSource: ByteSource): string; | ||
/** | ||
* Decodes a string into base64. | ||
* Decodes a base64 string into bytes. | ||
* | ||
@@ -30,2 +31,3 @@ * @param {string} string Base64-encoded string | ||
export function base64ToBytes(string: string): Bytes; | ||
export type ByteSource = Bytes | Buffer | Uint8Array | Iterable<number>; | ||
//# sourceMappingURL=bytes.d.ts.map |
@@ -0,22 +1,41 @@ | ||
// @ts-check | ||
/// <reference path="./types.js" /> | ||
import { Fail } from '@agoric/assert'; | ||
import { encodeBase64, decodeBase64 } from '@endo/base64'; | ||
/** @typedef {Bytes | Buffer | Uint8Array | Iterable<number>} ByteSource */ | ||
/** | ||
* Convert some data to bytes. | ||
* @param {ByteSource} contents | ||
*/ | ||
const coerceToByteArray = contents => { | ||
if (typeof contents === 'string') { | ||
return Uint8Array.from(contents, c => { | ||
const b = c.charCodeAt(0); | ||
b <= 0xff || Fail`character cannot be coerced to an octet: ${c}`; | ||
return b; | ||
}); | ||
} else if (contents instanceof Uint8Array) { | ||
// Reconstruct to ensure we have a Uint8Array and not a Buffer. | ||
return new Uint8Array( | ||
contents.buffer, | ||
contents.byteOffset, | ||
contents.byteLength, | ||
); | ||
} | ||
return new Uint8Array(contents); | ||
}; | ||
/** | ||
* Convert a Uint8Array or other sequence of octets to a string representation | ||
* that `@endo/marshal` accepts as Passable. | ||
* | ||
* @param {Data} data | ||
* @param {ByteSource} byteSource | ||
* @returns {Bytes} | ||
*/ | ||
export function toBytes(data) { | ||
/** @type {Data | number[]} */ | ||
let bytes = data; | ||
// TODO: We really need marshallable TypedArrays. | ||
if (typeof bytes === 'string') { | ||
bytes = bytes.split('').map(c => c.charCodeAt(0)); | ||
} | ||
export function toBytes(byteSource) { | ||
// We return the raw characters in the lower half of | ||
// the String's representation. | ||
const buf = new Uint8Array(bytes); | ||
return String.fromCharCode.apply(null, buf); | ||
const buf = coerceToByteArray(byteSource); | ||
return String.fromCharCode(...buf); | ||
} | ||
@@ -37,16 +56,7 @@ | ||
* | ||
* @param {Data} data | ||
* @param {ByteSource} byteSource | ||
* @returns {string} base64 encoding | ||
*/ | ||
export function dataToBase64(data) { | ||
/** @type {Uint8Array} */ | ||
let bytes; | ||
if (typeof data === 'string') { | ||
bytes = new Uint8Array(data.length); | ||
for (let i = 0; i < data.length; i += 1) { | ||
bytes[i] = data.charCodeAt(i); | ||
} | ||
} else { | ||
bytes = new Uint8Array(data); | ||
} | ||
export function dataToBase64(byteSource) { | ||
const bytes = coerceToByteArray(byteSource); | ||
return encodeBase64(bytes); | ||
@@ -56,3 +66,3 @@ } | ||
/** | ||
* Decodes a string into base64. | ||
* Decodes a base64 string into bytes. | ||
* | ||
@@ -59,0 +69,0 @@ * @param {string} string Base64-encoded string |
export * from "./network.js"; | ||
export * from "./shapes.js"; | ||
export * from "./multiaddr.js"; | ||
@@ -3,0 +4,0 @@ export * from "./bytes.js"; |
export * from './network.js'; | ||
export * from './shapes.js'; | ||
export { prepareRouter, prepareRouterProtocol } from './router.js'; | ||
export * from './multiaddr.js'; | ||
export * from './bytes.js'; |
@@ -13,26 +13,30 @@ /** | ||
*/ | ||
export function prepareLoopbackProtocolHandler(zone: import('@agoric/base-zone').Zone, { when }: ReturnType<(zone: import("@agoric/base-zone").Zone, powers?: { | ||
export function prepareLoopbackProtocolHandler(zone: import('@agoric/base-zone').Zone, { watch, allVows }: ReturnType<(zone: import("@agoric/base-zone").Zone, powers?: { | ||
isRetryableReason?: ((reason: any) => boolean) | undefined; | ||
watchPromise?: ((p: PromiseLike<any>, watcher: import("@agoric/vow/src/watch-promise.js").PromiseWatcher, ...args: unknown[]) => void) | undefined; | ||
} | undefined) => { | ||
when: <T = any, TResult1 = import("@agoric/vow/src/E.js").Unwrap<T>, TResult2 = never>(specimenP: T, onFulfilled?: ((value: import("@agoric/vow/src/E.js").Unwrap<T>) => TResult1 | PromiseLike<TResult1>) | undefined, onRejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined) => Promise<TResult1 | TResult2>; | ||
when: <T, TResult1 = import("@agoric/vow").Unwrap<T>, TResult2 = never>(specimenP: T, onFulfilled?: ((value: import("@agoric/vow").Unwrap<T>) => TResult1 | PromiseLike<TResult1>) | undefined, onRejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined) => Promise<TResult1 | TResult2>; | ||
watch: <T_1 = any, TResult1_1 = T_1, TResult2_1 = T_1>(specimenP: import("@agoric/vow").ERef<T_1 | import("@agoric/vow").Vow<T_1>>, watcher?: import("@agoric/vow").Watcher<T_1, TResult1_1, TResult2_1> | undefined, watcherContext?: unknown) => import("@agoric/vow").Vow<TResult1_1 | TResult2_1>; | ||
makeVowKit: <T_2>() => import("@agoric/vow").VowKit<T_2>; | ||
}>): (instancePrefix?: string | undefined) => import("@endo/exo/src/exo-makers.js").Guarded<{ | ||
allVows: (vows: any) => import("@agoric/vow").Vow<any>; | ||
}>): (instancePrefix?: string | undefined) => import("@endo/exo").Guarded<{ | ||
onCreate(_impl: any, _protocolHandler: any): Promise<void>; | ||
generatePortID(_localAddr: any, _protocolHandler: any): Promise<string>; | ||
onBind(_port: any, _localAddr: any, _protocolHandler: any): Promise<void>; | ||
onConnect(_port: any, localAddr: any, remoteAddr: any, _chandler: any, protocolHandler: any): Promise<{ | ||
remoteInstance: any; | ||
handler: ConnectionHandler; | ||
}>; | ||
/** | ||
* @param {*} _port | ||
* @param {Endpoint} localAddr | ||
* @param {Endpoint} remoteAddr | ||
* @returns {PromiseVow<AttemptDescription>}} | ||
*/ | ||
onConnect(_port: any, localAddr: Endpoint, remoteAddr: Endpoint): PromiseVow<AttemptDescription>; | ||
onInstantiate(_port: any, _localAddr: any, _remote: any, _protocol: any): Promise<string>; | ||
onListen(port: any, localAddr: any, listenHandler: any, _protocolHandler: any): Promise<void>; | ||
/** | ||
* @param {Port} port | ||
* @param {Remote<Port>} port | ||
* @param {Endpoint} localAddr | ||
* @param {ListenHandler} listenHandler | ||
* @param {Remote<ListenHandler>} listenHandler | ||
* @param {*} _protocolHandler | ||
*/ | ||
onListenRemove(port: Port, localAddr: Endpoint, listenHandler: ListenHandler, _protocolHandler: any): Promise<void>; | ||
onListenRemove(port: Remote<Port>, localAddr: Endpoint, listenHandler: Remote<ListenHandler>, _protocolHandler: any): Promise<void>; | ||
onRevoke(_port: any, _localAddr: any, _protocolHandler: any): Promise<void>; | ||
@@ -45,55 +49,4 @@ }>; | ||
export const ENDPOINT_SEPARATOR: "/"; | ||
export namespace Shape { | ||
let ConnectionI: import("@endo/patterns").InterfaceGuard<{ | ||
send: import("@endo/patterns").MethodGuard; | ||
close: import("@endo/patterns").MethodGuard; | ||
getLocalAddress: import("@endo/patterns").MethodGuard; | ||
getRemoteAddress: import("@endo/patterns").MethodGuard; | ||
}>; | ||
let InboundAttemptI: import("@endo/patterns").InterfaceGuard<{ | ||
accept: import("@endo/patterns").MethodGuard; | ||
getLocalAddress: import("@endo/patterns").MethodGuard; | ||
getRemoteAddress: import("@endo/patterns").MethodGuard; | ||
close: import("@endo/patterns").MethodGuard; | ||
}>; | ||
let PortI: import("@endo/patterns").InterfaceGuard<{ | ||
getLocalAddress: import("@endo/patterns").MethodGuard; | ||
addListener: import("@endo/patterns").MethodGuard; | ||
connect: import("@endo/patterns").MethodGuard; | ||
removeListener: import("@endo/patterns").MethodGuard; | ||
revoke: import("@endo/patterns").MethodGuard; | ||
}>; | ||
let ProtocolHandlerI: import("@endo/patterns").InterfaceGuard<{ | ||
onCreate: import("@endo/patterns").MethodGuard; | ||
generatePortID: import("@endo/patterns").MethodGuard; | ||
onBind: import("@endo/patterns").MethodGuard; | ||
onListen: import("@endo/patterns").MethodGuard; | ||
onListenRemove: import("@endo/patterns").MethodGuard; | ||
onInstantiate: import("@endo/patterns").MethodGuard; | ||
onConnect: import("@endo/patterns").MethodGuard; | ||
onRevoke: import("@endo/patterns").MethodGuard; | ||
}>; | ||
let ProtocolImplI: import("@endo/patterns").InterfaceGuard<{ | ||
bind: import("@endo/patterns").MethodGuard; | ||
inbound: import("@endo/patterns").MethodGuard; | ||
outbound: import("@endo/patterns").MethodGuard; | ||
}>; | ||
function Vow$(shape: any): import("@endo/patterns").Matcher; | ||
let AttemptDescription: import("@endo/patterns").Matcher; | ||
let Opts: import("@endo/patterns").Matcher; | ||
let Data: import("@endo/patterns").Matcher; | ||
let Bytes: import("@endo/patterns").Matcher; | ||
let Endpoint: import("@endo/patterns").Matcher; | ||
let Vow: import("@endo/patterns").Matcher; | ||
let ConnectionHandler: import("@endo/patterns").Matcher; | ||
let Connection: import("@endo/patterns").Matcher; | ||
let InboundAttempt: import("@endo/patterns").Matcher; | ||
let Listener: import("@endo/patterns").Matcher; | ||
let ListenHandler: import("@endo/patterns").Matcher; | ||
let Port: import("@endo/patterns").Matcher; | ||
let ProtocolHandler: import("@endo/patterns").Matcher; | ||
let ProtocolImpl: import("@endo/patterns").Matcher; | ||
} | ||
export function rethrowUnlessMissing(err: unknown): undefined; | ||
export function crossoverConnection(zone: import('@agoric/zone').Zone, handler0: ConnectionHandler, addr0: Endpoint, handler1: ConnectionHandler, addr1: Endpoint, makeConnection: (opts: ConnectionOpts) => Connection, current?: WeakSetStore<Closable>): Connection[]; | ||
export function crossoverConnection(zone: import('@agoric/zone').Zone, handler0: import('@agoric/vow').Remote<Required<ConnectionHandler>>, addr0: Endpoint, handler1: import('@agoric/vow').Remote<Required<ConnectionHandler>>, addr1: Endpoint, makeConnection: (opts: ConnectionOpts) => Connection, current?: globalThis.WeakSetStore<Closable> | undefined): Connection[]; | ||
export function prepareNetworkProtocol(zone: import('@agoric/base-zone').Zone, powers: ReturnType<(zone: import("@agoric/base-zone").Zone, powers?: { | ||
@@ -103,7 +56,8 @@ isRetryableReason?: ((reason: any) => boolean) | undefined; | ||
} | undefined) => { | ||
when: <T = any, TResult1 = import("@agoric/vow/src/E.js").Unwrap<T>, TResult2 = never>(specimenP: T, onFulfilled?: ((value: import("@agoric/vow/src/E.js").Unwrap<T>) => TResult1 | PromiseLike<TResult1>) | undefined, onRejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined) => Promise<TResult1 | TResult2>; | ||
when: <T, TResult1 = import("@agoric/vow").Unwrap<T>, TResult2 = never>(specimenP: T, onFulfilled?: ((value: import("@agoric/vow").Unwrap<T>) => TResult1 | PromiseLike<TResult1>) | undefined, onRejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined) => Promise<TResult1 | TResult2>; | ||
watch: <T_1 = any, TResult1_1 = T_1, TResult2_1 = T_1>(specimenP: import("@agoric/vow").ERef<T_1 | import("@agoric/vow").Vow<T_1>>, watcher?: import("@agoric/vow").Watcher<T_1, TResult1_1, TResult2_1> | undefined, watcherContext?: unknown) => import("@agoric/vow").Vow<TResult1_1 | TResult2_1>; | ||
makeVowKit: <T_2>() => import("@agoric/vow").VowKit<T_2>; | ||
}>): (protocolHandler: ProtocolHandler) => Protocol; | ||
export function prepareEchoConnectionKit(zone: import('@agoric/base-zone').Zone): () => import("@endo/exo/src/exo-makers.js").GuardedKit<{ | ||
allVows: (vows: any) => import("@agoric/vow").Vow<any>; | ||
}>): (protocolHandler: Remote<ProtocolHandler>) => Protocol; | ||
export function prepareEchoConnectionKit(zone: import('@agoric/base-zone').Zone): () => import("@endo/exo").GuardedKit<{ | ||
handler: { | ||
@@ -124,3 +78,3 @@ /** | ||
listener: { | ||
onAccept(_port: any, _localAddr: any, _remoteAddr: any, _listenHandler: any): Promise<import("@endo/exo/src/exo-makers.js").Guarded<{ | ||
onAccept(_port: any, _localAddr: any, _remoteAddr: any, _listenHandler: any): Promise<import("@endo/exo").Guarded<{ | ||
/** | ||
@@ -144,3 +98,3 @@ * @param {Connection} _connection | ||
addrs: Endpoint[]; | ||
handlers: ConnectionHandler[]; | ||
handlers: import('@agoric/vow').Remote<Required<ConnectionHandler>>[]; | ||
conns: MapStore<number, Connection>; | ||
@@ -147,0 +101,0 @@ current: WeakSetStore<Closable>; |
1403
src/network.js
@@ -6,4 +6,4 @@ // @ts-check | ||
import { Fail } from '@agoric/assert'; | ||
import { whileTrue } from '@agoric/internal'; | ||
import { toBytes } from './bytes.js'; | ||
import { Shape } from './shapes.js'; | ||
@@ -19,125 +19,2 @@ import '@agoric/store/exported.js'; | ||
const Shape1 = /** @type {const} */ ({ | ||
/** | ||
* Data is string | Buffer | ArrayBuffer | ||
* but only string is passable | ||
*/ | ||
Data: M.string(), | ||
Bytes: M.string(), | ||
Endpoint: M.string(), | ||
// TODO: match on "Vow" tag | ||
// @endo/patterns supports it as of | ||
// https://github.com/endojs/endo/pull/2091 | ||
// but that's not in agoric-sdk yet. | ||
// For now, use M.any() to avoid: | ||
// cannot check unrecognized tag "Vow": "[Vow]" | ||
Vow: M.any(), | ||
ConnectionHandler: M.remotable('ConnectionHandler'), | ||
Connection: M.remotable('Connection'), | ||
InboundAttempt: M.remotable('InboundAttempt'), | ||
Listener: M.remotable('Listener'), | ||
ListenHandler: M.remotable('ListenHandler'), | ||
Port: M.remotable('Port'), | ||
ProtocolHandler: M.remotable('ProtocolHandler'), | ||
ProtocolImpl: M.remotable('ProtocolImpl'), | ||
}); | ||
const Shape2 = /** @type {const} */ ({ | ||
...Shape1, | ||
Vow$: shape => M.or(shape, Shape1.Vow), | ||
AttemptDescription: M.splitRecord( | ||
{ handler: Shape1.ConnectionHandler }, | ||
{ remoteAddress: Shape1.Endpoint, localAddress: Shape1.Endpoint }, | ||
), | ||
Opts: M.recordOf(M.string(), M.any()), | ||
}); | ||
export const Shape = /** @type {const} */ harden({ | ||
...Shape2, | ||
ConnectionI: M.interface('Connection', { | ||
send: M.callWhen(Shape2.Data) | ||
.optional(Shape2.Opts) | ||
.returns(Shape2.Vow$(Shape2.Bytes)), | ||
close: M.callWhen().returns(Shape2.Vow$(M.undefined())), | ||
getLocalAddress: M.call().returns(Shape2.Endpoint), | ||
getRemoteAddress: M.call().returns(Shape2.Endpoint), | ||
}), | ||
InboundAttemptI: M.interface('InboundAttempt', { | ||
accept: M.callWhen(Shape2.AttemptDescription).returns( | ||
Shape2.Vow$(Shape2.Connection), | ||
), | ||
getLocalAddress: M.call().returns(Shape2.Endpoint), | ||
getRemoteAddress: M.call().returns(Shape2.Endpoint), | ||
close: M.callWhen().returns(Shape2.Vow$(M.undefined())), | ||
}), | ||
PortI: M.interface('Port', { | ||
getLocalAddress: M.call().returns(Shape2.Endpoint), | ||
addListener: M.callWhen(Shape2.Listener).returns( | ||
Shape2.Vow$(M.undefined()), | ||
), | ||
connect: M.callWhen(Shape2.Endpoint) | ||
.optional(Shape2.ConnectionHandler) | ||
.returns(Shape2.Vow$(Shape2.Connection)), | ||
removeListener: M.callWhen(Shape2.Listener).returns( | ||
Shape2.Vow$(M.undefined()), | ||
), | ||
revoke: M.callWhen().returns(M.undefined()), | ||
}), | ||
ProtocolHandlerI: M.interface('ProtocolHandler', { | ||
onCreate: M.callWhen(M.remotable(), Shape2.ProtocolHandler).returns( | ||
Shape2.Vow$(M.undefined()), | ||
), | ||
generatePortID: M.callWhen(Shape2.Endpoint, Shape2.ProtocolHandler).returns( | ||
Shape2.Vow$(M.string()), | ||
), | ||
onBind: M.callWhen( | ||
Shape2.Port, | ||
Shape2.Endpoint, | ||
Shape2.ProtocolHandler, | ||
).returns(Shape2.Vow$(M.undefined())), | ||
onListen: M.callWhen( | ||
Shape2.Port, | ||
Shape2.Endpoint, | ||
Shape2.ListenHandler, | ||
Shape2.ProtocolHandler, | ||
).returns(Shape2.Vow$(M.undefined())), | ||
onListenRemove: M.callWhen( | ||
Shape2.Port, | ||
Shape2.Endpoint, | ||
Shape2.ListenHandler, | ||
Shape2.ProtocolHandler, | ||
).returns(Shape2.Vow$(M.undefined())), | ||
onInstantiate: M.callWhen( | ||
Shape2.Port, | ||
Shape2.Endpoint, | ||
Shape2.Endpoint, | ||
Shape2.ProtocolHandler, | ||
).returns(Shape2.Vow$(Shape2.Endpoint)), | ||
onConnect: M.callWhen( | ||
Shape2.Port, | ||
Shape2.Endpoint, | ||
Shape2.Endpoint, | ||
Shape2.ConnectionHandler, | ||
Shape2.ProtocolHandler, | ||
).returns(Shape2.Vow$(Shape2.AttemptDescription)), | ||
onRevoke: M.callWhen( | ||
Shape2.Port, | ||
Shape2.Endpoint, | ||
Shape2.ProtocolHandler, | ||
).returns(Shape2.Vow$(M.undefined())), | ||
}), | ||
ProtocolImplI: M.interface('ProtocolImpl', { | ||
bind: M.callWhen(Shape2.Endpoint).returns(Shape2.Vow$(Shape2.Port)), | ||
inbound: M.callWhen(Shape2.Endpoint, Shape2.Endpoint).returns( | ||
Shape2.Vow$(Shape2.InboundAttempt), | ||
), | ||
outbound: M.callWhen( | ||
Shape2.Port, | ||
Shape2.Endpoint, | ||
Shape2.ConnectionHandler, | ||
).returns(Shape2.Vow$(Shape2.Connection)), | ||
}), | ||
}); | ||
/** @param {unknown} err */ | ||
@@ -149,3 +26,3 @@ export const rethrowUnlessMissing = err => { | ||
!(err instanceof TypeError) || | ||
!err.message.match(/target has no method|is not a function$/) | ||
!String(err.message).match(/target has no method|is not a function$/) | ||
) { | ||
@@ -178,3 +55,3 @@ throw err; | ||
* @property {Endpoint[]} addrs | ||
* @property {ConnectionHandler[]} handlers | ||
* @property {import('@agoric/vow').Remote<Required<ConnectionHandler>>[]} handlers | ||
* @property {MapStore<number, Connection>} conns | ||
@@ -190,4 +67,4 @@ * @property {WeakSetStore<Closable>} current | ||
*/ | ||
const prepareHalfConnection = (zone, { when }) => { | ||
const makeHalfConnection = zone.exoClass( | ||
const prepareHalfConnection = (zone, { watch }) => { | ||
const makeHalfConnectionKit = zone.exoClassKit( | ||
'Connection', | ||
@@ -197,5 +74,2 @@ Shape.ConnectionI, | ||
({ addrs, handlers, conns, current, l, r }) => { | ||
/** @type {string | undefined} */ | ||
let closed; | ||
return { | ||
@@ -208,47 +82,82 @@ addrs, | ||
r, | ||
closed, | ||
/** @type {string | undefined} */ | ||
closed: undefined, | ||
}; | ||
}, | ||
{ | ||
getLocalAddress() { | ||
const { addrs, l } = this.state; | ||
return addrs[l]; | ||
}, | ||
getRemoteAddress() { | ||
const { addrs, r } = this.state; | ||
return addrs[r]; | ||
}, | ||
/** @param {Data} packetBytes */ | ||
async send(packetBytes) { | ||
const { closed, handlers, r, conns } = this.state; | ||
if (closed) { | ||
throw closed; | ||
} | ||
connection: { | ||
getLocalAddress() { | ||
const { addrs, l } = this.state; | ||
return addrs[l]; | ||
}, | ||
getRemoteAddress() { | ||
const { addrs, r } = this.state; | ||
return addrs[r]; | ||
}, | ||
/** @param {Bytes} packetBytes */ | ||
async send(packetBytes) { | ||
const { closed, handlers, r, conns } = this.state; | ||
if (closed) { | ||
throw Error(closed); | ||
} | ||
const ack = await when( | ||
E(handlers[r]) | ||
.onReceive(conns.get(r), toBytes(packetBytes), handlers[r]) | ||
.catch(rethrowUnlessMissing), | ||
); | ||
const innerVow = watch( | ||
E(handlers[r]).onReceive( | ||
conns.get(r), | ||
toBytes(packetBytes), | ||
handlers[r], | ||
), | ||
this.facets.openConnectionAckWatcher, | ||
); | ||
return watch(innerVow, this.facets.rethrowUnlessMissingWatcher); | ||
}, | ||
async close() { | ||
const { closed, current, conns, l, handlers } = this.state; | ||
if (closed) { | ||
throw Error(closed); | ||
} | ||
this.state.closed = 'Connection closed'; | ||
current.delete(conns.get(l)); | ||
const innerVow = watch( | ||
E(this.state.handlers[l]).onClose( | ||
conns.get(l), | ||
undefined, | ||
handlers[l], | ||
), | ||
this.facets.sinkWatcher, | ||
); | ||
return toBytes(ack || ''); | ||
return watch(innerVow, this.facets.rethrowUnlessMissingWatcher); | ||
}, | ||
}, | ||
async close() { | ||
const { closed, current, conns, l, handlers } = this.state; | ||
if (closed) { | ||
throw Error(closed); | ||
} | ||
this.state.closed = 'Connection closed'; | ||
current.delete(conns.get(l)); | ||
await when( | ||
E(this.state.handlers[l]).onClose( | ||
conns.get(l), | ||
undefined, | ||
handlers[l], | ||
), | ||
).catch(rethrowUnlessMissing); | ||
openConnectionAckWatcher: { | ||
onFulfilled(ack) { | ||
return toBytes(ack || ''); | ||
}, | ||
}, | ||
rethrowUnlessMissingWatcher: { | ||
onRejected(e) { | ||
rethrowUnlessMissing(e); | ||
}, | ||
}, | ||
sinkWatcher: { | ||
onFulfilled(_value) { | ||
return undefined; | ||
}, | ||
}, | ||
}, | ||
); | ||
const makeHalfConnection = ({ addrs, handlers, conns, current, l, r }) => { | ||
const { connection } = makeHalfConnectionKit({ | ||
addrs, | ||
handlers, | ||
conns, | ||
current, | ||
l, | ||
r, | ||
}); | ||
return harden(connection); | ||
}; | ||
return makeHalfConnection; | ||
@@ -259,8 +168,8 @@ }; | ||
* @param {import('@agoric/zone').Zone} zone | ||
* @param {ConnectionHandler} handler0 | ||
* @param {import('@agoric/vow').Remote<Required<ConnectionHandler>>} handler0 | ||
* @param {Endpoint} addr0 | ||
* @param {ConnectionHandler} handler1 | ||
* @param {import('@agoric/vow').Remote<Required<ConnectionHandler>>} handler1 | ||
* @param {Endpoint} addr1 | ||
* @param {(opts: ConnectionOpts) => Connection} makeConnection | ||
* @param {WeakSetStore<Closable>} current | ||
* @param {WeakSetStore<Closable>} [current] | ||
*/ | ||
@@ -281,3 +190,3 @@ export const crossoverConnection = ( | ||
/** @type {ConnectionHandler[]} */ | ||
/** @type {import('@agoric/vow').Remote<Required<ConnectionHandler>>[]} */ | ||
const handlers = harden([handler0, handler1]); | ||
@@ -320,4 +229,4 @@ /** @type {Endpoint[]} */ | ||
*/ | ||
const prepareInboundAttempt = (zone, makeConnection, { when }) => { | ||
const makeInboundAttempt = zone.exoClass( | ||
const prepareInboundAttempt = (zone, makeConnection, { watch }) => { | ||
const makeInboundAttemptKit = zone.exoClassKit( | ||
'InboundAttempt', | ||
@@ -329,5 +238,5 @@ Shape.InboundAttemptI, | ||
* @param {string} opts.remoteAddr | ||
* @param { MapStore<Port, SetStore<Closable>> } opts.currentConnections | ||
* @param {MapStore<Port, SetStore<Closable>>} opts.currentConnections | ||
* @param {string} opts.listenPrefix | ||
* @param {MapStore<Endpoint, [Port, ListenHandler]>} opts.listening | ||
* @param {MapStore<Endpoint, [Port, import('@agoric/vow').Remote<Required<ListenHandler>>]>} opts.listening | ||
*/ | ||
@@ -354,71 +263,121 @@ ({ | ||
{ | ||
getLocalAddress() { | ||
// Return address metadata. | ||
return this.state.localAddr; | ||
}, | ||
getRemoteAddress() { | ||
return this.state.remoteAddr; | ||
}, | ||
async close() { | ||
const { consummated, localAddr, remoteAddr } = this.state; | ||
const { listening, listenPrefix, currentConnections } = this.state; | ||
inboundAttempt: { | ||
getLocalAddress() { | ||
// Return address metadata. | ||
return this.state.localAddr; | ||
}, | ||
getRemoteAddress() { | ||
return this.state.remoteAddr; | ||
}, | ||
async close() { | ||
const { consummated, localAddr, remoteAddr } = this.state; | ||
const { listening, listenPrefix, currentConnections } = this.state; | ||
if (consummated) { | ||
throw Error(consummated); | ||
} | ||
this.state.consummated = 'Already closed'; | ||
if (consummated) { | ||
throw Error(consummated); | ||
} | ||
this.state.consummated = 'Already closed'; | ||
const [port, listener] = listening.get(listenPrefix); | ||
const [port, listener] = listening.get(listenPrefix); | ||
const current = currentConnections.get(port); | ||
current.delete(this.self); | ||
const current = currentConnections.get(port); | ||
current.delete(this.facets.inboundAttempt); | ||
await when( | ||
E(listener).onReject(port, localAddr, remoteAddr, listener), | ||
).catch(rethrowUnlessMissing); | ||
}, | ||
/** | ||
* @param {object} opts | ||
* @param {string} [opts.localAddress] | ||
* @param {string} [opts.remoteAddress] | ||
* @param {ConnectionHandler} opts.handler | ||
*/ | ||
async accept({ localAddress, remoteAddress, handler: rchandler }) { | ||
const { consummated, localAddr, remoteAddr } = this.state; | ||
const { listening, listenPrefix, currentConnections } = this.state; | ||
if (consummated) { | ||
throw Error(consummated); | ||
} | ||
this.state.consummated = 'Already accepted'; | ||
const innerVow = watch( | ||
E(listener).onReject(port, localAddr, remoteAddr, listener), | ||
this.facets.sinkWatcher, | ||
); | ||
if (localAddress === undefined) { | ||
localAddress = localAddr; | ||
} | ||
return watch(innerVow, this.facets.rethrowUnlessMissingWatcher); | ||
}, | ||
/** | ||
* @param {object} opts | ||
* @param {string} [opts.localAddress] | ||
* @param {string} [opts.remoteAddress] | ||
* @param {import('@agoric/vow').Remote<ConnectionHandler>} opts.handler | ||
*/ | ||
async accept({ localAddress, remoteAddress, handler: rchandler }) { | ||
const { consummated, localAddr, remoteAddr } = this.state; | ||
const { listening, listenPrefix, currentConnections } = this.state; | ||
if (consummated) { | ||
throw Error(consummated); | ||
} | ||
if (remoteAddress === undefined) { | ||
remoteAddress = remoteAddr; | ||
} | ||
if (localAddress === undefined) { | ||
localAddress = localAddr; | ||
} | ||
this.state.consummated = `${localAddress} Already accepted`; | ||
const [port, listener] = listening.get(listenPrefix); | ||
const current = currentConnections.get(port); | ||
if (remoteAddress === undefined) { | ||
remoteAddress = remoteAddr; | ||
} | ||
current.delete(this.self); | ||
const [port, listener] = listening.get(listenPrefix); | ||
const current = currentConnections.get(port); | ||
const lchandler = await when( | ||
E(listener).onAccept(port, localAddress, remoteAddress, listener), | ||
); | ||
current.delete(this.facets.inboundAttempt); | ||
return crossoverConnection( | ||
zone, | ||
lchandler, | ||
localAddress, | ||
rchandler, | ||
remoteAddress, | ||
makeConnection, | ||
current, | ||
)[1]; | ||
return watch( | ||
E(listener).onAccept(port, localAddress, remoteAddress, listener), | ||
this.facets.inboundAttemptAcceptWatcher, | ||
{ | ||
localAddress, | ||
rchandler, | ||
remoteAddress, | ||
current, | ||
}, | ||
); | ||
}, | ||
}, | ||
inboundAttemptAcceptWatcher: { | ||
onFulfilled(lchandler, watchContext) { | ||
const { localAddress, rchandler, remoteAddress, current } = | ||
watchContext; | ||
return crossoverConnection( | ||
zone, | ||
/** @type {import('@agoric/vow').Remote<Required<ConnectionHandler>>} */ ( | ||
lchandler | ||
), | ||
localAddress, | ||
/** @type {import('@agoric/vow').Remote<Required<ConnectionHandler>>} */ ( | ||
rchandler | ||
), | ||
remoteAddress, | ||
makeConnection, | ||
current, | ||
)[1]; | ||
}, | ||
}, | ||
rethrowUnlessMissingWatcher: { | ||
onRejected(e) { | ||
rethrowUnlessMissing(e); | ||
}, | ||
}, | ||
sinkWatcher: { | ||
onFulfilled(_value) { | ||
return undefined; | ||
}, | ||
}, | ||
}, | ||
); | ||
const makeInboundAttempt = ({ | ||
localAddr, | ||
remoteAddr, | ||
currentConnections, | ||
listenPrefix, | ||
listening, | ||
}) => { | ||
const { inboundAttempt } = makeInboundAttemptKit({ | ||
localAddr, | ||
remoteAddr, | ||
currentConnections, | ||
listenPrefix, | ||
listening, | ||
}); | ||
return harden(inboundAttempt); | ||
}; | ||
return makeInboundAttempt; | ||
@@ -438,20 +397,27 @@ }; | ||
*/ | ||
const preparePort = (zone, { when }) => { | ||
const preparePort = (zone, powers) => { | ||
const makeIncapable = zone.exoClass('Incapable', undefined, () => ({}), {}); | ||
const makePort = zone.exoClass( | ||
'Port', | ||
Shape.PortI, | ||
/** | ||
* @param {object} opts | ||
* @param {Endpoint} opts.localAddr | ||
* @param {MapStore<Endpoint, [Port, ListenHandler]>} opts.listening | ||
* @param {SetStore<Connection>} opts.openConnections | ||
* @param {MapStore<Port, SetStore<Closable>>} opts.currentConnections | ||
* @param {MapStore<string, Port>} opts.boundPorts | ||
* @param {ProtocolHandler} opts.protocolHandler | ||
* @param {ProtocolImpl} opts.protocolImpl | ||
*/ | ||
({ | ||
localAddr, | ||
const { watch, allVows } = powers; | ||
/** | ||
* @param {object} opts | ||
* @param {Endpoint} opts.localAddr | ||
* @param {MapStore<Endpoint, [Port, import('@agoric/vow').Remote<Required<ListenHandler>>]>} opts.listening | ||
* @param {SetStore<import('@agoric/vow').Remote<Connection>>} opts.openConnections | ||
* @param {MapStore<Port, SetStore<Closable>>} opts.currentConnections | ||
* @param {MapStore<string, Port>} opts.boundPorts | ||
* @param {import('@agoric/vow').Remote<ProtocolHandler>} opts.protocolHandler | ||
* @param {Remote<ProtocolImpl>} opts.protocolImpl | ||
*/ | ||
const initPort = ({ | ||
localAddr, | ||
listening, | ||
openConnections, | ||
currentConnections, | ||
boundPorts, | ||
protocolHandler, | ||
protocolImpl, | ||
}) => { | ||
return { | ||
listening, | ||
@@ -461,18 +427,12 @@ openConnections, | ||
boundPorts, | ||
localAddr, | ||
protocolHandler, | ||
protocolImpl, | ||
}) => { | ||
return { | ||
listening, | ||
openConnections, | ||
currentConnections, | ||
boundPorts, | ||
localAddr, | ||
protocolHandler, | ||
protocolImpl, | ||
/** @type {RevokeState | undefined} */ | ||
revoked: undefined, | ||
}; | ||
}, | ||
{ | ||
/** @type {RevokeState | undefined} */ | ||
revoked: undefined, | ||
}; | ||
}; | ||
const makePortKit = zone.exoClassKit('Port', Shape.PortI, initPort, { | ||
port: { | ||
getLocalAddress() { | ||
@@ -482,3 +442,3 @@ // Works even after revoke(). | ||
}, | ||
/** @param {ListenHandler} listenHandler */ | ||
/** @param {import('@agoric/vow').Remote<ListenHandler>} listenHandler */ | ||
async addListener(listenHandler) { | ||
@@ -496,6 +456,15 @@ const { revoked, listening, localAddr, protocolHandler } = this.state; | ||
} | ||
listening.set(localAddr, [this.self, listenHandler]); | ||
listening.set(localAddr, [ | ||
this.facets.port, | ||
/** @type {Remote<Required<ListenHandler>>} */ (listenHandler), | ||
]); | ||
E(lhandler).onRemove(lport, lhandler).catch(rethrowUnlessMissing); | ||
} else { | ||
listening.init(localAddr, harden([this.self, listenHandler])); | ||
listening.init( | ||
localAddr, | ||
harden([ | ||
this.facets.port, | ||
/** @type {Remote<Required<ListenHandler>>} */ (listenHandler), | ||
]), | ||
); | ||
} | ||
@@ -505,5 +474,5 @@ | ||
await when( | ||
const innerVow = watch( | ||
E(protocolHandler).onListen( | ||
this.self, | ||
this.facets.port, | ||
localAddr, | ||
@@ -513,8 +482,8 @@ listenHandler, | ||
), | ||
this.facets.portAddListenerWatcher, | ||
{ listenHandler }, | ||
); | ||
await when(E(listenHandler).onListen(this.self, listenHandler)).catch( | ||
rethrowUnlessMissing, | ||
); | ||
return watch(innerVow, this.facets.rethrowUnlessMissingWatcher); | ||
}, | ||
/** @param {ListenHandler} listenHandler */ | ||
/** @param {Remote<ListenHandler>} listenHandler */ | ||
async removeListener(listenHandler) { | ||
@@ -526,5 +495,6 @@ const { listening, localAddr, protocolHandler } = this.state; | ||
listening.delete(localAddr); | ||
await when( | ||
const innerVow = watch( | ||
E(protocolHandler).onListenRemove( | ||
this.self, | ||
this.facets.port, | ||
localAddr, | ||
@@ -534,17 +504,18 @@ listenHandler, | ||
), | ||
this.facets.portRemoveListenerWatcher, | ||
{ listenHandler }, | ||
); | ||
await when(E(listenHandler).onRemove(this.self, listenHandler)).catch( | ||
rethrowUnlessMissing, | ||
); | ||
return watch(innerVow, this.facets.rethrowUnlessMissingWatcher); | ||
}, | ||
/** | ||
* @param {Endpoint} remotePort | ||
* @param {ConnectionHandler} connectionHandler | ||
* @param {Remote<ConnectionHandler>} [connectionHandler] | ||
*/ | ||
async connect( | ||
remotePort, | ||
connectionHandler = /** @type {any} */ (makeIncapable()), | ||
connectionHandler = /** @type {Remote<ConnectionHandler>} */ ( | ||
makeIncapable() | ||
), | ||
) { | ||
const { revoked, localAddr, protocolImpl, openConnections } = | ||
this.state; | ||
const { revoked, localAddr, protocolImpl } = this.state; | ||
@@ -554,6 +525,46 @@ !revoked || Fail`Port ${localAddr} is revoked`; | ||
const dst = harden(remotePort); | ||
return watch( | ||
E(protocolImpl).outbound(this.facets.port, dst, connectionHandler), | ||
this.facets.portConnectWatcher, | ||
{ revoked }, | ||
); | ||
}, | ||
async revoke() { | ||
const { revoked, localAddr } = this.state; | ||
const { protocolHandler } = this.state; | ||
const conn = await when( | ||
protocolImpl.outbound(this.self, dst, connectionHandler), | ||
revoked !== RevokeState.REVOKED || | ||
Fail`Port ${localAddr} is already revoked`; | ||
this.state.revoked = RevokeState.REVOKING; | ||
const revokeVow = watch( | ||
E(protocolHandler).onRevoke( | ||
this.facets.port, | ||
localAddr, | ||
protocolHandler, | ||
), | ||
this.facets.portRevokeWatcher, | ||
); | ||
return watch(revokeVow, this.facets.portRevokeCleanupWatcher); | ||
}, | ||
}, | ||
portAddListenerWatcher: { | ||
onFulfilled(_value, watcherContext) { | ||
const { listenHandler } = watcherContext; | ||
return E(listenHandler).onListen(this.facets.port, listenHandler); | ||
}, | ||
}, | ||
portRemoveListenerWatcher: { | ||
onFulfilled(_value, watcherContext) { | ||
const { listenHandler } = watcherContext; | ||
return E(listenHandler).onRemove(this.facets.port, listenHandler); | ||
}, | ||
}, | ||
portConnectWatcher: { | ||
onFulfilled(conn, watchContext) { | ||
const { revoked } = watchContext; | ||
const { openConnections } = this.state; | ||
if (revoked) { | ||
@@ -566,29 +577,74 @@ void E(conn).close(); | ||
}, | ||
async revoke() { | ||
const { revoked, localAddr } = this.state; | ||
const { protocolHandler, currentConnections, listening, boundPorts } = | ||
this.state; | ||
}, | ||
portRevokeWatcher: { | ||
onFulfilled(_value) { | ||
const { currentConnections, listening, localAddr } = this.state; | ||
const port = this.facets.port; | ||
revoked !== RevokeState.REVOKED || | ||
Fail`Port ${localAddr} is already revoked`; | ||
this.state.revoked = RevokeState.REVOKING; | ||
await when( | ||
E(protocolHandler).onRevoke(this.self, localAddr, protocolHandler), | ||
// Clean up everything we did. | ||
const values = [...currentConnections.get(port).values()]; | ||
/** @type {import('@agoric/vow').Specimen[]} */ | ||
const ps = []; | ||
ps.push( | ||
...values.map(conn => | ||
watch(E(conn).close(), this.facets.sinkWatcher), | ||
), | ||
); | ||
this.state.revoked = RevokeState.REVOKED; | ||
// Clean up everything we did. | ||
const values = [...currentConnections.get(this.self).values()]; | ||
const ps = values.map(conn => when(E(conn).close()).catch(_ => {})); | ||
if (listening.has(localAddr)) { | ||
const listener = listening.get(localAddr)[1]; | ||
ps.push(this.self.removeListener(listener)); | ||
ps.push(port.removeListener(listener)); | ||
} | ||
await Promise.all(ps); | ||
currentConnections.delete(this.self); | ||
return watch(allVows(ps), this.facets.rethrowUnlessMissingWatcher); | ||
}, | ||
}, | ||
sinkWatcher: { | ||
onFulfilled() { | ||
return undefined; | ||
}, | ||
onRejected() { | ||
return undefined; | ||
}, | ||
}, | ||
portRevokeCleanupWatcher: { | ||
onFulfilled(_value) { | ||
const { currentConnections, boundPorts, localAddr } = this.state; | ||
this.state.revoked = RevokeState.REVOKED; | ||
currentConnections.delete(this.facets.port); | ||
boundPorts.delete(localAddr); | ||
}, | ||
}, | ||
); | ||
rethrowUnlessMissingWatcher: { | ||
onRejected(e) { | ||
rethrowUnlessMissing(e); | ||
}, | ||
}, | ||
}); | ||
const makePort = ({ | ||
localAddr, | ||
listening, | ||
openConnections, | ||
currentConnections, | ||
boundPorts, | ||
protocolHandler, | ||
protocolImpl, | ||
}) => { | ||
const { port } = makePortKit({ | ||
localAddr, | ||
listening, | ||
openConnections, | ||
currentConnections, | ||
boundPorts, | ||
protocolHandler, | ||
protocolImpl, | ||
}); | ||
return harden(port); | ||
}; | ||
return makePort; | ||
@@ -603,3 +659,5 @@ }; | ||
const makeConnection = prepareHalfConnection(zone, powers); | ||
const { when } = powers; | ||
const { watch } = powers; | ||
const makeInboundAttempt = prepareInboundAttempt( | ||
@@ -610,6 +668,8 @@ zone, | ||
); | ||
const makePort = preparePort(zone, powers); | ||
const detached = zone.detached(); | ||
const makeBinderKit = zone.exoClassKit( | ||
const makeFullBinderKit = zone.exoClassKit( | ||
'binder', | ||
@@ -619,11 +679,62 @@ { | ||
binder: M.interface('Binder', { | ||
bind: M.callWhen(Shape.Endpoint).returns(Shape.Port), | ||
bind: M.callWhen(Shape.Endpoint).returns(Shape.Vow$(Shape.Port)), | ||
}), | ||
binderInboundInstantiateWatcher: M.interface( | ||
'BinderInboundInstantiateWatcher', | ||
{ | ||
onFulfilled: M.call(M.any()).rest(M.any()).returns(M.any()), | ||
}, | ||
), | ||
binderInboundInstantiateCatchWatcher: M.interface( | ||
'BinderInboundInstantiateCatchWatcher', | ||
{ | ||
onRejected: M.call(M.any()).rest(M.any()).returns(M.any()), | ||
}, | ||
), | ||
binderOutboundInstantiateWatcher: M.interface( | ||
'BinderOutboundInstantiateWatcher', | ||
{ | ||
onFulfilled: M.call(M.any()).rest(M.any()).returns(M.any()), | ||
}, | ||
), | ||
binderOutboundConnectWatcher: M.interface( | ||
'BinderOutboundConnectWatcher', | ||
{ | ||
onFulfilled: M.call(M.any()).rest(M.any()).returns(M.any()), | ||
}, | ||
), | ||
binderOutboundCatchWatcher: M.interface('BinderOutboundCatchWatcher', { | ||
onRejected: M.call(M.any()).rest(M.any()).returns(M.any()), | ||
}), | ||
binderOutboundInboundWatcher: M.interface( | ||
'BinderOutboundInboundWatcher', | ||
{ | ||
onFulfilled: M.call(M.any()).rest(M.any()).returns(M.any()), | ||
}, | ||
), | ||
binderOutboundAcceptWatcher: M.interface('BinderOutboundAcceptWatcher', { | ||
onFulfilled: M.call(M.any()).rest(M.any()).returns(M.any()), | ||
}), | ||
binderBindGeneratePortWatcher: M.interface( | ||
'BinderBindGeneratePortWatcher', | ||
{ | ||
onFulfilled: M.call(M.any()).rest(M.any()).returns(M.any()), | ||
}, | ||
), | ||
binderPortWatcher: M.interface('BinderPortWatcher', { | ||
onFulfilled: M.call(M.any()).rest(M.any()).returns(M.any()), | ||
}), | ||
binderBindWatcher: M.interface('BinderBindWatcher', { | ||
onFulfilled: M.call(M.any()).rest(M.any()).returns(M.any()), | ||
}), | ||
rethrowUnlessMissingWatcher: M.interface('RethrowUnlessMissingWatcher', { | ||
onRejected: M.call(M.any()).rest(M.any()).returns(M.any()), | ||
}), | ||
}, | ||
/** | ||
* @param {object} opts | ||
* @param { MapStore<Port, SetStore<Closable>> } opts.currentConnections | ||
* @param {MapStore<Port, SetStore<Closable>>} opts.currentConnections | ||
* @param {MapStore<string, Port>} opts.boundPorts | ||
* @param {MapStore<Endpoint, [Port, ListenHandler]>} opts.listening | ||
* @param {ProtocolHandler} opts.protocolHandler | ||
* @param {MapStore<Endpoint, [Port, Remote<Required<ListenHandler>>]>} opts.listening | ||
* @param {Remote<ProtocolHandler>} opts.protocolHandler | ||
*/ | ||
@@ -641,4 +752,2 @@ ({ currentConnections, boundPorts, listening, protocolHandler }) => { | ||
protocolHandler, | ||
/** @type {Endpoint | undefined} */ | ||
localAddr: undefined, | ||
}; | ||
@@ -653,45 +762,54 @@ }, | ||
async inbound(listenAddr, remoteAddr) { | ||
const { listening, protocolHandler, currentConnections } = this.state; | ||
const { listening, protocolHandler } = this.state; | ||
let lastFailure = Error(`No listeners for ${listenAddr}`); | ||
for await (const listenPrefix of getPrefixes(listenAddr)) { | ||
const prefixes = getPrefixes(listenAddr); | ||
let listenPrefixIndex = 0; | ||
let listenPrefix; | ||
while (listenPrefixIndex < prefixes.length) { | ||
listenPrefix = prefixes[listenPrefixIndex]; | ||
if (!listening.has(listenPrefix)) { | ||
listenPrefixIndex += 1; | ||
continue; | ||
} | ||
const [port, _] = listening.get(listenPrefix); | ||
let localAddr; | ||
await (async () => { | ||
// See if our protocol is willing to receive this connection. | ||
const localInstance = await when( | ||
E(protocolHandler).onInstantiate( | ||
port, | ||
listenPrefix, | ||
remoteAddr, | ||
protocolHandler, | ||
), | ||
).catch(rethrowUnlessMissing); | ||
localAddr = localInstance | ||
? `${listenAddr}/${localInstance}` | ||
: listenAddr; | ||
})().catch(e => { | ||
lastFailure = e; | ||
}); | ||
if (!localAddr) { | ||
continue; | ||
} | ||
// We have a legitimate inbound attempt. | ||
const current = currentConnections.get(port); | ||
const inboundAttempt = makeInboundAttempt({ | ||
localAddr, | ||
break; | ||
} | ||
if (listenPrefixIndex >= prefixes.length) { | ||
throw Error(`No listeners for ${listenAddr}`); | ||
} | ||
const [port] = listening.get(/** @type {string} **/ (listenPrefix)); | ||
const innerVow = watch( | ||
E( | ||
/** @type {Remote<Required<ProtocolHandler>>} */ ( | ||
protocolHandler | ||
), | ||
).onInstantiate( | ||
/** @type {Port} **/ (port), | ||
prefixes[listenPrefixIndex], | ||
remoteAddr, | ||
currentConnections, | ||
listenPrefix, | ||
listening, | ||
}); | ||
protocolHandler, | ||
), | ||
this.facets.binderInboundInstantiateWatcher, | ||
{ | ||
listenAddr, | ||
remoteAddr, | ||
port, | ||
listenPrefixIndex, | ||
}, | ||
); | ||
current.add(inboundAttempt); | ||
return inboundAttempt; | ||
} | ||
throw lastFailure; | ||
return watch( | ||
innerVow, | ||
this.facets.binderInboundInstantiateCatchWatcher, | ||
{ | ||
listenPrefixIndex, | ||
listenAddr, | ||
remoteAddr, | ||
lastFailure: Error(`No listeners for ${listenAddr}`), | ||
}, | ||
); | ||
}, | ||
@@ -704,3 +822,3 @@ /** | ||
async outbound(port, remoteAddr, lchandler) { | ||
const { protocolHandler, currentConnections } = this.state; | ||
const { protocolHandler } = this.state; | ||
@@ -710,4 +828,10 @@ const localAddr = await E(port).getLocalAddress(); | ||
// Allocate a local address. | ||
const initialLocalInstance = await when( | ||
E(protocolHandler).onInstantiate( | ||
const instantiateInnerVow = watch( | ||
E( | ||
/** @type {Remote<Required<ProtocolHandler>>} */ ( | ||
protocolHandler | ||
), | ||
).onInstantiate(port, localAddr, remoteAddr, protocolHandler), | ||
this.facets.binderOutboundInstantiateWatcher, | ||
{ | ||
port, | ||
@@ -717,41 +841,173 @@ localAddr, | ||
protocolHandler, | ||
), | ||
).catch(rethrowUnlessMissing); | ||
const initialLocalAddr = initialLocalInstance | ||
? `${localAddr}/${initialLocalInstance}` | ||
: localAddr; | ||
}, | ||
); | ||
let lastFailure; | ||
let accepted; | ||
await (async () => { | ||
// Attempt the loopback connection. | ||
const attempt = await when( | ||
this.facets.protocolImpl.inbound(remoteAddr, initialLocalAddr), | ||
); | ||
accepted = await when(attempt.accept({ handler: lchandler })); | ||
})().catch(e => { | ||
lastFailure = e; | ||
const instantiateVow = watch( | ||
instantiateInnerVow, | ||
this.facets.rethrowUnlessMissingWatcher, | ||
); | ||
const attemptVow = watch( | ||
instantiateVow, | ||
this.facets.binderOutboundInboundWatcher, | ||
{ | ||
localAddr, | ||
remoteAddr, | ||
}, | ||
); | ||
const acceptedVow = watch( | ||
attemptVow, | ||
this.facets.binderOutboundAcceptWatcher, | ||
{ | ||
handler: lchandler, | ||
}, | ||
); | ||
return watch(acceptedVow, this.facets.binderOutboundCatchWatcher, { | ||
port, | ||
remoteAddr, | ||
lchandler, | ||
localAddr, | ||
}); | ||
if (accepted) { | ||
return accepted; | ||
}, | ||
async bind(localAddr) { | ||
return this.facets.binder.bind(localAddr); | ||
}, | ||
}, | ||
binder: { | ||
/** @param {string} localAddr */ | ||
async bind(localAddr) { | ||
const { protocolHandler } = this.state; | ||
// Check if we are underspecified (ends in slash) | ||
const underspecified = localAddr.endsWith(ENDPOINT_SEPARATOR); | ||
const localAddrVow = watch( | ||
E(protocolHandler).generatePortID(localAddr, protocolHandler), | ||
this.facets.binderBindGeneratePortWatcher, | ||
{ | ||
underspecified, | ||
localAddr, | ||
}, | ||
); | ||
return watch(localAddrVow, this.facets.binderBindWatcher); | ||
}, | ||
}, | ||
binderInboundInstantiateWatcher: { | ||
onFulfilled(localInstance, watchContext) { | ||
const { listenAddr, remoteAddr, port, listenPrefixIndex } = | ||
watchContext; | ||
const { listening, currentConnections } = this.state; | ||
const prefixes = getPrefixes(listenAddr); | ||
const localAddr = localInstance | ||
? `${listenAddr}/${localInstance}` | ||
: listenAddr; | ||
const current = currentConnections.get(port); | ||
const inboundAttempt = makeInboundAttempt({ | ||
localAddr, | ||
remoteAddr, | ||
currentConnections, | ||
listenPrefix: prefixes[listenPrefixIndex], | ||
listening, | ||
}); | ||
current.add(inboundAttempt); | ||
return inboundAttempt; | ||
}, | ||
}, | ||
binderInboundInstantiateCatchWatcher: { | ||
onRejected(e, watchContext) { | ||
let { lastFailure, listenPrefixIndex } = watchContext; | ||
try { | ||
rethrowUnlessMissing(e); | ||
} catch (innerE) { | ||
lastFailure = innerE; | ||
} | ||
const { listenAddr, remoteAddr } = watchContext; | ||
const { listening, protocolHandler } = this.state; | ||
const prefixes = getPrefixes(listenAddr); | ||
let listenPrefix; | ||
listenPrefixIndex += 1; | ||
while (listenPrefixIndex < prefixes.length) { | ||
listenPrefix = prefixes[listenPrefixIndex]; | ||
if (!listening.has(listenPrefix)) { | ||
listenPrefixIndex += 1; | ||
continue; | ||
} | ||
break; | ||
} | ||
if (listenPrefixIndex >= prefixes.length) { | ||
throw lastFailure; | ||
} | ||
const [port] = listening.get(/** @type {string} */ (listenPrefix)); | ||
const innerVow = watch( | ||
E( | ||
/** @type {Remote<Required<ProtocolHandler>>} */ ( | ||
protocolHandler | ||
), | ||
).onInstantiate( | ||
port, | ||
prefixes[listenPrefixIndex], | ||
remoteAddr, | ||
protocolHandler, | ||
), | ||
this.facets.binderInboundInstantiateWatcher, | ||
{ | ||
listenAddr, | ||
remoteAddr, | ||
port, | ||
listenPrefixIndex, | ||
}, | ||
); | ||
return watch( | ||
innerVow, | ||
this.facets.binderInboundInstantiateCatchWatcher, | ||
{ | ||
...watchContext, | ||
lastFailure, | ||
listenPrefixIndex, | ||
}, | ||
); | ||
}, | ||
}, | ||
binderOutboundInstantiateWatcher: { | ||
onFulfilled(localInstance, watchContext) { | ||
const { localAddr } = watchContext; | ||
return localInstance ? `${localAddr}/${localInstance}` : localAddr; | ||
}, | ||
}, | ||
binderOutboundConnectWatcher: { | ||
onFulfilled( | ||
{ | ||
handler: rchandler, | ||
remoteAddress: negotiatedRemoteAddress, | ||
localAddress: negotiatedLocalAddress, | ||
}, | ||
watchContext, | ||
) { | ||
const { | ||
remoteAddress = remoteAddr, | ||
handler: rchandler, | ||
localAddress = localAddr, | ||
} = | ||
/** @type {Partial<AttemptDescription>} */ | ||
( | ||
await when( | ||
E(protocolHandler).onConnect( | ||
port, | ||
initialLocalAddr, | ||
remoteAddr, | ||
lchandler, | ||
protocolHandler, | ||
), | ||
) | ||
); | ||
lastFailure, | ||
lchandler, | ||
localAddr: requestedLocalAddress, | ||
remoteAddr: requestedRemoteAddress, | ||
port, | ||
} = watchContext; | ||
const { currentConnections } = this.state; | ||
if (!rchandler) { | ||
@@ -762,8 +1018,13 @@ throw lastFailure; | ||
const current = currentConnections.get(port); | ||
return crossoverConnection( | ||
zone, | ||
lchandler, | ||
localAddress, | ||
rchandler, | ||
remoteAddress, | ||
/** @type {import('@agoric/vow').Remote<Required<ConnectionHandler>>} */ ( | ||
lchandler | ||
), | ||
negotiatedLocalAddress || requestedLocalAddress, | ||
/** @type {import('@agoric/vow').Remote<Required<ConnectionHandler>>} */ ( | ||
rchandler | ||
), | ||
negotiatedRemoteAddress || requestedRemoteAddress, | ||
makeConnection, | ||
@@ -773,11 +1034,93 @@ current, | ||
}, | ||
async bind(localAddr) { | ||
return this.facets.binder.bind(localAddr); | ||
}, | ||
binderOutboundCatchWatcher: { | ||
onRejected(e, watchContext) { | ||
let lastFailure; | ||
try { | ||
rethrowUnlessMissing(e); | ||
} catch (innerE) { | ||
lastFailure = innerE; | ||
} | ||
const { port, remoteAddr, lchandler, localAddr } = watchContext; | ||
const { protocolHandler } = this.state; | ||
const connectVow = watch( | ||
E(protocolHandler).onConnect( | ||
port, | ||
localAddr, | ||
remoteAddr, | ||
lchandler, | ||
protocolHandler, | ||
), | ||
); | ||
return watch(connectVow, this.facets.binderOutboundConnectWatcher, { | ||
lastFailure, | ||
remoteAddr, | ||
localAddr, | ||
lchandler, | ||
port, | ||
}); | ||
}, | ||
}, | ||
binder: { | ||
/** @param {string} localAddr */ | ||
async bind(localAddr) { | ||
binderOutboundInboundWatcher: { | ||
onFulfilled(initialLocalAddress, watchContext) { | ||
const { remoteAddr, localAddr } = watchContext; | ||
if (initialLocalAddress === undefined) { | ||
initialLocalAddress = localAddr; | ||
} | ||
// Attempt the loopback connection. | ||
return this.facets.protocolImpl.inbound( | ||
remoteAddr, | ||
initialLocalAddress, | ||
); | ||
}, | ||
}, | ||
binderOutboundAcceptWatcher: { | ||
onFulfilled(attempt, watchContext) { | ||
const { handler } = watchContext; | ||
return E(attempt).accept({ handler }); | ||
}, | ||
}, | ||
binderBindGeneratePortWatcher: { | ||
onFulfilled(portID, watchContext) { | ||
const { localAddr, underspecified } = watchContext; | ||
const { protocolHandler, boundPorts } = this.state; | ||
if (!underspecified) { | ||
return localAddr; | ||
} | ||
const newAddr = `${localAddr}${portID}`; | ||
if (!boundPorts.has(newAddr)) { | ||
return newAddr; | ||
} | ||
return watch( | ||
E(protocolHandler).generatePortID(localAddr, protocolHandler), | ||
this.facets.binderBindGeneratePortWatcher, | ||
watchContext, | ||
); | ||
}, | ||
}, | ||
binderPortWatcher: { | ||
onFulfilled(_value, watchContext) { | ||
const { port, localAddr } = watchContext; | ||
const { boundPorts, currentConnections } = this.state; | ||
boundPorts.init(localAddr, port); | ||
currentConnections.init( | ||
port, | ||
zone.detached().setStore('connections'), | ||
); | ||
return port; | ||
}, | ||
}, | ||
binderBindWatcher: { | ||
onFulfilled(localAddr) { | ||
const { | ||
protocolHandler, | ||
boundPorts, | ||
@@ -787,19 +1130,5 @@ listening, | ||
currentConnections, | ||
protocolHandler, | ||
} = this.state; | ||
// Check if we are underspecified (ends in slash) | ||
const underspecified = localAddr.endsWith(ENDPOINT_SEPARATOR); | ||
for await (const _ of whileTrue(() => underspecified)) { | ||
const portID = await when( | ||
E(protocolHandler).generatePortID(localAddr, protocolHandler), | ||
); | ||
const newAddr = `${localAddr}${portID}`; | ||
if (!boundPorts.has(newAddr)) { | ||
localAddr = newAddr; | ||
break; | ||
} | ||
} | ||
this.state.localAddr = localAddr; | ||
if (boundPorts.has(localAddr)) { | ||
@@ -819,13 +1148,34 @@ return boundPorts.get(localAddr); | ||
await when( | ||
return watch( | ||
E(protocolHandler).onBind(port, localAddr, protocolHandler), | ||
this.facets.binderPortWatcher, | ||
{ | ||
port, | ||
localAddr, | ||
}, | ||
); | ||
boundPorts.init(localAddr, harden(port)); | ||
currentConnections.init(port, detached.setStore('connections')); | ||
return port; | ||
}, | ||
}, | ||
rethrowUnlessMissingWatcher: { | ||
onRejected(e) { | ||
rethrowUnlessMissing(e); | ||
}, | ||
}, | ||
}, | ||
); | ||
const makeBinderKit = ({ | ||
currentConnections, | ||
boundPorts, | ||
listening, | ||
protocolHandler, | ||
}) => { | ||
const { protocolImpl, binder } = makeFullBinderKit({ | ||
currentConnections, | ||
boundPorts, | ||
listening, | ||
protocolHandler, | ||
}); | ||
return harden({ protocolImpl, binder }); | ||
}; | ||
return makeBinderKit; | ||
@@ -842,3 +1192,3 @@ }; | ||
/** | ||
* @param {ProtocolHandler} protocolHandler | ||
* @param {Remote<ProtocolHandler>} protocolHandler | ||
* @returns {Protocol} | ||
@@ -855,3 +1205,3 @@ */ | ||
/** @type {MapStore<Endpoint, [Port, ListenHandler]>} */ | ||
/** @type {MapStore<Endpoint, [Port, Remote<Required<ListenHandler>>]>} */ | ||
const listening = detached.mapStore('listening'); | ||
@@ -885,10 +1235,10 @@ | ||
onReceive: M.callWhen( | ||
Shape2.Connection, | ||
Shape2.Bytes, | ||
Shape2.ConnectionHandler, | ||
Shape.Connection, | ||
Shape.Bytes, | ||
Shape.ConnectionHandler, | ||
) | ||
.optional(Shape2.Opts) | ||
.returns(Shape2.Data), | ||
onClose: M.callWhen(Shape2.Connection) | ||
.optional(M.any(), Shape2.ConnectionHandler) | ||
.optional(Shape.Opts) | ||
.returns(Shape.Data), | ||
onClose: M.callWhen(Shape.Connection) | ||
.optional(M.any(), Shape.ConnectionHandler) | ||
.returns(M.undefined()), | ||
@@ -909,6 +1259,5 @@ }), | ||
() => { | ||
/** @type {string | undefined} */ | ||
let closed; | ||
return { | ||
closed, | ||
/** @type {string | undefined} */ | ||
closed: undefined, | ||
}; | ||
@@ -927,3 +1276,3 @@ }, | ||
if (closed) { | ||
throw closed; | ||
throw Error(closed); | ||
} | ||
@@ -949,3 +1298,3 @@ return bytes; | ||
async onAccept(_port, _localAddr, _remoteAddr, _listenHandler) { | ||
return harden(this.facets.handler); | ||
return this.facets.handler; | ||
}, | ||
@@ -968,97 +1317,153 @@ async onListen(port, _listenHandler) { | ||
*/ | ||
export function prepareLoopbackProtocolHandler(zone, { when }) { | ||
export function prepareLoopbackProtocolHandler(zone, { watch, allVows }) { | ||
const detached = zone.detached(); | ||
const makeLoopbackProtocolHandler = zone.exoClass( | ||
/** @param {string} [instancePrefix] */ | ||
const initHandler = (instancePrefix = 'nonce/') => { | ||
/** @type {MapStore<string, [Remote<Port>, Remote<Required<ListenHandler>>]>} */ | ||
const listeners = detached.mapStore('localAddr'); | ||
return { | ||
listeners, | ||
portNonce: 0n, | ||
instancePrefix, | ||
instanceNonce: 0n, | ||
}; | ||
}; | ||
const makeLoopbackProtocolHandlerKit = zone.exoClassKit( | ||
'ProtocolHandler', | ||
Shape.ProtocolHandlerI, | ||
/** @param {string} [instancePrefix] */ | ||
(instancePrefix = 'nonce/') => { | ||
/** @type {MapStore<string, [Port, ListenHandler]>} */ | ||
const listeners = detached.mapStore('localAddr'); | ||
initHandler, | ||
{ | ||
protocolHandler: { | ||
async onCreate(_impl, _protocolHandler) { | ||
// noop | ||
}, | ||
async generatePortID(_localAddr, _protocolHandler) { | ||
this.state.portNonce += 1n; | ||
return `port${this.state.portNonce}`; | ||
}, | ||
async onBind(_port, _localAddr, _protocolHandler) { | ||
// noop, for now; Maybe handle a bind? | ||
}, | ||
/** | ||
* @param {*} _port | ||
* @param {Endpoint} localAddr | ||
* @param {Endpoint} remoteAddr | ||
* @returns {PromiseVow<AttemptDescription>}} | ||
*/ | ||
async onConnect(_port, localAddr, remoteAddr) { | ||
const { listeners } = this.state; | ||
const [lport, lhandler] = listeners.get(remoteAddr); | ||
return { | ||
listeners, | ||
portNonce: 0n, | ||
instancePrefix, | ||
instanceNonce: 0n, | ||
}; | ||
}, | ||
{ | ||
async onCreate(_impl, _protocolHandler) { | ||
// noop | ||
const acceptVow = watch( | ||
E(lhandler).onAccept(lport, remoteAddr, localAddr, lhandler), | ||
this.facets.protocolHandlerAcceptWatcher, | ||
); | ||
const instantiateInnerVow = watch( | ||
E(this.facets.protocolHandler).onInstantiate( | ||
lport, | ||
remoteAddr, | ||
localAddr, | ||
this.facets.protocolHandler, | ||
), | ||
this.facets.protocolHandlerInstantiateWatcher, | ||
); | ||
const instantiateVow = watch( | ||
instantiateInnerVow, | ||
this.facets.rethrowUnlessMissingWatcher, | ||
); | ||
return watch( | ||
allVows([acceptVow, instantiateVow]), | ||
this.facets.protocolHandlerConnectWatcher, | ||
); | ||
}, | ||
async onInstantiate(_port, _localAddr, _remote, _protocol) { | ||
const { instancePrefix } = this.state; | ||
this.state.instanceNonce += 1n; | ||
return `${instancePrefix}${this.state.instanceNonce}`; | ||
}, | ||
async onListen(port, localAddr, listenHandler, _protocolHandler) { | ||
const { listeners } = this.state; | ||
// This implementation has a simple last-one-wins replacement policy. | ||
// Other handlers might use different policies. | ||
if (listeners.has(localAddr)) { | ||
const lhandler = listeners.get(localAddr)[1]; | ||
if (lhandler !== listenHandler) { | ||
listeners.set( | ||
localAddr, | ||
harden([ | ||
port, | ||
/** @type {Remote<Required<ListenHandler>>} */ ( | ||
listenHandler | ||
), | ||
]), | ||
); | ||
} | ||
} else { | ||
listeners.init( | ||
localAddr, | ||
harden([ | ||
port, | ||
/** @type {Remote<Required<ListenHandler>>} */ (listenHandler), | ||
]), | ||
); | ||
} | ||
}, | ||
/** | ||
* @param {Remote<Port>} port | ||
* @param {Endpoint} localAddr | ||
* @param {Remote<ListenHandler>} listenHandler | ||
* @param {*} _protocolHandler | ||
*/ | ||
async onListenRemove(port, localAddr, listenHandler, _protocolHandler) { | ||
const { listeners } = this.state; | ||
const [lport, lhandler] = listeners.get(localAddr); | ||
lport === port || Fail`Port does not match listener on ${localAddr}`; | ||
lhandler === listenHandler || | ||
Fail`Listen handler does not match listener on ${localAddr}`; | ||
listeners.delete(localAddr); | ||
}, | ||
async onRevoke(_port, _localAddr, _protocolHandler) { | ||
// This is an opportunity to clean up resources. | ||
}, | ||
}, | ||
async generatePortID(_localAddr, _protocolHandler) { | ||
this.state.portNonce += 1n; | ||
return `port${this.state.portNonce}`; | ||
protocolHandlerAcceptWatcher: { | ||
onFulfilled(rchandler) { | ||
return rchandler; | ||
}, | ||
}, | ||
async onBind(_port, _localAddr, _protocolHandler) { | ||
// noop, for now; Maybe handle a bind? | ||
protocolHandlerConnectWatcher: { | ||
onFulfilled(results) { | ||
return { | ||
remoteInstance: results[0], | ||
handler: results[1], | ||
}; | ||
}, | ||
}, | ||
async onConnect( | ||
_port, | ||
localAddr, | ||
remoteAddr, | ||
_chandler, | ||
protocolHandler, | ||
) { | ||
const { listeners } = this.state; | ||
const [lport, lhandler] = listeners.get(remoteAddr); | ||
const rchandler = await when( | ||
E(lhandler).onAccept(lport, remoteAddr, localAddr, lhandler), | ||
); | ||
// console.log(`rchandler is`, rchandler); | ||
const remoteInstance = await when( | ||
E(protocolHandler).onInstantiate( | ||
lport, | ||
remoteAddr, | ||
localAddr, | ||
protocolHandler, | ||
), | ||
).catch(rethrowUnlessMissing); | ||
return { | ||
remoteInstance, | ||
handler: rchandler, | ||
}; | ||
protocolHandlerInstantiateWatcher: { | ||
onFulfilled(remoteInstance) { | ||
return remoteInstance; | ||
}, | ||
}, | ||
async onInstantiate(_port, _localAddr, _remote, _protocol) { | ||
const { instancePrefix } = this.state; | ||
this.state.instanceNonce += 1n; | ||
return `${instancePrefix}${this.state.instanceNonce}`; | ||
rethrowUnlessMissingWatcher: { | ||
onRejected(e) { | ||
rethrowUnlessMissing(e); | ||
}, | ||
}, | ||
async onListen(port, localAddr, listenHandler, _protocolHandler) { | ||
const { listeners } = this.state; | ||
// This implementation has a simple last-one-wins replacement policy. | ||
// Other handlers might use different policies. | ||
if (listeners.has(localAddr)) { | ||
const lhandler = listeners.get(localAddr)[1]; | ||
if (lhandler !== listenHandler) { | ||
listeners.set(localAddr, [port, listenHandler]); | ||
} | ||
} else { | ||
listeners.init(localAddr, harden([port, listenHandler])); | ||
} | ||
}, | ||
/** | ||
* @param {Port} port | ||
* @param {Endpoint} localAddr | ||
* @param {ListenHandler} listenHandler | ||
* @param {*} _protocolHandler | ||
*/ | ||
async onListenRemove(port, localAddr, listenHandler, _protocolHandler) { | ||
const { listeners } = this.state; | ||
const [lport, lhandler] = listeners.get(localAddr); | ||
lport === port || Fail`Port does not match listener on ${localAddr}`; | ||
lhandler === listenHandler || | ||
Fail`Listen handler does not match listener on ${localAddr}`; | ||
listeners.delete(localAddr); | ||
}, | ||
async onRevoke(_port, _localAddr, _protocolHandler) { | ||
// This is an opportunity to clean up resources. | ||
}, | ||
}, | ||
); | ||
/** @param {string} [instancePrefix] */ | ||
const makeLoopbackProtocolHandler = instancePrefix => { | ||
const { protocolHandler } = makeLoopbackProtocolHandlerKit(instancePrefix); | ||
return harden(protocolHandler); | ||
}; | ||
return makeLoopbackProtocolHandler; | ||
} |
@@ -16,3 +16,3 @@ /** | ||
}>; | ||
export function prepareRouter<T>(zone: import('@agoric/base-zone').Zone): () => import("@endo/exo/src/exo-makers.js").Guarded<{ | ||
export function prepareRouter<T>(zone: import('@agoric/base-zone').Zone): () => import("@endo/exo").Guarded<{ | ||
/** @param {Endpoint} addr */ | ||
@@ -35,25 +35,26 @@ getRoutes(addr: Endpoint): [string, T][]; | ||
} | undefined) => { | ||
when: <T = any, TResult1 = import("@agoric/vow/src/E.js").Unwrap<T>, TResult2 = never>(specimenP: T, onFulfilled?: ((value: import("@agoric/vow/src/E.js").Unwrap<T>) => TResult1 | PromiseLike<TResult1>) | undefined, onRejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined) => Promise<TResult1 | TResult2>; | ||
when: <T, TResult1 = import("@agoric/vow").Unwrap<T>, TResult2 = never>(specimenP: T, onFulfilled?: ((value: import("@agoric/vow").Unwrap<T>) => TResult1 | PromiseLike<TResult1>) | undefined, onRejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined) => Promise<TResult1 | TResult2>; | ||
watch: <T_1 = any, TResult1_1 = T_1, TResult2_1 = T_1>(specimenP: import("@agoric/vow").ERef<T_1 | import("@agoric/vow").Vow<T_1>>, watcher?: import("@agoric/vow").Watcher<T_1, TResult1_1, TResult2_1> | undefined, watcherContext?: unknown) => import("@agoric/vow").Vow<TResult1_1 | TResult2_1>; | ||
makeVowKit: <T_2>() => import("@agoric/vow").VowKit<T_2>; | ||
}>, E?: ((<T_3>(x: T_3) => import("@endo/eventual-send/src/E.js").ECallableOrMethods<import("@endo/eventual-send").RemoteFunctions<T_3>>) & { | ||
readonly get: <T_1>(x: T_1) => import("@endo/eventual-send/src/E.js").EGetters<import("@endo/eventual-send").LocalRecord<T_1>>; | ||
allVows: (vows: any) => import("@agoric/vow").Vow<any>; | ||
}>, E?: ((<T_3>(x: T_3) => import("../../../node_modules/@endo/eventual-send/src/E.js").ECallableOrMethods<import("@endo/eventual-send").RemoteFunctions<T_3>>) & { | ||
readonly get: <T_1_1>(x: T_1_1) => import("../../../node_modules/@endo/eventual-send/src/E.js").EGetters<import("@endo/eventual-send").LocalRecord<T_1_1>>; | ||
readonly resolve: { | ||
(): Promise<void>; | ||
<T_2>(value: T_2): Promise<Awaited<T_2>>; | ||
<T_3>(value: T_3 | PromiseLike<T_3>): Promise<Awaited<T_3>>; | ||
<T_2_1>(value: T_2_1): Promise<Awaited<T_2_1>>; | ||
<T_3_1>(value: T_3_1 | PromiseLike<T_3_1>): Promise<Awaited<T_3_1>>; | ||
}; | ||
readonly sendOnly: <T_4>(x: T_4) => import("@endo/eventual-send/src/E.js").ESendOnlyCallableOrMethods<import("@endo/eventual-send").RemoteFunctions<T_4>>; | ||
readonly sendOnly: <T_4>(x: T_4) => import("../../../node_modules/@endo/eventual-send/src/E.js").ESendOnlyCallableOrMethods<import("@endo/eventual-send").RemoteFunctions<T_4>>; | ||
readonly when: <T_5, U = T_5>(x: T_5 | PromiseLike<T_5>, onfulfilled?: ((value: T_5) => import("@endo/eventual-send").ERef<U>) | undefined, onrejected?: ((reason: any) => import("@endo/eventual-send").ERef<U>) | undefined) => Promise<U>; | ||
}) | undefined): () => import("@endo/exo/src/exo-makers.js").Guarded<{ | ||
}) | undefined): () => import("@endo/exo").Guarded<{ | ||
/** | ||
* @param {string[]} paths | ||
* @param {ProtocolHandler} protocolHandler | ||
* @param {Remote<ProtocolHandler>} protocolHandler | ||
*/ | ||
registerProtocolHandler(paths: string[], protocolHandler: ProtocolHandler): void; | ||
registerProtocolHandler(paths: string[], protocolHandler: Remote<ProtocolHandler>): void; | ||
/** | ||
* @param {string} prefix | ||
* @param {ProtocolHandler} protocolHandler | ||
* @param {Remote<ProtocolHandler>} protocolHandler | ||
*/ | ||
unregisterProtocolHandler(prefix: string, protocolHandler: ProtocolHandler): void; | ||
unregisterProtocolHandler(prefix: string, protocolHandler: Remote<ProtocolHandler>): void; | ||
/** @param {Endpoint} localAddr */ | ||
@@ -60,0 +61,0 @@ bind(localAddr: Endpoint): Promise<Port | import("@agoric/vow").Vow<Port>>; |
@@ -5,7 +5,4 @@ // @ts-check | ||
import { Fail } from '@agoric/assert'; | ||
import { | ||
ENDPOINT_SEPARATOR, | ||
Shape, | ||
prepareNetworkProtocol, | ||
} from './network.js'; | ||
import { ENDPOINT_SEPARATOR, prepareNetworkProtocol } from './network.js'; | ||
import { Shape } from './shapes.js'; | ||
@@ -63,3 +60,3 @@ import '@agoric/store/exported.js'; | ||
// Trim off the last value (after the slash). | ||
const defaultPrefix = prefix.substr( | ||
const defaultPrefix = prefix.slice( | ||
0, | ||
@@ -136,3 +133,3 @@ prefix.lastIndexOf(ENDPOINT_SEPARATOR) + 1, | ||
/** @type {MapStore<string, ProtocolHandler>} */ | ||
/** @type {MapStore<string, Remote<ProtocolHandler>>} */ | ||
const protocolHandlers = detached.mapStore('prefix'); | ||
@@ -149,3 +146,3 @@ | ||
* @param {string[]} paths | ||
* @param {ProtocolHandler} protocolHandler | ||
* @param {Remote<ProtocolHandler>} protocolHandler | ||
*/ | ||
@@ -164,3 +161,3 @@ registerProtocolHandler(paths, protocolHandler) { | ||
* @param {string} prefix | ||
* @param {ProtocolHandler} protocolHandler | ||
* @param {Remote<ProtocolHandler>} protocolHandler | ||
*/ | ||
@@ -171,3 +168,3 @@ unregisterProtocolHandler(prefix, protocolHandler) { | ||
Fail`Protocol handler is not registered at prefix ${prefix}`; | ||
// TODO: unmap protocol hanlders to their corresponding protocol | ||
// TODO: unmap protocol handlers to their corresponding protocol | ||
// e.g. using a map | ||
@@ -174,0 +171,0 @@ // before unregistering |
@@ -1,3 +0,13 @@ | ||
type PromiseVow<T> = Promise<T | import('@agoric/vow').Vow<T>>; | ||
type Data = string | Buffer | ArrayBuffer; | ||
type PromiseVow<T> = import('@agoric/vow').PromiseVow<T>; | ||
type Remote<T> = import('@agoric/vow').Remote<T>; | ||
/** | ||
* Rearrange the exo types to make a cast of the methods (M) and init function (I) to a specific type. | ||
*/ | ||
type ExoClassMethods<M extends import("@endo/exo").Methods, I extends (...args: any[]) => any> = M & ThisType<{ | ||
self: import('@endo/exo').Guarded<M>; | ||
state: ReturnType<I>; | ||
}>; | ||
/** | ||
* Each character code carries 8-bit octets. Eventually we want to use passable Uint8Arrays. | ||
*/ | ||
type Bytes = string; | ||
@@ -40,11 +50,11 @@ /** | ||
*/ | ||
addListener: (acceptHandler: ListenHandler) => PromiseVow<void>; | ||
addListener: (acceptHandler: Remote<ListenHandler>) => PromiseVow<void>; | ||
/** | ||
* Make an outbound connection | ||
*/ | ||
connect: (remote: Endpoint, connectionHandler?: ConnectionHandler) => PromiseVow<Connection>; | ||
connect: (remote: Endpoint, connectionHandler?: Remote<ConnectionHandler>) => PromiseVow<Connection>; | ||
/** | ||
* Remove the currently-bound listener | ||
*/ | ||
removeListener: (acceptHandler: ListenHandler) => PromiseVow<void>; | ||
removeListener: (acceptHandler: Remote<ListenHandler>) => PromiseVow<void>; | ||
/** | ||
@@ -54,3 +64,3 @@ * Deallocate the port entirely, removing all | ||
*/ | ||
revoke: () => void; | ||
revoke: () => PromiseVow<void>; | ||
}; | ||
@@ -62,18 +72,17 @@ /** | ||
/** | ||
* The | ||
* listener has been registered | ||
* The listener has been registered | ||
*/ | ||
onListen?: ((port: Port, l: ListenHandler) => PromiseVow<void>) | undefined; | ||
onListen?: ((port: Remote<Port>, l: Remote<ListenHandler>) => PromiseVow<void>) | undefined; | ||
/** | ||
* A new connection is incoming | ||
*/ | ||
onAccept: (port: Port, localAddr: Endpoint, remoteAddr: Endpoint, l: ListenHandler) => PromiseVow<ConnectionHandler>; | ||
onAccept: (port: Remote<Port>, localAddr: Endpoint, remoteAddr: Endpoint, l: Remote<ListenHandler>) => PromiseVow<Remote<ConnectionHandler>>; | ||
/** | ||
* The connection was rejected | ||
*/ | ||
onReject?: ((port: Port, localAddr: Endpoint, remoteAddr: Endpoint, l: ListenHandler) => PromiseVow<void>) | undefined; | ||
onReject?: ((port: Remote<Port>, localAddr: Endpoint, remoteAddr: Endpoint, l: Remote<ListenHandler>) => PromiseVow<void>) | undefined; | ||
/** | ||
* There was an error while listening | ||
*/ | ||
onError?: ((port: Port, rej: any, l: ListenHandler) => PromiseVow<void>) | undefined; | ||
onError?: ((port: Remote<Port>, rej: any, l: Remote<ListenHandler>) => PromiseVow<void>) | undefined; | ||
/** | ||
@@ -83,3 +92,3 @@ * The | ||
*/ | ||
onRemove?: ((port: Port, l: ListenHandler) => PromiseVow<void>) | undefined; | ||
onRemove?: ((port: Remote<Port>, l: Remote<ListenHandler>) => PromiseVow<void>) | undefined; | ||
}; | ||
@@ -90,3 +99,3 @@ type Connection = { | ||
*/ | ||
send: (packetBytes: Data, opts?: Record<string, any>) => PromiseVow<Bytes>; | ||
send: (packetBytes: Bytes, opts?: Record<string, any>) => PromiseVow<Bytes>; | ||
/** | ||
@@ -113,11 +122,11 @@ * Close both ends of the connection | ||
*/ | ||
onOpen?: ((connection: Connection, localAddr: Endpoint, remoteAddr: Endpoint, c: ConnectionHandler) => PromiseVow<void>) | undefined; | ||
onOpen?: ((connection: Remote<Connection>, localAddr: Endpoint, remoteAddr: Endpoint, c: Remote<ConnectionHandler>) => PromiseVow<void>) | undefined; | ||
/** | ||
* The connection received a packet | ||
*/ | ||
onReceive?: ((connection: Connection, ack: Bytes, c: ConnectionHandler, opts?: Record<string, any>) => PromiseVow<Data>) | undefined; | ||
onReceive?: ((connection: Remote<Connection>, ack: Bytes, c: Remote<ConnectionHandler>, opts?: Record<string, any>) => PromiseVow<Bytes>) | undefined; | ||
/** | ||
* The connection has been closed | ||
*/ | ||
onClose?: ((connection: Connection, reason?: CloseReason, c?: ConnectionHandler) => PromiseVow<void>) | undefined; | ||
onClose?: ((connection: Remote<Connection>, reason?: CloseReason, c?: Remote<ConnectionHandler>) => PromiseVow<void>) | undefined; | ||
}; | ||
@@ -129,3 +138,3 @@ /** | ||
type AttemptDescription = { | ||
handler: ConnectionHandler; | ||
handler: Remote<ConnectionHandler>; | ||
remoteAddress?: string | undefined; | ||
@@ -142,31 +151,31 @@ localAddress?: string | undefined; | ||
*/ | ||
onCreate: (protocol: ProtocolImpl, p: ProtocolHandler) => PromiseVow<void>; | ||
onCreate: (protocol: Remote<ProtocolImpl>, p: Remote<ProtocolHandler>) => PromiseVow<void>; | ||
/** | ||
* Create a fresh port identifier for this protocol | ||
*/ | ||
generatePortID: (localAddr: Endpoint, p: ProtocolHandler) => PromiseVow<string>; | ||
generatePortID: (localAddr: Endpoint, p: Remote<ProtocolHandler>) => PromiseVow<string>; | ||
/** | ||
* A port will be bound | ||
*/ | ||
onBind: (port: Port, localAddr: Endpoint, p: ProtocolHandler) => PromiseVow<void>; | ||
onBind: (port: Remote<Port>, localAddr: Endpoint, p: Remote<ProtocolHandler>) => PromiseVow<void>; | ||
/** | ||
* A port was listening | ||
*/ | ||
onListen: (port: Port, localAddr: Endpoint, listenHandler: ListenHandler, p: ProtocolHandler) => PromiseVow<void>; | ||
onListen: (port: Remote<Port>, localAddr: Endpoint, listenHandler: Remote<ListenHandler>, p: Remote<ProtocolHandler>) => PromiseVow<void>; | ||
/** | ||
* A port listener has been reset | ||
*/ | ||
onListenRemove: (port: Port, localAddr: Endpoint, listenHandler: ListenHandler, p: ProtocolHandler) => PromiseVow<void>; | ||
onListenRemove: (port: Remote<Port>, localAddr: Endpoint, listenHandler: Remote<ListenHandler>, p: Remote<ProtocolHandler>) => PromiseVow<void>; | ||
/** | ||
* Return unique suffix for local address | ||
*/ | ||
onInstantiate?: ((port: Port, localAddr: Endpoint, remote: Endpoint, p: ProtocolHandler) => PromiseVow<Endpoint>) | undefined; | ||
onInstantiate?: ((port: Remote<Port>, localAddr: Endpoint, remote: Endpoint, p: Remote<ProtocolHandler>) => PromiseVow<Endpoint>) | undefined; | ||
/** | ||
* A port initiates an outbound connection | ||
*/ | ||
onConnect: (port: Port, localAddr: Endpoint, remote: Endpoint, c: ConnectionHandler, p: ProtocolHandler) => PromiseVow<AttemptDescription>; | ||
onConnect: (port: Remote<Port>, localAddr: Endpoint, remote: Endpoint, c: Remote<ConnectionHandler>, p: Remote<ProtocolHandler>) => PromiseVow<AttemptDescription>; | ||
/** | ||
* The port is being completely destroyed | ||
*/ | ||
onRevoke: (port: Port, localAddr: Endpoint, p: ProtocolHandler) => PromiseVow<void>; | ||
onRevoke: (port: Remote<Port>, localAddr: Endpoint, p: Remote<ProtocolHandler>) => PromiseVow<void>; | ||
}; | ||
@@ -204,3 +213,3 @@ /** | ||
*/ | ||
bind: (prefix: Endpoint) => PromiseVow<Port>; | ||
bind: (prefix: Endpoint) => PromiseVow<Remote<Port>>; | ||
/** | ||
@@ -213,4 +222,4 @@ * Make an attempt to connect into this protocol | ||
*/ | ||
outbound: (port: Port, remoteAddr: Endpoint, connectionHandler: ConnectionHandler) => PromiseVow<Connection>; | ||
outbound: (port: Remote<Port>, remoteAddr: Endpoint, connectionHandler: Remote<ConnectionHandler>) => PromiseVow<Connection>; | ||
}; | ||
//# sourceMappingURL=types.d.ts.map |
101
src/types.js
@@ -5,12 +5,22 @@ // @ts-check | ||
* @template T | ||
* @typedef {Promise<T | import('@agoric/vow').Vow<T>>} PromiseVow | ||
* @typedef {import('@agoric/vow').PromiseVow<T>} PromiseVow | ||
*/ | ||
/** | ||
* @typedef {string | Buffer | ArrayBuffer} Data | ||
* | ||
* @typedef {string} Bytes | ||
* @template T | ||
* @typedef {import('@agoric/vow').Remote<T>} Remote | ||
*/ | ||
/** | ||
* @template {import('@endo/exo').Methods} M | ||
* @template {(...args: any[]) => any} I | ||
* @typedef {M & ThisType<{ self: import('@endo/exo').Guarded<M>, state: ReturnType<I> }>} ExoClassMethods | ||
* Rearrange the exo types to make a cast of the methods (M) and init function (I) to a specific type. | ||
*/ | ||
/** | ||
* @typedef {string} Bytes Each character code carries 8-bit octets. Eventually we want to use passable Uint8Arrays. | ||
*/ | ||
/** | ||
* @typedef {string} Endpoint A local or remote address See multiaddr.js for an | ||
@@ -35,12 +45,12 @@ * opinionated router implementation | ||
* port | ||
* @property {(acceptHandler: ListenHandler) => PromiseVow<void>} addListener | ||
* @property {(acceptHandler: Remote<ListenHandler>) => PromiseVow<void>} addListener | ||
* Begin accepting incoming connections | ||
* @property {( | ||
* remote: Endpoint, | ||
* connectionHandler?: ConnectionHandler, | ||
* connectionHandler?: Remote<ConnectionHandler>, | ||
* ) => PromiseVow<Connection>} connect | ||
* Make an outbound connection | ||
* @property {(acceptHandler: ListenHandler) => PromiseVow<void>} removeListener | ||
* @property {(acceptHandler: Remote<ListenHandler>) => PromiseVow<void>} removeListener | ||
* Remove the currently-bound listener | ||
* @property {() => void} revoke Deallocate the port entirely, removing all | ||
* @property {() => PromiseVow<void>} revoke Deallocate the port entirely, removing all | ||
* listeners and closing all active connections | ||
@@ -51,21 +61,20 @@ */ | ||
* @typedef {object} ListenHandler A handler for incoming connections | ||
* @property {(port: Port, l: ListenHandler) => PromiseVow<void>} [onListen] The | ||
* listener has been registered | ||
* @property {(port: Remote<Port>, l: Remote<ListenHandler>) => PromiseVow<void>} [onListen] The listener has been registered | ||
* @property {( | ||
* port: Port, | ||
* port: Remote<Port>, | ||
* localAddr: Endpoint, | ||
* remoteAddr: Endpoint, | ||
* l: ListenHandler, | ||
* ) => PromiseVow<ConnectionHandler>} onAccept | ||
* l: Remote<ListenHandler>, | ||
* ) => PromiseVow<Remote<ConnectionHandler>>} onAccept | ||
* A new connection is incoming | ||
* @property {( | ||
* port: Port, | ||
* port: Remote<Port>, | ||
* localAddr: Endpoint, | ||
* remoteAddr: Endpoint, | ||
* l: ListenHandler, | ||
* l: Remote<ListenHandler>, | ||
* ) => PromiseVow<void>} [onReject] | ||
* The connection was rejected | ||
* @property {(port: Port, rej: any, l: ListenHandler) => PromiseVow<void>} [onError] | ||
* @property {(port: Remote<Port>, rej: any, l: Remote<ListenHandler>) => PromiseVow<void>} [onError] | ||
* There was an error while listening | ||
* @property {(port: Port, l: ListenHandler) => PromiseVow<void>} [onRemove] The | ||
* @property {(port: Remote<Port>, l: Remote<ListenHandler>) => PromiseVow<void>} [onRemove] The | ||
* listener has been removed | ||
@@ -77,3 +86,3 @@ */ | ||
* @property {( | ||
* packetBytes: Data, | ||
* packetBytes: Bytes, | ||
* opts?: Record<string, any>, | ||
@@ -91,19 +100,19 @@ * ) => PromiseVow<Bytes>} send | ||
* @property {( | ||
* connection: Connection, | ||
* connection: Remote<Connection>, | ||
* localAddr: Endpoint, | ||
* remoteAddr: Endpoint, | ||
* c: ConnectionHandler, | ||
* c: Remote<ConnectionHandler>, | ||
* ) => PromiseVow<void>} [onOpen] | ||
* The connection has been opened | ||
* @property {( | ||
* connection: Connection, | ||
* connection: Remote<Connection>, | ||
* ack: Bytes, | ||
* c: ConnectionHandler, | ||
* c: Remote<ConnectionHandler>, | ||
* opts?: Record<string, any>, | ||
* ) => PromiseVow<Data>} [onReceive] | ||
* ) => PromiseVow<Bytes>} [onReceive] | ||
* The connection received a packet | ||
* @property {( | ||
* connection: Connection, | ||
* connection: Remote<Connection>, | ||
* reason?: CloseReason, | ||
* c?: ConnectionHandler, | ||
* c?: Remote<ConnectionHandler>, | ||
* ) => PromiseVow<void>} [onClose] | ||
@@ -117,3 +126,3 @@ * The connection has been closed | ||
* @typedef {object} AttemptDescription | ||
* @property {ConnectionHandler} handler | ||
* @property {Remote<ConnectionHandler>} handler | ||
* @property {Endpoint} [remoteAddress] | ||
@@ -126,45 +135,45 @@ * @property {Endpoint} [localAddress] | ||
* implementation will invoke | ||
* @property {(protocol: ProtocolImpl, p: ProtocolHandler) => PromiseVow<void>} onCreate | ||
* @property {(protocol: Remote<ProtocolImpl>, p: Remote<ProtocolHandler>) => PromiseVow<void>} onCreate | ||
* This protocol is created | ||
* @property {(localAddr: Endpoint, p: ProtocolHandler) => PromiseVow<string>} generatePortID | ||
* @property {(localAddr: Endpoint, p: Remote<ProtocolHandler>) => PromiseVow<string>} generatePortID | ||
* Create a fresh port identifier for this protocol | ||
* @property {( | ||
* port: Port, | ||
* port: Remote<Port>, | ||
* localAddr: Endpoint, | ||
* p: ProtocolHandler, | ||
* p: Remote<ProtocolHandler>, | ||
* ) => PromiseVow<void>} onBind | ||
* A port will be bound | ||
* @property {( | ||
* port: Port, | ||
* port: Remote<Port>, | ||
* localAddr: Endpoint, | ||
* listenHandler: ListenHandler, | ||
* p: ProtocolHandler, | ||
* listenHandler: Remote<ListenHandler>, | ||
* p: Remote<ProtocolHandler>, | ||
* ) => PromiseVow<void>} onListen | ||
* A port was listening | ||
* @property {( | ||
* port: Port, | ||
* port: Remote<Port>, | ||
* localAddr: Endpoint, | ||
* listenHandler: ListenHandler, | ||
* p: ProtocolHandler, | ||
* listenHandler: Remote<ListenHandler>, | ||
* p: Remote<ProtocolHandler>, | ||
* ) => PromiseVow<void>} onListenRemove | ||
* A port listener has been reset | ||
* @property {( | ||
* port: Port, | ||
* port: Remote<Port>, | ||
* localAddr: Endpoint, | ||
* remote: Endpoint, | ||
* p: ProtocolHandler, | ||
* p: Remote<ProtocolHandler>, | ||
* ) => PromiseVow<Endpoint>} [onInstantiate] | ||
* Return unique suffix for local address | ||
* @property {( | ||
* port: Port, | ||
* port: Remote<Port>, | ||
* localAddr: Endpoint, | ||
* remote: Endpoint, | ||
* c: ConnectionHandler, | ||
* p: ProtocolHandler, | ||
* c: Remote<ConnectionHandler>, | ||
* p: Remote<ProtocolHandler>, | ||
* ) => PromiseVow<AttemptDescription>} onConnect | ||
* A port initiates an outbound connection | ||
* @property {( | ||
* port: Port, | ||
* port: Remote<Port>, | ||
* localAddr: Endpoint, | ||
* p: ProtocolHandler, | ||
* p: Remote<ProtocolHandler>, | ||
* ) => PromiseVow<void>} onRevoke | ||
@@ -183,3 +192,3 @@ * The port is being completely destroyed | ||
* @typedef {object} ProtocolImpl Things the protocol can do for us | ||
* @property {(prefix: Endpoint) => PromiseVow<Port>} bind Claim a port, or if | ||
* @property {(prefix: Endpoint) => PromiseVow<Remote<Port>>} bind Claim a port, or if | ||
* ending in ENDPOINT_SEPARATOR, a fresh name | ||
@@ -192,7 +201,7 @@ * @property {( | ||
* @property {( | ||
* port: Port, | ||
* port: Remote<Port>, | ||
* remoteAddr: Endpoint, | ||
* connectionHandler: ConnectionHandler, | ||
* connectionHandler: Remote<ConnectionHandler>, | ||
* ) => PromiseVow<Connection>} outbound | ||
* Create an outbound connection | ||
*/ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Manifest confusion
Supply chain riskThis package has inconsistent metadata. This could be malicious or caused by an error when publishing the package.
Found 1 instance in 1 package
Manifest confusion
Supply chain riskThis package has inconsistent metadata. This could be malicious or caused by an error when publishing the package.
Found 1 instance in 1 package
122918
30
2625
Updated@endo/base64@^1.0.4
Updated@endo/far@^1.1.1
Updated@endo/patterns@^1.3.1
Updated@endo/promise-kit@^1.1.1