@matter/protocol 0.12.4-alpha.0-20250224-e0964a795 → 0.12.4-alpha.0-20250224-46934b522
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/dist/cjs/interaction/InteractionClient.d.ts +6 -2
- package/dist/cjs/interaction/InteractionClient.d.ts.map +1 -1
- package/dist/cjs/interaction/InteractionClient.js +3 -2
- package/dist/cjs/interaction/InteractionClient.js.map +1 -1
- package/dist/cjs/interaction/InteractionServer.d.ts +18 -1
- package/dist/cjs/interaction/InteractionServer.d.ts.map +1 -1
- package/dist/cjs/interaction/InteractionServer.js +117 -41
- package/dist/cjs/interaction/InteractionServer.js.map +1 -1
- package/dist/cjs/interaction/ServerSubscription.d.ts +8 -16
- package/dist/cjs/interaction/ServerSubscription.d.ts.map +1 -1
- package/dist/cjs/interaction/ServerSubscription.js +78 -55
- package/dist/cjs/interaction/ServerSubscription.js.map +1 -1
- package/dist/cjs/interaction/Subscription.d.ts +7 -1
- package/dist/cjs/interaction/Subscription.d.ts.map +1 -1
- package/dist/cjs/interaction/Subscription.js +25 -2
- package/dist/cjs/interaction/Subscription.js.map +1 -1
- package/dist/cjs/peer/ControllerCommissioner.d.ts.map +1 -1
- package/dist/cjs/peer/ControllerCommissioner.js +4 -5
- package/dist/cjs/peer/ControllerCommissioner.js.map +1 -1
- package/dist/cjs/peer/PeerAddress.d.ts +5 -0
- package/dist/cjs/peer/PeerAddress.d.ts.map +1 -1
- package/dist/cjs/peer/PeerAddress.js +13 -1
- package/dist/cjs/peer/PeerAddress.js.map +1 -1
- package/dist/cjs/peer/PeerSet.d.ts +6 -2
- package/dist/cjs/peer/PeerSet.d.ts.map +1 -1
- package/dist/cjs/peer/PeerSet.js +18 -8
- package/dist/cjs/peer/PeerSet.js.map +1 -1
- package/dist/cjs/securechannel/SecureChannelMessenger.d.ts +1 -0
- package/dist/cjs/securechannel/SecureChannelMessenger.d.ts.map +1 -1
- package/dist/cjs/securechannel/SecureChannelMessenger.js +3 -0
- package/dist/cjs/securechannel/SecureChannelMessenger.js.map +1 -1
- package/dist/cjs/session/SecureSession.d.ts +1 -1
- package/dist/cjs/session/SecureSession.d.ts.map +1 -1
- package/dist/cjs/session/SecureSession.js +3 -2
- package/dist/cjs/session/SecureSession.js.map +1 -1
- package/dist/cjs/session/Session.d.ts +1 -0
- package/dist/cjs/session/Session.d.ts.map +1 -1
- package/dist/cjs/session/Session.js +1 -0
- package/dist/cjs/session/Session.js.map +1 -1
- package/dist/cjs/session/SessionManager.d.ts +2 -2
- package/dist/cjs/session/SessionManager.d.ts.map +1 -1
- package/dist/cjs/session/SessionManager.js +5 -9
- package/dist/cjs/session/SessionManager.js.map +1 -1
- package/dist/esm/interaction/InteractionClient.d.ts +6 -2
- package/dist/esm/interaction/InteractionClient.d.ts.map +1 -1
- package/dist/esm/interaction/InteractionClient.js +3 -2
- package/dist/esm/interaction/InteractionClient.js.map +1 -1
- package/dist/esm/interaction/InteractionServer.d.ts +18 -1
- package/dist/esm/interaction/InteractionServer.d.ts.map +1 -1
- package/dist/esm/interaction/InteractionServer.js +118 -42
- package/dist/esm/interaction/InteractionServer.js.map +1 -1
- package/dist/esm/interaction/ServerSubscription.d.ts +8 -16
- package/dist/esm/interaction/ServerSubscription.d.ts.map +1 -1
- package/dist/esm/interaction/ServerSubscription.js +78 -55
- package/dist/esm/interaction/ServerSubscription.js.map +1 -1
- package/dist/esm/interaction/Subscription.d.ts +7 -1
- package/dist/esm/interaction/Subscription.d.ts.map +1 -1
- package/dist/esm/interaction/Subscription.js +26 -3
- package/dist/esm/interaction/Subscription.js.map +1 -1
- package/dist/esm/peer/ControllerCommissioner.d.ts.map +1 -1
- package/dist/esm/peer/ControllerCommissioner.js +4 -5
- package/dist/esm/peer/ControllerCommissioner.js.map +1 -1
- package/dist/esm/peer/PeerAddress.d.ts +5 -0
- package/dist/esm/peer/PeerAddress.d.ts.map +1 -1
- package/dist/esm/peer/PeerAddress.js +13 -1
- package/dist/esm/peer/PeerAddress.js.map +1 -1
- package/dist/esm/peer/PeerSet.d.ts +6 -2
- package/dist/esm/peer/PeerSet.d.ts.map +1 -1
- package/dist/esm/peer/PeerSet.js +18 -8
- package/dist/esm/peer/PeerSet.js.map +1 -1
- package/dist/esm/securechannel/SecureChannelMessenger.d.ts +1 -0
- package/dist/esm/securechannel/SecureChannelMessenger.d.ts.map +1 -1
- package/dist/esm/securechannel/SecureChannelMessenger.js +3 -0
- package/dist/esm/securechannel/SecureChannelMessenger.js.map +1 -1
- package/dist/esm/session/SecureSession.d.ts +1 -1
- package/dist/esm/session/SecureSession.d.ts.map +1 -1
- package/dist/esm/session/SecureSession.js +3 -2
- package/dist/esm/session/SecureSession.js.map +1 -1
- package/dist/esm/session/Session.d.ts +1 -0
- package/dist/esm/session/Session.d.ts.map +1 -1
- package/dist/esm/session/Session.js +1 -0
- package/dist/esm/session/Session.js.map +1 -1
- package/dist/esm/session/SessionManager.d.ts +2 -2
- package/dist/esm/session/SessionManager.d.ts.map +1 -1
- package/dist/esm/session/SessionManager.js +6 -10
- package/dist/esm/session/SessionManager.js.map +1 -1
- package/package.json +6 -6
- package/src/interaction/InteractionClient.ts +8 -3
- package/src/interaction/InteractionServer.ts +158 -45
- package/src/interaction/ServerSubscription.ts +87 -63
- package/src/interaction/Subscription.ts +34 -6
- package/src/peer/ControllerCommissioner.ts +4 -5
- package/src/peer/PeerAddress.ts +14 -0
- package/src/peer/PeerSet.ts +31 -9
- package/src/securechannel/SecureChannelMessenger.ts +4 -0
- package/src/session/SecureSession.ts +3 -2
- package/src/session/Session.ts +1 -0
- package/src/session/SessionManager.ts +5 -9
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { Logger } from "#general";
|
|
7
|
+
import { InternalError, Logger, Observable } from "#general";
|
|
8
8
|
import { type SecureSession } from "#session/SecureSession.js";
|
|
9
9
|
import { TlvAttributePath, TlvDataVersionFilter, TlvEventFilter, TlvEventPath, TypeFromSchema } from "#types";
|
|
10
10
|
|
|
@@ -29,15 +29,13 @@ export abstract class Subscription {
|
|
|
29
29
|
#isClosed?: boolean;
|
|
30
30
|
#isCanceledByPeer?: boolean;
|
|
31
31
|
#criteria: SubscriptionCriteria;
|
|
32
|
+
#cancelled = Observable<[subscription: Subscription]>();
|
|
33
|
+
#maxIntervalMs?: number;
|
|
32
34
|
|
|
33
35
|
constructor(session: SecureSession, id: SubscriptionId, criteria: SubscriptionCriteria) {
|
|
34
36
|
this.#session = session;
|
|
35
37
|
this.#id = id;
|
|
36
38
|
this.#criteria = criteria;
|
|
37
|
-
|
|
38
|
-
// TODO Do not add to session but to node/peer
|
|
39
|
-
this.#session.subscriptions.add(this);
|
|
40
|
-
logger.debug(`Added subscription ${this.#id} to ${this.#session.name}`);
|
|
41
39
|
}
|
|
42
40
|
|
|
43
41
|
get id() {
|
|
@@ -60,6 +58,28 @@ export abstract class Subscription {
|
|
|
60
58
|
return this.#session;
|
|
61
59
|
}
|
|
62
60
|
|
|
61
|
+
get cancelled() {
|
|
62
|
+
return this.#cancelled;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
get maxIntervalMs(): number {
|
|
66
|
+
if (this.#maxIntervalMs === undefined) {
|
|
67
|
+
throw new InternalError("Subscription MaxIntervalMs accessed before it was set");
|
|
68
|
+
}
|
|
69
|
+
return this.#maxIntervalMs;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
set maxIntervalMs(value: number) {
|
|
73
|
+
if (this.#maxIntervalMs !== undefined) {
|
|
74
|
+
throw new InternalError("Subscription MaxIntervalMs set twice. This should never happen.");
|
|
75
|
+
}
|
|
76
|
+
this.#maxIntervalMs = value;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
get maxInterval(): number {
|
|
80
|
+
return Math.ceil(this.maxIntervalMs / 1000);
|
|
81
|
+
}
|
|
82
|
+
|
|
63
83
|
/**
|
|
64
84
|
* Update session state. This probably is meaningless except in a server context.
|
|
65
85
|
*/
|
|
@@ -77,7 +97,7 @@ export abstract class Subscription {
|
|
|
77
97
|
}
|
|
78
98
|
|
|
79
99
|
/** Close the subscription with the option to gracefully flush outstanding data. */
|
|
80
|
-
abstract close(graceful: boolean): Promise<void>;
|
|
100
|
+
abstract close(graceful: boolean, cancelledByPeer?: boolean): Promise<void>;
|
|
81
101
|
|
|
82
102
|
/**
|
|
83
103
|
* Destroy the subscription. Unsubscribe from all attributes and events and stop all timers.
|
|
@@ -86,5 +106,13 @@ export abstract class Subscription {
|
|
|
86
106
|
this.#isClosed = true;
|
|
87
107
|
this.#session.subscriptions.delete(this);
|
|
88
108
|
logger.debug(`Removed subscription ${this.id} from ${this.#session.name}`);
|
|
109
|
+
|
|
110
|
+
this.#cancelled.emit(this);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
protected activate() {
|
|
114
|
+
// TODO Do not add to session but to node/peer
|
|
115
|
+
this.#session.subscriptions.add(this);
|
|
116
|
+
logger.debug(`Added subscription ${this.#id} to ${this.#session.name}`);
|
|
89
117
|
}
|
|
90
118
|
}
|
|
@@ -407,15 +407,14 @@ export class ControllerCommissioner {
|
|
|
407
407
|
}
|
|
408
408
|
|
|
409
409
|
// Look for the device broadcast over MDNS and do CASE pairing
|
|
410
|
-
return await this.#context.clients.connect(
|
|
411
|
-
|
|
412
|
-
{
|
|
410
|
+
return await this.#context.clients.connect(address, {
|
|
411
|
+
discoveryOptions: {
|
|
413
412
|
discoveryType: NodeDiscoveryType.TimedDiscovery,
|
|
414
413
|
timeoutSeconds: 120,
|
|
415
414
|
discoveryData,
|
|
416
415
|
},
|
|
417
|
-
true,
|
|
418
|
-
); // Wait maximum 120s to find the operational device for commissioning process
|
|
416
|
+
allowUnknownPeer: true,
|
|
417
|
+
}); // Wait maximum 120s to find the operational device for commissioning process
|
|
419
418
|
},
|
|
420
419
|
);
|
|
421
420
|
|
package/src/peer/PeerAddress.ts
CHANGED
|
@@ -86,3 +86,17 @@ export class PeerAddressMap<T> extends Map<PeerAddress, T> {
|
|
|
86
86
|
return super.get(PeerAddress(key));
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
|
+
|
|
90
|
+
export class PeerAddressSet extends Set<PeerAddress> {
|
|
91
|
+
override add(value: PeerAddress) {
|
|
92
|
+
return super.add(PeerAddress(value));
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
override has(value: PeerAddress) {
|
|
96
|
+
return super.has(PeerAddress(value));
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
override delete(value: PeerAddress) {
|
|
100
|
+
return super.delete(PeerAddress(value));
|
|
101
|
+
}
|
|
102
|
+
}
|
package/src/peer/PeerSet.ts
CHANGED
|
@@ -144,6 +144,7 @@ export class PeerSet implements ImmutableSet<OperationalPeer>, ObservableSet<Ope
|
|
|
144
144
|
|
|
145
145
|
this.#sessions.resubmissionStarted.on(this.#handleResubmissionStarted.bind(this));
|
|
146
146
|
|
|
147
|
+
/** A channel was added by ourselves */
|
|
147
148
|
this.#channels.added.on((address, msgChannel) => {
|
|
148
149
|
if (isIpNetworkChannel(msgChannel.channel)) {
|
|
149
150
|
// Update the channel address if it has one
|
|
@@ -230,7 +231,15 @@ export class PeerSet implements ImmutableSet<OperationalPeer>, ObservableSet<Ope
|
|
|
230
231
|
/**
|
|
231
232
|
* Ensure there is a channel to the designated peer.
|
|
232
233
|
*/
|
|
233
|
-
async ensureConnection(
|
|
234
|
+
async ensureConnection(
|
|
235
|
+
address: PeerAddress,
|
|
236
|
+
options: {
|
|
237
|
+
discoveryOptions: DiscoveryOptions;
|
|
238
|
+
allowUnknownPeer?: boolean;
|
|
239
|
+
operationalAddress?: ServerAddressIp;
|
|
240
|
+
},
|
|
241
|
+
) {
|
|
242
|
+
const { discoveryOptions, allowUnknownPeer, operationalAddress } = options;
|
|
234
243
|
if (!this.#peersByAddress.has(address) && !allowUnknownPeer) {
|
|
235
244
|
throw new UnknownNodeError(`Cannot connect to unknown device ${PeerAddress(address)}`);
|
|
236
245
|
}
|
|
@@ -246,7 +255,7 @@ export class PeerSet implements ImmutableSet<OperationalPeer>, ObservableSet<Ope
|
|
|
246
255
|
const { promise, resolver, rejecter } = createPromise<MessageChannel>();
|
|
247
256
|
this.#runningPeerReconnections.set(address, { promise, rejecter });
|
|
248
257
|
|
|
249
|
-
this.#resume(address, discoveryOptions)
|
|
258
|
+
this.#resume(address, discoveryOptions, operationalAddress)
|
|
250
259
|
.then(channel => {
|
|
251
260
|
this.#runningPeerReconnections.delete(address);
|
|
252
261
|
resolver(channel);
|
|
@@ -268,7 +277,9 @@ export class PeerSet implements ImmutableSet<OperationalPeer>, ObservableSet<Ope
|
|
|
268
277
|
return new ReconnectableExchangeProvider(this.#exchanges, this.#channels, address, async () => {
|
|
269
278
|
if (!initiallyConnected && !this.#channels.hasChannel(address)) {
|
|
270
279
|
// We got an uninitialized node, so do the first connection as usual
|
|
271
|
-
await this.ensureConnection(address, {
|
|
280
|
+
await this.ensureConnection(address, {
|
|
281
|
+
discoveryOptions: { discoveryType: NodeDiscoveryType.None },
|
|
282
|
+
});
|
|
272
283
|
initiallyConnected = true; // We only do this connection once, rest is handled in following code
|
|
273
284
|
if (this.#channels.hasChannel(address)) {
|
|
274
285
|
return;
|
|
@@ -366,18 +377,22 @@ export class PeerSet implements ImmutableSet<OperationalPeer>, ObservableSet<Ope
|
|
|
366
377
|
* device is discovered again using its operational instance details.
|
|
367
378
|
* It returns the operational MessageChannel on success.
|
|
368
379
|
*/
|
|
369
|
-
async #resume(address: PeerAddress, discoveryOptions?: DiscoveryOptions) {
|
|
380
|
+
async #resume(address: PeerAddress, discoveryOptions?: DiscoveryOptions, tryOperationalAddress?: ServerAddressIp) {
|
|
370
381
|
const { discoveryType } = discoveryOptions ?? {};
|
|
382
|
+
|
|
371
383
|
const operationalAddress =
|
|
372
|
-
|
|
384
|
+
tryOperationalAddress ??
|
|
385
|
+
(discoveryType === NodeDiscoveryType.None
|
|
373
386
|
? this.#getLastOperationalAddress(address)
|
|
374
|
-
: this.#knownOperationalAddressFor(address);
|
|
387
|
+
: this.#knownOperationalAddressFor(address));
|
|
388
|
+
|
|
375
389
|
try {
|
|
376
390
|
return await this.#connectOrDiscoverNode(address, operationalAddress, discoveryOptions);
|
|
377
391
|
} catch (error) {
|
|
378
392
|
if (
|
|
379
393
|
(error instanceof DiscoveryError || error instanceof NoResponseTimeoutError) &&
|
|
380
|
-
this.#peersByAddress.has(address)
|
|
394
|
+
this.#peersByAddress.has(address) &&
|
|
395
|
+
tryOperationalAddress === undefined
|
|
381
396
|
) {
|
|
382
397
|
logger.info(`Resume failed, remove all sessions for ${PeerAddress(address)}`);
|
|
383
398
|
// We remove all sessions, this also informs the PairedNode class
|
|
@@ -432,7 +447,13 @@ export class PeerSet implements ImmutableSet<OperationalPeer>, ObservableSet<Ope
|
|
|
432
447
|
operationalAddress !== undefined &&
|
|
433
448
|
(runningDiscoveryType === NodeDiscoveryType.None || requestedDiscoveryType === NodeDiscoveryType.None)
|
|
434
449
|
) {
|
|
435
|
-
const directReconnection = await this.#reconnectKnownAddress(
|
|
450
|
+
const directReconnection = await this.#reconnectKnownAddress(
|
|
451
|
+
address,
|
|
452
|
+
operationalAddress,
|
|
453
|
+
discoveryData,
|
|
454
|
+
// When we use a timeout for discovery also use this for reconnecting to the node
|
|
455
|
+
timeoutSeconds ? timeoutSeconds * 1000 : undefined,
|
|
456
|
+
);
|
|
436
457
|
if (directReconnection !== undefined) {
|
|
437
458
|
return directReconnection;
|
|
438
459
|
}
|
|
@@ -567,6 +588,7 @@ export class PeerSet implements ImmutableSet<OperationalPeer>, ObservableSet<Ope
|
|
|
567
588
|
address = PeerAddress(address);
|
|
568
589
|
|
|
569
590
|
const { ip, port } = operationalAddress;
|
|
591
|
+
const startTime = Time.nowMs();
|
|
570
592
|
try {
|
|
571
593
|
logger.debug(
|
|
572
594
|
`Resuming connection to ${PeerAddress(address)} at ${ip}:${port}${
|
|
@@ -585,7 +607,7 @@ export class PeerSet implements ImmutableSet<OperationalPeer>, ObservableSet<Ope
|
|
|
585
607
|
error,
|
|
586
608
|
);
|
|
587
609
|
// We remove all sessions, this also informs the PairedNode class
|
|
588
|
-
await this.#sessions.removeAllSessionsForNode(address);
|
|
610
|
+
await this.#sessions.removeAllSessionsForNode(address, false, startTime);
|
|
589
611
|
return undefined;
|
|
590
612
|
} else {
|
|
591
613
|
throw error;
|
|
@@ -43,6 +43,10 @@ export class SecureChannelMessenger {
|
|
|
43
43
|
this.#defaultExpectedProcessingTimeMs = defaultExpectedProcessingTimeMs;
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
+
get channel() {
|
|
47
|
+
return this.exchange.channel;
|
|
48
|
+
}
|
|
49
|
+
|
|
46
50
|
async nextMessage(
|
|
47
51
|
expectedMessageType: number,
|
|
48
52
|
expectedProcessingTimeMs = this.#defaultExpectedProcessingTimeMs,
|
|
@@ -292,11 +292,12 @@ export class SecureSession extends Session {
|
|
|
292
292
|
return this.#fabric;
|
|
293
293
|
}
|
|
294
294
|
|
|
295
|
-
async clearSubscriptions(flushSubscriptions = false) {
|
|
295
|
+
async clearSubscriptions(flushSubscriptions = false, cancelledByPeer = false) {
|
|
296
296
|
const subscriptions = [...this.#subscriptions]; // get all values because subscriptions will remove themselves when cancelled
|
|
297
297
|
for (const subscription of subscriptions) {
|
|
298
|
-
await subscription.close(flushSubscriptions);
|
|
298
|
+
await subscription.close(flushSubscriptions, cancelledByPeer);
|
|
299
299
|
}
|
|
300
|
+
return subscriptions.length;
|
|
300
301
|
}
|
|
301
302
|
|
|
302
303
|
/** Ends a session. Outstanding subscription data will be flushed before the session is destroyed. */
|
package/src/session/Session.ts
CHANGED
|
@@ -62,6 +62,7 @@ export abstract class Session {
|
|
|
62
62
|
abstract get closingAfterExchangeFinished(): boolean;
|
|
63
63
|
#manager?: SessionManager;
|
|
64
64
|
timestamp = Time.nowMs();
|
|
65
|
+
readonly createdAt = Time.nowMs();
|
|
65
66
|
activeTimestamp = 0;
|
|
66
67
|
protected readonly idleIntervalMs: number;
|
|
67
68
|
protected readonly activeIntervalMs: number;
|
|
@@ -378,11 +378,12 @@ export class SessionManager {
|
|
|
378
378
|
});
|
|
379
379
|
}
|
|
380
380
|
|
|
381
|
-
async removeAllSessionsForNode(address: PeerAddress, sendClose = false) {
|
|
381
|
+
async removeAllSessionsForNode(address: PeerAddress, sendClose = false, closeBeforeCreatedTimestamp?: number) {
|
|
382
382
|
await this.#construction;
|
|
383
383
|
|
|
384
384
|
for (const session of this.#sessions) {
|
|
385
385
|
if (!session.isSecure) continue;
|
|
386
|
+
if (closeBeforeCreatedTimestamp !== undefined && session.createdAt >= closeBeforeCreatedTimestamp) continue;
|
|
386
387
|
const secureSession = session;
|
|
387
388
|
if (secureSession.peerIs(address)) {
|
|
388
389
|
await secureSession.destroy(sendClose, false);
|
|
@@ -564,17 +565,12 @@ export class SessionManager {
|
|
|
564
565
|
}
|
|
565
566
|
|
|
566
567
|
/** Clears all subscriptions for a given node and returns how many were cleared. */
|
|
567
|
-
async clearSubscriptionsForNode(
|
|
568
|
+
async clearSubscriptionsForNode(peerAddress: PeerAddress, flushSubscriptions?: boolean) {
|
|
568
569
|
let clearedCount = 0;
|
|
569
570
|
for (const session of this.#sessions) {
|
|
570
|
-
if (session.
|
|
571
|
-
|
|
571
|
+
if (PeerAddress.is(session.peerAddress, peerAddress)) {
|
|
572
|
+
clearedCount += await session.clearSubscriptions(flushSubscriptions, true);
|
|
572
573
|
}
|
|
573
|
-
if (session.peerNodeId !== nodeId) {
|
|
574
|
-
continue;
|
|
575
|
-
}
|
|
576
|
-
await session.clearSubscriptions(flushSubscriptions);
|
|
577
|
-
clearedCount++;
|
|
578
574
|
}
|
|
579
575
|
return clearedCount;
|
|
580
576
|
}
|