@agoric/swingset-vat 0.32.3-dev-a2db142.0 → 0.32.3-dev-9d4eaad.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agoric/swingset-vat",
3
- "version": "0.32.3-dev-a2db142.0+a2db142",
3
+ "version": "0.32.3-dev-9d4eaad.0+9d4eaad",
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-a2db142.0+a2db142",
31
- "@agoric/internal": "0.3.3-dev-a2db142.0+a2db142",
32
- "@agoric/store": "0.9.3-dev-a2db142.0+a2db142",
33
- "@agoric/swing-store": "0.9.2-dev-a2db142.0+a2db142",
34
- "@agoric/swingset-liveslots": "0.10.3-dev-a2db142.0+a2db142",
35
- "@agoric/swingset-xsnap-supervisor": "0.10.3-dev-a2db142.0+a2db142",
36
- "@agoric/time": "0.3.3-dev-a2db142.0+a2db142",
37
- "@agoric/vat-data": "0.5.3-dev-a2db142.0+a2db142",
38
- "@agoric/xsnap": "0.14.3-dev-a2db142.0+a2db142",
39
- "@agoric/xsnap-lockdown": "0.14.1-dev-a2db142.0+a2db142",
30
+ "@agoric/assert": "0.6.1-dev-9d4eaad.0+9d4eaad",
31
+ "@agoric/internal": "0.3.3-dev-9d4eaad.0+9d4eaad",
32
+ "@agoric/store": "0.9.3-dev-9d4eaad.0+9d4eaad",
33
+ "@agoric/swing-store": "0.9.2-dev-9d4eaad.0+9d4eaad",
34
+ "@agoric/swingset-liveslots": "0.10.3-dev-9d4eaad.0+9d4eaad",
35
+ "@agoric/swingset-xsnap-supervisor": "0.10.3-dev-9d4eaad.0+9d4eaad",
36
+ "@agoric/time": "0.3.3-dev-9d4eaad.0+9d4eaad",
37
+ "@agoric/vat-data": "0.5.3-dev-9d4eaad.0+9d4eaad",
38
+ "@agoric/xsnap": "0.14.3-dev-9d4eaad.0+9d4eaad",
39
+ "@agoric/xsnap-lockdown": "0.14.1-dev-9d4eaad.0+9d4eaad",
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": "a2db1428393bcca3175179f9cfe76c92a4eb1b3f"
96
+ "gitHead": "9d4eaadaa3caa031a0410f747ff06a4855ece40a"
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,4 +0,0 @@
1
- export * from './network.js';
2
- export { default as makeRouter } from './router.js';
3
- export * from './multiaddr.js';
4
- export * from './bytes.js';
@@ -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
- */