@agoric/swingset-vat 0.32.3-dev-c4e4693.0 → 0.32.3-dev-2f092c3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +12 -12
- package/src/vats/network/bytes.js +0 -63
- package/src/vats/network/index.js +0 -4
- package/src/vats/network/multiaddr.js +0 -65
- package/src/vats/network/network.js +0 -610
- package/src/vats/network/router.js +0 -115
- package/src/vats/network/types.js +0 -85
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agoric/swingset-vat",
|
|
3
|
-
"version": "0.32.3-dev-
|
|
3
|
+
"version": "0.32.3-dev-2f092c3.0+2f092c3",
|
|
4
4
|
"description": "Vat/Container Launcher",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|
|
@@ -27,16 +27,16 @@
|
|
|
27
27
|
"@types/yargs-parser": "^21.0.0"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@agoric/assert": "0.6.1-dev-
|
|
31
|
-
"@agoric/internal": "0.3.3-dev-
|
|
32
|
-
"@agoric/store": "0.9.3-dev-
|
|
33
|
-
"@agoric/swing-store": "0.9.2-dev-
|
|
34
|
-
"@agoric/swingset-liveslots": "0.10.3-dev-
|
|
35
|
-
"@agoric/swingset-xsnap-supervisor": "0.10.3-dev-
|
|
36
|
-
"@agoric/time": "0.3.3-dev-
|
|
37
|
-
"@agoric/vat-data": "0.5.3-dev-
|
|
38
|
-
"@agoric/xsnap": "0.14.3-dev-
|
|
39
|
-
"@agoric/xsnap-lockdown": "0.14.1-dev-
|
|
30
|
+
"@agoric/assert": "0.6.1-dev-2f092c3.0+2f092c3",
|
|
31
|
+
"@agoric/internal": "0.3.3-dev-2f092c3.0+2f092c3",
|
|
32
|
+
"@agoric/store": "0.9.3-dev-2f092c3.0+2f092c3",
|
|
33
|
+
"@agoric/swing-store": "0.9.2-dev-2f092c3.0+2f092c3",
|
|
34
|
+
"@agoric/swingset-liveslots": "0.10.3-dev-2f092c3.0+2f092c3",
|
|
35
|
+
"@agoric/swingset-xsnap-supervisor": "0.10.3-dev-2f092c3.0+2f092c3",
|
|
36
|
+
"@agoric/time": "0.3.3-dev-2f092c3.0+2f092c3",
|
|
37
|
+
"@agoric/vat-data": "0.5.3-dev-2f092c3.0+2f092c3",
|
|
38
|
+
"@agoric/xsnap": "0.14.3-dev-2f092c3.0+2f092c3",
|
|
39
|
+
"@agoric/xsnap-lockdown": "0.14.1-dev-2f092c3.0+2f092c3",
|
|
40
40
|
"@endo/base64": "^0.2.32",
|
|
41
41
|
"@endo/bundle-source": "^2.5.2",
|
|
42
42
|
"@endo/captp": "^3.1.2",
|
|
@@ -93,5 +93,5 @@
|
|
|
93
93
|
"publishConfig": {
|
|
94
94
|
"access": "public"
|
|
95
95
|
},
|
|
96
|
-
"gitHead": "
|
|
96
|
+
"gitHead": "2f092c3a20ac275c3402645d3d984a3657cf20d5"
|
|
97
97
|
}
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import './types.js';
|
|
2
|
-
import { encodeBase64, decodeBase64 } from '@endo/base64';
|
|
3
|
-
|
|
4
|
-
/* eslint-disable no-bitwise */
|
|
5
|
-
/**
|
|
6
|
-
* Convert some data to bytes.
|
|
7
|
-
*
|
|
8
|
-
* @param {Data} data
|
|
9
|
-
* @returns {Bytes}
|
|
10
|
-
*/
|
|
11
|
-
export function toBytes(data) {
|
|
12
|
-
/** @type {Data | number[]} */
|
|
13
|
-
let bytes = data;
|
|
14
|
-
// TODO: We really need marshallable TypedArrays.
|
|
15
|
-
if (typeof bytes === 'string') {
|
|
16
|
-
bytes = bytes.split('').map(c => c.charCodeAt(0));
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
// We return the raw characters in the lower half of
|
|
20
|
-
// the String's representation.
|
|
21
|
-
const buf = new Uint8Array(bytes);
|
|
22
|
-
return String.fromCharCode.apply(null, buf);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Convert bytes to a String.
|
|
27
|
-
*
|
|
28
|
-
* @param {Bytes} bytes
|
|
29
|
-
* @returns {string}
|
|
30
|
-
*/
|
|
31
|
-
export function bytesToString(bytes) {
|
|
32
|
-
return bytes;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Base64, as specified in https://tools.ietf.org/html/rfc4648#section-4
|
|
37
|
-
*
|
|
38
|
-
* @param {Data} data
|
|
39
|
-
* @returns {string} base64 encoding
|
|
40
|
-
*/
|
|
41
|
-
export function dataToBase64(data) {
|
|
42
|
-
/** @type {Uint8Array?} */
|
|
43
|
-
let bytes;
|
|
44
|
-
if (typeof data === 'string') {
|
|
45
|
-
bytes = new Uint8Array(data.length);
|
|
46
|
-
for (let i = 0; i < data.length; i += 1) {
|
|
47
|
-
bytes[i] = data.charCodeAt(i);
|
|
48
|
-
}
|
|
49
|
-
} else {
|
|
50
|
-
bytes = new Uint8Array(data);
|
|
51
|
-
}
|
|
52
|
-
return encodeBase64(bytes);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Decodes a string into base64.
|
|
57
|
-
*
|
|
58
|
-
* @param {string} string Base64-encoded string
|
|
59
|
-
* @returns {Bytes} decoded bytes
|
|
60
|
-
*/
|
|
61
|
-
export function base64ToBytes(string) {
|
|
62
|
-
return toBytes(decodeBase64(string));
|
|
63
|
-
}
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @typedef {[string, string][]} Multiaddr
|
|
3
|
-
* @typedef {string} Textaddr An address string formatted as in https://github.com/multiformats/multiaddr
|
|
4
|
-
*
|
|
5
|
-
* Here is the difference between Textaddr and Multiaddr:
|
|
6
|
-
*
|
|
7
|
-
* unspecified port on local ibc interface: /if/ibc0 [['if', 'ibc0']]
|
|
8
|
-
* specific local port: /if/ibc0/ordered/transfer [['if', 'ibc0'], ['ordered', 'transfer']]
|
|
9
|
-
*
|
|
10
|
-
* remote pointer to chain: /dnsaddr/ibc.testnet.agoric.com/ordered/transfer
|
|
11
|
-
* [['dnsaddr', 'ibc.testnet.agoric.com'], ['ordered', 'transfer']]
|
|
12
|
-
* resolve step to another pointer: /dnsaddr/rpc.testnet.agoric.com/ibc/testnet-1.19.0/gci/4bc8d.../ordered/transfer
|
|
13
|
-
* [['dnsaddr', 'rpc.testnet.agoric.com'], ['ibc', 'testnet-1.19.0'], ['gci', '4bc8d...'], ['ordered', 'transfer']]
|
|
14
|
-
* resolve to the individual interfaces: /ip4/172.17.0.4/tcp/26657/tendermint/0.33/ibc/testnet-1.19.0/gci/4bc8d.../ordered/transfer
|
|
15
|
-
* [['ip4', '172.17.0.4'], ['tcp', '26657'], ['tendermint', '0.33'],
|
|
16
|
-
* ['ibc', 'testnet-1.19.0'], ['gci', '4bc8d...'], ['ordered', 'transfer']]
|
|
17
|
-
*/
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Transform a text address to a parsed multiaddr
|
|
21
|
-
*
|
|
22
|
-
* @param {Textaddr} ma
|
|
23
|
-
* @returns {Multiaddr}
|
|
24
|
-
*/
|
|
25
|
-
export function parse(ma) {
|
|
26
|
-
if (typeof ma !== 'string') {
|
|
27
|
-
return ma;
|
|
28
|
-
}
|
|
29
|
-
let s = ma;
|
|
30
|
-
let m;
|
|
31
|
-
/**
|
|
32
|
-
* @type {[string, string][]}
|
|
33
|
-
*/
|
|
34
|
-
const acc = [];
|
|
35
|
-
// eslint-disable-next-line no-cond-assign
|
|
36
|
-
while ((m = s.match(/^\/([^/]*)(\/([^/]*))?/))) {
|
|
37
|
-
s = s.substr(m[0].length);
|
|
38
|
-
if (m[2]) {
|
|
39
|
-
acc.push([m[1], m[3]]);
|
|
40
|
-
} else {
|
|
41
|
-
// @ts-expect-error '[string]' is not assignable to parameter of type '[string, string]'
|
|
42
|
-
acc.push([m[1]]);
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
if (s !== '' || s === ma) {
|
|
46
|
-
throw TypeError(
|
|
47
|
-
`Error parsing Multiaddr ${JSON.stringify(ma)} at ${JSON.stringify(s)}`,
|
|
48
|
-
);
|
|
49
|
-
}
|
|
50
|
-
return acc;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Transform a parsed multiaddr to a string.
|
|
55
|
-
*
|
|
56
|
-
* @param {Multiaddr|Textaddr} ma
|
|
57
|
-
* @returns {Textaddr}
|
|
58
|
-
*/
|
|
59
|
-
export function unparse(ma) {
|
|
60
|
-
if (typeof ma === 'string') {
|
|
61
|
-
return ma;
|
|
62
|
-
}
|
|
63
|
-
const joined = ma.map(kv => kv.join('/')).join('/');
|
|
64
|
-
return `/${joined}`;
|
|
65
|
-
}
|
|
@@ -1,610 +0,0 @@
|
|
|
1
|
-
import { makeScalarMapStore, makeLegacyMap } from '@agoric/store';
|
|
2
|
-
import { Far, E } from '@endo/far';
|
|
3
|
-
import { makePromiseKit } from '@endo/promise-kit';
|
|
4
|
-
import { Fail } from '@agoric/assert';
|
|
5
|
-
import { whileTrue } from '@agoric/internal';
|
|
6
|
-
import { toBytes } from './bytes.js';
|
|
7
|
-
|
|
8
|
-
import '@agoric/store/exported.js';
|
|
9
|
-
import './types.js';
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Compatibility note: this must match what our peers use,
|
|
13
|
-
* so don't change it casually.
|
|
14
|
-
*/
|
|
15
|
-
export const ENDPOINT_SEPARATOR = '/';
|
|
16
|
-
|
|
17
|
-
export const rethrowUnlessMissing = err => {
|
|
18
|
-
// Ugly hack rather than being able to determine if the function
|
|
19
|
-
// exists.
|
|
20
|
-
if (
|
|
21
|
-
!(err instanceof TypeError) ||
|
|
22
|
-
!err.message.match(/target has no method|is not a function$/)
|
|
23
|
-
) {
|
|
24
|
-
throw err;
|
|
25
|
-
}
|
|
26
|
-
return undefined;
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Create a handled Connection.
|
|
31
|
-
*
|
|
32
|
-
* @param {ConnectionHandler} handler
|
|
33
|
-
* @param {Endpoint} localAddr
|
|
34
|
-
* @param {Endpoint} remoteAddr
|
|
35
|
-
* @param {Set<Closable>} [current]
|
|
36
|
-
* @returns {Connection}
|
|
37
|
-
*/
|
|
38
|
-
export const makeConnection = (
|
|
39
|
-
handler,
|
|
40
|
-
localAddr,
|
|
41
|
-
remoteAddr,
|
|
42
|
-
current = new Set(),
|
|
43
|
-
) => {
|
|
44
|
-
let closed;
|
|
45
|
-
/**
|
|
46
|
-
* @type {Set<import('@endo/promise-kit').PromiseKit<Bytes>>}
|
|
47
|
-
*/
|
|
48
|
-
const pendingAcks = new Set();
|
|
49
|
-
/**
|
|
50
|
-
* @type {Connection}
|
|
51
|
-
*/
|
|
52
|
-
const connection = Far('Connection', {
|
|
53
|
-
getLocalAddress() {
|
|
54
|
-
return localAddr;
|
|
55
|
-
},
|
|
56
|
-
getRemoteAddress() {
|
|
57
|
-
return remoteAddr;
|
|
58
|
-
},
|
|
59
|
-
async close() {
|
|
60
|
-
if (closed) {
|
|
61
|
-
throw closed;
|
|
62
|
-
}
|
|
63
|
-
current.delete(connection);
|
|
64
|
-
closed = Error('Connection closed');
|
|
65
|
-
for (const ackDeferred of [...pendingAcks.values()]) {
|
|
66
|
-
pendingAcks.delete(ackDeferred);
|
|
67
|
-
ackDeferred.reject(closed);
|
|
68
|
-
}
|
|
69
|
-
await E(handler)
|
|
70
|
-
.onClose(connection, undefined, handler)
|
|
71
|
-
.catch(rethrowUnlessMissing);
|
|
72
|
-
},
|
|
73
|
-
async send(data, opts) {
|
|
74
|
-
// console.log('send', data, local === srcHandler);
|
|
75
|
-
if (closed) {
|
|
76
|
-
throw closed;
|
|
77
|
-
}
|
|
78
|
-
const bytes = toBytes(data);
|
|
79
|
-
const ackDeferred = makePromiseKit();
|
|
80
|
-
pendingAcks.add(ackDeferred);
|
|
81
|
-
E(handler)
|
|
82
|
-
.onReceive(connection, bytes, handler, opts)
|
|
83
|
-
.catch(err => {
|
|
84
|
-
rethrowUnlessMissing(err);
|
|
85
|
-
return '';
|
|
86
|
-
})
|
|
87
|
-
.then(
|
|
88
|
-
ack => {
|
|
89
|
-
pendingAcks.delete(ackDeferred);
|
|
90
|
-
ackDeferred.resolve(toBytes(ack));
|
|
91
|
-
},
|
|
92
|
-
err => {
|
|
93
|
-
pendingAcks.delete(ackDeferred);
|
|
94
|
-
ackDeferred.reject(err);
|
|
95
|
-
},
|
|
96
|
-
);
|
|
97
|
-
return ackDeferred.promise;
|
|
98
|
-
},
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
current.add(connection);
|
|
102
|
-
E(handler)
|
|
103
|
-
.onOpen(connection, localAddr, remoteAddr, handler)
|
|
104
|
-
.catch(rethrowUnlessMissing);
|
|
105
|
-
return connection;
|
|
106
|
-
};
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* @param {ConnectionHandler} handler0
|
|
110
|
-
* @param {Endpoint} addr0
|
|
111
|
-
* @param {ConnectionHandler} handler1
|
|
112
|
-
* @param {Endpoint} addr1
|
|
113
|
-
* @param {WeakSet<Connection>} [current]
|
|
114
|
-
* @returns {[Connection, Connection]}
|
|
115
|
-
*/
|
|
116
|
-
export function crossoverConnection(
|
|
117
|
-
handler0,
|
|
118
|
-
addr0,
|
|
119
|
-
handler1,
|
|
120
|
-
addr1,
|
|
121
|
-
current = new WeakSet(),
|
|
122
|
-
) {
|
|
123
|
-
/**
|
|
124
|
-
* @type {Connection[]}
|
|
125
|
-
*/
|
|
126
|
-
const conns = [];
|
|
127
|
-
/**
|
|
128
|
-
* @type {ConnectionHandler[]}
|
|
129
|
-
*/
|
|
130
|
-
const handlers = [handler0, handler1];
|
|
131
|
-
/**
|
|
132
|
-
* @type {Endpoint[]}
|
|
133
|
-
*/
|
|
134
|
-
const addrs = [addr0, addr1];
|
|
135
|
-
|
|
136
|
-
function makeHalfConnection(l, r) {
|
|
137
|
-
let closed;
|
|
138
|
-
conns[l] = Far('Connection', {
|
|
139
|
-
getLocalAddress() {
|
|
140
|
-
return addrs[l];
|
|
141
|
-
},
|
|
142
|
-
getRemoteAddress() {
|
|
143
|
-
return addrs[r];
|
|
144
|
-
},
|
|
145
|
-
async send(packetBytes) {
|
|
146
|
-
if (closed) {
|
|
147
|
-
throw closed;
|
|
148
|
-
}
|
|
149
|
-
const ack = await E(handlers[r])
|
|
150
|
-
.onReceive(conns[r], toBytes(packetBytes), handlers[r])
|
|
151
|
-
.catch(rethrowUnlessMissing);
|
|
152
|
-
return toBytes(ack || '');
|
|
153
|
-
},
|
|
154
|
-
async close() {
|
|
155
|
-
if (closed) {
|
|
156
|
-
throw closed;
|
|
157
|
-
}
|
|
158
|
-
closed = Error('Connection closed');
|
|
159
|
-
current.delete(conns[l]);
|
|
160
|
-
await E(handlers[l])
|
|
161
|
-
.onClose(conns[l], undefined, handlers[l])
|
|
162
|
-
.catch(rethrowUnlessMissing);
|
|
163
|
-
},
|
|
164
|
-
});
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
makeHalfConnection(0, 1);
|
|
168
|
-
makeHalfConnection(1, 0);
|
|
169
|
-
|
|
170
|
-
/**
|
|
171
|
-
* @param {number} l local side of the connection
|
|
172
|
-
* @param {number} r remote side of the connection
|
|
173
|
-
*/
|
|
174
|
-
function openHalfConnection(l, r) {
|
|
175
|
-
current.add(conns[l]);
|
|
176
|
-
E(handlers[l])
|
|
177
|
-
.onOpen(conns[l], addrs[l], addrs[r], handlers[l])
|
|
178
|
-
.catch(rethrowUnlessMissing);
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
openHalfConnection(0, 1);
|
|
182
|
-
openHalfConnection(1, 0);
|
|
183
|
-
|
|
184
|
-
const [conn0, conn1] = conns;
|
|
185
|
-
return [conn0, conn1];
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
/**
|
|
189
|
-
* Get the list of prefixes from longest to shortest.
|
|
190
|
-
*
|
|
191
|
-
* @param {string} addr
|
|
192
|
-
*/
|
|
193
|
-
export function getPrefixes(addr) {
|
|
194
|
-
const parts = addr.split(ENDPOINT_SEPARATOR);
|
|
195
|
-
|
|
196
|
-
/**
|
|
197
|
-
* @type {string[]}
|
|
198
|
-
*/
|
|
199
|
-
const ret = [];
|
|
200
|
-
for (let i = parts.length; i > 0; i -= 1) {
|
|
201
|
-
// Try most specific match.
|
|
202
|
-
const prefix = parts.slice(0, i).join(ENDPOINT_SEPARATOR);
|
|
203
|
-
ret.push(prefix);
|
|
204
|
-
}
|
|
205
|
-
return ret;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
/**
|
|
209
|
-
* Create a protocol that has a handler.
|
|
210
|
-
*
|
|
211
|
-
* @param {ProtocolHandler} protocolHandler
|
|
212
|
-
* @returns {Protocol} the local capability for connecting and listening
|
|
213
|
-
*/
|
|
214
|
-
export function makeNetworkProtocol(protocolHandler) {
|
|
215
|
-
/** @type {LegacyMap<Port, Set<Closable>>} */
|
|
216
|
-
// Legacy because we're storing a JS Set
|
|
217
|
-
const currentConnections = makeLegacyMap('port');
|
|
218
|
-
|
|
219
|
-
/**
|
|
220
|
-
* Currently must be a single listenHandler.
|
|
221
|
-
* TODO: Do something sensible with multiple handlers?
|
|
222
|
-
*
|
|
223
|
-
* @type {MapStore<Endpoint, [Port, ListenHandler]>}
|
|
224
|
-
*/
|
|
225
|
-
const listening = makeScalarMapStore('localAddr');
|
|
226
|
-
|
|
227
|
-
/**
|
|
228
|
-
* @type {MapStore<string, Port>}
|
|
229
|
-
*/
|
|
230
|
-
const boundPorts = makeScalarMapStore('localAddr');
|
|
231
|
-
|
|
232
|
-
/**
|
|
233
|
-
* @param {Endpoint} localAddr
|
|
234
|
-
*/
|
|
235
|
-
const bind = async localAddr => {
|
|
236
|
-
// Check if we are underspecified (ends in slash)
|
|
237
|
-
const underspecified = localAddr.endsWith(ENDPOINT_SEPARATOR);
|
|
238
|
-
for await (const _ of whileTrue(() => underspecified)) {
|
|
239
|
-
const portID = await E(protocolHandler).generatePortID(
|
|
240
|
-
localAddr,
|
|
241
|
-
protocolHandler,
|
|
242
|
-
);
|
|
243
|
-
const newAddr = `${localAddr}${portID}`;
|
|
244
|
-
if (!boundPorts.has(newAddr)) {
|
|
245
|
-
localAddr = newAddr;
|
|
246
|
-
break;
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
if (boundPorts.has(localAddr)) {
|
|
251
|
-
return boundPorts.get(localAddr);
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
/**
|
|
255
|
-
* @enum {number}
|
|
256
|
-
*/
|
|
257
|
-
const RevokeState = {
|
|
258
|
-
NOT_REVOKED: 0,
|
|
259
|
-
REVOKING: 1,
|
|
260
|
-
REVOKED: 2,
|
|
261
|
-
};
|
|
262
|
-
|
|
263
|
-
/**
|
|
264
|
-
* @type {RevokeState}
|
|
265
|
-
*/
|
|
266
|
-
let revoked = RevokeState.NOT_REVOKED;
|
|
267
|
-
const openConnections = new Set();
|
|
268
|
-
|
|
269
|
-
/**
|
|
270
|
-
* @type {Port}
|
|
271
|
-
*/
|
|
272
|
-
const port = Far('Port', {
|
|
273
|
-
getLocalAddress() {
|
|
274
|
-
// Works even after revoke().
|
|
275
|
-
return localAddr;
|
|
276
|
-
},
|
|
277
|
-
async addListener(listenHandler) {
|
|
278
|
-
!revoked || Fail`Port ${localAddr} is revoked`;
|
|
279
|
-
listenHandler || Fail`listenHandler is not defined`;
|
|
280
|
-
if (listening.has(localAddr)) {
|
|
281
|
-
// Last one wins.
|
|
282
|
-
const [lport, lhandler] = listening.get(localAddr);
|
|
283
|
-
if (lhandler === listenHandler) {
|
|
284
|
-
return;
|
|
285
|
-
}
|
|
286
|
-
listening.set(localAddr, [port, listenHandler]);
|
|
287
|
-
E(lhandler).onRemove(lport, lhandler).catch(rethrowUnlessMissing);
|
|
288
|
-
} else {
|
|
289
|
-
listening.init(localAddr, [port, listenHandler]);
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
// TODO: Check that the listener defines onAccept.
|
|
293
|
-
|
|
294
|
-
await E(protocolHandler).onListen(
|
|
295
|
-
port,
|
|
296
|
-
localAddr,
|
|
297
|
-
listenHandler,
|
|
298
|
-
protocolHandler,
|
|
299
|
-
);
|
|
300
|
-
await E(listenHandler)
|
|
301
|
-
.onListen(port, listenHandler)
|
|
302
|
-
.catch(rethrowUnlessMissing);
|
|
303
|
-
},
|
|
304
|
-
async removeListener(listenHandler) {
|
|
305
|
-
listening.has(localAddr) || Fail`Port ${localAddr} is not listening`;
|
|
306
|
-
listening.get(localAddr)[1] === listenHandler ||
|
|
307
|
-
Fail`Port ${localAddr} handler to remove is not listening`;
|
|
308
|
-
listening.delete(localAddr);
|
|
309
|
-
await E(protocolHandler).onListenRemove(
|
|
310
|
-
port,
|
|
311
|
-
localAddr,
|
|
312
|
-
listenHandler,
|
|
313
|
-
protocolHandler,
|
|
314
|
-
);
|
|
315
|
-
await E(listenHandler)
|
|
316
|
-
.onRemove(port, listenHandler)
|
|
317
|
-
.catch(rethrowUnlessMissing);
|
|
318
|
-
},
|
|
319
|
-
async connect(remotePort, connectionHandler = {}) {
|
|
320
|
-
!revoked || Fail`Port ${localAddr} is revoked`;
|
|
321
|
-
/**
|
|
322
|
-
* @type {Endpoint}
|
|
323
|
-
*/
|
|
324
|
-
const dst = harden(remotePort);
|
|
325
|
-
// eslint-disable-next-line no-use-before-define
|
|
326
|
-
const conn = await protocolImpl.outbound(port, dst, connectionHandler);
|
|
327
|
-
if (revoked) {
|
|
328
|
-
void E(conn).close();
|
|
329
|
-
} else {
|
|
330
|
-
openConnections.add(conn);
|
|
331
|
-
}
|
|
332
|
-
return conn;
|
|
333
|
-
},
|
|
334
|
-
async revoke() {
|
|
335
|
-
revoked !== RevokeState.REVOKED ||
|
|
336
|
-
Fail`Port ${localAddr} is already revoked`;
|
|
337
|
-
revoked = RevokeState.REVOKING;
|
|
338
|
-
await E(protocolHandler).onRevoke(port, localAddr, protocolHandler);
|
|
339
|
-
revoked = RevokeState.REVOKED;
|
|
340
|
-
|
|
341
|
-
// Clean up everything we did.
|
|
342
|
-
const ps = [...currentConnections.get(port)].map(conn =>
|
|
343
|
-
E(conn)
|
|
344
|
-
.close()
|
|
345
|
-
.catch(_ => {}),
|
|
346
|
-
);
|
|
347
|
-
if (listening.has(localAddr)) {
|
|
348
|
-
const listener = listening.get(localAddr)[1];
|
|
349
|
-
ps.push(port.removeListener(listener));
|
|
350
|
-
}
|
|
351
|
-
await Promise.all(ps);
|
|
352
|
-
currentConnections.delete(port);
|
|
353
|
-
boundPorts.delete(localAddr);
|
|
354
|
-
return `Port ${localAddr} revoked`;
|
|
355
|
-
},
|
|
356
|
-
});
|
|
357
|
-
|
|
358
|
-
await E(protocolHandler).onBind(port, localAddr, protocolHandler);
|
|
359
|
-
boundPorts.init(localAddr, port);
|
|
360
|
-
currentConnections.init(port, new Set());
|
|
361
|
-
return port;
|
|
362
|
-
};
|
|
363
|
-
|
|
364
|
-
/**
|
|
365
|
-
* @type {ProtocolImpl}
|
|
366
|
-
*/
|
|
367
|
-
const protocolImpl = Far('ProtocolImpl', {
|
|
368
|
-
bind,
|
|
369
|
-
async inbound(listenAddr, remoteAddr) {
|
|
370
|
-
let lastFailure = Error(`No listeners for ${listenAddr}`);
|
|
371
|
-
for await (const listenPrefix of getPrefixes(listenAddr)) {
|
|
372
|
-
if (!listening.has(listenPrefix)) {
|
|
373
|
-
continue;
|
|
374
|
-
}
|
|
375
|
-
const [port, listener] = listening.get(listenPrefix);
|
|
376
|
-
let localAddr;
|
|
377
|
-
await (async () => {
|
|
378
|
-
// See if our protocol is willing to receive this connection.
|
|
379
|
-
const localInstance = await E(protocolHandler)
|
|
380
|
-
.onInstantiate(port, listenPrefix, remoteAddr, protocolHandler)
|
|
381
|
-
.catch(rethrowUnlessMissing);
|
|
382
|
-
localAddr = localInstance
|
|
383
|
-
? `${listenAddr}/${localInstance}`
|
|
384
|
-
: listenAddr;
|
|
385
|
-
})().catch(e => {
|
|
386
|
-
lastFailure = e;
|
|
387
|
-
});
|
|
388
|
-
if (!localAddr) {
|
|
389
|
-
continue;
|
|
390
|
-
}
|
|
391
|
-
// We have a legitimate inbound attempt.
|
|
392
|
-
let consummated;
|
|
393
|
-
const current = currentConnections.get(port);
|
|
394
|
-
const inboundAttempt = Far('InboundAttempt', {
|
|
395
|
-
getLocalAddress() {
|
|
396
|
-
// Return address metadata.
|
|
397
|
-
return localAddr;
|
|
398
|
-
},
|
|
399
|
-
getRemoteAddress() {
|
|
400
|
-
return remoteAddr;
|
|
401
|
-
},
|
|
402
|
-
async close() {
|
|
403
|
-
if (consummated) {
|
|
404
|
-
throw consummated;
|
|
405
|
-
}
|
|
406
|
-
consummated = Error(`Already closed`);
|
|
407
|
-
current.delete(inboundAttempt);
|
|
408
|
-
await E(listener)
|
|
409
|
-
.onReject(port, localAddr, remoteAddr, listener)
|
|
410
|
-
.catch(rethrowUnlessMissing);
|
|
411
|
-
},
|
|
412
|
-
async accept({
|
|
413
|
-
localAddress = localAddr,
|
|
414
|
-
remoteAddress = remoteAddr,
|
|
415
|
-
handler: rchandler,
|
|
416
|
-
}) {
|
|
417
|
-
if (consummated) {
|
|
418
|
-
throw consummated;
|
|
419
|
-
}
|
|
420
|
-
consummated = Error(`Already accepted`);
|
|
421
|
-
current.delete(inboundAttempt);
|
|
422
|
-
|
|
423
|
-
const lchandler = await E(listener).onAccept(
|
|
424
|
-
port,
|
|
425
|
-
localAddr,
|
|
426
|
-
remoteAddr,
|
|
427
|
-
listener,
|
|
428
|
-
);
|
|
429
|
-
|
|
430
|
-
return crossoverConnection(
|
|
431
|
-
lchandler,
|
|
432
|
-
localAddress,
|
|
433
|
-
rchandler,
|
|
434
|
-
remoteAddress,
|
|
435
|
-
current,
|
|
436
|
-
)[1];
|
|
437
|
-
},
|
|
438
|
-
});
|
|
439
|
-
current.add(inboundAttempt);
|
|
440
|
-
return inboundAttempt;
|
|
441
|
-
}
|
|
442
|
-
throw lastFailure;
|
|
443
|
-
},
|
|
444
|
-
async outbound(port, remoteAddr, lchandler) {
|
|
445
|
-
const localAddr =
|
|
446
|
-
/** @type {string} */
|
|
447
|
-
(await E(port).getLocalAddress());
|
|
448
|
-
|
|
449
|
-
// Allocate a local address.
|
|
450
|
-
const initialLocalInstance = await E(protocolHandler)
|
|
451
|
-
.onInstantiate(port, localAddr, remoteAddr, protocolHandler)
|
|
452
|
-
.catch(rethrowUnlessMissing);
|
|
453
|
-
const initialLocalAddr = initialLocalInstance
|
|
454
|
-
? `${localAddr}/${initialLocalInstance}`
|
|
455
|
-
: localAddr;
|
|
456
|
-
|
|
457
|
-
let lastFailure;
|
|
458
|
-
let accepted;
|
|
459
|
-
await (async () => {
|
|
460
|
-
// Attempt the loopback connection.
|
|
461
|
-
const attempt = await protocolImpl.inbound(
|
|
462
|
-
remoteAddr,
|
|
463
|
-
initialLocalAddr,
|
|
464
|
-
);
|
|
465
|
-
accepted = await attempt.accept({ handler: lchandler });
|
|
466
|
-
})().catch(e => {
|
|
467
|
-
lastFailure = e;
|
|
468
|
-
});
|
|
469
|
-
if (accepted) {
|
|
470
|
-
return accepted;
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
const {
|
|
474
|
-
remoteAddress = remoteAddr,
|
|
475
|
-
handler: rchandler,
|
|
476
|
-
localAddress = localAddr,
|
|
477
|
-
} =
|
|
478
|
-
/** @type {Partial<AttemptDescription>} */
|
|
479
|
-
(
|
|
480
|
-
await E(protocolHandler).onConnect(
|
|
481
|
-
port,
|
|
482
|
-
initialLocalAddr,
|
|
483
|
-
remoteAddr,
|
|
484
|
-
lchandler,
|
|
485
|
-
protocolHandler,
|
|
486
|
-
)
|
|
487
|
-
);
|
|
488
|
-
|
|
489
|
-
if (!rchandler) {
|
|
490
|
-
throw lastFailure;
|
|
491
|
-
}
|
|
492
|
-
|
|
493
|
-
const current = currentConnections.get(port);
|
|
494
|
-
return crossoverConnection(
|
|
495
|
-
lchandler,
|
|
496
|
-
localAddress,
|
|
497
|
-
rchandler,
|
|
498
|
-
remoteAddress,
|
|
499
|
-
current,
|
|
500
|
-
)[0];
|
|
501
|
-
},
|
|
502
|
-
});
|
|
503
|
-
|
|
504
|
-
// Wire up the local protocol to the handler.
|
|
505
|
-
void E(protocolHandler).onCreate(protocolImpl, protocolHandler);
|
|
506
|
-
|
|
507
|
-
// Return the user-facing protocol.
|
|
508
|
-
return Far('binder', { bind });
|
|
509
|
-
}
|
|
510
|
-
|
|
511
|
-
/**
|
|
512
|
-
* Create a ConnectionHandler that just echoes its packets.
|
|
513
|
-
*
|
|
514
|
-
* @returns {ConnectionHandler}
|
|
515
|
-
*/
|
|
516
|
-
export function makeEchoConnectionHandler() {
|
|
517
|
-
let closed;
|
|
518
|
-
/**
|
|
519
|
-
* @type {Connection}
|
|
520
|
-
*/
|
|
521
|
-
return Far('ConnectionHandler', {
|
|
522
|
-
async onReceive(_connection, bytes, _connectionHandler) {
|
|
523
|
-
if (closed) {
|
|
524
|
-
throw closed;
|
|
525
|
-
}
|
|
526
|
-
return bytes;
|
|
527
|
-
},
|
|
528
|
-
async onClose(_connection, _reason, _connectionHandler) {
|
|
529
|
-
if (closed) {
|
|
530
|
-
throw closed;
|
|
531
|
-
}
|
|
532
|
-
closed = Error('Connection closed');
|
|
533
|
-
},
|
|
534
|
-
});
|
|
535
|
-
}
|
|
536
|
-
|
|
537
|
-
export function makeNonceMaker(prefix = '', suffix = '') {
|
|
538
|
-
let nonce = 0;
|
|
539
|
-
return async () => {
|
|
540
|
-
nonce += 1;
|
|
541
|
-
return `${prefix}${nonce}${suffix}`;
|
|
542
|
-
};
|
|
543
|
-
}
|
|
544
|
-
|
|
545
|
-
/**
|
|
546
|
-
* Create a protocol handler that just connects to itself.
|
|
547
|
-
*
|
|
548
|
-
* @param {ProtocolHandler['onInstantiate']} [onInstantiate]
|
|
549
|
-
* @returns {ProtocolHandler} The localhost handler
|
|
550
|
-
*/
|
|
551
|
-
export function makeLoopbackProtocolHandler(
|
|
552
|
-
onInstantiate = makeNonceMaker('nonce/'),
|
|
553
|
-
) {
|
|
554
|
-
/**
|
|
555
|
-
* @type {MapStore<string, [Port, ListenHandler]>}
|
|
556
|
-
*/
|
|
557
|
-
const listeners = makeScalarMapStore('localAddr');
|
|
558
|
-
|
|
559
|
-
const makePortID = makeNonceMaker('port');
|
|
560
|
-
|
|
561
|
-
return Far('ProtocolHandler', {
|
|
562
|
-
// eslint-disable-next-line no-empty-function
|
|
563
|
-
async onCreate(_impl, _protocolHandler) {
|
|
564
|
-
// TODO
|
|
565
|
-
},
|
|
566
|
-
async generatePortID(_protocolHandler) {
|
|
567
|
-
return makePortID();
|
|
568
|
-
},
|
|
569
|
-
async onBind(_port, _localAddr, _protocolHandler) {
|
|
570
|
-
// TODO: Maybe handle a bind?
|
|
571
|
-
},
|
|
572
|
-
async onConnect(_port, localAddr, remoteAddr, _chandler, protocolHandler) {
|
|
573
|
-
const [lport, lhandler] = listeners.get(remoteAddr);
|
|
574
|
-
const rchandler =
|
|
575
|
-
/** @type {ConnectionHandler} */
|
|
576
|
-
(await E(lhandler).onAccept(lport, remoteAddr, localAddr, lhandler));
|
|
577
|
-
// console.log(`rchandler is`, rchandler);
|
|
578
|
-
const remoteInstance = await E(protocolHandler)
|
|
579
|
-
.onInstantiate(lport, remoteAddr, localAddr, protocolHandler)
|
|
580
|
-
.catch(rethrowUnlessMissing);
|
|
581
|
-
return {
|
|
582
|
-
remoteInstance,
|
|
583
|
-
handler: rchandler,
|
|
584
|
-
};
|
|
585
|
-
},
|
|
586
|
-
onInstantiate,
|
|
587
|
-
async onListen(port, localAddr, listenHandler, _protocolHandler) {
|
|
588
|
-
// TODO: Implement other listener replacement policies.
|
|
589
|
-
if (listeners.has(localAddr)) {
|
|
590
|
-
const lhandler = listeners.get(localAddr)[1];
|
|
591
|
-
if (lhandler !== listenHandler) {
|
|
592
|
-
// Last-one-wins.
|
|
593
|
-
listeners.set(localAddr, [port, listenHandler]);
|
|
594
|
-
}
|
|
595
|
-
} else {
|
|
596
|
-
listeners.init(localAddr, [port, listenHandler]);
|
|
597
|
-
}
|
|
598
|
-
},
|
|
599
|
-
async onListenRemove(port, localAddr, listenHandler, _protocolHandler) {
|
|
600
|
-
const [lport, lhandler] = listeners.get(localAddr);
|
|
601
|
-
lport === port || Fail`Port does not match listener on ${localAddr}`;
|
|
602
|
-
lhandler === listenHandler ||
|
|
603
|
-
Fail`Listen handler does not match listener on ${localAddr}`;
|
|
604
|
-
listeners.delete(localAddr);
|
|
605
|
-
},
|
|
606
|
-
async onRevoke(_port, _localAddr, _protocolHandler) {
|
|
607
|
-
// TODO: maybe clean up?
|
|
608
|
-
},
|
|
609
|
-
});
|
|
610
|
-
}
|
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
import { Far, E as defaultE } from '@endo/far';
|
|
2
|
-
import { makeScalarMapStore } from '@agoric/store';
|
|
3
|
-
import { Fail } from '@agoric/assert';
|
|
4
|
-
import { makeNetworkProtocol, ENDPOINT_SEPARATOR } from './network.js';
|
|
5
|
-
|
|
6
|
-
import '@agoric/store/exported.js';
|
|
7
|
-
import './types.js';
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* @template T
|
|
11
|
-
* @typedef {object} Router A delimited string router implementation
|
|
12
|
-
* @property {(addr: string) => [string, T][]} getRoutes Return the match and route in order of preference
|
|
13
|
-
* @property {(prefix: string, route: T) => void} register Add a prefix->route to the database
|
|
14
|
-
* @property {(prefix: string, route: T) => void} unregister Remove a prefix->route from the database
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Create a slash-delimited router.
|
|
19
|
-
*
|
|
20
|
-
* @template T
|
|
21
|
-
* @returns {Router<T>} a new Router
|
|
22
|
-
*/
|
|
23
|
-
export default function makeRouter() {
|
|
24
|
-
/**
|
|
25
|
-
* @type {MapStore<string, T>}
|
|
26
|
-
*/
|
|
27
|
-
const prefixToRoute = makeScalarMapStore('prefix');
|
|
28
|
-
return Far('Router', {
|
|
29
|
-
getRoutes(addr) {
|
|
30
|
-
const parts = addr.split(ENDPOINT_SEPARATOR);
|
|
31
|
-
/**
|
|
32
|
-
* @type {[string, T][]}
|
|
33
|
-
*/
|
|
34
|
-
const ret = [];
|
|
35
|
-
for (let i = parts.length; i > 0; i -= 1) {
|
|
36
|
-
// Try most specific match.
|
|
37
|
-
const prefix = parts.slice(0, i).join(ENDPOINT_SEPARATOR);
|
|
38
|
-
if (prefixToRoute.has(prefix)) {
|
|
39
|
-
ret.push([prefix, prefixToRoute.get(prefix)]);
|
|
40
|
-
}
|
|
41
|
-
// Trim off the last value (after the slash).
|
|
42
|
-
const defaultPrefix = prefix.substr(
|
|
43
|
-
0,
|
|
44
|
-
prefix.lastIndexOf(ENDPOINT_SEPARATOR) + 1,
|
|
45
|
-
);
|
|
46
|
-
if (prefixToRoute.has(defaultPrefix)) {
|
|
47
|
-
ret.push([defaultPrefix, prefixToRoute.get(defaultPrefix)]);
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
return harden(ret);
|
|
51
|
-
},
|
|
52
|
-
register(prefix, route) {
|
|
53
|
-
prefixToRoute.init(prefix, route);
|
|
54
|
-
},
|
|
55
|
-
unregister(prefix, route) {
|
|
56
|
-
prefixToRoute.get(prefix) === route ||
|
|
57
|
-
Fail`Router is not registered at prefix ${prefix}`;
|
|
58
|
-
prefixToRoute.delete(prefix);
|
|
59
|
-
},
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* @typedef {object} RouterProtocol
|
|
65
|
-
* @property {(prefix: string) => Promise<Port>} bind
|
|
66
|
-
* @property {(paths: string[], protocolHandler: ProtocolHandler) => void} registerProtocolHandler
|
|
67
|
-
* @property {(prefix: string, protocolHandler: ProtocolHandler) => void} unregisterProtocolHandler
|
|
68
|
-
*/
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Create a router that behaves like a Protocol.
|
|
72
|
-
*
|
|
73
|
-
* @param {typeof defaultE} [E] Eventual sender
|
|
74
|
-
* @returns {RouterProtocol} The new delegated protocol
|
|
75
|
-
*/
|
|
76
|
-
export function makeRouterProtocol(E = defaultE) {
|
|
77
|
-
const router = makeRouter();
|
|
78
|
-
/** @type {MapStore<string, Protocol>} */
|
|
79
|
-
const protocols = makeScalarMapStore('prefix');
|
|
80
|
-
/** @type {MapStore<string, ProtocolHandler>} */
|
|
81
|
-
const protocolHandlers = makeScalarMapStore('prefix');
|
|
82
|
-
|
|
83
|
-
function registerProtocolHandler(paths, protocolHandler) {
|
|
84
|
-
const protocol = makeNetworkProtocol(protocolHandler);
|
|
85
|
-
for (const prefix of paths) {
|
|
86
|
-
router.register(prefix, protocol);
|
|
87
|
-
protocols.init(prefix, protocol);
|
|
88
|
-
protocolHandlers.init(prefix, protocolHandler);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// FIXME: Buggy.
|
|
93
|
-
// Needs to account for multiple paths.
|
|
94
|
-
function unregisterProtocolHandler(prefix, protocolHandler) {
|
|
95
|
-
const ph = protocolHandlers.get(prefix);
|
|
96
|
-
ph === protocolHandler ||
|
|
97
|
-
Fail`Protocol handler is not registered at prefix ${prefix}`;
|
|
98
|
-
router.unregister(prefix, ph);
|
|
99
|
-
protocols.delete(prefix);
|
|
100
|
-
protocolHandlers.delete(prefix);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/** @type {Protocol['bind']} */
|
|
104
|
-
async function bind(localAddr) {
|
|
105
|
-
const [route] = router.getRoutes(localAddr);
|
|
106
|
-
route !== undefined || Fail`No registered router for ${localAddr}`;
|
|
107
|
-
return E(route[1]).bind(localAddr);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
return Far('RouterProtocol', {
|
|
111
|
-
bind,
|
|
112
|
-
registerProtocolHandler,
|
|
113
|
-
unregisterProtocolHandler,
|
|
114
|
-
});
|
|
115
|
-
}
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @typedef {string|Buffer|ArrayBuffer} Data
|
|
3
|
-
* @typedef {string} Bytes
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* @typedef {string} Endpoint A local or remote address
|
|
8
|
-
* See multiaddr.js for an opinionated router implementation
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* @typedef {object} Closable A closable object
|
|
13
|
-
* @property {() => Promise<void>} close Terminate the object
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* @typedef {object} Protocol The network Protocol
|
|
18
|
-
* @property {(prefix: Endpoint) => Promise<Port>} bind Claim a port, or if ending in ENDPOINT_SEPARATOR, a fresh name
|
|
19
|
-
*/
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* @typedef {object} Port A port that has been bound to a protocol
|
|
23
|
-
* @property {() => Endpoint} getLocalAddress Get the locally bound name of this port
|
|
24
|
-
* @property {(acceptHandler: ListenHandler) => Promise<void>} addListener Begin accepting incoming connections
|
|
25
|
-
* @property {(remote: Endpoint, connectionHandler?: ConnectionHandler) => Promise<Connection>} connect Make an outbound connection
|
|
26
|
-
* @property {(acceptHandler: ListenHandler) => Promise<void>} removeListener Remove the currently-bound listener
|
|
27
|
-
* @property {() => void} revoke Deallocate the port entirely, removing all listeners and closing all active connections
|
|
28
|
-
*/
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* @typedef {object} ListenHandler A handler for incoming connections
|
|
32
|
-
* @property {(port: Port, l: ListenHandler) => Promise<void>} [onListen] The listener has been registered
|
|
33
|
-
* @property {(port: Port, localAddr: Endpoint, remoteAddr: Endpoint, l: ListenHandler) => Promise<ConnectionHandler>} onAccept A new connection is incoming
|
|
34
|
-
* @property {(port: Port, localAddr: Endpoint, remoteAddr: Endpoint, l: ListenHandler) => Promise<void>} [onReject] The connection was rejected
|
|
35
|
-
* @property {(port: Port, rej: any, l: ListenHandler) => Promise<void>} [onError] There was an error while listening
|
|
36
|
-
* @property {(port: Port, l: ListenHandler) => Promise<void>} [onRemove] The listener has been removed
|
|
37
|
-
*/
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* @typedef {object} Connection
|
|
41
|
-
* @property {(packetBytes: Data, opts?: Record<string, any>) => Promise<Bytes>} send Send a packet on the connection
|
|
42
|
-
* @property {() => Promise<void>} close Close both ends of the connection
|
|
43
|
-
* @property {() => Endpoint} getLocalAddress Get the locally bound name of this connection
|
|
44
|
-
* @property {() => Endpoint} getRemoteAddress Get the name of the counterparty
|
|
45
|
-
*/
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* @typedef {object} ConnectionHandler A handler for a given Connection
|
|
49
|
-
* @property {(connection: Connection, localAddr: Endpoint, remoteAddr: Endpoint, c: ConnectionHandler) => void} [onOpen] The connection has been opened
|
|
50
|
-
* @property {(connection: Connection, packetBytes: Bytes, c: ConnectionHandler, opts?: Record<string, any>) => Promise<Data>} [onReceive] The connection received a packet
|
|
51
|
-
* @property {(connection: Connection, reason?: CloseReason, c?: ConnectionHandler) => Promise<void>} [onClose] The connection has been closed
|
|
52
|
-
*
|
|
53
|
-
* @typedef {any?} CloseReason The reason a connection was closed
|
|
54
|
-
*/
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* @typedef {object} AttemptDescription
|
|
58
|
-
* @property {ConnectionHandler} handler
|
|
59
|
-
* @property {Endpoint} [remoteAddress]
|
|
60
|
-
* @property {Endpoint} [localAddress]
|
|
61
|
-
*/
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* @typedef {object} ProtocolHandler A handler for things the protocol implementation will invoke
|
|
65
|
-
* @property {(protocol: ProtocolImpl, p: ProtocolHandler) => Promise<void>} onCreate This protocol is created
|
|
66
|
-
* @property {(localAddr: Endpoint, p: ProtocolHandler) => Promise<string>} generatePortID Create a fresh port identifier for this protocol
|
|
67
|
-
* @property {(port: Port, localAddr: Endpoint, p: ProtocolHandler) => Promise<void>} onBind A port will be bound
|
|
68
|
-
* @property {(port: Port, localAddr: Endpoint, listenHandler: ListenHandler, p: ProtocolHandler) => Promise<void>} onListen A port was listening
|
|
69
|
-
* @property {(port: Port, localAddr: Endpoint, listenHandler: ListenHandler, p: ProtocolHandler) => Promise<void>} onListenRemove A port listener has been reset
|
|
70
|
-
* @property {(port: Port, localAddr: Endpoint, remote: Endpoint, p: ProtocolHandler) => Promise<Endpoint>} [onInstantiate] Return unique suffix for
|
|
71
|
-
* local address
|
|
72
|
-
* @property {(port: Port, localAddr: Endpoint, remote: Endpoint, c: ConnectionHandler, p: ProtocolHandler) => Promise<AttemptDescription>} onConnect A port initiates an outbound connection
|
|
73
|
-
* @property {(port: Port, localAddr: Endpoint, p: ProtocolHandler) => Promise<void>} onRevoke The port is being completely destroyed
|
|
74
|
-
*
|
|
75
|
-
* @typedef {object} InboundAttempt An inbound connection attempt
|
|
76
|
-
* @property {(desc: AttemptDescription) => Promise<Connection>} accept Establish the connection
|
|
77
|
-
* @property {() => Endpoint} getLocalAddress Return the local address for this attempt
|
|
78
|
-
* @property {() => Endpoint} getRemoteAddress Return the remote address for this attempt
|
|
79
|
-
* @property {() => Promise<void>} close Abort the attempt
|
|
80
|
-
*
|
|
81
|
-
* @typedef {object} ProtocolImpl Things the protocol can do for us
|
|
82
|
-
* @property {(prefix: Endpoint) => Promise<Port>} bind Claim a port, or if ending in ENDPOINT_SEPARATOR, a fresh name
|
|
83
|
-
* @property {(listenAddr: Endpoint, remoteAddr: Endpoint) => Promise<InboundAttempt>} inbound Make an attempt to connect into this protocol
|
|
84
|
-
* @property {(port: Port, remoteAddr: Endpoint, connectionHandler: ConnectionHandler) => Promise<Connection>} outbound Create an outbound connection
|
|
85
|
-
*/
|