@agoric/network 0.1.1-orchestration-dev-096c4e8.0 → 0.1.1-other-dev-3eb1a1d.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/README.md +4 -7
- package/package.json +24 -26
- package/src/bytes.d.ts +23 -6
- package/src/bytes.d.ts.map +1 -1
- package/src/bytes.js +63 -26
- package/src/index.d.ts +2 -0
- package/src/index.js +3 -0
- package/src/multiaddr.d.ts.map +1 -1
- package/src/network.d.ts +85 -83
- package/src/network.d.ts.map +1 -1
- package/src/network.js +1100 -514
- package/src/router.d.ts +23 -21
- package/src/router.d.ts.map +1 -1
- package/src/router.js +22 -19
- package/src/shapes.d.ts +117 -0
- package/src/shapes.d.ts.map +1 -0
- package/src/shapes.js +191 -0
- package/src/types.d.ts +54 -42
- package/src/types.d.ts.map +1 -1
- package/src/types.js +63 -50
- package/exported.js +0 -1
- package/tsconfig.build.json +0 -6
- package/tsconfig.json +0 -14
- package/typedoc.json +0 -9
package/src/network.js
CHANGED
|
@@ -1,13 +1,23 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
|
|
3
|
+
/// <reference types="@agoric/store/exported.js" />
|
|
4
|
+
|
|
5
|
+
import { Fail } from '@endo/errors';
|
|
3
6
|
import { E } from '@endo/far';
|
|
4
7
|
import { M } from '@endo/patterns';
|
|
5
|
-
import { Fail } from '@agoric/assert';
|
|
6
|
-
import { whileTrue } from '@agoric/internal';
|
|
7
8
|
import { toBytes } from './bytes.js';
|
|
9
|
+
import { Shape } from './shapes.js';
|
|
8
10
|
|
|
9
|
-
import '@agoric/store/exported.js';
|
|
10
11
|
/// <reference path="./types.js" />
|
|
12
|
+
/**
|
|
13
|
+
* @import {AttemptDescription, Bytes, CloseReason, Closable, Connection, ConnectionHandler, Endpoint, ListenHandler, Port, Protocol, ProtocolHandler, ProtocolImpl} from './types.js';
|
|
14
|
+
* @import {PromiseVow, Remote, VowTools} from '@agoric/vow';
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/** @typedef {VowTools & { finalizer: Finalizer }} Powers */
|
|
18
|
+
|
|
19
|
+
const sink = () => {};
|
|
20
|
+
harden(sink);
|
|
11
21
|
|
|
12
22
|
/**
|
|
13
23
|
* Compatibility note: this must match what our peers use, so don't change it
|
|
@@ -15,128 +25,8 @@ import '@agoric/store/exported.js';
|
|
|
15
25
|
*/
|
|
16
26
|
export const ENDPOINT_SEPARATOR = '/';
|
|
17
27
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
* Data is string | Buffer | ArrayBuffer
|
|
21
|
-
* but only string is passable
|
|
22
|
-
*/
|
|
23
|
-
Data: M.string(),
|
|
24
|
-
Bytes: M.string(),
|
|
25
|
-
Endpoint: M.string(),
|
|
26
|
-
// TODO: match on "Vow" tag
|
|
27
|
-
// @endo/patterns supports it as of
|
|
28
|
-
// https://github.com/endojs/endo/pull/2091
|
|
29
|
-
// but that's not in agoric-sdk yet.
|
|
30
|
-
// For now, use M.any() to avoid:
|
|
31
|
-
// cannot check unrecognized tag "Vow": "[Vow]"
|
|
32
|
-
Vow: M.any(),
|
|
33
|
-
|
|
34
|
-
ConnectionHandler: M.remotable('ConnectionHandler'),
|
|
35
|
-
Connection: M.remotable('Connection'),
|
|
36
|
-
InboundAttempt: M.remotable('InboundAttempt'),
|
|
37
|
-
Listener: M.remotable('Listener'),
|
|
38
|
-
ListenHandler: M.remotable('ListenHandler'),
|
|
39
|
-
Port: M.remotable('Port'),
|
|
40
|
-
ProtocolHandler: M.remotable('ProtocolHandler'),
|
|
41
|
-
ProtocolImpl: M.remotable('ProtocolImpl'),
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
const Shape2 = /** @type {const} */ ({
|
|
45
|
-
...Shape1,
|
|
46
|
-
Vow$: shape => M.or(shape, Shape1.Vow),
|
|
47
|
-
AttemptDescription: M.splitRecord(
|
|
48
|
-
{ handler: Shape1.ConnectionHandler },
|
|
49
|
-
{ remoteAddress: Shape1.Endpoint, localAddress: Shape1.Endpoint },
|
|
50
|
-
),
|
|
51
|
-
Opts: M.recordOf(M.string(), M.any()),
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
export const Shape = /** @type {const} */ harden({
|
|
55
|
-
...Shape2,
|
|
56
|
-
ConnectionI: M.interface('Connection', {
|
|
57
|
-
send: M.callWhen(Shape2.Data)
|
|
58
|
-
.optional(Shape2.Opts)
|
|
59
|
-
.returns(Shape2.Vow$(Shape2.Bytes)),
|
|
60
|
-
close: M.callWhen().returns(Shape2.Vow$(M.undefined())),
|
|
61
|
-
getLocalAddress: M.call().returns(Shape2.Endpoint),
|
|
62
|
-
getRemoteAddress: M.call().returns(Shape2.Endpoint),
|
|
63
|
-
}),
|
|
64
|
-
InboundAttemptI: M.interface('InboundAttempt', {
|
|
65
|
-
accept: M.callWhen(Shape2.AttemptDescription).returns(
|
|
66
|
-
Shape2.Vow$(Shape2.Connection),
|
|
67
|
-
),
|
|
68
|
-
getLocalAddress: M.call().returns(Shape2.Endpoint),
|
|
69
|
-
getRemoteAddress: M.call().returns(Shape2.Endpoint),
|
|
70
|
-
close: M.callWhen().returns(Shape2.Vow$(M.undefined())),
|
|
71
|
-
}),
|
|
72
|
-
PortI: M.interface('Port', {
|
|
73
|
-
getLocalAddress: M.call().returns(Shape2.Endpoint),
|
|
74
|
-
addListener: M.callWhen(Shape2.Listener).returns(
|
|
75
|
-
Shape2.Vow$(M.undefined()),
|
|
76
|
-
),
|
|
77
|
-
connect: M.callWhen(Shape2.Endpoint)
|
|
78
|
-
.optional(Shape2.ConnectionHandler)
|
|
79
|
-
.returns(Shape2.Vow$(Shape2.Connection)),
|
|
80
|
-
removeListener: M.callWhen(Shape2.Listener).returns(
|
|
81
|
-
Shape2.Vow$(M.undefined()),
|
|
82
|
-
),
|
|
83
|
-
revoke: M.callWhen().returns(M.undefined()),
|
|
84
|
-
}),
|
|
85
|
-
ProtocolHandlerI: M.interface('ProtocolHandler', {
|
|
86
|
-
onCreate: M.callWhen(M.remotable(), Shape2.ProtocolHandler).returns(
|
|
87
|
-
Shape2.Vow$(M.undefined()),
|
|
88
|
-
),
|
|
89
|
-
generatePortID: M.callWhen(Shape2.Endpoint, Shape2.ProtocolHandler).returns(
|
|
90
|
-
Shape2.Vow$(M.string()),
|
|
91
|
-
),
|
|
92
|
-
onBind: M.callWhen(
|
|
93
|
-
Shape2.Port,
|
|
94
|
-
Shape2.Endpoint,
|
|
95
|
-
Shape2.ProtocolHandler,
|
|
96
|
-
).returns(Shape2.Vow$(M.undefined())),
|
|
97
|
-
onListen: M.callWhen(
|
|
98
|
-
Shape2.Port,
|
|
99
|
-
Shape2.Endpoint,
|
|
100
|
-
Shape2.ListenHandler,
|
|
101
|
-
Shape2.ProtocolHandler,
|
|
102
|
-
).returns(Shape2.Vow$(M.undefined())),
|
|
103
|
-
onListenRemove: M.callWhen(
|
|
104
|
-
Shape2.Port,
|
|
105
|
-
Shape2.Endpoint,
|
|
106
|
-
Shape2.ListenHandler,
|
|
107
|
-
Shape2.ProtocolHandler,
|
|
108
|
-
).returns(Shape2.Vow$(M.undefined())),
|
|
109
|
-
onInstantiate: M.callWhen(
|
|
110
|
-
Shape2.Port,
|
|
111
|
-
Shape2.Endpoint,
|
|
112
|
-
Shape2.Endpoint,
|
|
113
|
-
Shape2.ProtocolHandler,
|
|
114
|
-
).returns(Shape2.Vow$(Shape2.Endpoint)),
|
|
115
|
-
onConnect: M.callWhen(
|
|
116
|
-
Shape2.Port,
|
|
117
|
-
Shape2.Endpoint,
|
|
118
|
-
Shape2.Endpoint,
|
|
119
|
-
Shape2.ConnectionHandler,
|
|
120
|
-
Shape2.ProtocolHandler,
|
|
121
|
-
).returns(Shape2.Vow$(Shape2.AttemptDescription)),
|
|
122
|
-
onRevoke: M.callWhen(
|
|
123
|
-
Shape2.Port,
|
|
124
|
-
Shape2.Endpoint,
|
|
125
|
-
Shape2.ProtocolHandler,
|
|
126
|
-
).returns(Shape2.Vow$(M.undefined())),
|
|
127
|
-
}),
|
|
128
|
-
ProtocolImplI: M.interface('ProtocolImpl', {
|
|
129
|
-
bind: M.callWhen(Shape2.Endpoint).returns(Shape2.Vow$(Shape2.Port)),
|
|
130
|
-
inbound: M.callWhen(Shape2.Endpoint, Shape2.Endpoint).returns(
|
|
131
|
-
Shape2.Vow$(Shape2.InboundAttempt),
|
|
132
|
-
),
|
|
133
|
-
outbound: M.callWhen(
|
|
134
|
-
Shape2.Port,
|
|
135
|
-
Shape2.Endpoint,
|
|
136
|
-
Shape2.ConnectionHandler,
|
|
137
|
-
).returns(Shape2.Vow$(Shape2.Connection)),
|
|
138
|
-
}),
|
|
139
|
-
});
|
|
28
|
+
// Mark the finalizer close reason.
|
|
29
|
+
export const CLOSE_REASON_FINALIZER = 'closed-by-finalizer';
|
|
140
30
|
|
|
141
31
|
/** @param {unknown} err */
|
|
142
32
|
export const rethrowUnlessMissing = err => {
|
|
@@ -144,7 +34,7 @@ export const rethrowUnlessMissing = err => {
|
|
|
144
34
|
// exists.
|
|
145
35
|
if (
|
|
146
36
|
!(err instanceof TypeError) ||
|
|
147
|
-
!err.message.match(/target has no method|is not a function$/)
|
|
37
|
+
!String(err.message).match(/target has no method|is not a function$/)
|
|
148
38
|
) {
|
|
149
39
|
throw err;
|
|
150
40
|
}
|
|
@@ -169,10 +59,24 @@ export function getPrefixes(addr) {
|
|
|
169
59
|
return ret;
|
|
170
60
|
}
|
|
171
61
|
|
|
62
|
+
/**
|
|
63
|
+
* Validate IBC port name
|
|
64
|
+
* @param {string} specifiedName
|
|
65
|
+
*/
|
|
66
|
+
function throwIfInvalidPortName(specifiedName) {
|
|
67
|
+
// Contains between 2 and 128 characters
|
|
68
|
+
// Can contain alphanumeric characters
|
|
69
|
+
// Valid symbols: ., ,, _, +, -, #, [, ], <, >
|
|
70
|
+
const portNameRegex = new RegExp('^[a-zA-Z0-9.,_+\\-#<>\\[\\]]{2,128}$');
|
|
71
|
+
if (!portNameRegex.test(specifiedName)) {
|
|
72
|
+
throw Error(`Invalid IBC port name: ${specifiedName}`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
172
76
|
/**
|
|
173
77
|
* @typedef {object} ConnectionOpts
|
|
174
78
|
* @property {Endpoint[]} addrs
|
|
175
|
-
* @property {ConnectionHandler[]} handlers
|
|
79
|
+
* @property {Remote<Required<ConnectionHandler>>[]} handlers
|
|
176
80
|
* @property {MapStore<number, Connection>} conns
|
|
177
81
|
* @property {WeakSetStore<Closable>} current
|
|
178
82
|
* @property {0|1} l
|
|
@@ -181,17 +85,14 @@ export function getPrefixes(addr) {
|
|
|
181
85
|
|
|
182
86
|
/**
|
|
183
87
|
* @param {import('@agoric/base-zone').Zone} zone
|
|
184
|
-
* @param {
|
|
88
|
+
* @param {Powers} powers
|
|
185
89
|
*/
|
|
186
|
-
const prepareHalfConnection = (zone, {
|
|
187
|
-
const
|
|
90
|
+
const prepareHalfConnection = (zone, { watch, allVows, finalizer }) => {
|
|
91
|
+
const makeHalfConnectionKit = zone.exoClassKit(
|
|
188
92
|
'Connection',
|
|
189
93
|
Shape.ConnectionI,
|
|
190
94
|
/** @param {ConnectionOpts} opts */
|
|
191
95
|
({ addrs, handlers, conns, current, l, r }) => {
|
|
192
|
-
/** @type {string | undefined} */
|
|
193
|
-
let closed;
|
|
194
|
-
|
|
195
96
|
return {
|
|
196
97
|
addrs,
|
|
197
98
|
handlers,
|
|
@@ -199,62 +100,100 @@ const prepareHalfConnection = (zone, { when }) => {
|
|
|
199
100
|
current,
|
|
200
101
|
l,
|
|
201
102
|
r,
|
|
202
|
-
|
|
103
|
+
/** @type {string | undefined} */
|
|
104
|
+
closed: undefined,
|
|
203
105
|
};
|
|
204
106
|
},
|
|
205
107
|
{
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
108
|
+
connection: {
|
|
109
|
+
getLocalAddress() {
|
|
110
|
+
const { addrs, l } = this.state;
|
|
111
|
+
return addrs[l];
|
|
112
|
+
},
|
|
113
|
+
getRemoteAddress() {
|
|
114
|
+
const { addrs, r } = this.state;
|
|
115
|
+
return addrs[r];
|
|
116
|
+
},
|
|
117
|
+
/** @param {Bytes} packetBytes */
|
|
118
|
+
async send(packetBytes) {
|
|
119
|
+
const { closed, handlers, r, conns } = this.state;
|
|
120
|
+
if (closed) {
|
|
121
|
+
throw Error(closed);
|
|
122
|
+
}
|
|
220
123
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
124
|
+
const innerVow = watch(
|
|
125
|
+
E(handlers[r]).onReceive(
|
|
126
|
+
conns.get(r),
|
|
127
|
+
toBytes(packetBytes),
|
|
128
|
+
handlers[r],
|
|
129
|
+
),
|
|
130
|
+
this.facets.openConnectionAckWatcher,
|
|
131
|
+
);
|
|
132
|
+
return watch(innerVow, this.facets.rethrowUnlessMissingWatcher);
|
|
133
|
+
},
|
|
134
|
+
async close() {
|
|
135
|
+
const { closed, current, conns, l, r } = this.state;
|
|
136
|
+
if (closed) {
|
|
137
|
+
throw Error(closed);
|
|
138
|
+
}
|
|
139
|
+
this.state.closed = 'Connection closed';
|
|
140
|
+
|
|
141
|
+
// Tear down both sides.
|
|
142
|
+
const lconn = conns.get(l);
|
|
143
|
+
const rconn = conns.get(r);
|
|
144
|
+
current.delete(lconn);
|
|
145
|
+
current.delete(rconn);
|
|
146
|
+
|
|
147
|
+
const innerVow = watch(
|
|
148
|
+
allVows([finalizer.finalize(lconn), finalizer.finalize(rconn)]),
|
|
149
|
+
this.facets.sinkWatcher,
|
|
150
|
+
);
|
|
226
151
|
|
|
227
|
-
|
|
152
|
+
return watch(innerVow, this.facets.rethrowUnlessMissingWatcher);
|
|
153
|
+
},
|
|
228
154
|
},
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
155
|
+
openConnectionAckWatcher: {
|
|
156
|
+
onFulfilled(ack) {
|
|
157
|
+
return toBytes(ack || '');
|
|
158
|
+
},
|
|
159
|
+
},
|
|
160
|
+
rethrowUnlessMissingWatcher: {
|
|
161
|
+
onRejected(e) {
|
|
162
|
+
rethrowUnlessMissing(e);
|
|
163
|
+
},
|
|
164
|
+
},
|
|
165
|
+
sinkWatcher: {
|
|
166
|
+
onFulfilled(_value) {
|
|
167
|
+
return undefined;
|
|
168
|
+
},
|
|
243
169
|
},
|
|
244
170
|
},
|
|
245
171
|
);
|
|
246
172
|
|
|
173
|
+
const makeHalfConnection = ({ addrs, handlers, conns, current, l, r }) => {
|
|
174
|
+
const { connection } = makeHalfConnectionKit({
|
|
175
|
+
addrs,
|
|
176
|
+
handlers,
|
|
177
|
+
conns,
|
|
178
|
+
current,
|
|
179
|
+
l,
|
|
180
|
+
r,
|
|
181
|
+
});
|
|
182
|
+
return harden(connection);
|
|
183
|
+
};
|
|
184
|
+
|
|
247
185
|
return makeHalfConnection;
|
|
248
186
|
};
|
|
249
187
|
|
|
250
188
|
/**
|
|
251
189
|
* @param {import('@agoric/zone').Zone} zone
|
|
252
|
-
* @param {ConnectionHandler} handler0
|
|
190
|
+
* @param {Remote<Required<ConnectionHandler>>} handler0
|
|
253
191
|
* @param {Endpoint} addr0
|
|
254
|
-
* @param {ConnectionHandler} handler1
|
|
192
|
+
* @param {Remote<Required<ConnectionHandler>>} handler1
|
|
255
193
|
* @param {Endpoint} addr1
|
|
256
194
|
* @param {(opts: ConnectionOpts) => Connection} makeConnection
|
|
257
|
-
* @param {
|
|
195
|
+
* @param {Finalizer} finalizer
|
|
196
|
+
* @param {WeakSetStore<Closable>} [current]
|
|
258
197
|
*/
|
|
259
198
|
export const crossoverConnection = (
|
|
260
199
|
zone,
|
|
@@ -263,6 +202,7 @@ export const crossoverConnection = (
|
|
|
263
202
|
handler1,
|
|
264
203
|
addr1,
|
|
265
204
|
makeConnection,
|
|
205
|
+
finalizer,
|
|
266
206
|
current = zone.detached().weakSetStore('crossoverCurrentConnections'),
|
|
267
207
|
) => {
|
|
268
208
|
const detached = zone.detached();
|
|
@@ -270,7 +210,7 @@ export const crossoverConnection = (
|
|
|
270
210
|
/** @type {MapStore<number, Connection>} */
|
|
271
211
|
const conns = detached.mapStore('addrToConnections');
|
|
272
212
|
|
|
273
|
-
/** @type {ConnectionHandler[]} */
|
|
213
|
+
/** @type {Remote<Required<ConnectionHandler>>[]} */
|
|
274
214
|
const handlers = harden([handler0, handler1]);
|
|
275
215
|
/** @type {Endpoint[]} */
|
|
276
216
|
const addrs = harden([addr0, addr1]);
|
|
@@ -288,9 +228,13 @@ export const crossoverConnection = (
|
|
|
288
228
|
* @param {number} r remote side of the connection
|
|
289
229
|
*/
|
|
290
230
|
const openHalfConnection = (l, r) => {
|
|
291
|
-
|
|
231
|
+
const lconn = conns.get(l);
|
|
232
|
+
current.add(lconn);
|
|
233
|
+
if (!finalizer.has(lconn)) {
|
|
234
|
+
finalizer.initConnection(lconn, handlers[l]);
|
|
235
|
+
}
|
|
292
236
|
E(handlers[l])
|
|
293
|
-
.onOpen(
|
|
237
|
+
.onOpen(lconn, addrs[l], addrs[r], handlers[l])
|
|
294
238
|
.catch(rethrowUnlessMissing);
|
|
295
239
|
};
|
|
296
240
|
|
|
@@ -306,19 +250,19 @@ export const crossoverConnection = (
|
|
|
306
250
|
/**
|
|
307
251
|
* @param {import('@agoric/zone').Zone} zone
|
|
308
252
|
* @param {(opts: ConnectionOpts) => Connection} makeConnection
|
|
309
|
-
* @param {
|
|
253
|
+
* @param {Powers} powers
|
|
310
254
|
*/
|
|
311
|
-
const prepareInboundAttempt = (zone, makeConnection, {
|
|
312
|
-
const
|
|
255
|
+
const prepareInboundAttempt = (zone, makeConnection, { watch, finalizer }) => {
|
|
256
|
+
const makeInboundAttemptKit = zone.exoClassKit(
|
|
313
257
|
'InboundAttempt',
|
|
314
258
|
Shape.InboundAttemptI,
|
|
315
259
|
/**
|
|
316
260
|
* @param {object} opts
|
|
317
261
|
* @param {string} opts.localAddr
|
|
318
262
|
* @param {string} opts.remoteAddr
|
|
319
|
-
* @param {
|
|
263
|
+
* @param {MapStore<Port, SetStore<Closable>>} opts.currentConnections
|
|
320
264
|
* @param {string} opts.listenPrefix
|
|
321
|
-
* @param {MapStore<Endpoint, [Port, ListenHandler]>} opts.listening
|
|
265
|
+
* @param {MapStore<Endpoint, [Port, Remote<Required<ListenHandler>>]>} opts.listening
|
|
322
266
|
*/
|
|
323
267
|
({
|
|
324
268
|
localAddr,
|
|
@@ -327,7 +271,7 @@ const prepareInboundAttempt = (zone, makeConnection, { when }) => {
|
|
|
327
271
|
listenPrefix,
|
|
328
272
|
listening,
|
|
329
273
|
}) => {
|
|
330
|
-
/** @type {
|
|
274
|
+
/** @type {string | undefined} */
|
|
331
275
|
let consummated;
|
|
332
276
|
|
|
333
277
|
return {
|
|
@@ -340,132 +284,182 @@ const prepareInboundAttempt = (zone, makeConnection, { when }) => {
|
|
|
340
284
|
};
|
|
341
285
|
},
|
|
342
286
|
{
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
287
|
+
inboundAttempt: {
|
|
288
|
+
getLocalAddress() {
|
|
289
|
+
// Return address metadata.
|
|
290
|
+
return this.state.localAddr;
|
|
291
|
+
},
|
|
292
|
+
getRemoteAddress() {
|
|
293
|
+
return this.state.remoteAddr;
|
|
294
|
+
},
|
|
295
|
+
async close() {
|
|
296
|
+
const { consummated, localAddr, remoteAddr } = this.state;
|
|
297
|
+
const { listening, listenPrefix, currentConnections } = this.state;
|
|
353
298
|
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
299
|
+
if (consummated) {
|
|
300
|
+
throw Error(consummated);
|
|
301
|
+
}
|
|
302
|
+
this.state.consummated = 'Already closed';
|
|
358
303
|
|
|
359
|
-
|
|
304
|
+
const [port, listener] = listening.get(listenPrefix);
|
|
360
305
|
|
|
361
|
-
|
|
362
|
-
|
|
306
|
+
const current = currentConnections.get(port);
|
|
307
|
+
current.delete(this.facets.inboundAttempt);
|
|
308
|
+
finalizer.unpin(this.facets.inboundAttempt);
|
|
363
309
|
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
/**
|
|
369
|
-
* @param {object} opts
|
|
370
|
-
* @param {string} [opts.localAddress]
|
|
371
|
-
* @param {string} [opts.remoteAddress]
|
|
372
|
-
* @param {ConnectionHandler} opts.handler
|
|
373
|
-
*/
|
|
374
|
-
async accept({ localAddress, remoteAddress, handler: rchandler }) {
|
|
375
|
-
const { consummated, localAddr, remoteAddr } = this.state;
|
|
376
|
-
const { listening, listenPrefix, currentConnections } = this.state;
|
|
377
|
-
if (consummated) {
|
|
378
|
-
throw Error(consummated);
|
|
379
|
-
}
|
|
380
|
-
this.state.consummated = 'Already accepted';
|
|
310
|
+
const innerVow = watch(
|
|
311
|
+
E(listener).onReject(port, localAddr, remoteAddr, listener),
|
|
312
|
+
this.facets.sinkWatcher,
|
|
313
|
+
);
|
|
381
314
|
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
315
|
+
return watch(innerVow, this.facets.rethrowUnlessMissingWatcher);
|
|
316
|
+
},
|
|
317
|
+
/**
|
|
318
|
+
* @param {object} opts
|
|
319
|
+
* @param {string} [opts.localAddress]
|
|
320
|
+
* @param {string} [opts.remoteAddress]
|
|
321
|
+
* @param {Remote<ConnectionHandler>} opts.handler
|
|
322
|
+
*/
|
|
323
|
+
async accept({ localAddress, remoteAddress, handler: rchandler }) {
|
|
324
|
+
const { consummated, localAddr, remoteAddr } = this.state;
|
|
325
|
+
const { listening, listenPrefix, currentConnections } = this.state;
|
|
326
|
+
if (consummated) {
|
|
327
|
+
throw Error(consummated);
|
|
328
|
+
}
|
|
385
329
|
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
330
|
+
if (localAddress === undefined) {
|
|
331
|
+
localAddress = localAddr;
|
|
332
|
+
}
|
|
333
|
+
this.state.consummated = `${localAddress} Already accepted`;
|
|
389
334
|
|
|
390
|
-
|
|
391
|
-
|
|
335
|
+
if (remoteAddress === undefined) {
|
|
336
|
+
remoteAddress = remoteAddr;
|
|
337
|
+
}
|
|
392
338
|
|
|
393
|
-
|
|
339
|
+
const [port, listener] = listening.get(listenPrefix);
|
|
340
|
+
const current = currentConnections.get(port);
|
|
394
341
|
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
342
|
+
current.delete(this.facets.inboundAttempt);
|
|
343
|
+
|
|
344
|
+
return watch(
|
|
345
|
+
E(listener).onAccept(port, localAddress, remoteAddress, listener),
|
|
346
|
+
this.facets.inboundAttemptAcceptWatcher,
|
|
347
|
+
{
|
|
348
|
+
localAddress,
|
|
349
|
+
rchandler,
|
|
350
|
+
remoteAddress,
|
|
351
|
+
current,
|
|
352
|
+
},
|
|
353
|
+
);
|
|
354
|
+
},
|
|
355
|
+
},
|
|
356
|
+
inboundAttemptAcceptWatcher: {
|
|
357
|
+
onFulfilled(lchandler, watchContext) {
|
|
358
|
+
const { localAddress, rchandler, remoteAddress, current } =
|
|
359
|
+
watchContext;
|
|
398
360
|
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
361
|
+
return crossoverConnection(
|
|
362
|
+
zone,
|
|
363
|
+
/** @type {Remote<Required<ConnectionHandler>>} */ (lchandler),
|
|
364
|
+
localAddress,
|
|
365
|
+
/** @type {Remote<Required<ConnectionHandler>>} */ (rchandler),
|
|
366
|
+
remoteAddress,
|
|
367
|
+
makeConnection,
|
|
368
|
+
finalizer,
|
|
369
|
+
current,
|
|
370
|
+
)[1];
|
|
371
|
+
},
|
|
372
|
+
},
|
|
373
|
+
rethrowUnlessMissingWatcher: {
|
|
374
|
+
onRejected(e) {
|
|
375
|
+
rethrowUnlessMissing(e);
|
|
376
|
+
},
|
|
377
|
+
},
|
|
378
|
+
sinkWatcher: {
|
|
379
|
+
onFulfilled(_value) {
|
|
380
|
+
return undefined;
|
|
381
|
+
},
|
|
408
382
|
},
|
|
409
383
|
},
|
|
410
384
|
);
|
|
411
385
|
|
|
386
|
+
const makeInboundAttempt = ({
|
|
387
|
+
localAddr,
|
|
388
|
+
remoteAddr,
|
|
389
|
+
currentConnections,
|
|
390
|
+
listenPrefix,
|
|
391
|
+
listening,
|
|
392
|
+
}) => {
|
|
393
|
+
const { inboundAttempt } = makeInboundAttemptKit({
|
|
394
|
+
localAddr,
|
|
395
|
+
remoteAddr,
|
|
396
|
+
currentConnections,
|
|
397
|
+
listenPrefix,
|
|
398
|
+
listening,
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
return harden(inboundAttempt);
|
|
402
|
+
};
|
|
403
|
+
|
|
412
404
|
return makeInboundAttempt;
|
|
413
405
|
};
|
|
414
406
|
|
|
415
|
-
/** @enum {
|
|
407
|
+
/** @enum {typeof RevokeState[keyof typeof RevokeState]} */
|
|
416
408
|
const RevokeState = /** @type {const} */ ({
|
|
417
409
|
NOT_REVOKED: 0,
|
|
418
410
|
REVOKING: 1,
|
|
419
411
|
REVOKED: 2,
|
|
420
412
|
});
|
|
413
|
+
harden(RevokeState);
|
|
421
414
|
|
|
422
415
|
/**
|
|
423
416
|
* @param {import('@agoric/zone').Zone} zone
|
|
424
|
-
* @param {
|
|
417
|
+
* @param {Powers} powers
|
|
425
418
|
*/
|
|
426
|
-
const preparePort = (zone,
|
|
419
|
+
const preparePort = (zone, powers) => {
|
|
427
420
|
const makeIncapable = zone.exoClass('Incapable', undefined, () => ({}), {});
|
|
428
421
|
|
|
429
|
-
const
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
422
|
+
const { finalizer, watch, allVows } = powers;
|
|
423
|
+
|
|
424
|
+
/**
|
|
425
|
+
* @param {object} opts
|
|
426
|
+
* @param {Endpoint} opts.localAddr
|
|
427
|
+
* @param {MapStore<Endpoint, [Port, Remote<Required<ListenHandler>>]>} opts.listening
|
|
428
|
+
* @param {SetStore<Remote<Connection>>} opts.openConnections
|
|
429
|
+
* @param {MapStore<Port, SetStore<Closable>>} opts.currentConnections
|
|
430
|
+
* @param {MapStore<string, Port>} opts.boundPorts
|
|
431
|
+
* @param {Remote<ProtocolHandler>} opts.protocolHandler
|
|
432
|
+
* @param {Remote<ProtocolImpl>} opts.protocolImpl
|
|
433
|
+
*/
|
|
434
|
+
const initPort = ({
|
|
435
|
+
localAddr,
|
|
436
|
+
listening,
|
|
437
|
+
openConnections,
|
|
438
|
+
currentConnections,
|
|
439
|
+
boundPorts,
|
|
440
|
+
protocolHandler,
|
|
441
|
+
protocolImpl,
|
|
442
|
+
}) => {
|
|
443
|
+
return {
|
|
444
444
|
listening,
|
|
445
445
|
openConnections,
|
|
446
446
|
currentConnections,
|
|
447
447
|
boundPorts,
|
|
448
|
+
localAddr,
|
|
448
449
|
protocolHandler,
|
|
449
450
|
protocolImpl,
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
protocolHandler,
|
|
458
|
-
protocolImpl,
|
|
459
|
-
/** @type {RevokeState | undefined} */
|
|
460
|
-
revoked: undefined,
|
|
461
|
-
};
|
|
462
|
-
},
|
|
463
|
-
{
|
|
451
|
+
/** @type {RevokeState | undefined} */
|
|
452
|
+
revoked: undefined,
|
|
453
|
+
};
|
|
454
|
+
};
|
|
455
|
+
|
|
456
|
+
const makePortKit = zone.exoClassKit('Port', Shape.PortI, initPort, {
|
|
457
|
+
port: {
|
|
464
458
|
getLocalAddress() {
|
|
465
459
|
// Works even after revoke().
|
|
466
460
|
return this.state.localAddr;
|
|
467
461
|
},
|
|
468
|
-
/** @param {ListenHandler} listenHandler */
|
|
462
|
+
/** @param {Remote<ListenHandler>} listenHandler */
|
|
469
463
|
async addListener(listenHandler) {
|
|
470
464
|
const { revoked, listening, localAddr, protocolHandler } = this.state;
|
|
471
465
|
|
|
@@ -478,129 +472,278 @@ const preparePort = (zone, { when }) => {
|
|
|
478
472
|
if (lhandler === listenHandler) {
|
|
479
473
|
return;
|
|
480
474
|
}
|
|
481
|
-
listening.set(localAddr, [
|
|
475
|
+
listening.set(localAddr, [
|
|
476
|
+
this.facets.port,
|
|
477
|
+
/** @type {Remote<Required<ListenHandler>>} */ (listenHandler),
|
|
478
|
+
]);
|
|
482
479
|
E(lhandler).onRemove(lport, lhandler).catch(rethrowUnlessMissing);
|
|
483
480
|
} else {
|
|
484
|
-
listening.init(
|
|
481
|
+
listening.init(
|
|
482
|
+
localAddr,
|
|
483
|
+
harden([
|
|
484
|
+
this.facets.port,
|
|
485
|
+
/** @type {Remote<Required<ListenHandler>>} */ (listenHandler),
|
|
486
|
+
]),
|
|
487
|
+
);
|
|
485
488
|
}
|
|
486
489
|
|
|
487
490
|
// ASSUME: that the listener defines onAccept.
|
|
488
491
|
|
|
489
|
-
|
|
492
|
+
const innerVow = watch(
|
|
490
493
|
E(protocolHandler).onListen(
|
|
491
|
-
this.
|
|
494
|
+
this.facets.port,
|
|
492
495
|
localAddr,
|
|
493
496
|
listenHandler,
|
|
494
497
|
protocolHandler,
|
|
495
498
|
),
|
|
499
|
+
this.facets.portAddListenerWatcher,
|
|
500
|
+
{ listenHandler },
|
|
496
501
|
);
|
|
497
|
-
|
|
498
|
-
rethrowUnlessMissing,
|
|
499
|
-
);
|
|
502
|
+
return watch(innerVow, this.facets.rethrowUnlessMissingWatcher);
|
|
500
503
|
},
|
|
501
|
-
/** @param {ListenHandler} listenHandler */
|
|
504
|
+
/** @param {Remote<ListenHandler>} listenHandler */
|
|
502
505
|
async removeListener(listenHandler) {
|
|
503
506
|
const { listening, localAddr, protocolHandler } = this.state;
|
|
504
507
|
listening.has(localAddr) || Fail`Port ${localAddr} is not listening`;
|
|
505
508
|
listening.get(localAddr)[1] === listenHandler ||
|
|
506
509
|
Fail`Port ${localAddr} handler to remove is not listening`;
|
|
507
510
|
listening.delete(localAddr);
|
|
508
|
-
|
|
511
|
+
|
|
512
|
+
const innerVow = watch(
|
|
509
513
|
E(protocolHandler).onListenRemove(
|
|
510
|
-
this.
|
|
514
|
+
this.facets.port,
|
|
511
515
|
localAddr,
|
|
512
516
|
listenHandler,
|
|
513
517
|
protocolHandler,
|
|
514
518
|
),
|
|
519
|
+
this.facets.portRemoveListenerWatcher,
|
|
520
|
+
{ listenHandler },
|
|
515
521
|
);
|
|
516
|
-
|
|
517
|
-
rethrowUnlessMissing,
|
|
518
|
-
);
|
|
522
|
+
return watch(innerVow, this.facets.rethrowUnlessMissingWatcher);
|
|
519
523
|
},
|
|
520
524
|
/**
|
|
521
525
|
* @param {Endpoint} remotePort
|
|
522
|
-
* @param {ConnectionHandler} connectionHandler
|
|
526
|
+
* @param {Remote<ConnectionHandler>} [connectionHandler]
|
|
523
527
|
*/
|
|
524
528
|
async connect(
|
|
525
529
|
remotePort,
|
|
526
|
-
connectionHandler = /** @type {
|
|
530
|
+
connectionHandler = /** @type {Remote<ConnectionHandler>} */ (
|
|
531
|
+
makeIncapable()
|
|
532
|
+
),
|
|
527
533
|
) {
|
|
528
|
-
const { revoked, localAddr, protocolImpl
|
|
529
|
-
this.state;
|
|
534
|
+
const { revoked, localAddr, protocolImpl } = this.state;
|
|
530
535
|
|
|
531
536
|
!revoked || Fail`Port ${localAddr} is revoked`;
|
|
532
537
|
/** @type {Endpoint} */
|
|
533
538
|
const dst = harden(remotePort);
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
539
|
+
return watch(
|
|
540
|
+
E(protocolImpl).outbound(this.facets.port, dst, connectionHandler),
|
|
541
|
+
this.facets.portConnectWatcher,
|
|
542
|
+
{ chandler: connectionHandler },
|
|
537
543
|
);
|
|
538
|
-
if (revoked) {
|
|
539
|
-
void E(conn).close();
|
|
540
|
-
} else {
|
|
541
|
-
openConnections.add(conn);
|
|
542
|
-
}
|
|
543
|
-
return conn;
|
|
544
544
|
},
|
|
545
545
|
async revoke() {
|
|
546
546
|
const { revoked, localAddr } = this.state;
|
|
547
|
-
const { protocolHandler
|
|
548
|
-
this.state;
|
|
547
|
+
const { protocolHandler } = this.state;
|
|
549
548
|
|
|
550
549
|
revoked !== RevokeState.REVOKED ||
|
|
551
550
|
Fail`Port ${localAddr} is already revoked`;
|
|
551
|
+
|
|
552
552
|
this.state.revoked = RevokeState.REVOKING;
|
|
553
|
-
|
|
554
|
-
E(protocolHandler).onRevoke(
|
|
553
|
+
const revokeVow = watch(
|
|
554
|
+
E(protocolHandler).onRevoke(
|
|
555
|
+
this.facets.port,
|
|
556
|
+
localAddr,
|
|
557
|
+
protocolHandler,
|
|
558
|
+
),
|
|
559
|
+
this.facets.portRevokeWatcher,
|
|
555
560
|
);
|
|
556
|
-
|
|
561
|
+
|
|
562
|
+
return watch(revokeVow, this.facets.portRevokeCleanupWatcher);
|
|
563
|
+
},
|
|
564
|
+
},
|
|
565
|
+
portAddListenerWatcher: {
|
|
566
|
+
onFulfilled(_value, watcherContext) {
|
|
567
|
+
const { listenHandler } = watcherContext;
|
|
568
|
+
return E(listenHandler).onListen(this.facets.port, listenHandler);
|
|
569
|
+
},
|
|
570
|
+
},
|
|
571
|
+
portRemoveListenerWatcher: {
|
|
572
|
+
onFulfilled(_value, watcherContext) {
|
|
573
|
+
const { listenHandler } = watcherContext;
|
|
574
|
+
return E(listenHandler).onRemove(this.facets.port, listenHandler);
|
|
575
|
+
},
|
|
576
|
+
},
|
|
577
|
+
portConnectWatcher: {
|
|
578
|
+
onFulfilled(conn, { chandler }) {
|
|
579
|
+
const { openConnections, revoked } = this.state;
|
|
580
|
+
|
|
581
|
+
if (!finalizer.has(conn)) {
|
|
582
|
+
finalizer.initConnection(conn, chandler);
|
|
583
|
+
}
|
|
584
|
+
if (revoked) {
|
|
585
|
+
return finalizer.finalize(conn);
|
|
586
|
+
}
|
|
587
|
+
openConnections.add(conn);
|
|
588
|
+
return conn;
|
|
589
|
+
},
|
|
590
|
+
},
|
|
591
|
+
portRevokeWatcher: {
|
|
592
|
+
onFulfilled(_value) {
|
|
593
|
+
const { currentConnections, listening, localAddr } = this.state;
|
|
594
|
+
const port = this.facets.port;
|
|
557
595
|
|
|
558
596
|
// Clean up everything we did.
|
|
559
|
-
const values = [...currentConnections.get(
|
|
560
|
-
|
|
597
|
+
const values = [...currentConnections.get(port).values()];
|
|
598
|
+
|
|
599
|
+
const ps = [];
|
|
600
|
+
ps.push(
|
|
601
|
+
...values.map(obj =>
|
|
602
|
+
watch(finalizer.finalize(obj), this.facets.sinkWatcher),
|
|
603
|
+
),
|
|
604
|
+
);
|
|
605
|
+
|
|
561
606
|
if (listening.has(localAddr)) {
|
|
562
607
|
const listener = listening.get(localAddr)[1];
|
|
563
|
-
ps.push(
|
|
608
|
+
ps.push(port.removeListener(listener));
|
|
564
609
|
}
|
|
565
|
-
|
|
566
|
-
|
|
610
|
+
|
|
611
|
+
return watch(allVows(ps), this.facets.rethrowUnlessMissingWatcher);
|
|
612
|
+
},
|
|
613
|
+
},
|
|
614
|
+
sinkWatcher: {
|
|
615
|
+
onFulfilled() {
|
|
616
|
+
return undefined;
|
|
617
|
+
},
|
|
618
|
+
onRejected() {
|
|
619
|
+
return undefined;
|
|
620
|
+
},
|
|
621
|
+
},
|
|
622
|
+
portRevokeCleanupWatcher: {
|
|
623
|
+
onFulfilled(_value) {
|
|
624
|
+
const { currentConnections, boundPorts, localAddr } = this.state;
|
|
625
|
+
|
|
626
|
+
this.state.revoked = RevokeState.REVOKED;
|
|
627
|
+
|
|
628
|
+
currentConnections.delete(this.facets.port);
|
|
567
629
|
boundPorts.delete(localAddr);
|
|
568
630
|
},
|
|
569
631
|
},
|
|
570
|
-
|
|
632
|
+
rethrowUnlessMissingWatcher: {
|
|
633
|
+
onRejected(e) {
|
|
634
|
+
rethrowUnlessMissing(e);
|
|
635
|
+
},
|
|
636
|
+
},
|
|
637
|
+
});
|
|
638
|
+
|
|
639
|
+
const makePort = ({
|
|
640
|
+
localAddr,
|
|
641
|
+
listening,
|
|
642
|
+
openConnections,
|
|
643
|
+
currentConnections,
|
|
644
|
+
boundPorts,
|
|
645
|
+
protocolHandler,
|
|
646
|
+
protocolImpl,
|
|
647
|
+
}) => {
|
|
648
|
+
const { port } = makePortKit({
|
|
649
|
+
localAddr,
|
|
650
|
+
listening,
|
|
651
|
+
openConnections,
|
|
652
|
+
currentConnections,
|
|
653
|
+
boundPorts,
|
|
654
|
+
protocolHandler,
|
|
655
|
+
protocolImpl,
|
|
656
|
+
});
|
|
657
|
+
return harden(port);
|
|
658
|
+
};
|
|
571
659
|
|
|
572
660
|
return makePort;
|
|
573
661
|
};
|
|
574
662
|
|
|
575
663
|
/**
|
|
576
664
|
* @param {import('@agoric/base-zone').Zone} zone
|
|
577
|
-
* @param {
|
|
665
|
+
* @param {Powers} powers
|
|
578
666
|
*/
|
|
579
667
|
const prepareBinder = (zone, powers) => {
|
|
580
668
|
const makeConnection = prepareHalfConnection(zone, powers);
|
|
581
|
-
|
|
669
|
+
|
|
670
|
+
const { watch, finalizer } = powers;
|
|
671
|
+
|
|
582
672
|
const makeInboundAttempt = prepareInboundAttempt(
|
|
583
673
|
zone,
|
|
584
674
|
makeConnection,
|
|
585
675
|
powers,
|
|
586
676
|
);
|
|
677
|
+
|
|
587
678
|
const makePort = preparePort(zone, powers);
|
|
679
|
+
|
|
588
680
|
const detached = zone.detached();
|
|
589
681
|
|
|
590
|
-
const
|
|
682
|
+
const makeFullBinderKit = zone.exoClassKit(
|
|
591
683
|
'binder',
|
|
592
684
|
{
|
|
593
685
|
protocolImpl: Shape.ProtocolImplI,
|
|
594
686
|
binder: M.interface('Binder', {
|
|
595
|
-
|
|
687
|
+
bindPort: M.callWhen(Shape.Endpoint).returns(Shape.Vow$(Shape.Port)),
|
|
688
|
+
}),
|
|
689
|
+
binderInboundInstantiateWatcher: M.interface(
|
|
690
|
+
'BinderInboundInstantiateWatcher',
|
|
691
|
+
{
|
|
692
|
+
onFulfilled: M.call(M.any()).rest(M.any()).returns(M.any()),
|
|
693
|
+
},
|
|
694
|
+
),
|
|
695
|
+
binderInboundInstantiateCatchWatcher: M.interface(
|
|
696
|
+
'BinderInboundInstantiateCatchWatcher',
|
|
697
|
+
{
|
|
698
|
+
onRejected: M.call(M.any()).rest(M.any()).returns(M.any()),
|
|
699
|
+
},
|
|
700
|
+
),
|
|
701
|
+
binderOutboundInstantiateWatcher: M.interface(
|
|
702
|
+
'BinderOutboundInstantiateWatcher',
|
|
703
|
+
{
|
|
704
|
+
onFulfilled: M.call(M.any()).rest(M.any()).returns(M.any()),
|
|
705
|
+
},
|
|
706
|
+
),
|
|
707
|
+
binderOutboundConnectWatcher: M.interface(
|
|
708
|
+
'BinderOutboundConnectWatcher',
|
|
709
|
+
{
|
|
710
|
+
onFulfilled: M.call(M.any()).rest(M.any()).returns(M.any()),
|
|
711
|
+
},
|
|
712
|
+
),
|
|
713
|
+
binderOutboundCatchWatcher: M.interface('BinderOutboundCatchWatcher', {
|
|
714
|
+
onRejected: M.call(M.any()).rest(M.any()).returns(M.any()),
|
|
715
|
+
}),
|
|
716
|
+
binderOutboundInboundWatcher: M.interface(
|
|
717
|
+
'BinderOutboundInboundWatcher',
|
|
718
|
+
{
|
|
719
|
+
onFulfilled: M.call(M.any()).rest(M.any()).returns(M.any()),
|
|
720
|
+
},
|
|
721
|
+
),
|
|
722
|
+
binderOutboundAcceptWatcher: M.interface('BinderOutboundAcceptWatcher', {
|
|
723
|
+
onFulfilled: M.call(M.any()).rest(M.any()).returns(M.any()),
|
|
724
|
+
}),
|
|
725
|
+
binderBindGeneratePortWatcher: M.interface(
|
|
726
|
+
'BinderBindGeneratePortWatcher',
|
|
727
|
+
{
|
|
728
|
+
onFulfilled: M.call(M.any()).rest(M.any()).returns(M.any()),
|
|
729
|
+
},
|
|
730
|
+
),
|
|
731
|
+
binderPortWatcher: M.interface('BinderPortWatcher', {
|
|
732
|
+
onFulfilled: M.call(M.any()).rest(M.any()).returns(M.any()),
|
|
733
|
+
}),
|
|
734
|
+
binderBindWatcher: M.interface('BinderBindWatcher', {
|
|
735
|
+
onFulfilled: M.call(M.any()).rest(M.any()).returns(M.any()),
|
|
736
|
+
}),
|
|
737
|
+
rethrowUnlessMissingWatcher: M.interface('RethrowUnlessMissingWatcher', {
|
|
738
|
+
onRejected: M.call(M.any()).rest(M.any()).returns(M.any()),
|
|
596
739
|
}),
|
|
597
740
|
},
|
|
598
741
|
/**
|
|
599
742
|
* @param {object} opts
|
|
600
|
-
* @param {
|
|
743
|
+
* @param {MapStore<Port, SetStore<Closable>>} opts.currentConnections
|
|
601
744
|
* @param {MapStore<string, Port>} opts.boundPorts
|
|
602
|
-
* @param {MapStore<Endpoint, [Port, ListenHandler]>} opts.listening
|
|
603
|
-
* @param {ProtocolHandler} opts.protocolHandler
|
|
745
|
+
* @param {MapStore<Endpoint, [Port, Remote<Required<ListenHandler>>]>} opts.listening
|
|
746
|
+
* @param {Remote<ProtocolHandler>} opts.protocolHandler
|
|
604
747
|
*/
|
|
605
748
|
({ currentConnections, boundPorts, listening, protocolHandler }) => {
|
|
606
749
|
/** @type {SetStore<Connection>} */
|
|
@@ -613,8 +756,6 @@ const prepareBinder = (zone, powers) => {
|
|
|
613
756
|
revoked: RevokeState.NOT_REVOKED,
|
|
614
757
|
openConnections,
|
|
615
758
|
protocolHandler,
|
|
616
|
-
/** @type {Endpoint | undefined} */
|
|
617
|
-
localAddr: undefined,
|
|
618
759
|
};
|
|
619
760
|
},
|
|
620
761
|
{
|
|
@@ -624,49 +765,58 @@ const prepareBinder = (zone, powers) => {
|
|
|
624
765
|
* @param {Endpoint} remoteAddr
|
|
625
766
|
*/
|
|
626
767
|
async inbound(listenAddr, remoteAddr) {
|
|
627
|
-
const { listening, protocolHandler
|
|
768
|
+
const { listening, protocolHandler } = this.state;
|
|
769
|
+
|
|
770
|
+
const prefixes = getPrefixes(listenAddr);
|
|
771
|
+
let listenPrefixIndex = 0;
|
|
772
|
+
let listenPrefix;
|
|
628
773
|
|
|
629
|
-
|
|
630
|
-
|
|
774
|
+
while (listenPrefixIndex < prefixes.length) {
|
|
775
|
+
listenPrefix = prefixes[listenPrefixIndex];
|
|
631
776
|
if (!listening.has(listenPrefix)) {
|
|
777
|
+
listenPrefixIndex += 1;
|
|
632
778
|
continue;
|
|
633
779
|
}
|
|
634
|
-
const [port, _] = listening.get(listenPrefix);
|
|
635
|
-
let localAddr;
|
|
636
780
|
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
const localInstance = await when(
|
|
640
|
-
E(protocolHandler).onInstantiate(
|
|
641
|
-
port,
|
|
642
|
-
listenPrefix,
|
|
643
|
-
remoteAddr,
|
|
644
|
-
protocolHandler,
|
|
645
|
-
),
|
|
646
|
-
).catch(rethrowUnlessMissing);
|
|
647
|
-
localAddr = localInstance
|
|
648
|
-
? `${listenAddr}/${localInstance}`
|
|
649
|
-
: listenAddr;
|
|
650
|
-
})().catch(e => {
|
|
651
|
-
lastFailure = e;
|
|
652
|
-
});
|
|
653
|
-
if (!localAddr) {
|
|
654
|
-
continue;
|
|
655
|
-
}
|
|
656
|
-
// We have a legitimate inbound attempt.
|
|
657
|
-
const current = currentConnections.get(port);
|
|
658
|
-
const inboundAttempt = makeInboundAttempt({
|
|
659
|
-
localAddr,
|
|
660
|
-
remoteAddr,
|
|
661
|
-
currentConnections,
|
|
662
|
-
listenPrefix,
|
|
663
|
-
listening,
|
|
664
|
-
});
|
|
781
|
+
break;
|
|
782
|
+
}
|
|
665
783
|
|
|
666
|
-
|
|
667
|
-
|
|
784
|
+
if (listenPrefixIndex >= prefixes.length) {
|
|
785
|
+
throw Error(`No listeners for ${listenAddr}`);
|
|
668
786
|
}
|
|
669
|
-
|
|
787
|
+
|
|
788
|
+
const [port] = listening.get(/** @type {string} **/ (listenPrefix));
|
|
789
|
+
|
|
790
|
+
const innerVow = watch(
|
|
791
|
+
E(
|
|
792
|
+
/** @type {Remote<Required<ProtocolHandler>>} */ (
|
|
793
|
+
protocolHandler
|
|
794
|
+
),
|
|
795
|
+
).onInstantiate(
|
|
796
|
+
/** @type {Port} **/ (port),
|
|
797
|
+
prefixes[listenPrefixIndex],
|
|
798
|
+
remoteAddr,
|
|
799
|
+
protocolHandler,
|
|
800
|
+
),
|
|
801
|
+
this.facets.binderInboundInstantiateWatcher,
|
|
802
|
+
{
|
|
803
|
+
listenAddr,
|
|
804
|
+
remoteAddr,
|
|
805
|
+
port,
|
|
806
|
+
listenPrefixIndex,
|
|
807
|
+
},
|
|
808
|
+
);
|
|
809
|
+
|
|
810
|
+
return watch(
|
|
811
|
+
innerVow,
|
|
812
|
+
this.facets.binderInboundInstantiateCatchWatcher,
|
|
813
|
+
{
|
|
814
|
+
listenPrefixIndex,
|
|
815
|
+
listenAddr,
|
|
816
|
+
remoteAddr,
|
|
817
|
+
lastFailure: Error(`No listeners for ${listenAddr}`),
|
|
818
|
+
},
|
|
819
|
+
);
|
|
670
820
|
},
|
|
671
821
|
/**
|
|
672
822
|
* @param {Port} port
|
|
@@ -674,101 +824,310 @@ const prepareBinder = (zone, powers) => {
|
|
|
674
824
|
* @param {ConnectionHandler} lchandler
|
|
675
825
|
*/
|
|
676
826
|
async outbound(port, remoteAddr, lchandler) {
|
|
677
|
-
const { protocolHandler
|
|
827
|
+
const { protocolHandler } = this.state;
|
|
678
828
|
|
|
679
829
|
const localAddr = await E(port).getLocalAddress();
|
|
680
830
|
|
|
681
831
|
// Allocate a local address.
|
|
682
|
-
const
|
|
683
|
-
E(
|
|
832
|
+
const instantiateInnerVow = watch(
|
|
833
|
+
E(
|
|
834
|
+
/** @type {Remote<Required<ProtocolHandler>>} */ (
|
|
835
|
+
protocolHandler
|
|
836
|
+
),
|
|
837
|
+
).onInstantiate(port, localAddr, remoteAddr, protocolHandler),
|
|
838
|
+
this.facets.binderOutboundInstantiateWatcher,
|
|
839
|
+
{
|
|
684
840
|
port,
|
|
685
841
|
localAddr,
|
|
686
842
|
remoteAddr,
|
|
687
843
|
protocolHandler,
|
|
688
|
-
|
|
689
|
-
)
|
|
690
|
-
const initialLocalAddr = initialLocalInstance
|
|
691
|
-
? `${localAddr}/${initialLocalInstance}`
|
|
692
|
-
: localAddr;
|
|
844
|
+
},
|
|
845
|
+
);
|
|
693
846
|
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
847
|
+
const instantiateVow = watch(
|
|
848
|
+
instantiateInnerVow,
|
|
849
|
+
this.facets.rethrowUnlessMissingWatcher,
|
|
850
|
+
);
|
|
851
|
+
|
|
852
|
+
const attemptVow = watch(
|
|
853
|
+
instantiateVow,
|
|
854
|
+
this.facets.binderOutboundInboundWatcher,
|
|
855
|
+
{
|
|
856
|
+
localAddr,
|
|
857
|
+
remoteAddr,
|
|
858
|
+
},
|
|
859
|
+
);
|
|
860
|
+
const acceptedVow = watch(
|
|
861
|
+
attemptVow,
|
|
862
|
+
this.facets.binderOutboundAcceptWatcher,
|
|
863
|
+
{
|
|
864
|
+
handler: lchandler,
|
|
865
|
+
},
|
|
866
|
+
);
|
|
867
|
+
|
|
868
|
+
return watch(acceptedVow, this.facets.binderOutboundCatchWatcher, {
|
|
869
|
+
port,
|
|
870
|
+
remoteAddr,
|
|
871
|
+
lchandler,
|
|
872
|
+
localAddr,
|
|
704
873
|
});
|
|
705
|
-
|
|
706
|
-
|
|
874
|
+
},
|
|
875
|
+
async bindPort(localAddr) {
|
|
876
|
+
return this.facets.binder.bindPort(localAddr);
|
|
877
|
+
},
|
|
878
|
+
},
|
|
879
|
+
binder: {
|
|
880
|
+
/** @param {string} localAddr */
|
|
881
|
+
async bindPort(localAddr) {
|
|
882
|
+
const { protocolHandler } = this.state;
|
|
883
|
+
|
|
884
|
+
// Check if we are underspecified (ends in slash)
|
|
885
|
+
const underspecified = localAddr.endsWith(ENDPOINT_SEPARATOR);
|
|
886
|
+
|
|
887
|
+
const localAddrVow = watch(
|
|
888
|
+
E(protocolHandler).generatePortID(localAddr, protocolHandler),
|
|
889
|
+
this.facets.binderBindGeneratePortWatcher,
|
|
890
|
+
{
|
|
891
|
+
underspecified,
|
|
892
|
+
localAddr,
|
|
893
|
+
},
|
|
894
|
+
);
|
|
895
|
+
|
|
896
|
+
return watch(localAddrVow, this.facets.binderBindWatcher);
|
|
897
|
+
},
|
|
898
|
+
},
|
|
899
|
+
binderInboundInstantiateWatcher: {
|
|
900
|
+
onFulfilled(localInstance, watchContext) {
|
|
901
|
+
const { listenAddr, remoteAddr, port, listenPrefixIndex } =
|
|
902
|
+
watchContext;
|
|
903
|
+
const { listening, currentConnections } = this.state;
|
|
904
|
+
const prefixes = getPrefixes(listenAddr);
|
|
905
|
+
|
|
906
|
+
const localAddr = localInstance
|
|
907
|
+
? `${listenAddr}/${localInstance}`
|
|
908
|
+
: listenAddr;
|
|
909
|
+
const current = currentConnections.get(port);
|
|
910
|
+
const inboundAttempt = makeInboundAttempt({
|
|
911
|
+
localAddr,
|
|
912
|
+
remoteAddr,
|
|
913
|
+
currentConnections,
|
|
914
|
+
listenPrefix: prefixes[listenPrefixIndex],
|
|
915
|
+
listening,
|
|
916
|
+
});
|
|
917
|
+
|
|
918
|
+
current.add(inboundAttempt);
|
|
919
|
+
finalizer.initCloser(inboundAttempt);
|
|
920
|
+
return inboundAttempt;
|
|
921
|
+
},
|
|
922
|
+
},
|
|
923
|
+
binderInboundInstantiateCatchWatcher: {
|
|
924
|
+
onRejected(e, watchContext) {
|
|
925
|
+
let { lastFailure, listenPrefixIndex } = watchContext;
|
|
926
|
+
|
|
927
|
+
try {
|
|
928
|
+
rethrowUnlessMissing(e);
|
|
929
|
+
} catch (innerE) {
|
|
930
|
+
lastFailure = innerE;
|
|
707
931
|
}
|
|
708
932
|
|
|
709
|
-
const {
|
|
710
|
-
|
|
933
|
+
const { listenAddr, remoteAddr } = watchContext;
|
|
934
|
+
|
|
935
|
+
const { listening, protocolHandler } = this.state;
|
|
936
|
+
|
|
937
|
+
const prefixes = getPrefixes(listenAddr);
|
|
938
|
+
|
|
939
|
+
let listenPrefix;
|
|
940
|
+
|
|
941
|
+
listenPrefixIndex += 1;
|
|
942
|
+
|
|
943
|
+
while (listenPrefixIndex < prefixes.length) {
|
|
944
|
+
listenPrefix = prefixes[listenPrefixIndex];
|
|
945
|
+
if (!listening.has(listenPrefix)) {
|
|
946
|
+
listenPrefixIndex += 1;
|
|
947
|
+
continue;
|
|
948
|
+
}
|
|
949
|
+
|
|
950
|
+
break;
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
if (listenPrefixIndex >= prefixes.length) {
|
|
954
|
+
throw lastFailure;
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
const [port] = listening.get(/** @type {string} */ (listenPrefix));
|
|
958
|
+
|
|
959
|
+
const innerVow = watch(
|
|
960
|
+
E(
|
|
961
|
+
/** @type {Remote<Required<ProtocolHandler>>} */ (
|
|
962
|
+
protocolHandler
|
|
963
|
+
),
|
|
964
|
+
).onInstantiate(
|
|
965
|
+
port,
|
|
966
|
+
prefixes[listenPrefixIndex],
|
|
967
|
+
remoteAddr,
|
|
968
|
+
protocolHandler,
|
|
969
|
+
),
|
|
970
|
+
this.facets.binderInboundInstantiateWatcher,
|
|
971
|
+
{
|
|
972
|
+
listenAddr,
|
|
973
|
+
remoteAddr,
|
|
974
|
+
port,
|
|
975
|
+
listenPrefixIndex,
|
|
976
|
+
},
|
|
977
|
+
);
|
|
978
|
+
|
|
979
|
+
return watch(
|
|
980
|
+
innerVow,
|
|
981
|
+
this.facets.binderInboundInstantiateCatchWatcher,
|
|
982
|
+
{
|
|
983
|
+
...watchContext,
|
|
984
|
+
lastFailure,
|
|
985
|
+
listenPrefixIndex,
|
|
986
|
+
},
|
|
987
|
+
);
|
|
988
|
+
},
|
|
989
|
+
},
|
|
990
|
+
binderOutboundInstantiateWatcher: {
|
|
991
|
+
onFulfilled(localInstance, watchContext) {
|
|
992
|
+
const { localAddr } = watchContext;
|
|
993
|
+
|
|
994
|
+
return localInstance ? `${localAddr}/${localInstance}` : localAddr;
|
|
995
|
+
},
|
|
996
|
+
},
|
|
997
|
+
binderOutboundConnectWatcher: {
|
|
998
|
+
onFulfilled(
|
|
999
|
+
{
|
|
711
1000
|
handler: rchandler,
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
1001
|
+
remoteAddress: negotiatedRemoteAddress,
|
|
1002
|
+
localAddress: negotiatedLocalAddress,
|
|
1003
|
+
},
|
|
1004
|
+
watchContext,
|
|
1005
|
+
) {
|
|
1006
|
+
const {
|
|
1007
|
+
lastFailure,
|
|
1008
|
+
lchandler,
|
|
1009
|
+
localAddr: requestedLocalAddress,
|
|
1010
|
+
remoteAddr: requestedRemoteAddress,
|
|
1011
|
+
port,
|
|
1012
|
+
} = watchContext;
|
|
1013
|
+
|
|
1014
|
+
const { currentConnections } = this.state;
|
|
726
1015
|
|
|
727
1016
|
if (!rchandler) {
|
|
728
1017
|
throw lastFailure;
|
|
729
1018
|
}
|
|
730
1019
|
|
|
731
1020
|
const current = currentConnections.get(port);
|
|
1021
|
+
|
|
732
1022
|
return crossoverConnection(
|
|
733
1023
|
zone,
|
|
734
|
-
lchandler,
|
|
735
|
-
|
|
736
|
-
rchandler,
|
|
737
|
-
|
|
1024
|
+
/** @type {Remote<Required<ConnectionHandler>>} */ (lchandler),
|
|
1025
|
+
negotiatedLocalAddress || requestedLocalAddress,
|
|
1026
|
+
/** @type {Remote<Required<ConnectionHandler>>} */ (rchandler),
|
|
1027
|
+
negotiatedRemoteAddress || requestedRemoteAddress,
|
|
738
1028
|
makeConnection,
|
|
1029
|
+
finalizer,
|
|
739
1030
|
current,
|
|
740
1031
|
)[0];
|
|
741
1032
|
},
|
|
742
|
-
|
|
743
|
-
|
|
1033
|
+
},
|
|
1034
|
+
binderOutboundCatchWatcher: {
|
|
1035
|
+
onRejected(e, watchContext) {
|
|
1036
|
+
let lastFailure;
|
|
1037
|
+
|
|
1038
|
+
try {
|
|
1039
|
+
rethrowUnlessMissing(e);
|
|
1040
|
+
} catch (innerE) {
|
|
1041
|
+
lastFailure = innerE;
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
const { port, remoteAddr, lchandler, localAddr } = watchContext;
|
|
1045
|
+
|
|
1046
|
+
const { protocolHandler } = this.state;
|
|
1047
|
+
|
|
1048
|
+
const connectVow = watch(
|
|
1049
|
+
E(protocolHandler).onConnect(
|
|
1050
|
+
port,
|
|
1051
|
+
localAddr,
|
|
1052
|
+
remoteAddr,
|
|
1053
|
+
lchandler,
|
|
1054
|
+
protocolHandler,
|
|
1055
|
+
),
|
|
1056
|
+
);
|
|
1057
|
+
|
|
1058
|
+
return watch(connectVow, this.facets.binderOutboundConnectWatcher, {
|
|
1059
|
+
lastFailure,
|
|
1060
|
+
remoteAddr,
|
|
1061
|
+
localAddr,
|
|
1062
|
+
lchandler,
|
|
1063
|
+
port,
|
|
1064
|
+
});
|
|
744
1065
|
},
|
|
745
1066
|
},
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
1067
|
+
binderOutboundInboundWatcher: {
|
|
1068
|
+
onFulfilled(initialLocalAddress, watchContext) {
|
|
1069
|
+
const { remoteAddr, localAddr } = watchContext;
|
|
1070
|
+
|
|
1071
|
+
if (initialLocalAddress === undefined) {
|
|
1072
|
+
initialLocalAddress = localAddr;
|
|
1073
|
+
}
|
|
1074
|
+
|
|
1075
|
+
// Attempt the loopback connection.
|
|
1076
|
+
return this.facets.protocolImpl.inbound(
|
|
1077
|
+
remoteAddr,
|
|
1078
|
+
initialLocalAddress,
|
|
1079
|
+
);
|
|
1080
|
+
},
|
|
1081
|
+
},
|
|
1082
|
+
binderOutboundAcceptWatcher: {
|
|
1083
|
+
onFulfilled(attempt, watchContext) {
|
|
1084
|
+
const { handler } = watchContext;
|
|
1085
|
+
return E(attempt).accept({ handler });
|
|
1086
|
+
},
|
|
1087
|
+
},
|
|
1088
|
+
binderBindGeneratePortWatcher: {
|
|
1089
|
+
onFulfilled(portID, watchContext) {
|
|
1090
|
+
const { localAddr, underspecified } = watchContext;
|
|
1091
|
+
const { protocolHandler, boundPorts } = this.state;
|
|
1092
|
+
|
|
1093
|
+
if (!underspecified) {
|
|
1094
|
+
return localAddr;
|
|
1095
|
+
}
|
|
1096
|
+
|
|
1097
|
+
const newAddr = `${localAddr}${portID}`;
|
|
1098
|
+
if (!boundPorts.has(newAddr)) {
|
|
1099
|
+
return newAddr;
|
|
1100
|
+
}
|
|
1101
|
+
return watch(
|
|
1102
|
+
E(protocolHandler).generatePortID(localAddr, protocolHandler),
|
|
1103
|
+
this.facets.binderBindGeneratePortWatcher,
|
|
1104
|
+
watchContext,
|
|
1105
|
+
);
|
|
1106
|
+
},
|
|
1107
|
+
},
|
|
1108
|
+
binderPortWatcher: {
|
|
1109
|
+
onFulfilled(_value, watchContext) {
|
|
1110
|
+
const { port, localAddr } = watchContext;
|
|
1111
|
+
const { boundPorts, currentConnections } = this.state;
|
|
1112
|
+
|
|
1113
|
+
boundPorts.init(localAddr, port);
|
|
1114
|
+
currentConnections.init(
|
|
1115
|
+
port,
|
|
1116
|
+
zone.detached().setStore('connections'),
|
|
1117
|
+
);
|
|
1118
|
+
return port;
|
|
1119
|
+
},
|
|
1120
|
+
},
|
|
1121
|
+
binderBindWatcher: {
|
|
1122
|
+
onFulfilled(localAddr) {
|
|
749
1123
|
const {
|
|
750
|
-
protocolHandler,
|
|
751
1124
|
boundPorts,
|
|
752
1125
|
listening,
|
|
753
1126
|
openConnections,
|
|
754
1127
|
currentConnections,
|
|
1128
|
+
protocolHandler,
|
|
755
1129
|
} = this.state;
|
|
756
1130
|
|
|
757
|
-
// Check if we are underspecified (ends in slash)
|
|
758
|
-
const underspecified = localAddr.endsWith(ENDPOINT_SEPARATOR);
|
|
759
|
-
for await (const _ of whileTrue(() => underspecified)) {
|
|
760
|
-
const portID = await when(
|
|
761
|
-
E(protocolHandler).generatePortID(localAddr, protocolHandler),
|
|
762
|
-
);
|
|
763
|
-
const newAddr = `${localAddr}${portID}`;
|
|
764
|
-
if (!boundPorts.has(newAddr)) {
|
|
765
|
-
localAddr = newAddr;
|
|
766
|
-
break;
|
|
767
|
-
}
|
|
768
|
-
}
|
|
769
|
-
|
|
770
|
-
this.state.localAddr = localAddr;
|
|
771
|
-
|
|
772
1131
|
if (boundPorts.has(localAddr)) {
|
|
773
1132
|
return boundPorts.get(localAddr);
|
|
774
1133
|
}
|
|
@@ -783,29 +1142,50 @@ const prepareBinder = (zone, powers) => {
|
|
|
783
1142
|
protocolImpl: this.facets.protocolImpl,
|
|
784
1143
|
});
|
|
785
1144
|
|
|
786
|
-
|
|
1145
|
+
return watch(
|
|
787
1146
|
E(protocolHandler).onBind(port, localAddr, protocolHandler),
|
|
1147
|
+
this.facets.binderPortWatcher,
|
|
1148
|
+
{
|
|
1149
|
+
port,
|
|
1150
|
+
localAddr,
|
|
1151
|
+
},
|
|
788
1152
|
);
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
1153
|
+
},
|
|
1154
|
+
},
|
|
1155
|
+
rethrowUnlessMissingWatcher: {
|
|
1156
|
+
onRejected(e) {
|
|
1157
|
+
rethrowUnlessMissing(e);
|
|
792
1158
|
},
|
|
793
1159
|
},
|
|
794
1160
|
},
|
|
795
1161
|
);
|
|
796
1162
|
|
|
1163
|
+
const makeBinderKit = ({
|
|
1164
|
+
currentConnections,
|
|
1165
|
+
boundPorts,
|
|
1166
|
+
listening,
|
|
1167
|
+
protocolHandler,
|
|
1168
|
+
}) => {
|
|
1169
|
+
const { protocolImpl, binder } = makeFullBinderKit({
|
|
1170
|
+
currentConnections,
|
|
1171
|
+
boundPorts,
|
|
1172
|
+
listening,
|
|
1173
|
+
protocolHandler,
|
|
1174
|
+
});
|
|
1175
|
+
return harden({ protocolImpl, binder });
|
|
1176
|
+
};
|
|
797
1177
|
return makeBinderKit;
|
|
798
1178
|
};
|
|
799
1179
|
|
|
800
1180
|
/**
|
|
801
1181
|
* @param {import('@agoric/base-zone').Zone} zone
|
|
802
|
-
* @param {
|
|
1182
|
+
* @param {Powers} powers
|
|
803
1183
|
*/
|
|
804
1184
|
export const prepareNetworkProtocol = (zone, powers) => {
|
|
805
1185
|
const makeBinderKit = prepareBinder(zone, powers);
|
|
806
1186
|
|
|
807
1187
|
/**
|
|
808
|
-
* @param {ProtocolHandler} protocolHandler
|
|
1188
|
+
* @param {Remote<ProtocolHandler>} protocolHandler
|
|
809
1189
|
* @returns {Protocol}
|
|
810
1190
|
*/
|
|
811
1191
|
const makeNetworkProtocol = protocolHandler => {
|
|
@@ -817,7 +1197,7 @@ export const prepareNetworkProtocol = (zone, powers) => {
|
|
|
817
1197
|
/** @type {MapStore<string, Port>} */
|
|
818
1198
|
const boundPorts = detached.mapStore('addrToPort');
|
|
819
1199
|
|
|
820
|
-
/** @type {MapStore<Endpoint, [Port, ListenHandler]>} */
|
|
1200
|
+
/** @type {MapStore<Endpoint, [Port, Remote<Required<ListenHandler>>]>} */
|
|
821
1201
|
const listening = detached.mapStore('listening');
|
|
822
1202
|
|
|
823
1203
|
const { binder, protocolImpl } = makeBinderKit({
|
|
@@ -846,14 +1226,14 @@ export const prepareEchoConnectionKit = zone => {
|
|
|
846
1226
|
{
|
|
847
1227
|
handler: M.interface('ConnectionHandler', {
|
|
848
1228
|
onReceive: M.callWhen(
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
1229
|
+
Shape.Connection,
|
|
1230
|
+
Shape.Bytes,
|
|
1231
|
+
Shape.ConnectionHandler,
|
|
852
1232
|
)
|
|
853
|
-
.optional(
|
|
854
|
-
.returns(
|
|
855
|
-
onClose: M.callWhen(
|
|
856
|
-
.optional(M.any(),
|
|
1233
|
+
.optional(Shape.Opts)
|
|
1234
|
+
.returns(Shape.Data),
|
|
1235
|
+
onClose: M.callWhen(Shape.Connection)
|
|
1236
|
+
.optional(M.any(), Shape.ConnectionHandler)
|
|
857
1237
|
.returns(M.undefined()),
|
|
858
1238
|
}),
|
|
859
1239
|
listener: M.interface('Listener', {
|
|
@@ -869,10 +1249,9 @@ export const prepareEchoConnectionKit = zone => {
|
|
|
869
1249
|
}),
|
|
870
1250
|
},
|
|
871
1251
|
() => {
|
|
872
|
-
/** @type {string | undefined} */
|
|
873
|
-
let closed;
|
|
874
1252
|
return {
|
|
875
|
-
|
|
1253
|
+
/** @type {string | undefined} */
|
|
1254
|
+
closed: undefined,
|
|
876
1255
|
};
|
|
877
1256
|
},
|
|
878
1257
|
{
|
|
@@ -886,28 +1265,28 @@ export const prepareEchoConnectionKit = zone => {
|
|
|
886
1265
|
const { closed } = this.state;
|
|
887
1266
|
|
|
888
1267
|
if (closed) {
|
|
889
|
-
throw closed;
|
|
1268
|
+
throw Error(closed);
|
|
890
1269
|
}
|
|
891
1270
|
return bytes;
|
|
892
1271
|
},
|
|
893
1272
|
/**
|
|
894
1273
|
* @param {Connection} _connection
|
|
895
|
-
* @param {CloseReason} [
|
|
1274
|
+
* @param {CloseReason} [reason]
|
|
896
1275
|
* @param {ConnectionHandler} [_connectionHandler]
|
|
897
1276
|
*/
|
|
898
|
-
async onClose(_connection,
|
|
1277
|
+
async onClose(_connection, reason, _connectionHandler) {
|
|
899
1278
|
const { closed } = this.state;
|
|
900
1279
|
|
|
901
1280
|
if (closed) {
|
|
902
1281
|
throw Error(closed);
|
|
903
1282
|
}
|
|
904
1283
|
|
|
905
|
-
this.state.closed = 'Connection closed';
|
|
1284
|
+
this.state.closed = reason || 'Connection closed';
|
|
906
1285
|
},
|
|
907
1286
|
},
|
|
908
1287
|
listener: {
|
|
909
1288
|
async onAccept(_port, _localAddr, _remoteAddr, _listenHandler) {
|
|
910
|
-
return
|
|
1289
|
+
return this.facets.handler;
|
|
911
1290
|
},
|
|
912
1291
|
async onListen(port, _listenHandler) {
|
|
913
1292
|
console.debug(`listening on echo port: ${port}`);
|
|
@@ -918,106 +1297,313 @@ export const prepareEchoConnectionKit = zone => {
|
|
|
918
1297
|
|
|
919
1298
|
return makeEchoConnectionKit;
|
|
920
1299
|
};
|
|
1300
|
+
/** @typedef {ReturnType<typeof prepareEchoConnectionKit>} MakeEchoConnectionKit */
|
|
921
1301
|
|
|
922
1302
|
/**
|
|
923
1303
|
* Create a protocol handler that just connects to itself.
|
|
924
1304
|
*
|
|
925
1305
|
* @param {import('@agoric/base-zone').Zone} zone
|
|
926
|
-
* @param {
|
|
1306
|
+
* @param {VowTools} powers
|
|
927
1307
|
*/
|
|
928
|
-
export function prepareLoopbackProtocolHandler(zone, {
|
|
1308
|
+
export function prepareLoopbackProtocolHandler(zone, { watch, allVows }) {
|
|
929
1309
|
const detached = zone.detached();
|
|
930
1310
|
|
|
931
|
-
|
|
1311
|
+
/** @param {string} [instancePrefix] */
|
|
1312
|
+
const initHandler = (instancePrefix = 'nonce/') => {
|
|
1313
|
+
/** @type {MapStore<string, [Remote<Port>, Remote<Required<ListenHandler>>]>} */
|
|
1314
|
+
const listeners = detached.mapStore('localAddr');
|
|
1315
|
+
|
|
1316
|
+
return {
|
|
1317
|
+
listeners,
|
|
1318
|
+
portNonce: 0n,
|
|
1319
|
+
instancePrefix,
|
|
1320
|
+
instanceNonce: 0n,
|
|
1321
|
+
};
|
|
1322
|
+
};
|
|
1323
|
+
|
|
1324
|
+
const makeLoopbackProtocolHandlerKit = zone.exoClassKit(
|
|
932
1325
|
'ProtocolHandler',
|
|
933
1326
|
Shape.ProtocolHandlerI,
|
|
934
1327
|
/** @param {string} [instancePrefix] */
|
|
935
|
-
|
|
936
|
-
/** @type {MapStore<string, [Port, ListenHandler]>} */
|
|
937
|
-
const listeners = detached.mapStore('localAddr');
|
|
938
|
-
|
|
939
|
-
return {
|
|
940
|
-
listeners,
|
|
941
|
-
portNonce: 0n,
|
|
942
|
-
instancePrefix,
|
|
943
|
-
instanceNonce: 0n,
|
|
944
|
-
};
|
|
945
|
-
},
|
|
1328
|
+
initHandler,
|
|
946
1329
|
{
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
1330
|
+
protocolHandler: {
|
|
1331
|
+
async onCreate(_impl, _protocolHandler) {
|
|
1332
|
+
// noop
|
|
1333
|
+
},
|
|
1334
|
+
async generatePortID(_localAddr, _protocolHandler) {
|
|
1335
|
+
this.state.portNonce += 1n;
|
|
1336
|
+
return `port${this.state.portNonce}`;
|
|
1337
|
+
},
|
|
1338
|
+
async onBind(_port, _localAddr, _protocolHandler) {
|
|
1339
|
+
// noop, for now; Maybe handle a bind?
|
|
1340
|
+
},
|
|
1341
|
+
/**
|
|
1342
|
+
* @param {*} _port
|
|
1343
|
+
* @param {Endpoint} localAddr
|
|
1344
|
+
* @param {Endpoint} remoteAddr
|
|
1345
|
+
* @returns {import('@agoric/vow').PromiseVow<AttemptDescription>}}
|
|
1346
|
+
*/
|
|
1347
|
+
async onConnect(_port, localAddr, remoteAddr) {
|
|
1348
|
+
const { listeners } = this.state;
|
|
1349
|
+
const [lport, lhandler] = listeners.get(remoteAddr);
|
|
1350
|
+
|
|
1351
|
+
const acceptVow = watch(
|
|
1352
|
+
E(lhandler).onAccept(lport, remoteAddr, localAddr, lhandler),
|
|
1353
|
+
this.facets.protocolHandlerAcceptWatcher,
|
|
1354
|
+
);
|
|
1355
|
+
|
|
1356
|
+
const instantiateInnerVow = watch(
|
|
1357
|
+
E(this.facets.protocolHandler).onInstantiate(
|
|
1358
|
+
lport,
|
|
1359
|
+
remoteAddr,
|
|
1360
|
+
localAddr,
|
|
1361
|
+
this.facets.protocolHandler,
|
|
1362
|
+
),
|
|
1363
|
+
this.facets.protocolHandlerInstantiateWatcher,
|
|
1364
|
+
);
|
|
1365
|
+
|
|
1366
|
+
const instantiateVow = watch(
|
|
1367
|
+
instantiateInnerVow,
|
|
1368
|
+
this.facets.rethrowUnlessMissingWatcher,
|
|
1369
|
+
);
|
|
1370
|
+
return watch(
|
|
1371
|
+
allVows([acceptVow, instantiateVow]),
|
|
1372
|
+
this.facets.protocolHandlerConnectWatcher,
|
|
1373
|
+
);
|
|
1374
|
+
},
|
|
1375
|
+
async onInstantiate(_port, _localAddr, _remote, _protocol) {
|
|
1376
|
+
const { instancePrefix } = this.state;
|
|
1377
|
+
this.state.instanceNonce += 1n;
|
|
1378
|
+
return `${instancePrefix}${this.state.instanceNonce}`;
|
|
1379
|
+
},
|
|
1380
|
+
async onListen(port, localAddr, listenHandler, _protocolHandler) {
|
|
1381
|
+
const { listeners } = this.state;
|
|
1382
|
+
|
|
1383
|
+
// This implementation has a simple last-one-wins replacement policy.
|
|
1384
|
+
// Other handlers might use different policies.
|
|
1385
|
+
if (listeners.has(localAddr)) {
|
|
1386
|
+
const lhandler = listeners.get(localAddr)[1];
|
|
1387
|
+
if (lhandler !== listenHandler) {
|
|
1388
|
+
listeners.set(
|
|
1389
|
+
localAddr,
|
|
1390
|
+
harden([
|
|
1391
|
+
port,
|
|
1392
|
+
/** @type {Remote<Required<ListenHandler>>} */ (
|
|
1393
|
+
listenHandler
|
|
1394
|
+
),
|
|
1395
|
+
]),
|
|
1396
|
+
);
|
|
1397
|
+
}
|
|
1398
|
+
} else {
|
|
1399
|
+
listeners.init(
|
|
1400
|
+
localAddr,
|
|
1401
|
+
harden([
|
|
1402
|
+
port,
|
|
1403
|
+
/** @type {Remote<Required<ListenHandler>>} */ (listenHandler),
|
|
1404
|
+
]),
|
|
1405
|
+
);
|
|
1406
|
+
}
|
|
1407
|
+
},
|
|
1408
|
+
/**
|
|
1409
|
+
* @param {Remote<Port>} port
|
|
1410
|
+
* @param {Endpoint} localAddr
|
|
1411
|
+
* @param {Remote<ListenHandler>} listenHandler
|
|
1412
|
+
* @param {*} _protocolHandler
|
|
1413
|
+
*/
|
|
1414
|
+
async onListenRemove(port, localAddr, listenHandler, _protocolHandler) {
|
|
1415
|
+
const { listeners } = this.state;
|
|
1416
|
+
const [lport, lhandler] = listeners.get(localAddr);
|
|
1417
|
+
lport === port || Fail`Port does not match listener on ${localAddr}`;
|
|
1418
|
+
lhandler === listenHandler ||
|
|
1419
|
+
Fail`Listen handler does not match listener on ${localAddr}`;
|
|
1420
|
+
listeners.delete(localAddr);
|
|
1421
|
+
},
|
|
1422
|
+
async onRevoke(_port, _localAddr, _protocolHandler) {
|
|
1423
|
+
// This is an opportunity to clean up resources.
|
|
1424
|
+
},
|
|
953
1425
|
},
|
|
954
|
-
|
|
955
|
-
|
|
1426
|
+
protocolHandlerAcceptWatcher: {
|
|
1427
|
+
onFulfilled(rchandler) {
|
|
1428
|
+
return rchandler;
|
|
1429
|
+
},
|
|
956
1430
|
},
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
const { listeners } = this.state;
|
|
965
|
-
const [lport, lhandler] = listeners.get(remoteAddr);
|
|
966
|
-
const rchandler = await when(
|
|
967
|
-
E(lhandler).onAccept(lport, remoteAddr, localAddr, lhandler),
|
|
968
|
-
);
|
|
969
|
-
// console.log(`rchandler is`, rchandler);
|
|
970
|
-
const remoteInstance = await when(
|
|
971
|
-
E(protocolHandler).onInstantiate(
|
|
972
|
-
lport,
|
|
973
|
-
remoteAddr,
|
|
974
|
-
localAddr,
|
|
975
|
-
protocolHandler,
|
|
976
|
-
),
|
|
977
|
-
).catch(rethrowUnlessMissing);
|
|
978
|
-
return {
|
|
979
|
-
remoteInstance,
|
|
980
|
-
handler: rchandler,
|
|
981
|
-
};
|
|
982
|
-
},
|
|
983
|
-
async onInstantiate(_port, _localAddr, _remote, _protocol) {
|
|
984
|
-
const { instancePrefix } = this.state;
|
|
985
|
-
this.state.instanceNonce += 1n;
|
|
986
|
-
return `${instancePrefix}${this.state.instanceNonce}`;
|
|
987
|
-
},
|
|
988
|
-
async onListen(port, localAddr, listenHandler, _protocolHandler) {
|
|
989
|
-
const { listeners } = this.state;
|
|
990
|
-
|
|
991
|
-
// This implementation has a simple last-one-wins replacement policy.
|
|
992
|
-
// Other handlers might use different policies.
|
|
993
|
-
if (listeners.has(localAddr)) {
|
|
994
|
-
const lhandler = listeners.get(localAddr)[1];
|
|
995
|
-
if (lhandler !== listenHandler) {
|
|
996
|
-
listeners.set(localAddr, [port, listenHandler]);
|
|
997
|
-
}
|
|
998
|
-
} else {
|
|
999
|
-
listeners.init(localAddr, harden([port, listenHandler]));
|
|
1000
|
-
}
|
|
1431
|
+
protocolHandlerConnectWatcher: {
|
|
1432
|
+
onFulfilled(results) {
|
|
1433
|
+
return {
|
|
1434
|
+
remoteInstance: results[0],
|
|
1435
|
+
handler: results[1],
|
|
1436
|
+
};
|
|
1437
|
+
},
|
|
1001
1438
|
},
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
* @param {*} _protocolHandler
|
|
1007
|
-
*/
|
|
1008
|
-
async onListenRemove(port, localAddr, listenHandler, _protocolHandler) {
|
|
1009
|
-
const { listeners } = this.state;
|
|
1010
|
-
const [lport, lhandler] = listeners.get(localAddr);
|
|
1011
|
-
lport === port || Fail`Port does not match listener on ${localAddr}`;
|
|
1012
|
-
lhandler === listenHandler ||
|
|
1013
|
-
Fail`Listen handler does not match listener on ${localAddr}`;
|
|
1014
|
-
listeners.delete(localAddr);
|
|
1439
|
+
protocolHandlerInstantiateWatcher: {
|
|
1440
|
+
onFulfilled(remoteInstance) {
|
|
1441
|
+
return remoteInstance;
|
|
1442
|
+
},
|
|
1015
1443
|
},
|
|
1016
|
-
|
|
1017
|
-
|
|
1444
|
+
rethrowUnlessMissingWatcher: {
|
|
1445
|
+
onRejected(e) {
|
|
1446
|
+
rethrowUnlessMissing(e);
|
|
1447
|
+
},
|
|
1018
1448
|
},
|
|
1019
1449
|
},
|
|
1020
1450
|
);
|
|
1021
1451
|
|
|
1452
|
+
/** @param {string} [instancePrefix] */
|
|
1453
|
+
const makeLoopbackProtocolHandler = instancePrefix => {
|
|
1454
|
+
const { protocolHandler } = makeLoopbackProtocolHandlerKit(instancePrefix);
|
|
1455
|
+
return harden(protocolHandler);
|
|
1456
|
+
};
|
|
1457
|
+
|
|
1022
1458
|
return makeLoopbackProtocolHandler;
|
|
1023
1459
|
}
|
|
1460
|
+
|
|
1461
|
+
/**
|
|
1462
|
+
*
|
|
1463
|
+
* @param {import('@agoric/base-zone').Zone} zone
|
|
1464
|
+
* @param {Powers} powers
|
|
1465
|
+
*/
|
|
1466
|
+
export const preparePortAllocator = (zone, { watch }) =>
|
|
1467
|
+
zone.exoClass(
|
|
1468
|
+
'PortAllocator',
|
|
1469
|
+
M.interface('PortAllocator', {
|
|
1470
|
+
allocateCustomIBCPort: M.callWhen()
|
|
1471
|
+
.optional(M.string())
|
|
1472
|
+
.returns(Shape.Vow$(Shape.Port)),
|
|
1473
|
+
allocateICAControllerPort: M.callWhen().returns(Shape.Vow$(Shape.Port)),
|
|
1474
|
+
allocateICQControllerPort: M.callWhen().returns(Shape.Vow$(Shape.Port)),
|
|
1475
|
+
allocateCustomLocalPort: M.callWhen()
|
|
1476
|
+
.optional(M.string())
|
|
1477
|
+
.returns(Shape.Vow$(Shape.Port)),
|
|
1478
|
+
}),
|
|
1479
|
+
/**
|
|
1480
|
+
*
|
|
1481
|
+
* @param {object} opts
|
|
1482
|
+
* @param {Protocol} opts.protocol
|
|
1483
|
+
*/
|
|
1484
|
+
({ protocol }) => ({ protocol, lastICAPortNum: 0n, lastICQPortNum: 0n }),
|
|
1485
|
+
{
|
|
1486
|
+
async allocateCustomIBCPort(specifiedName = '') {
|
|
1487
|
+
const { state } = this;
|
|
1488
|
+
let localAddr = `/ibc-port/`;
|
|
1489
|
+
|
|
1490
|
+
if (specifiedName) {
|
|
1491
|
+
throwIfInvalidPortName(specifiedName);
|
|
1492
|
+
|
|
1493
|
+
localAddr = `/ibc-port/custom-${specifiedName}`;
|
|
1494
|
+
}
|
|
1495
|
+
|
|
1496
|
+
// Allocate an IBC port with a unique generated name.
|
|
1497
|
+
return watch(E(state.protocol).bindPort(localAddr));
|
|
1498
|
+
},
|
|
1499
|
+
async allocateICAControllerPort() {
|
|
1500
|
+
const { state } = this;
|
|
1501
|
+
state.lastICAPortNum += 1n;
|
|
1502
|
+
return watch(
|
|
1503
|
+
E(state.protocol).bindPort(
|
|
1504
|
+
`/ibc-port/icacontroller-${state.lastICAPortNum}`,
|
|
1505
|
+
),
|
|
1506
|
+
);
|
|
1507
|
+
},
|
|
1508
|
+
async allocateICQControllerPort() {
|
|
1509
|
+
const { state } = this;
|
|
1510
|
+
state.lastICQPortNum += 1n;
|
|
1511
|
+
return watch(
|
|
1512
|
+
E(state.protocol).bindPort(
|
|
1513
|
+
`/ibc-port/icqcontroller-${state.lastICQPortNum}`,
|
|
1514
|
+
),
|
|
1515
|
+
);
|
|
1516
|
+
},
|
|
1517
|
+
async allocateCustomLocalPort(specifiedName = '') {
|
|
1518
|
+
const { state } = this;
|
|
1519
|
+
|
|
1520
|
+
let localAddr = `/local/`;
|
|
1521
|
+
|
|
1522
|
+
if (specifiedName) {
|
|
1523
|
+
throwIfInvalidPortName(specifiedName);
|
|
1524
|
+
|
|
1525
|
+
localAddr = `/local/custom-${specifiedName}`;
|
|
1526
|
+
}
|
|
1527
|
+
|
|
1528
|
+
// Allocate a local port with a unique generated name.
|
|
1529
|
+
return watch(E(state.protocol).bindPort(localAddr));
|
|
1530
|
+
},
|
|
1531
|
+
},
|
|
1532
|
+
);
|
|
1533
|
+
/** @typedef {ReturnType<ReturnType<typeof preparePortAllocator>>} PortAllocator */
|
|
1534
|
+
|
|
1535
|
+
/**
|
|
1536
|
+
* Return a package-specific singleton that pins objects until they are
|
|
1537
|
+
* explicitly unpinned or finalized. It needs to pin objects only because they
|
|
1538
|
+
* are resources that need to be released.
|
|
1539
|
+
*
|
|
1540
|
+
* The reason this functionality wasn't just baked into the other network exos
|
|
1541
|
+
* is to maintain upgrade-compatible with minimal additional changes.
|
|
1542
|
+
*
|
|
1543
|
+
* @param {import('@agoric/base-zone').Zone} zone
|
|
1544
|
+
* @param {VowTools} vowTools
|
|
1545
|
+
*/
|
|
1546
|
+
const prepareFinalizer = (zone, { watch }) => {
|
|
1547
|
+
/**
|
|
1548
|
+
* @type {MapStore<{},
|
|
1549
|
+
* { conn: Remote<Connection>, handler: Remote<Required<ConnectionHandler>>} |
|
|
1550
|
+
* { closer: Remote<{ close(): PromiseVow<any> }> }
|
|
1551
|
+
* >}
|
|
1552
|
+
*/
|
|
1553
|
+
const objToFinalizerInfo = zone.mapStore('objToFinalizerInfo');
|
|
1554
|
+
return zone.exo('NetworkFinalizer', undefined, {
|
|
1555
|
+
has(obj) {
|
|
1556
|
+
return objToFinalizerInfo.has(obj);
|
|
1557
|
+
},
|
|
1558
|
+
/**
|
|
1559
|
+
* Add a connection and handler for an `onClose` method to be called upon
|
|
1560
|
+
* finalization.
|
|
1561
|
+
* @param {Remote<Connection>} conn
|
|
1562
|
+
* @param {Remote<Required<ConnectionHandler>>} handler
|
|
1563
|
+
*/
|
|
1564
|
+
initConnection(conn, handler) {
|
|
1565
|
+
objToFinalizerInfo.init(conn, harden({ conn, handler }));
|
|
1566
|
+
},
|
|
1567
|
+
/**
|
|
1568
|
+
* Add an object with a `close` method to be called (such as an
|
|
1569
|
+
* `inboundAttempt`) upon finalization.
|
|
1570
|
+
* @param {Remote<{ close(): PromiseVow<any> }>} closer
|
|
1571
|
+
*/
|
|
1572
|
+
initCloser(closer) {
|
|
1573
|
+
objToFinalizerInfo.init(closer, harden({ closer }));
|
|
1574
|
+
},
|
|
1575
|
+
finalize(obj) {
|
|
1576
|
+
if (!objToFinalizerInfo.has(obj)) {
|
|
1577
|
+
return;
|
|
1578
|
+
}
|
|
1579
|
+
const disposeInfo = objToFinalizerInfo.get(obj);
|
|
1580
|
+
if ('conn' in disposeInfo) {
|
|
1581
|
+
// A connection+handler.
|
|
1582
|
+
const { conn, handler } = disposeInfo;
|
|
1583
|
+
objToFinalizerInfo.delete(obj);
|
|
1584
|
+
return watch(E(handler).onClose(conn, CLOSE_REASON_FINALIZER, handler));
|
|
1585
|
+
} else if ('closer' in disposeInfo) {
|
|
1586
|
+
// Just something with a `close` method.
|
|
1587
|
+
const { closer } = disposeInfo;
|
|
1588
|
+
objToFinalizerInfo.delete(obj);
|
|
1589
|
+
return watch(E(closer).close());
|
|
1590
|
+
}
|
|
1591
|
+
},
|
|
1592
|
+
unpin(obj) {
|
|
1593
|
+
objToFinalizerInfo.delete(obj);
|
|
1594
|
+
},
|
|
1595
|
+
});
|
|
1596
|
+
};
|
|
1597
|
+
harden(prepareFinalizer);
|
|
1598
|
+
|
|
1599
|
+
/**
|
|
1600
|
+
* @param {import('@agoric/base-zone').Zone} zone
|
|
1601
|
+
* @param {VowTools} vowTools
|
|
1602
|
+
* @returns {Powers}
|
|
1603
|
+
*/
|
|
1604
|
+
export const prepareNetworkPowers = (zone, vowTools) => {
|
|
1605
|
+
const finalizer = prepareFinalizer(zone, vowTools);
|
|
1606
|
+
return harden({ ...vowTools, finalizer });
|
|
1607
|
+
};
|
|
1608
|
+
|
|
1609
|
+
/** @typedef {ReturnType<typeof prepareFinalizer>} Finalizer */
|