@matter/protocol 0.12.4-alpha.0-20250223-1e0341a1a → 0.12.4-alpha.0-20250224-e0964a795
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/action/client/ClientInteraction.d.ts +38 -0
- package/dist/cjs/action/client/ClientInteraction.d.ts.map +1 -0
- package/dist/cjs/action/client/ClientInteraction.js +91 -0
- package/dist/cjs/action/client/ClientInteraction.js.map +6 -0
- package/dist/cjs/action/client/index.d.ts +7 -0
- package/dist/cjs/action/client/index.d.ts.map +1 -0
- package/dist/cjs/action/client/index.js +24 -0
- package/dist/cjs/action/client/index.js.map +6 -0
- package/dist/cjs/action/index.d.ts +1 -0
- package/dist/cjs/action/index.d.ts.map +1 -1
- package/dist/cjs/action/index.js +1 -0
- package/dist/cjs/action/index.js.map +1 -1
- package/dist/cjs/interaction/DecodedDataReport.d.ts +15 -0
- package/dist/cjs/interaction/DecodedDataReport.d.ts.map +1 -0
- package/dist/cjs/interaction/DecodedDataReport.js +42 -0
- package/dist/cjs/interaction/DecodedDataReport.js.map +6 -0
- package/dist/cjs/interaction/InteractionClient.d.ts +13 -23
- package/dist/cjs/interaction/InteractionClient.d.ts.map +1 -1
- package/dist/cjs/interaction/InteractionClient.js +99 -127
- package/dist/cjs/interaction/InteractionClient.js.map +1 -1
- package/dist/cjs/interaction/InteractionMessenger.d.ts +94 -1
- package/dist/cjs/interaction/InteractionMessenger.d.ts.map +1 -1
- package/dist/cjs/interaction/InteractionMessenger.js +56 -37
- package/dist/cjs/interaction/InteractionMessenger.js.map +1 -1
- package/dist/cjs/interaction/InteractionServer.d.ts +4 -2
- package/dist/cjs/interaction/InteractionServer.d.ts.map +1 -1
- package/dist/cjs/interaction/InteractionServer.js +12 -4
- package/dist/cjs/interaction/InteractionServer.js.map +1 -1
- package/dist/cjs/interaction/SubscriptionClient.d.ts +38 -0
- package/dist/cjs/interaction/SubscriptionClient.d.ts.map +1 -0
- package/dist/cjs/interaction/SubscriptionClient.js +98 -0
- package/dist/cjs/interaction/SubscriptionClient.js.map +6 -0
- package/dist/cjs/interaction/index.d.ts +1 -0
- package/dist/cjs/interaction/index.d.ts.map +1 -1
- package/dist/cjs/interaction/index.js +1 -0
- package/dist/cjs/interaction/index.js.map +1 -1
- package/dist/cjs/peer/ControllerCommissioner.d.ts +2 -2
- package/dist/cjs/peer/ControllerCommissioner.d.ts.map +1 -1
- package/dist/cjs/peer/ControllerCommissioner.js +4 -3
- package/dist/cjs/peer/ControllerCommissioner.js.map +1 -1
- package/dist/cjs/peer/InteractionQueue.d.ts +11 -0
- package/dist/cjs/peer/InteractionQueue.d.ts.map +1 -0
- package/dist/cjs/peer/InteractionQueue.js +42 -0
- package/dist/cjs/peer/InteractionQueue.js.map +6 -0
- package/dist/cjs/peer/PeerAddressStore.d.ts +1 -1
- package/dist/cjs/peer/PeerAddressStore.d.ts.map +1 -1
- package/dist/cjs/peer/PeerSet.d.ts +16 -7
- package/dist/cjs/peer/PeerSet.d.ts.map +1 -1
- package/dist/cjs/peer/PeerSet.js +58 -61
- package/dist/cjs/peer/PeerSet.js.map +1 -1
- package/dist/cjs/peer/PhysicalDeviceProperties.d.ts +26 -0
- package/dist/cjs/peer/PhysicalDeviceProperties.d.ts.map +1 -0
- package/dist/cjs/peer/PhysicalDeviceProperties.js +74 -0
- package/dist/cjs/peer/PhysicalDeviceProperties.js.map +6 -0
- package/dist/cjs/peer/index.d.ts +1 -0
- package/dist/cjs/peer/index.d.ts.map +1 -1
- package/dist/cjs/peer/index.js +1 -0
- package/dist/cjs/peer/index.js.map +1 -1
- package/dist/cjs/protocol/ExchangeManager.d.ts +1 -0
- package/dist/cjs/protocol/ExchangeManager.d.ts.map +1 -1
- package/dist/cjs/protocol/ExchangeManager.js +6 -3
- package/dist/cjs/protocol/ExchangeManager.js.map +1 -1
- package/dist/cjs/protocol/ExchangeProvider.d.ts +13 -1
- package/dist/cjs/protocol/ExchangeProvider.d.ts.map +1 -1
- package/dist/cjs/protocol/ExchangeProvider.js +2 -0
- package/dist/cjs/protocol/ExchangeProvider.js.map +1 -1
- package/dist/cjs/protocol/ProtocolHandler.d.ts +1 -1
- package/dist/cjs/protocol/ProtocolHandler.d.ts.map +1 -1
- package/dist/cjs/securechannel/SecureChannelProtocol.d.ts +1 -1
- package/dist/cjs/securechannel/SecureChannelProtocol.d.ts.map +1 -1
- package/dist/cjs/securechannel/SecureChannelProtocol.js +1 -3
- package/dist/cjs/securechannel/SecureChannelProtocol.js.map +1 -1
- package/dist/cjs/session/SessionManager.d.ts.map +1 -1
- package/dist/cjs/session/SessionManager.js +1 -0
- package/dist/cjs/session/SessionManager.js.map +1 -1
- package/dist/cjs/session/case/CaseServer.d.ts +1 -1
- package/dist/cjs/session/case/CaseServer.d.ts.map +1 -1
- package/dist/cjs/session/case/CaseServer.js +1 -3
- package/dist/cjs/session/case/CaseServer.js.map +1 -1
- package/dist/cjs/session/pase/PaseServer.d.ts +2 -3
- package/dist/cjs/session/pase/PaseServer.d.ts.map +1 -1
- package/dist/cjs/session/pase/PaseServer.js +12 -14
- package/dist/cjs/session/pase/PaseServer.js.map +1 -1
- package/dist/esm/action/client/ClientInteraction.d.ts +38 -0
- package/dist/esm/action/client/ClientInteraction.d.ts.map +1 -0
- package/dist/esm/action/client/ClientInteraction.js +71 -0
- package/dist/esm/action/client/ClientInteraction.js.map +6 -0
- package/dist/esm/action/client/index.d.ts +7 -0
- package/dist/esm/action/client/index.d.ts.map +1 -0
- package/dist/esm/action/client/index.js +7 -0
- package/dist/esm/action/client/index.js.map +6 -0
- package/dist/esm/action/index.d.ts +1 -0
- package/dist/esm/action/index.d.ts.map +1 -1
- package/dist/esm/action/index.js +1 -0
- package/dist/esm/action/index.js.map +1 -1
- package/dist/esm/interaction/DecodedDataReport.d.ts +15 -0
- package/dist/esm/interaction/DecodedDataReport.d.ts.map +1 -0
- package/dist/esm/interaction/DecodedDataReport.js +22 -0
- package/dist/esm/interaction/DecodedDataReport.js.map +6 -0
- package/dist/esm/interaction/InteractionClient.d.ts +13 -23
- package/dist/esm/interaction/InteractionClient.d.ts.map +1 -1
- package/dist/esm/interaction/InteractionClient.js +101 -134
- package/dist/esm/interaction/InteractionClient.js.map +1 -1
- package/dist/esm/interaction/InteractionMessenger.d.ts +94 -1
- package/dist/esm/interaction/InteractionMessenger.d.ts.map +1 -1
- package/dist/esm/interaction/InteractionMessenger.js +56 -37
- package/dist/esm/interaction/InteractionMessenger.js.map +1 -1
- package/dist/esm/interaction/InteractionServer.d.ts +4 -2
- package/dist/esm/interaction/InteractionServer.d.ts.map +1 -1
- package/dist/esm/interaction/InteractionServer.js +12 -4
- package/dist/esm/interaction/InteractionServer.js.map +1 -1
- package/dist/esm/interaction/SubscriptionClient.d.ts +38 -0
- package/dist/esm/interaction/SubscriptionClient.d.ts.map +1 -0
- package/dist/esm/interaction/SubscriptionClient.js +78 -0
- package/dist/esm/interaction/SubscriptionClient.js.map +6 -0
- package/dist/esm/interaction/index.d.ts +1 -0
- package/dist/esm/interaction/index.d.ts.map +1 -1
- package/dist/esm/interaction/index.js +1 -0
- package/dist/esm/interaction/index.js.map +1 -1
- package/dist/esm/peer/ControllerCommissioner.d.ts +2 -2
- package/dist/esm/peer/ControllerCommissioner.d.ts.map +1 -1
- package/dist/esm/peer/ControllerCommissioner.js +6 -5
- package/dist/esm/peer/ControllerCommissioner.js.map +1 -1
- package/dist/esm/peer/InteractionQueue.d.ts +11 -0
- package/dist/esm/peer/InteractionQueue.d.ts.map +1 -0
- package/dist/esm/peer/InteractionQueue.js +22 -0
- package/dist/esm/peer/InteractionQueue.js.map +6 -0
- package/dist/esm/peer/PeerAddressStore.d.ts +1 -1
- package/dist/esm/peer/PeerAddressStore.d.ts.map +1 -1
- package/dist/esm/peer/PeerSet.d.ts +16 -7
- package/dist/esm/peer/PeerSet.d.ts.map +1 -1
- package/dist/esm/peer/PeerSet.js +59 -62
- package/dist/esm/peer/PeerSet.js.map +1 -1
- package/dist/esm/peer/PhysicalDeviceProperties.d.ts +26 -0
- package/dist/esm/peer/PhysicalDeviceProperties.d.ts.map +1 -0
- package/dist/esm/peer/PhysicalDeviceProperties.js +54 -0
- package/dist/esm/peer/PhysicalDeviceProperties.js.map +6 -0
- package/dist/esm/peer/index.d.ts +1 -0
- package/dist/esm/peer/index.d.ts.map +1 -1
- package/dist/esm/peer/index.js +1 -0
- package/dist/esm/peer/index.js.map +1 -1
- package/dist/esm/protocol/ExchangeManager.d.ts +1 -0
- package/dist/esm/protocol/ExchangeManager.d.ts.map +1 -1
- package/dist/esm/protocol/ExchangeManager.js +6 -3
- package/dist/esm/protocol/ExchangeManager.js.map +1 -1
- package/dist/esm/protocol/ExchangeProvider.d.ts +13 -1
- package/dist/esm/protocol/ExchangeProvider.d.ts.map +1 -1
- package/dist/esm/protocol/ExchangeProvider.js +2 -0
- package/dist/esm/protocol/ExchangeProvider.js.map +1 -1
- package/dist/esm/protocol/ProtocolHandler.d.ts +1 -1
- package/dist/esm/protocol/ProtocolHandler.d.ts.map +1 -1
- package/dist/esm/securechannel/SecureChannelProtocol.d.ts +1 -1
- package/dist/esm/securechannel/SecureChannelProtocol.d.ts.map +1 -1
- package/dist/esm/securechannel/SecureChannelProtocol.js +1 -3
- package/dist/esm/securechannel/SecureChannelProtocol.js.map +1 -1
- package/dist/esm/session/SessionManager.d.ts.map +1 -1
- package/dist/esm/session/SessionManager.js +1 -0
- package/dist/esm/session/SessionManager.js.map +1 -1
- package/dist/esm/session/case/CaseServer.d.ts +1 -1
- package/dist/esm/session/case/CaseServer.d.ts.map +1 -1
- package/dist/esm/session/case/CaseServer.js +1 -3
- package/dist/esm/session/case/CaseServer.js.map +1 -1
- package/dist/esm/session/pase/PaseServer.d.ts +2 -3
- package/dist/esm/session/pase/PaseServer.d.ts.map +1 -1
- package/dist/esm/session/pase/PaseServer.js +12 -14
- package/dist/esm/session/pase/PaseServer.js.map +1 -1
- package/package.json +6 -6
- package/src/action/client/ClientInteraction.ts +110 -0
- package/src/action/client/index.ts +7 -0
- package/src/action/index.ts +1 -0
- package/src/interaction/DecodedDataReport.ts +29 -0
- package/src/interaction/InteractionClient.ts +112 -164
- package/src/interaction/InteractionMessenger.ts +63 -43
- package/src/interaction/InteractionServer.ts +18 -5
- package/src/interaction/SubscriptionClient.ts +107 -0
- package/src/interaction/index.ts +1 -0
- package/src/peer/ControllerCommissioner.ts +7 -6
- package/src/peer/InteractionQueue.ts +22 -0
- package/src/peer/PeerAddressStore.ts +1 -1
- package/src/peer/PeerSet.ts +69 -76
- package/src/peer/PhysicalDeviceProperties.ts +80 -0
- package/src/peer/index.ts +1 -0
- package/src/protocol/ExchangeManager.ts +7 -3
- package/src/protocol/ExchangeProvider.ts +14 -1
- package/src/protocol/ProtocolHandler.ts +1 -1
- package/src/securechannel/SecureChannelProtocol.ts +1 -3
- package/src/session/SessionManager.ts +1 -0
- package/src/session/case/CaseServer.ts +2 -4
- package/src/session/pase/PaseServer.ts +13 -15
package/src/peer/PeerSet.ts
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
import { DiscoveryData, ScannerSet } from "#common/Scanner.js";
|
|
8
8
|
import {
|
|
9
9
|
anyPromise,
|
|
10
|
+
AsyncObservable,
|
|
10
11
|
BasicSet,
|
|
11
12
|
ChannelType,
|
|
12
13
|
Construction,
|
|
@@ -22,13 +23,12 @@ import {
|
|
|
22
23
|
NetInterfaceSet,
|
|
23
24
|
NoResponseTimeoutError,
|
|
24
25
|
ObservableSet,
|
|
25
|
-
PromiseQueue,
|
|
26
26
|
ServerAddressIp,
|
|
27
27
|
serverAddressToString,
|
|
28
28
|
Time,
|
|
29
29
|
Timer,
|
|
30
30
|
} from "#general";
|
|
31
|
-
import {
|
|
31
|
+
import { SubscriptionClient } from "#interaction/SubscriptionClient.js";
|
|
32
32
|
import { MdnsScanner } from "#mdns/MdnsScanner.js";
|
|
33
33
|
import { PeerAddress, PeerAddressMap } from "#peer/PeerAddress.js";
|
|
34
34
|
import { CaseClient, SecureSession, Session } from "#session/index.js";
|
|
@@ -39,6 +39,7 @@ import { ChannelNotConnectedError, ExchangeManager, MessageChannel } from "../pr
|
|
|
39
39
|
import { ReconnectableExchangeProvider } from "../protocol/ExchangeProvider.js";
|
|
40
40
|
import { RetransmissionLimitReachedError } from "../protocol/MessageExchange.js";
|
|
41
41
|
import { ControllerDiscovery, DiscoveryError, PairRetransmissionLimitReachedError } from "./ControllerDiscovery.js";
|
|
42
|
+
import { InteractionQueue } from "./InteractionQueue.js";
|
|
42
43
|
import { OperationalPeer } from "./OperationalPeer.js";
|
|
43
44
|
import { PeerAddressStore, PeerDataStore } from "./PeerAddressStore.js";
|
|
44
45
|
|
|
@@ -47,9 +48,6 @@ const logger = Logger.get("PeerSet");
|
|
|
47
48
|
const RECONNECTION_POLLING_INTERVAL_MS = 600_000; // 10 minutes
|
|
48
49
|
const RETRANSMISSION_DISCOVERY_TIMEOUT_S = 5;
|
|
49
50
|
|
|
50
|
-
const CONCURRENT_QUEUED_INTERACTIONS = 4;
|
|
51
|
-
const INTERACTION_QUEUE_DELAY_MS = 100;
|
|
52
|
-
|
|
53
51
|
/**
|
|
54
52
|
* Types of discovery that may be performed when connecting operationally.
|
|
55
53
|
*/
|
|
@@ -93,6 +91,7 @@ export interface PeerSetContext {
|
|
|
93
91
|
sessions: SessionManager;
|
|
94
92
|
channels: ChannelManager;
|
|
95
93
|
exchanges: ExchangeManager;
|
|
94
|
+
subscriptionClient: SubscriptionClient;
|
|
96
95
|
scanners: ScannerSet;
|
|
97
96
|
netInterfaces: NetInterfaceSet;
|
|
98
97
|
store: PeerAddressStore;
|
|
@@ -105,6 +104,7 @@ export class PeerSet implements ImmutableSet<OperationalPeer>, ObservableSet<Ope
|
|
|
105
104
|
readonly #sessions: SessionManager;
|
|
106
105
|
readonly #channels: ChannelManager;
|
|
107
106
|
readonly #exchanges: ExchangeManager;
|
|
107
|
+
readonly #subscriptionClient: SubscriptionClient;
|
|
108
108
|
readonly #scanners: ScannerSet;
|
|
109
109
|
readonly #netInterfaces: NetInterfaceSet;
|
|
110
110
|
readonly #caseClient: CaseClient;
|
|
@@ -117,16 +117,17 @@ export class PeerSet implements ImmutableSet<OperationalPeer>, ObservableSet<Ope
|
|
|
117
117
|
}>();
|
|
118
118
|
readonly #construction: Construction<PeerSet>;
|
|
119
119
|
readonly #store: PeerAddressStore;
|
|
120
|
-
readonly #interactionQueue = new
|
|
120
|
+
readonly #interactionQueue = new InteractionQueue();
|
|
121
121
|
readonly #nodeCachedData = new PeerAddressMap<PeerDataStore>(); // Temporarily until we store it in new API
|
|
122
|
-
readonly #
|
|
122
|
+
readonly #disconnected = AsyncObservable<[address: PeerAddress]>();
|
|
123
123
|
|
|
124
124
|
constructor(context: PeerSetContext) {
|
|
125
|
-
const { sessions, channels, exchanges, scanners, netInterfaces, store } = context;
|
|
125
|
+
const { sessions, channels, exchanges, subscriptionClient, scanners, netInterfaces, store } = context;
|
|
126
126
|
|
|
127
127
|
this.#sessions = sessions;
|
|
128
128
|
this.#channels = channels;
|
|
129
129
|
this.#exchanges = exchanges;
|
|
130
|
+
this.#subscriptionClient = subscriptionClient;
|
|
130
131
|
this.#scanners = scanners;
|
|
131
132
|
this.#netInterfaces = netInterfaces;
|
|
132
133
|
this.#store = store;
|
|
@@ -165,6 +166,10 @@ export class PeerSet implements ImmutableSet<OperationalPeer>, ObservableSet<Ope
|
|
|
165
166
|
return this.#peers.deleted;
|
|
166
167
|
}
|
|
167
168
|
|
|
169
|
+
get disconnected() {
|
|
170
|
+
return this.#disconnected;
|
|
171
|
+
}
|
|
172
|
+
|
|
168
173
|
has(item: PeerAddress | OperationalPeer) {
|
|
169
174
|
if ("address" in item) {
|
|
170
175
|
return this.#peers.has(item);
|
|
@@ -201,6 +206,7 @@ export class PeerSet implements ImmutableSet<OperationalPeer>, ObservableSet<Ope
|
|
|
201
206
|
sessions: env.get(SessionManager),
|
|
202
207
|
channels: env.get(ChannelManager),
|
|
203
208
|
exchanges: env.get(ExchangeManager),
|
|
209
|
+
subscriptionClient: env.get(SubscriptionClient),
|
|
204
210
|
scanners: env.get(ScannerSet),
|
|
205
211
|
netInterfaces: env.get(NetInterfaceSet),
|
|
206
212
|
store: env.get(PeerAddressStore),
|
|
@@ -213,20 +219,18 @@ export class PeerSet implements ImmutableSet<OperationalPeer>, ObservableSet<Ope
|
|
|
213
219
|
return this.#peers;
|
|
214
220
|
}
|
|
215
221
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
async connect(
|
|
220
|
-
address: PeerAddress,
|
|
221
|
-
discoveryOptions: DiscoveryOptions,
|
|
222
|
-
allowUnknownPeer = false,
|
|
223
|
-
): Promise<InteractionClient> {
|
|
224
|
-
await this.#ensureConnection(address, discoveryOptions, allowUnknownPeer);
|
|
222
|
+
get subscriptionClient() {
|
|
223
|
+
return this.#subscriptionClient;
|
|
224
|
+
}
|
|
225
225
|
|
|
226
|
-
|
|
226
|
+
get interactionQueue() {
|
|
227
|
+
return this.#interactionQueue;
|
|
227
228
|
}
|
|
228
229
|
|
|
229
|
-
|
|
230
|
+
/**
|
|
231
|
+
* Ensure there is a channel to the designated peer.
|
|
232
|
+
*/
|
|
233
|
+
async ensureConnection(address: PeerAddress, discoveryOptions: DiscoveryOptions, allowUnknownPeer = false) {
|
|
230
234
|
if (!this.#peersByAddress.has(address) && !allowUnknownPeer) {
|
|
231
235
|
throw new UnknownNodeError(`Cannot connect to unknown device ${PeerAddress(address)}`);
|
|
232
236
|
}
|
|
@@ -256,62 +260,44 @@ export class PeerSet implements ImmutableSet<OperationalPeer>, ObservableSet<Ope
|
|
|
256
260
|
}
|
|
257
261
|
}
|
|
258
262
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
const nodeStore = this.get(address)?.dataStore;
|
|
266
|
-
await nodeStore?.construction; // Lazy initialize the data if not already done
|
|
267
|
-
|
|
263
|
+
/**
|
|
264
|
+
* Obtain an exchange provider for the designated peer.
|
|
265
|
+
*/
|
|
266
|
+
async exchangeProviderFor(address: PeerAddress, discoveryOptions?: DiscoveryOptions) {
|
|
268
267
|
let initiallyConnected = this.#channels.hasChannel(address);
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
return;
|
|
277
|
-
}
|
|
268
|
+
return new ReconnectableExchangeProvider(this.#exchanges, this.#channels, address, async () => {
|
|
269
|
+
if (!initiallyConnected && !this.#channels.hasChannel(address)) {
|
|
270
|
+
// We got an uninitialized node, so do the first connection as usual
|
|
271
|
+
await this.ensureConnection(address, { discoveryType: NodeDiscoveryType.None });
|
|
272
|
+
initiallyConnected = true; // We only do this connection once, rest is handled in following code
|
|
273
|
+
if (this.#channels.hasChannel(address)) {
|
|
274
|
+
return;
|
|
278
275
|
}
|
|
276
|
+
}
|
|
279
277
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
}
|
|
285
|
-
await this.#channels.removeAllNodeChannels(address);
|
|
278
|
+
if (!this.#channels.hasChannel(address)) {
|
|
279
|
+
throw new RetransmissionLimitReachedError(`Device ${PeerAddress(address)} is currently not reachable.`);
|
|
280
|
+
}
|
|
281
|
+
await this.#channels.removeAllNodeChannels(address);
|
|
286
282
|
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
) {
|
|
306
|
-
throw new RetransmissionLimitReachedError(`${PeerAddress(address)} is not reachable.`);
|
|
307
|
-
}
|
|
308
|
-
}),
|
|
309
|
-
address,
|
|
310
|
-
this.#interactionQueue,
|
|
311
|
-
nodeStore,
|
|
312
|
-
);
|
|
313
|
-
this.#clients.set(address, client);
|
|
314
|
-
return client;
|
|
283
|
+
// Enrich discoveryData with data from the node store when not provided
|
|
284
|
+
const { discoveryData } = discoveryOptions ?? {
|
|
285
|
+
discoveryData: this.#peersByAddress.get(address)?.discoveryData,
|
|
286
|
+
};
|
|
287
|
+
// Try to use first result for one last try before we need to reconnect
|
|
288
|
+
const operationalAddress = this.#knownOperationalAddressFor(address, true);
|
|
289
|
+
if (operationalAddress === undefined) {
|
|
290
|
+
logger.info(
|
|
291
|
+
`Re-discovering device failed (no address found), remove all sessions for ${PeerAddress(address)}`,
|
|
292
|
+
);
|
|
293
|
+
// We remove all sessions, this also informs the PairedNode class
|
|
294
|
+
await this.#sessions.removeAllSessionsForNode(address);
|
|
295
|
+
throw new RetransmissionLimitReachedError(`No operational address found for ${PeerAddress(address)}`);
|
|
296
|
+
}
|
|
297
|
+
if ((await this.#reconnectKnownAddress(address, operationalAddress, discoveryData, 2_000)) === undefined) {
|
|
298
|
+
throw new RetransmissionLimitReachedError(`${PeerAddress(address)} is not reachable.`);
|
|
299
|
+
}
|
|
300
|
+
});
|
|
315
301
|
}
|
|
316
302
|
|
|
317
303
|
/**
|
|
@@ -327,10 +313,15 @@ export class PeerSet implements ImmutableSet<OperationalPeer>, ObservableSet<Ope
|
|
|
327
313
|
/**
|
|
328
314
|
* Terminate any active peer connection.
|
|
329
315
|
*/
|
|
330
|
-
async disconnect(
|
|
331
|
-
this
|
|
316
|
+
async disconnect(peer: PeerAddress | OperationalPeer, sendSessionClose = true) {
|
|
317
|
+
const address = this.get(peer)?.address;
|
|
318
|
+
if (address === undefined) {
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
|
|
332
322
|
await this.#sessions.removeAllSessionsForNode(address, sendSessionClose);
|
|
333
323
|
await this.#channels.removeAllNodeChannels(address);
|
|
324
|
+
await this.#disconnected.emit(address);
|
|
334
325
|
}
|
|
335
326
|
|
|
336
327
|
/**
|
|
@@ -348,7 +339,6 @@ export class PeerSet implements ImmutableSet<OperationalPeer>, ObservableSet<Ope
|
|
|
348
339
|
await this.#store.deletePeer(address);
|
|
349
340
|
await this.disconnect(address, false);
|
|
350
341
|
await this.#sessions.deleteResumptionRecord(address);
|
|
351
|
-
this.#clients.delete(address);
|
|
352
342
|
}
|
|
353
343
|
|
|
354
344
|
async close() {
|
|
@@ -358,8 +348,11 @@ export class PeerSet implements ImmutableSet<OperationalPeer>, ObservableSet<Ope
|
|
|
358
348
|
// This ends discovery without triggering promises
|
|
359
349
|
mdnsScanner?.cancelOperationalDeviceDiscovery(this.#sessions.fabricFor(address), address.nodeId, false);
|
|
360
350
|
}
|
|
361
|
-
|
|
362
|
-
this.#
|
|
351
|
+
|
|
352
|
+
for (const { address } of this.#peers) {
|
|
353
|
+
await this.disconnect(address, false);
|
|
354
|
+
}
|
|
355
|
+
|
|
363
356
|
this.#interactionQueue.close();
|
|
364
357
|
this.#runningPeerReconnections.forEach(({ rejecter }) =>
|
|
365
358
|
rejecter(new ChannelNotConnectedError("PeerSet closed")),
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2022-2025 Matter.js Authors
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { Logger } from "#general";
|
|
8
|
+
|
|
9
|
+
const logger = Logger.get("PhysicalDeviceProperties");
|
|
10
|
+
|
|
11
|
+
const DEFAULT_SUBSCRIPTION_FLOOR_DEFAULT_S = 1;
|
|
12
|
+
const DEFAULT_SUBSCRIPTION_FLOOR_ICD_S = 0;
|
|
13
|
+
const DEFAULT_SUBSCRIPTION_CEILING_WIFI_S = 60;
|
|
14
|
+
const DEFAULT_SUBSCRIPTION_CEILING_THREAD_S = 60;
|
|
15
|
+
const DEFAULT_SUBSCRIPTION_CEILING_THREAD_SLEEPY_S = 180;
|
|
16
|
+
const DEFAULT_SUBSCRIPTION_CEILING_BATTERY_POWERED_S = 600;
|
|
17
|
+
|
|
18
|
+
export interface PhysicalDeviceProperties {
|
|
19
|
+
threadConnected: boolean;
|
|
20
|
+
wifiConnected: boolean;
|
|
21
|
+
ethernetConnected: boolean;
|
|
22
|
+
rootEndpointServerList: number[];
|
|
23
|
+
isBatteryPowered: boolean;
|
|
24
|
+
isIntermittentlyConnected: boolean;
|
|
25
|
+
isThreadSleepyEndDevice: boolean;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export namespace PhysicalDeviceProperties {
|
|
29
|
+
export function determineSubscriptionParameters(options?: {
|
|
30
|
+
properties?: PhysicalDeviceProperties;
|
|
31
|
+
description?: string;
|
|
32
|
+
subscribeMinIntervalFloorSeconds?: number;
|
|
33
|
+
subscribeMaxIntervalCeilingSeconds?: number;
|
|
34
|
+
}) {
|
|
35
|
+
const { properties } = options ?? {};
|
|
36
|
+
|
|
37
|
+
let {
|
|
38
|
+
description,
|
|
39
|
+
subscribeMinIntervalFloorSeconds: minIntervalFloorSeconds,
|
|
40
|
+
subscribeMaxIntervalCeilingSeconds: maxIntervalCeilingSeconds,
|
|
41
|
+
} = options ?? {};
|
|
42
|
+
|
|
43
|
+
if (description === undefined) {
|
|
44
|
+
description = "Node";
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const { isBatteryPowered, isIntermittentlyConnected, threadConnected, isThreadSleepyEndDevice } =
|
|
48
|
+
properties ?? {};
|
|
49
|
+
|
|
50
|
+
if (isIntermittentlyConnected) {
|
|
51
|
+
if (minIntervalFloorSeconds !== undefined && minIntervalFloorSeconds !== DEFAULT_SUBSCRIPTION_FLOOR_ICD_S) {
|
|
52
|
+
logger.info(
|
|
53
|
+
`${description}: Overwriting minIntervalFloorSeconds for intermittently connected device to ${DEFAULT_SUBSCRIPTION_FLOOR_ICD_S}`,
|
|
54
|
+
);
|
|
55
|
+
minIntervalFloorSeconds = DEFAULT_SUBSCRIPTION_FLOOR_ICD_S;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const defaultCeiling = isBatteryPowered
|
|
60
|
+
? DEFAULT_SUBSCRIPTION_CEILING_BATTERY_POWERED_S
|
|
61
|
+
: isThreadSleepyEndDevice
|
|
62
|
+
? DEFAULT_SUBSCRIPTION_CEILING_THREAD_SLEEPY_S
|
|
63
|
+
: threadConnected
|
|
64
|
+
? DEFAULT_SUBSCRIPTION_CEILING_THREAD_S
|
|
65
|
+
: DEFAULT_SUBSCRIPTION_CEILING_WIFI_S;
|
|
66
|
+
if (maxIntervalCeilingSeconds === undefined) {
|
|
67
|
+
maxIntervalCeilingSeconds = defaultCeiling;
|
|
68
|
+
}
|
|
69
|
+
if (maxIntervalCeilingSeconds < defaultCeiling) {
|
|
70
|
+
logger.debug(
|
|
71
|
+
`${description}: maxIntervalCeilingSeconds ideally is ${defaultCeiling}s instead of ${maxIntervalCeilingSeconds}s due to device type`,
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return {
|
|
76
|
+
minIntervalFloorSeconds: minIntervalFloorSeconds ?? DEFAULT_SUBSCRIPTION_FLOOR_DEFAULT_S,
|
|
77
|
+
maxIntervalCeilingSeconds,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
}
|
package/src/peer/index.ts
CHANGED
|
@@ -150,6 +150,10 @@ export class ExchangeManager {
|
|
|
150
150
|
return instance;
|
|
151
151
|
}
|
|
152
152
|
|
|
153
|
+
get channels() {
|
|
154
|
+
return this.#channelManager;
|
|
155
|
+
}
|
|
156
|
+
|
|
153
157
|
hasProtocolHandler(protocolId: number) {
|
|
154
158
|
return this.#protocols.has(protocolId);
|
|
155
159
|
}
|
|
@@ -159,10 +163,10 @@ export class ExchangeManager {
|
|
|
159
163
|
}
|
|
160
164
|
|
|
161
165
|
addProtocolHandler(protocol: ProtocolHandler) {
|
|
162
|
-
if (this.hasProtocolHandler(protocol.
|
|
163
|
-
throw new ImplementationError(`Handler for protocol ${protocol.
|
|
166
|
+
if (this.hasProtocolHandler(protocol.id)) {
|
|
167
|
+
throw new ImplementationError(`Handler for protocol ${protocol.id} already registered.`);
|
|
164
168
|
}
|
|
165
|
-
this.#protocols.set(protocol.
|
|
169
|
+
this.#protocols.set(protocol.id, protocol);
|
|
166
170
|
}
|
|
167
171
|
|
|
168
172
|
initiateExchange(address: PeerAddress, protocolId: number) {
|
|
@@ -12,8 +12,13 @@ import { MessageExchange } from "../protocol/MessageExchange.js";
|
|
|
12
12
|
import { ProtocolHandler } from "../protocol/ProtocolHandler.js";
|
|
13
13
|
import { Session } from "../session/Session.js";
|
|
14
14
|
|
|
15
|
+
/**
|
|
16
|
+
* Interface for obtaining an exchange with a specific peer.
|
|
17
|
+
*/
|
|
15
18
|
export abstract class ExchangeProvider {
|
|
16
|
-
|
|
19
|
+
abstract readonly supportsReconnect: boolean;
|
|
20
|
+
|
|
21
|
+
constructor(protected readonly exchangeManager: ExchangeManager) {}
|
|
17
22
|
|
|
18
23
|
hasProtocolHandler(protocolId: number) {
|
|
19
24
|
return this.exchangeManager.hasProtocolHandler(protocolId);
|
|
@@ -33,8 +38,12 @@ export abstract class ExchangeProvider {
|
|
|
33
38
|
abstract channelType: ChannelType;
|
|
34
39
|
}
|
|
35
40
|
|
|
41
|
+
/**
|
|
42
|
+
* Manages an exchange over an established channel.
|
|
43
|
+
*/
|
|
36
44
|
export class DedicatedChannelExchangeProvider extends ExchangeProvider {
|
|
37
45
|
#channel: MessageChannel;
|
|
46
|
+
readonly supportsReconnect = false;
|
|
38
47
|
|
|
39
48
|
constructor(exchangeManager: ExchangeManager, channel: MessageChannel) {
|
|
40
49
|
super(exchangeManager);
|
|
@@ -58,7 +67,11 @@ export class DedicatedChannelExchangeProvider extends ExchangeProvider {
|
|
|
58
67
|
}
|
|
59
68
|
}
|
|
60
69
|
|
|
70
|
+
/**
|
|
71
|
+
* Manages peer exchange that will reestablish automatically in the case of communication failure.
|
|
72
|
+
*/
|
|
61
73
|
export class ReconnectableExchangeProvider extends ExchangeProvider {
|
|
74
|
+
readonly supportsReconnect = true;
|
|
62
75
|
readonly #address: PeerAddress;
|
|
63
76
|
readonly #reconnectChannelFunc: () => Promise<void>;
|
|
64
77
|
readonly #channelUpdated = Observable<[void]>();
|
|
@@ -8,7 +8,7 @@ import { Message } from "../codec/MessageCodec.js";
|
|
|
8
8
|
import { MessageExchange } from "./MessageExchange.js";
|
|
9
9
|
|
|
10
10
|
export interface ProtocolHandler {
|
|
11
|
-
|
|
11
|
+
readonly id: number;
|
|
12
12
|
onNewExchange(exchange: MessageExchange, message: Message): Promise<void>;
|
|
13
13
|
close(): Promise<void>;
|
|
14
14
|
}
|
|
@@ -28,9 +28,7 @@ import { TlvSecureChannelStatusMessage } from "./SecureChannelStatusMessageSchem
|
|
|
28
28
|
const logger = Logger.get("SecureChannelProtocol");
|
|
29
29
|
|
|
30
30
|
export class StatusReportOnlySecureChannelProtocol implements ProtocolHandler {
|
|
31
|
-
|
|
32
|
-
return SECURE_CHANNEL_PROTOCOL_ID;
|
|
33
|
-
}
|
|
31
|
+
readonly id = SECURE_CHANNEL_PROTOCOL_ID;
|
|
34
32
|
|
|
35
33
|
async onNewExchange(exchange: MessageExchange, message: Message) {
|
|
36
34
|
const messageType = message.payloadHeader.messageType;
|
|
@@ -30,6 +30,8 @@ import { CaseServerMessenger } from "./CaseMessenger.js";
|
|
|
30
30
|
const logger = Logger.get("CaseServer");
|
|
31
31
|
|
|
32
32
|
export class CaseServer implements ProtocolHandler {
|
|
33
|
+
readonly id = SECURE_CHANNEL_PROTOCOL_ID;
|
|
34
|
+
|
|
33
35
|
#sessions: SessionManager;
|
|
34
36
|
#fabrics: FabricManager;
|
|
35
37
|
|
|
@@ -58,10 +60,6 @@ export class CaseServer implements ProtocolHandler {
|
|
|
58
60
|
}
|
|
59
61
|
}
|
|
60
62
|
|
|
61
|
-
getId(): number {
|
|
62
|
-
return SECURE_CHANNEL_PROTOCOL_ID;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
63
|
private async handleSigma1(messenger: CaseServerMessenger) {
|
|
66
64
|
logger.info(`Received pairing request from ${messenger.getChannelName()}`);
|
|
67
65
|
// Generate pairing info
|
|
@@ -33,8 +33,10 @@ const PASE_COMMISSIONING_MAX_ERRORS = 20;
|
|
|
33
33
|
export class MaximumPasePairingErrorsReachedError extends MatterFlowError {}
|
|
34
34
|
|
|
35
35
|
export class PaseServer implements ProtocolHandler {
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
readonly id = SECURE_CHANNEL_PROTOCOL_ID;
|
|
37
|
+
|
|
38
|
+
#pairingTimer: Timer | undefined;
|
|
39
|
+
#pairingErrors = 0;
|
|
38
40
|
|
|
39
41
|
static async fromPin(sessions: SessionManager, setupPinCode: number, pbkdfParameters: PbkdfParameters) {
|
|
40
42
|
const { w0, L } = await Spake2p.computeW0L(pbkdfParameters, setupPinCode);
|
|
@@ -58,18 +60,14 @@ export class PaseServer implements ProtocolHandler {
|
|
|
58
60
|
private readonly pbkdfParameters?: PbkdfParameters,
|
|
59
61
|
) {}
|
|
60
62
|
|
|
61
|
-
getId(): number {
|
|
62
|
-
return SECURE_CHANNEL_PROTOCOL_ID;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
63
|
async onNewExchange(exchange: MessageExchange) {
|
|
66
64
|
const messenger = new PaseServerMessenger(exchange);
|
|
67
65
|
try {
|
|
68
66
|
await this.handlePairingRequest(messenger);
|
|
69
67
|
} catch (error) {
|
|
70
|
-
this
|
|
68
|
+
this.#pairingErrors++;
|
|
71
69
|
logger.error(
|
|
72
|
-
`An error occurred during the PASE commissioning (${this
|
|
70
|
+
`An error occurred during the PASE commissioning (${this.#pairingErrors}/${PASE_COMMISSIONING_MAX_ERRORS}):`,
|
|
73
71
|
error,
|
|
74
72
|
);
|
|
75
73
|
|
|
@@ -77,7 +75,7 @@ export class PaseServer implements ProtocolHandler {
|
|
|
77
75
|
const sendError = !(error instanceof ChannelStatusResponseError);
|
|
78
76
|
await this.cancelPairing(messenger, sendError);
|
|
79
77
|
|
|
80
|
-
if (this
|
|
78
|
+
if (this.#pairingErrors >= PASE_COMMISSIONING_MAX_ERRORS) {
|
|
81
79
|
throw new MaximumPasePairingErrorsReachedError(
|
|
82
80
|
`Pase server: Too many errors during PASE commissioning, aborting commissioning window`,
|
|
83
81
|
);
|
|
@@ -99,7 +97,7 @@ export class PaseServer implements ProtocolHandler {
|
|
|
99
97
|
);
|
|
100
98
|
}
|
|
101
99
|
|
|
102
|
-
if (this
|
|
100
|
+
if (this.#pairingTimer !== undefined && this.#pairingTimer.isRunning) {
|
|
103
101
|
throw new MatterFlowError(
|
|
104
102
|
"Pase server: Pairing already in progress (PASE establishment Timer running), ignoring new exchange.",
|
|
105
103
|
);
|
|
@@ -107,7 +105,7 @@ export class PaseServer implements ProtocolHandler {
|
|
|
107
105
|
|
|
108
106
|
logger.info(`Received pairing request from ${messenger.getChannelName()}.`);
|
|
109
107
|
|
|
110
|
-
this
|
|
108
|
+
this.#pairingTimer = Time.getTimer("PASE pairing timeout", PASE_PAIRING_TIMEOUT_MS, () =>
|
|
111
109
|
this.cancelPairing(messenger),
|
|
112
110
|
).start();
|
|
113
111
|
|
|
@@ -167,13 +165,13 @@ export class PaseServer implements ProtocolHandler {
|
|
|
167
165
|
await messenger.sendSuccess();
|
|
168
166
|
await messenger.close();
|
|
169
167
|
|
|
170
|
-
this
|
|
171
|
-
this
|
|
168
|
+
this.#pairingTimer?.stop();
|
|
169
|
+
this.#pairingTimer = undefined;
|
|
172
170
|
}
|
|
173
171
|
|
|
174
172
|
async cancelPairing(messenger: PaseServerMessenger, sendError = true) {
|
|
175
|
-
this
|
|
176
|
-
this
|
|
173
|
+
this.#pairingTimer?.stop();
|
|
174
|
+
this.#pairingTimer = undefined;
|
|
177
175
|
|
|
178
176
|
if (sendError) {
|
|
179
177
|
await messenger.sendError(ProtocolStatusCode.InvalidParam);
|