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