@project-chip/matter.js 0.11.0-alpha.0-20240926-407400ecb → 0.11.0-alpha.0-20241002-e7b377c34
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/CommissioningController.d.ts +17 -35
- package/dist/cjs/CommissioningController.d.ts.map +1 -1
- package/dist/cjs/CommissioningController.js +37 -5
- package/dist/cjs/CommissioningController.js.map +1 -1
- package/dist/cjs/CommissioningServer.d.ts.map +1 -1
- package/dist/cjs/CommissioningServer.js +28 -13
- package/dist/cjs/CommissioningServer.js.map +1 -1
- package/dist/cjs/MatterController.d.ts +32 -70
- package/dist/cjs/MatterController.d.ts.map +1 -1
- package/dist/cjs/MatterController.js +138 -579
- package/dist/cjs/MatterController.js.map +2 -2
- package/dist/cjs/PaseCommissioner.d.ts.map +1 -1
- package/dist/cjs/PaseCommissioner.js +9 -10
- package/dist/cjs/PaseCommissioner.js.map +2 -2
- package/dist/cjs/cluster/server/AccessControlServer.d.ts.map +1 -1
- package/dist/cjs/cluster/server/AccessControlServer.js +4 -2
- package/dist/cjs/cluster/server/AccessControlServer.js.map +1 -1
- package/dist/cjs/cluster/server/AdministratorCommissioningServer.d.ts.map +1 -1
- package/dist/cjs/cluster/server/AdministratorCommissioningServer.js +1 -1
- package/dist/cjs/cluster/server/AdministratorCommissioningServer.js.map +1 -1
- package/dist/cjs/cluster/server/ClusterServer.d.ts.map +1 -1
- package/dist/cjs/cluster/server/ClusterServer.js +3 -0
- package/dist/cjs/cluster/server/ClusterServer.js.map +1 -1
- package/dist/cjs/cluster/server/ClusterServerTypes.d.ts +5 -5
- package/dist/cjs/cluster/server/ClusterServerTypes.d.ts.map +1 -1
- package/dist/cjs/cluster/server/OperationalCredentialsServer.d.ts.map +1 -1
- package/dist/cjs/cluster/server/OperationalCredentialsServer.js +9 -10
- package/dist/cjs/cluster/server/OperationalCredentialsServer.js.map +1 -1
- package/dist/cjs/compat/interaction.d.ts +3 -2
- package/dist/cjs/compat/interaction.d.ts.map +1 -1
- package/dist/cjs/compat/interaction.js +8 -6
- package/dist/cjs/compat/interaction.js.map +1 -1
- package/dist/cjs/compat/protocol.d.ts +1 -1
- package/dist/cjs/compat/protocol.d.ts.map +1 -1
- package/dist/cjs/compat/protocol.js +1 -2
- package/dist/cjs/compat/protocol.js.map +1 -1
- package/dist/cjs/compat/securechannel.d.ts +2 -1
- package/dist/cjs/compat/securechannel.d.ts.map +1 -1
- package/dist/cjs/compat/securechannel.js +4 -3
- package/dist/cjs/compat/securechannel.js.map +1 -1
- package/dist/cjs/compat/util.d.ts +1 -1
- package/dist/cjs/compat/util.d.ts.map +1 -1
- package/dist/cjs/compat/util.js +1 -1
- package/dist/cjs/device/LegacyInteractionServer.d.ts +2 -2
- package/dist/cjs/device/LegacyInteractionServer.d.ts.map +1 -1
- package/dist/cjs/device/LegacyInteractionServer.js +3 -4
- package/dist/cjs/device/LegacyInteractionServer.js.map +1 -1
- package/dist/cjs/device/PairedNode.d.ts +1 -2
- package/dist/cjs/device/PairedNode.d.ts.map +1 -1
- package/dist/cjs/device/PairedNode.js +2 -3
- package/dist/cjs/device/PairedNode.js.map +1 -1
- package/dist/esm/CommissioningController.d.ts +17 -35
- package/dist/esm/CommissioningController.d.ts.map +1 -1
- package/dist/esm/CommissioningController.js +41 -5
- package/dist/esm/CommissioningController.js.map +1 -1
- package/dist/esm/CommissioningServer.d.ts.map +1 -1
- package/dist/esm/CommissioningServer.js +28 -13
- package/dist/esm/CommissioningServer.js.map +1 -1
- package/dist/esm/MatterController.d.ts +32 -70
- package/dist/esm/MatterController.d.ts.map +1 -1
- package/dist/esm/MatterController.js +144 -601
- package/dist/esm/MatterController.js.map +2 -2
- package/dist/esm/PaseCommissioner.d.ts.map +1 -1
- package/dist/esm/PaseCommissioner.js +12 -11
- package/dist/esm/PaseCommissioner.js.map +1 -1
- package/dist/esm/cluster/server/AccessControlServer.d.ts.map +1 -1
- package/dist/esm/cluster/server/AccessControlServer.js +4 -2
- package/dist/esm/cluster/server/AccessControlServer.js.map +1 -1
- package/dist/esm/cluster/server/AdministratorCommissioningServer.d.ts.map +1 -1
- package/dist/esm/cluster/server/AdministratorCommissioningServer.js +1 -1
- package/dist/esm/cluster/server/AdministratorCommissioningServer.js.map +1 -1
- package/dist/esm/cluster/server/ClusterServer.d.ts.map +1 -1
- package/dist/esm/cluster/server/ClusterServer.js +3 -0
- package/dist/esm/cluster/server/ClusterServer.js.map +1 -1
- package/dist/esm/cluster/server/ClusterServerTypes.d.ts +5 -5
- package/dist/esm/cluster/server/ClusterServerTypes.d.ts.map +1 -1
- package/dist/esm/cluster/server/OperationalCredentialsServer.d.ts.map +1 -1
- package/dist/esm/cluster/server/OperationalCredentialsServer.js +9 -11
- package/dist/esm/cluster/server/OperationalCredentialsServer.js.map +1 -1
- package/dist/esm/compat/interaction.d.ts +3 -2
- package/dist/esm/compat/interaction.d.ts.map +1 -1
- package/dist/esm/compat/interaction.js +14 -15
- package/dist/esm/compat/interaction.js.map +1 -1
- package/dist/esm/compat/protocol.d.ts +1 -1
- package/dist/esm/compat/protocol.d.ts.map +1 -1
- package/dist/esm/compat/protocol.js +2 -4
- package/dist/esm/compat/protocol.js.map +1 -1
- package/dist/esm/compat/securechannel.d.ts +2 -1
- package/dist/esm/compat/securechannel.d.ts.map +1 -1
- package/dist/esm/compat/securechannel.js +1 -3
- package/dist/esm/compat/securechannel.js.map +1 -1
- package/dist/esm/compat/util.d.ts +1 -1
- package/dist/esm/compat/util.d.ts.map +1 -1
- package/dist/esm/compat/util.js +2 -2
- package/dist/esm/compat/util.js.map +1 -1
- package/dist/esm/device/LegacyInteractionServer.d.ts +2 -2
- package/dist/esm/device/LegacyInteractionServer.d.ts.map +1 -1
- package/dist/esm/device/LegacyInteractionServer.js +3 -4
- package/dist/esm/device/LegacyInteractionServer.js.map +1 -1
- package/dist/esm/device/PairedNode.d.ts +1 -2
- package/dist/esm/device/PairedNode.d.ts.map +1 -1
- package/dist/esm/device/PairedNode.js +1 -1
- package/dist/esm/device/PairedNode.js.map +1 -1
- package/package.json +8 -8
- package/src/CommissioningController.ts +56 -47
- package/src/CommissioningServer.ts +27 -12
- package/src/MatterController.ts +177 -816
- package/src/PaseCommissioner.ts +11 -11
- package/src/cluster/server/AccessControlServer.ts +2 -0
- package/src/cluster/server/AdministratorCommissioningServer.ts +1 -1
- package/src/cluster/server/ClusterServer.ts +4 -0
- package/src/cluster/server/ClusterServerTypes.ts +5 -5
- package/src/cluster/server/OperationalCredentialsServer.ts +13 -13
- package/src/compat/interaction.ts +14 -13
- package/src/compat/protocol.ts +2 -3
- package/src/compat/securechannel.ts +2 -3
- package/src/compat/util.ts +1 -1
- package/src/device/LegacyInteractionServer.ts +4 -4
- package/src/device/PairedNode.ts +1 -1
|
@@ -18,13 +18,11 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
18
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
19
|
var MatterController_exports = {};
|
|
20
20
|
__export(MatterController_exports, {
|
|
21
|
-
MatterController: () => MatterController
|
|
22
|
-
NodeDiscoveryType: () => NodeDiscoveryType
|
|
21
|
+
MatterController: () => MatterController
|
|
23
22
|
});
|
|
24
23
|
module.exports = __toCommonJS(MatterController_exports);
|
|
25
24
|
var import_clusters = require("#clusters");
|
|
26
25
|
var import_general = require("#general");
|
|
27
|
-
var import_model = require("#model");
|
|
28
26
|
var import_protocol = require("#protocol");
|
|
29
27
|
var import_types = require("#types");
|
|
30
28
|
/**
|
|
@@ -38,21 +36,12 @@ const TlvCommissioningSuccessFailureResponse = (0, import_types.TlvObject)({
|
|
|
38
36
|
/** Should help developers in troubleshooting errors. The value MAY go into logs or crash reports, not User UIs. */
|
|
39
37
|
debugText: (0, import_types.TlvField)(1, import_types.TlvString.bound({ maxLength: 128 }))
|
|
40
38
|
});
|
|
39
|
+
const DEFAULT_ADMIN_VENDOR_ID = (0, import_types.VendorId)(65521);
|
|
41
40
|
const DEFAULT_FABRIC_INDEX = (0, import_types.FabricIndex)(1);
|
|
42
41
|
const DEFAULT_FABRIC_ID = (0, import_types.FabricId)(1);
|
|
43
|
-
const DEFAULT_ADMIN_VENDOR_ID = (0, import_types.VendorId)(65521);
|
|
44
|
-
const RECONNECTION_POLLING_INTERVAL_MS = 6e5;
|
|
45
|
-
const RETRANSMISSION_DISCOVERY_TIMEOUT_MS = 5e3;
|
|
46
42
|
const CONTROLLER_CONNECTIONS_PER_FABRIC_AND_NODE = 3;
|
|
47
43
|
const CONTROLLER_MAX_PATHS_PER_INVOKE = 10;
|
|
48
44
|
const logger = import_general.Logger.get("MatterController");
|
|
49
|
-
var NodeDiscoveryType = /* @__PURE__ */ ((NodeDiscoveryType2) => {
|
|
50
|
-
NodeDiscoveryType2[NodeDiscoveryType2["None"] = 0] = "None";
|
|
51
|
-
NodeDiscoveryType2[NodeDiscoveryType2["RetransmissionDiscovery"] = 1] = "RetransmissionDiscovery";
|
|
52
|
-
NodeDiscoveryType2[NodeDiscoveryType2["TimedDiscovery"] = 2] = "TimedDiscovery";
|
|
53
|
-
NodeDiscoveryType2[NodeDiscoveryType2["FullDiscovery"] = 3] = "FullDiscovery";
|
|
54
|
-
return NodeDiscoveryType2;
|
|
55
|
-
})(NodeDiscoveryType || {});
|
|
56
45
|
class MatterController {
|
|
57
46
|
static async create(options) {
|
|
58
47
|
const {
|
|
@@ -60,11 +49,10 @@ class MatterController {
|
|
|
60
49
|
rootCertificateStorage,
|
|
61
50
|
fabricStorage,
|
|
62
51
|
nodesStorage,
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
netInterfaceIpv6,
|
|
52
|
+
scanners,
|
|
53
|
+
netInterfaces,
|
|
66
54
|
sessionClosedCallback,
|
|
67
|
-
adminVendorId
|
|
55
|
+
adminVendorId,
|
|
68
56
|
adminFabricId = (0, import_types.FabricId)(DEFAULT_FABRIC_ID),
|
|
69
57
|
adminFabricIndex = (0, import_types.FabricIndex)(DEFAULT_FABRIC_INDEX),
|
|
70
58
|
caseAuthenticatedTags
|
|
@@ -77,18 +65,16 @@ class MatterController {
|
|
|
77
65
|
sessionStorage,
|
|
78
66
|
fabricStorage,
|
|
79
67
|
nodesStorage,
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
netInterfaceIpv6,
|
|
68
|
+
scanners,
|
|
69
|
+
netInterfaces,
|
|
83
70
|
certificateManager,
|
|
84
71
|
fabric,
|
|
85
|
-
adminVendorId: fabric.rootVendorId,
|
|
86
72
|
sessionClosedCallback
|
|
87
73
|
});
|
|
88
74
|
} else {
|
|
89
75
|
const rootNodeId = import_types.NodeId.randomOperationalNodeId();
|
|
90
76
|
const ipkValue = import_general.Crypto.getRandomData(import_general.CRYPTO_SYMMETRIC_KEY_LENGTH);
|
|
91
|
-
const fabricBuilder = new import_protocol.FabricBuilder().setRootCert(certificateManager.rootCert).setRootNodeId(rootNodeId).setIdentityProtectionKey(ipkValue).setRootVendorId(adminVendorId);
|
|
77
|
+
const fabricBuilder = new import_protocol.FabricBuilder().setRootCert(certificateManager.rootCert).setRootNodeId(rootNodeId).setIdentityProtectionKey(ipkValue).setRootVendorId(adminVendorId ?? DEFAULT_ADMIN_VENDOR_ID);
|
|
92
78
|
fabricBuilder.setOperationalCert(
|
|
93
79
|
certificateManager.generateNoc(
|
|
94
80
|
fabricBuilder.publicKey,
|
|
@@ -102,12 +88,10 @@ class MatterController {
|
|
|
102
88
|
sessionStorage,
|
|
103
89
|
fabricStorage,
|
|
104
90
|
nodesStorage,
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
netInterfaceIpv6,
|
|
91
|
+
scanners,
|
|
92
|
+
netInterfaces,
|
|
108
93
|
certificateManager,
|
|
109
94
|
fabric,
|
|
110
|
-
adminVendorId,
|
|
111
95
|
sessionClosedCallback
|
|
112
96
|
});
|
|
113
97
|
}
|
|
@@ -115,19 +99,9 @@ class MatterController {
|
|
|
115
99
|
return controller;
|
|
116
100
|
}
|
|
117
101
|
static async createAsPaseCommissioner(options) {
|
|
118
|
-
const {
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
mdnsScanner,
|
|
122
|
-
netInterfaceIpv4,
|
|
123
|
-
netInterfaceIpv6,
|
|
124
|
-
sessionClosedCallback
|
|
125
|
-
} = options;
|
|
126
|
-
try {
|
|
127
|
-
import_protocol.Ble.get();
|
|
128
|
-
} catch (error) {
|
|
129
|
-
import_general.NoProviderError.accept(error);
|
|
130
|
-
if (!mdnsScanner || !netInterfaceIpv6) {
|
|
102
|
+
const { rootCertificateData, fabricData, scanners, netInterfaces, sessionClosedCallback } = options;
|
|
103
|
+
if (!netInterfaces.hasInterfaceFor(import_general.ChannelType.BLE)) {
|
|
104
|
+
if (!scanners.hasScannerFor(import_general.ChannelType.UDP) || !netInterfaces.hasInterfaceFor(import_general.ChannelType.UDP, "::")) {
|
|
131
105
|
throw new import_general.ImplementationError(
|
|
132
106
|
"Ble must be initialized to create a Sub Commissioner without an IP network!"
|
|
133
107
|
);
|
|
@@ -143,37 +117,29 @@ class MatterController {
|
|
|
143
117
|
const controller = new MatterController({
|
|
144
118
|
sessionStorage,
|
|
145
119
|
nodesStorage,
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
netInterfaceIpv6,
|
|
120
|
+
scanners,
|
|
121
|
+
netInterfaces,
|
|
149
122
|
certificateManager,
|
|
150
123
|
fabric,
|
|
151
|
-
adminVendorId: fabric.rootVendorId,
|
|
152
124
|
sessionClosedCallback
|
|
153
125
|
});
|
|
154
126
|
await controller.construction;
|
|
155
127
|
return controller;
|
|
156
128
|
}
|
|
157
129
|
sessionManager;
|
|
130
|
+
netInterfaces = new import_general.NetInterfaceSet();
|
|
158
131
|
channelManager = new import_protocol.ChannelManager(CONTROLLER_CONNECTIONS_PER_FABRIC_AND_NODE);
|
|
159
132
|
exchangeManager;
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
netInterfaceBle;
|
|
163
|
-
bleScanner;
|
|
164
|
-
commissionedNodes = /* @__PURE__ */ new Map();
|
|
133
|
+
peers;
|
|
134
|
+
commissioner;
|
|
165
135
|
#construction;
|
|
166
136
|
sessionStorage;
|
|
167
137
|
fabricStorage;
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
netInterfaceIpv4;
|
|
171
|
-
netInterfaceIpv6;
|
|
138
|
+
nodesStore;
|
|
139
|
+
scanners;
|
|
172
140
|
certificateManager;
|
|
173
141
|
fabric;
|
|
174
|
-
adminVendorId;
|
|
175
142
|
sessionClosedCallback;
|
|
176
|
-
#runningNodeDiscoveries = /* @__PURE__ */ new Map();
|
|
177
143
|
get construction() {
|
|
178
144
|
return this.#construction;
|
|
179
145
|
}
|
|
@@ -182,48 +148,57 @@ class MatterController {
|
|
|
182
148
|
sessionStorage,
|
|
183
149
|
fabricStorage,
|
|
184
150
|
nodesStorage,
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
netInterfaceIpv6,
|
|
151
|
+
scanners,
|
|
152
|
+
netInterfaces,
|
|
188
153
|
certificateManager,
|
|
189
154
|
fabric,
|
|
190
|
-
sessionClosedCallback
|
|
191
|
-
adminVendorId
|
|
155
|
+
sessionClosedCallback
|
|
192
156
|
} = options;
|
|
193
157
|
this.sessionStorage = sessionStorage;
|
|
194
158
|
this.fabricStorage = fabricStorage;
|
|
195
|
-
this.
|
|
196
|
-
this.
|
|
197
|
-
this.netInterfaceIpv4 = netInterfaceIpv4;
|
|
198
|
-
this.netInterfaceIpv6 = netInterfaceIpv6;
|
|
159
|
+
this.scanners = scanners;
|
|
160
|
+
this.netInterfaces = netInterfaces;
|
|
199
161
|
this.certificateManager = certificateManager;
|
|
200
162
|
this.fabric = fabric;
|
|
201
163
|
this.sessionClosedCallback = sessionClosedCallback;
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
this.sessionManager
|
|
205
|
-
|
|
206
|
-
|
|
164
|
+
const fabricManager = new import_protocol.FabricManager();
|
|
165
|
+
fabricManager.addFabric(fabric);
|
|
166
|
+
this.sessionManager = new import_protocol.SessionManager({
|
|
167
|
+
fabrics: fabricManager,
|
|
168
|
+
storage: sessionStorage,
|
|
169
|
+
parameters: {
|
|
170
|
+
maxPathsPerInvoke: CONTROLLER_MAX_PATHS_PER_INVOKE
|
|
207
171
|
}
|
|
172
|
+
});
|
|
173
|
+
this.sessionManager.sessions.deleted.on(async (session) => {
|
|
208
174
|
this.sessionClosedCallback?.(session.peerNodeId);
|
|
209
175
|
});
|
|
210
|
-
this.exchangeManager = new import_protocol.ExchangeManager(
|
|
176
|
+
this.exchangeManager = new import_protocol.ExchangeManager({
|
|
177
|
+
sessionManager: this.sessionManager,
|
|
178
|
+
channelManager: this.channelManager,
|
|
179
|
+
transportInterfaces: this.netInterfaces
|
|
180
|
+
});
|
|
211
181
|
this.exchangeManager.addProtocolHandler(new import_protocol.StatusReportOnlySecureChannelProtocol());
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
this.
|
|
217
|
-
|
|
182
|
+
this.nodesStore = new CommissionedNodeStore(nodesStorage, fabric);
|
|
183
|
+
this.nodesStore.peers = this.peers = new import_protocol.PeerSet({
|
|
184
|
+
sessions: this.sessionManager,
|
|
185
|
+
channels: this.channelManager,
|
|
186
|
+
exchanges: this.exchangeManager,
|
|
187
|
+
scanners: this.scanners,
|
|
188
|
+
netInterfaces: this.netInterfaces,
|
|
189
|
+
store: this.nodesStore
|
|
190
|
+
});
|
|
191
|
+
this.commissioner = new import_protocol.ControllerCommissioner({
|
|
192
|
+
peers: this.peers,
|
|
193
|
+
scanners: this.scanners,
|
|
194
|
+
netInterfaces: this.netInterfaces,
|
|
195
|
+
exchanges: this.exchangeManager,
|
|
196
|
+
sessions: this.sessionManager,
|
|
197
|
+
certificates: this.certificateManager
|
|
198
|
+
});
|
|
218
199
|
this.#construction = (0, import_general.Construction)(this, async () => {
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
this.commissionedNodes.clear();
|
|
222
|
-
for (const [nodeId, details] of commissionedNodes) {
|
|
223
|
-
this.commissionedNodes.set(nodeId, details);
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
await this.sessionManager.initFromStorage([this.fabric]);
|
|
200
|
+
await this.peers.construction.ready;
|
|
201
|
+
await this.sessionManager.construction.ready;
|
|
227
202
|
});
|
|
228
203
|
}
|
|
229
204
|
get nodeId() {
|
|
@@ -238,44 +213,10 @@ class MatterController {
|
|
|
238
213
|
getFabrics() {
|
|
239
214
|
return [this.fabric];
|
|
240
215
|
}
|
|
241
|
-
/** Our own client/controller session parameters. */
|
|
242
|
-
get sessionParameters() {
|
|
243
|
-
return {
|
|
244
|
-
idleIntervalMs: import_protocol.SESSION_IDLE_INTERVAL_MS,
|
|
245
|
-
activeIntervalMs: import_protocol.SESSION_ACTIVE_INTERVAL_MS,
|
|
246
|
-
activeThresholdMs: import_protocol.SESSION_ACTIVE_THRESHOLD_MS,
|
|
247
|
-
dataModelRevision: import_model.Specification.DATA_MODEL_REVISION,
|
|
248
|
-
interactionModelRevision: import_model.Specification.INTERACTION_MODEL_REVISION,
|
|
249
|
-
specificationVersion: import_model.Specification.SPECIFICATION_VERSION,
|
|
250
|
-
maxPathsPerInvoke: CONTROLLER_MAX_PATHS_PER_INVOKE
|
|
251
|
-
};
|
|
252
|
-
}
|
|
253
|
-
addTransportInterface(netInterface) {
|
|
254
|
-
this.exchangeManager.addTransportInterface(netInterface);
|
|
255
|
-
}
|
|
256
216
|
collectScanners(discoveryCapabilities = { onIpNetwork: true }) {
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
}
|
|
261
|
-
if (discoveryCapabilities.ble) {
|
|
262
|
-
if (this.bleScanner === void 0) {
|
|
263
|
-
let ble;
|
|
264
|
-
try {
|
|
265
|
-
ble = import_protocol.Ble.get();
|
|
266
|
-
this.netInterfaceBle = ble.getBleCentralInterface();
|
|
267
|
-
this.addTransportInterface(this.netInterfaceBle);
|
|
268
|
-
this.bleScanner = ble.getBleScanner();
|
|
269
|
-
} catch (error) {
|
|
270
|
-
import_general.NoProviderError.accept(error);
|
|
271
|
-
logger.warn("BLE is not supported on this platform. The device to commission might not be found!");
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
if (this.bleScanner !== void 0) {
|
|
275
|
-
scannersToUse.push(this.bleScanner);
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
return scannersToUse;
|
|
217
|
+
return this.scanners.filter(
|
|
218
|
+
(scanner) => scanner.type === import_general.ChannelType.UDP || discoveryCapabilities.ble && scanner.type === import_general.ChannelType.BLE
|
|
219
|
+
);
|
|
279
220
|
}
|
|
280
221
|
/**
|
|
281
222
|
* Commission a device by its identifier and the Passcode. If a known address is provided this is tried first
|
|
@@ -289,186 +230,36 @@ class MatterController {
|
|
|
289
230
|
* Return true when the commissioning process is completed successfully, false on error.
|
|
290
231
|
*/
|
|
291
232
|
async commission(options, completeCommissioningCallback) {
|
|
292
|
-
const {
|
|
293
|
-
commissioning
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
discovery: { discoveryCapabilities = {}, knownAddress }
|
|
304
|
-
} = options;
|
|
305
|
-
let identifierData = "identifierData" in options.discovery ? options.discovery.identifierData : {};
|
|
306
|
-
if (this.mdnsScanner !== void 0 && this.netInterfaceIpv6 !== void 0) {
|
|
307
|
-
discoveryCapabilities.onIpNetwork = true;
|
|
308
|
-
}
|
|
309
|
-
if (commissionableDevice !== void 0) {
|
|
310
|
-
let { addresses } = commissionableDevice;
|
|
311
|
-
if (discoveryCapabilities.ble === true) {
|
|
312
|
-
discoveryCapabilities = { onIpNetwork: true, ble: addresses.some((address) => address.type === "ble") };
|
|
313
|
-
} else if (discoveryCapabilities.onIpNetwork === true) {
|
|
314
|
-
addresses = addresses.filter((address) => address.type !== "ble");
|
|
315
|
-
}
|
|
316
|
-
addresses.sort((a) => a.type === "udp" ? -1 : 1);
|
|
317
|
-
knownAddress = addresses[0];
|
|
318
|
-
if ("instanceId" in commissionableDevice && commissionableDevice.instanceId !== void 0) {
|
|
319
|
-
identifierData = { instanceId: commissionableDevice.instanceId };
|
|
320
|
-
} else {
|
|
321
|
-
identifierData = { longDiscriminator: commissionableDevice.D };
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
const scannersToUse = this.collectScanners(discoveryCapabilities);
|
|
325
|
-
logger.info(
|
|
326
|
-
`Commissioning device with identifier ${import_general.Logger.toJSON(identifierData)} and ${scannersToUse.length} scanners and knownAddress ${import_general.Logger.toJSON(knownAddress)}`
|
|
327
|
-
);
|
|
328
|
-
let paseSecureChannel;
|
|
329
|
-
let discoveryData;
|
|
330
|
-
if (knownAddress !== void 0) {
|
|
331
|
-
try {
|
|
332
|
-
paseSecureChannel = await this.initializePaseSecureChannel(knownAddress, passcode);
|
|
333
|
-
} catch (error) {
|
|
334
|
-
import_general.NoResponseTimeoutError.accept(error);
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
if (paseSecureChannel === void 0) {
|
|
338
|
-
const discoveredDevices = await import_protocol.ControllerDiscovery.discoverDeviceAddressesByIdentifier(
|
|
339
|
-
scannersToUse,
|
|
340
|
-
identifierData,
|
|
341
|
-
timeoutSeconds
|
|
342
|
-
);
|
|
343
|
-
const { result } = await import_protocol.ControllerDiscovery.iterateServerAddresses(
|
|
344
|
-
discoveredDevices,
|
|
345
|
-
import_general.NoResponseTimeoutError,
|
|
346
|
-
async () => scannersToUse.flatMap((scanner) => scanner.getDiscoveredCommissionableDevices(identifierData)),
|
|
347
|
-
async (address, device) => {
|
|
348
|
-
const channel = await this.initializePaseSecureChannel(address, passcode, device);
|
|
349
|
-
discoveryData = device;
|
|
350
|
-
return channel;
|
|
233
|
+
const commissioningOptions = {
|
|
234
|
+
...options.commissioning,
|
|
235
|
+
fabric: this.fabric,
|
|
236
|
+
discovery: options.discovery,
|
|
237
|
+
passcode: options.passcode
|
|
238
|
+
};
|
|
239
|
+
if (completeCommissioningCallback) {
|
|
240
|
+
commissioningOptions.performCaseCommissioning = async (peerAddress, discoveryData) => {
|
|
241
|
+
const result = await completeCommissioningCallback(peerAddress.nodeId, discoveryData);
|
|
242
|
+
if (!result) {
|
|
243
|
+
throw new import_protocol.RetransmissionLimitReachedError("Device could not be discovered");
|
|
351
244
|
}
|
|
352
|
-
|
|
353
|
-
paseSecureChannel = result;
|
|
245
|
+
};
|
|
354
246
|
}
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
discoveryData,
|
|
359
|
-
completeCommissioningCallback
|
|
360
|
-
);
|
|
247
|
+
const address = await this.commissioner.commission(commissioningOptions);
|
|
248
|
+
await this.fabricStorage?.set("fabric", this.fabric.toStorageObject());
|
|
249
|
+
return address.nodeId;
|
|
361
250
|
}
|
|
362
251
|
async disconnect(nodeId) {
|
|
363
|
-
|
|
364
|
-
await this.channelManager.removeAllNodeChannels(this.fabric, nodeId);
|
|
252
|
+
return this.peers.disconnect(this.fabric.addressOf(nodeId));
|
|
365
253
|
}
|
|
366
254
|
async removeNode(nodeId) {
|
|
367
|
-
|
|
368
|
-
await this.sessionManager.removeAllSessionsForNode(nodeId);
|
|
369
|
-
await this.sessionManager.removeResumptionRecord(nodeId);
|
|
370
|
-
await this.channelManager.removeAllNodeChannels(this.fabric, nodeId);
|
|
371
|
-
this.commissionedNodes.delete(nodeId);
|
|
372
|
-
await this.storeCommissionedNodes();
|
|
373
|
-
}
|
|
374
|
-
/**
|
|
375
|
-
* Method to start commission process with a PASE pairing.
|
|
376
|
-
* If this not successful and throws an RetransmissionLimitReachedError the address is invalid or the passcode
|
|
377
|
-
* is wrong.
|
|
378
|
-
*/
|
|
379
|
-
async initializePaseSecureChannel(address, passcode, device) {
|
|
380
|
-
let paseChannel;
|
|
381
|
-
if (device !== void 0) {
|
|
382
|
-
logger.info(`Commissioning device`, import_protocol.MdnsScanner.discoveryDataDiagnostics(device));
|
|
383
|
-
}
|
|
384
|
-
if (address.type === "udp") {
|
|
385
|
-
const { ip } = address;
|
|
386
|
-
const isIpv6Address = (0, import_general.isIPv6)(ip);
|
|
387
|
-
const paseInterface = isIpv6Address ? this.netInterfaceIpv6 : this.netInterfaceIpv4;
|
|
388
|
-
if (paseInterface === void 0) {
|
|
389
|
-
throw new import_protocol.PairRetransmissionLimitReachedError(
|
|
390
|
-
`IPv${isIpv6Address ? "6" : "4"} interface not initialized. Cannot use ${ip} for commissioning.`
|
|
391
|
-
);
|
|
392
|
-
}
|
|
393
|
-
paseChannel = await paseInterface.openChannel(address);
|
|
394
|
-
} else {
|
|
395
|
-
if (this.netInterfaceBle === void 0) {
|
|
396
|
-
throw new import_protocol.PairRetransmissionLimitReachedError(
|
|
397
|
-
`BLE interface not initialized. Cannot use ${address.peripheralAddress} for commissioning.`
|
|
398
|
-
);
|
|
399
|
-
}
|
|
400
|
-
paseChannel = await this.netInterfaceBle.openChannel(address);
|
|
401
|
-
}
|
|
402
|
-
const unsecureSession = this.sessionManager.createUnsecureSession({
|
|
403
|
-
// Use the session parameters from MDNS announcements when available and rest is assumed to be fallbacks
|
|
404
|
-
sessionParameters: {
|
|
405
|
-
idleIntervalMs: device?.SII,
|
|
406
|
-
activeIntervalMs: device?.SAI,
|
|
407
|
-
activeThresholdMs: device?.SAT
|
|
408
|
-
},
|
|
409
|
-
isInitiator: true
|
|
410
|
-
});
|
|
411
|
-
const paseUnsecureMessageChannel = new import_protocol.MessageChannel(paseChannel, unsecureSession);
|
|
412
|
-
const paseExchange = this.exchangeManager.initiateExchangeWithChannel(
|
|
413
|
-
paseUnsecureMessageChannel,
|
|
414
|
-
import_protocol.SECURE_CHANNEL_PROTOCOL_ID
|
|
415
|
-
);
|
|
416
|
-
let paseSecureSession;
|
|
417
|
-
try {
|
|
418
|
-
paseSecureSession = await this.paseClient.pair(this, paseExchange, passcode);
|
|
419
|
-
} catch (e) {
|
|
420
|
-
await paseExchange.close();
|
|
421
|
-
throw e;
|
|
422
|
-
}
|
|
423
|
-
await unsecureSession.destroy();
|
|
424
|
-
return new import_protocol.MessageChannel(paseChannel, paseSecureSession);
|
|
425
|
-
}
|
|
426
|
-
/**
|
|
427
|
-
* Method to commission a device with a PASE secure channel. It returns the NodeId of the commissioned device on
|
|
428
|
-
* success.
|
|
429
|
-
*/
|
|
430
|
-
async commissionDevice(paseSecureMessageChannel, commissioningOptions, discoveryData, completeCommissioningCallback) {
|
|
431
|
-
const peerNodeId = commissioningOptions.nodeId ?? import_types.NodeId.randomOperationalNodeId();
|
|
432
|
-
const commissioningManager = new import_protocol.ControllerCommissioner(
|
|
433
|
-
// Use the created secure session to do the commissioning
|
|
434
|
-
new import_protocol.InteractionClient(new import_protocol.ExchangeProvider(this.exchangeManager, paseSecureMessageChannel), peerNodeId),
|
|
435
|
-
this.certificateManager,
|
|
436
|
-
this.fabric,
|
|
437
|
-
commissioningOptions,
|
|
438
|
-
peerNodeId,
|
|
439
|
-
this.adminVendorId,
|
|
440
|
-
async () => {
|
|
441
|
-
await paseSecureMessageChannel.close();
|
|
442
|
-
if (completeCommissioningCallback !== void 0) {
|
|
443
|
-
if (!await completeCommissioningCallback(peerNodeId, discoveryData)) {
|
|
444
|
-
throw new import_protocol.RetransmissionLimitReachedError("Device could not be discovered");
|
|
445
|
-
}
|
|
446
|
-
throw new import_protocol.CommissioningSuccessfullyFinished();
|
|
447
|
-
}
|
|
448
|
-
return await this.connect(peerNodeId, {
|
|
449
|
-
discoveryType: 2 /* TimedDiscovery */,
|
|
450
|
-
timeoutSeconds: 120,
|
|
451
|
-
discoveryData
|
|
452
|
-
});
|
|
453
|
-
}
|
|
454
|
-
);
|
|
455
|
-
try {
|
|
456
|
-
await commissioningManager.executeCommissioning();
|
|
457
|
-
} catch (error) {
|
|
458
|
-
if (this.commissionedNodes.has(peerNodeId)) {
|
|
459
|
-
this.commissionedNodes.delete(peerNodeId);
|
|
460
|
-
}
|
|
461
|
-
throw error;
|
|
462
|
-
}
|
|
463
|
-
await this.fabricStorage?.set("fabric", this.fabric.toStorageObject());
|
|
464
|
-
return peerNodeId;
|
|
255
|
+
return this.peers.delete(this.fabric.addressOf(nodeId));
|
|
465
256
|
}
|
|
466
257
|
/**
|
|
467
258
|
* Method to complete the commissioning process to a node which was initialized with a PASE secure channel.
|
|
468
259
|
*/
|
|
469
260
|
async completeCommissioning(peerNodeId, discoveryData) {
|
|
470
261
|
const interactionClient = await this.connect(peerNodeId, {
|
|
471
|
-
discoveryType:
|
|
262
|
+
discoveryType: import_protocol.NodeDiscoveryType.TimedDiscovery,
|
|
472
263
|
timeoutSeconds: 120,
|
|
473
264
|
discoveryData
|
|
474
265
|
});
|
|
@@ -481,315 +272,44 @@ class MatterController {
|
|
|
481
272
|
useExtendedFailSafeMessageResponseTimeout: true
|
|
482
273
|
});
|
|
483
274
|
if (errorCode !== import_clusters.GeneralCommissioning.CommissioningError.Ok) {
|
|
484
|
-
|
|
485
|
-
this.commissionedNodes.delete(peerNodeId);
|
|
486
|
-
}
|
|
275
|
+
await this.peers.delete(this.fabric.addressOf(peerNodeId));
|
|
487
276
|
throw new import_protocol.CommissioningError(`Commission error on commissioningComplete: ${errorCode}, ${debugText}`);
|
|
488
277
|
}
|
|
489
278
|
await this.fabricStorage?.set("fabric", this.fabric.toStorageObject());
|
|
490
279
|
}
|
|
491
|
-
handleResubmissionStarted(peerNodeId) {
|
|
492
|
-
if (this.#runningNodeDiscoveries.has(peerNodeId)) {
|
|
493
|
-
return;
|
|
494
|
-
}
|
|
495
|
-
this.#runningNodeDiscoveries.set(peerNodeId, { type: 1 /* RetransmissionDiscovery */ });
|
|
496
|
-
this.mdnsScanner?.findOperationalDevice(this.fabric, peerNodeId, RETRANSMISSION_DISCOVERY_TIMEOUT_MS, true).catch((error) => {
|
|
497
|
-
logger.error(`Failed to discover device ${peerNodeId} after resubmission started.`, error);
|
|
498
|
-
}).finally(() => {
|
|
499
|
-
if (this.#runningNodeDiscoveries.get(peerNodeId)?.type === 1 /* RetransmissionDiscovery */) {
|
|
500
|
-
this.#runningNodeDiscoveries.delete(peerNodeId);
|
|
501
|
-
}
|
|
502
|
-
});
|
|
503
|
-
}
|
|
504
|
-
async reconnectKnownAddress(peerNodeId, operationalAddress, discoveryData, expectedProcessingTimeMs) {
|
|
505
|
-
const { ip, port } = operationalAddress;
|
|
506
|
-
try {
|
|
507
|
-
logger.debug(
|
|
508
|
-
`Resume device connection to configured server at ${ip}:${port}${expectedProcessingTimeMs !== void 0 ? ` with expected processing time of ${expectedProcessingTimeMs}ms` : ""} ...`
|
|
509
|
-
);
|
|
510
|
-
const channel = await this.pair(peerNodeId, operationalAddress, discoveryData, expectedProcessingTimeMs);
|
|
511
|
-
await this.setOperationalDeviceData(peerNodeId, operationalAddress);
|
|
512
|
-
return channel;
|
|
513
|
-
} catch (error) {
|
|
514
|
-
if (error instanceof import_general.NoResponseTimeoutError) {
|
|
515
|
-
logger.debug(
|
|
516
|
-
`Failed to resume connection to node ${peerNodeId} connection with ${ip}:${port}, discover the device ...`,
|
|
517
|
-
error
|
|
518
|
-
);
|
|
519
|
-
await this.sessionManager.removeAllSessionsForNode(peerNodeId);
|
|
520
|
-
return void 0;
|
|
521
|
-
} else {
|
|
522
|
-
throw error;
|
|
523
|
-
}
|
|
524
|
-
}
|
|
525
|
-
}
|
|
526
|
-
async connectOrDiscoverNode(peerNodeId, operationalAddress, discoveryOptions = {}) {
|
|
527
|
-
const {
|
|
528
|
-
discoveryType: requestedDiscoveryType = 3 /* FullDiscovery */,
|
|
529
|
-
timeoutSeconds,
|
|
530
|
-
discoveryData = this.commissionedNodes.get(peerNodeId)?.discoveryData
|
|
531
|
-
} = discoveryOptions;
|
|
532
|
-
if (timeoutSeconds !== void 0 && requestedDiscoveryType !== 2 /* TimedDiscovery */) {
|
|
533
|
-
throw new import_general.ImplementationError("Cannot set timeout without timed discovery.");
|
|
534
|
-
}
|
|
535
|
-
if (requestedDiscoveryType === 1 /* RetransmissionDiscovery */) {
|
|
536
|
-
throw new import_general.ImplementationError("Cannot set retransmission discovery type.");
|
|
537
|
-
}
|
|
538
|
-
if (this.mdnsScanner === void 0) {
|
|
539
|
-
throw new import_general.ImplementationError("Cannot discover device without mDNS scanner.");
|
|
540
|
-
}
|
|
541
|
-
const mdnsScanner = this.mdnsScanner;
|
|
542
|
-
const existingDiscoveryDetails = this.#runningNodeDiscoveries.get(peerNodeId) ?? {
|
|
543
|
-
type: 0 /* None */
|
|
544
|
-
};
|
|
545
|
-
if (existingDiscoveryDetails.type !== 0 /* None */ && existingDiscoveryDetails.type < requestedDiscoveryType) {
|
|
546
|
-
mdnsScanner.cancelOperationalDeviceDiscovery(this.fabric, peerNodeId);
|
|
547
|
-
this.#runningNodeDiscoveries.delete(peerNodeId);
|
|
548
|
-
existingDiscoveryDetails.type = 0 /* None */;
|
|
549
|
-
}
|
|
550
|
-
const { type: runningDiscoveryType, promises } = existingDiscoveryDetails;
|
|
551
|
-
if (operationalAddress !== void 0 && (runningDiscoveryType === 0 /* None */ || requestedDiscoveryType === 0 /* None */)) {
|
|
552
|
-
const directReconnection = await this.reconnectKnownAddress(peerNodeId, operationalAddress, discoveryData);
|
|
553
|
-
if (directReconnection !== void 0) {
|
|
554
|
-
return directReconnection;
|
|
555
|
-
}
|
|
556
|
-
if (requestedDiscoveryType === 0 /* None */) {
|
|
557
|
-
throw new import_protocol.DiscoveryError(`Node ${peerNodeId} is not reachable right now.`);
|
|
558
|
-
}
|
|
559
|
-
}
|
|
560
|
-
if (promises !== void 0) {
|
|
561
|
-
if (runningDiscoveryType > requestedDiscoveryType) {
|
|
562
|
-
throw new import_protocol.DiscoveryError(
|
|
563
|
-
`Node ${peerNodeId} is not reachable right now and discovery already running.`
|
|
564
|
-
);
|
|
565
|
-
} else {
|
|
566
|
-
return await (0, import_general.anyPromise)(promises);
|
|
567
|
-
}
|
|
568
|
-
}
|
|
569
|
-
const discoveryPromises = new Array();
|
|
570
|
-
let reconnectionPollingTimer;
|
|
571
|
-
if (operationalAddress !== void 0) {
|
|
572
|
-
if (requestedDiscoveryType === 3 /* FullDiscovery */) {
|
|
573
|
-
const { promise, resolver, rejecter } = (0, import_general.createPromise)();
|
|
574
|
-
reconnectionPollingTimer = import_general.Time.getPeriodicTimer(
|
|
575
|
-
"Controller reconnect",
|
|
576
|
-
RECONNECTION_POLLING_INTERVAL_MS,
|
|
577
|
-
async () => {
|
|
578
|
-
try {
|
|
579
|
-
logger.debug(`Polling for device at ${(0, import_general.serverAddressToString)(operationalAddress)} ...`);
|
|
580
|
-
const result = await this.reconnectKnownAddress(
|
|
581
|
-
peerNodeId,
|
|
582
|
-
operationalAddress,
|
|
583
|
-
discoveryData
|
|
584
|
-
);
|
|
585
|
-
if (result !== void 0 && reconnectionPollingTimer?.isRunning) {
|
|
586
|
-
reconnectionPollingTimer?.stop();
|
|
587
|
-
mdnsScanner.cancelOperationalDeviceDiscovery(this.fabric, peerNodeId);
|
|
588
|
-
this.#runningNodeDiscoveries.delete(peerNodeId);
|
|
589
|
-
resolver(result);
|
|
590
|
-
}
|
|
591
|
-
} catch (error) {
|
|
592
|
-
if (reconnectionPollingTimer?.isRunning) {
|
|
593
|
-
reconnectionPollingTimer?.stop();
|
|
594
|
-
mdnsScanner.cancelOperationalDeviceDiscovery(this.fabric, peerNodeId);
|
|
595
|
-
this.#runningNodeDiscoveries.delete(peerNodeId);
|
|
596
|
-
rejecter(error);
|
|
597
|
-
}
|
|
598
|
-
}
|
|
599
|
-
}
|
|
600
|
-
).start();
|
|
601
|
-
discoveryPromises.push(() => promise);
|
|
602
|
-
}
|
|
603
|
-
}
|
|
604
|
-
discoveryPromises.push(async () => {
|
|
605
|
-
const scanResult = await import_protocol.ControllerDiscovery.discoverOperationalDevice(
|
|
606
|
-
this.fabric,
|
|
607
|
-
peerNodeId,
|
|
608
|
-
mdnsScanner,
|
|
609
|
-
timeoutSeconds,
|
|
610
|
-
timeoutSeconds === void 0
|
|
611
|
-
);
|
|
612
|
-
const { timer } = this.#runningNodeDiscoveries.get(peerNodeId) ?? {};
|
|
613
|
-
timer?.stop();
|
|
614
|
-
this.#runningNodeDiscoveries.delete(peerNodeId);
|
|
615
|
-
const { result } = await import_protocol.ControllerDiscovery.iterateServerAddresses(
|
|
616
|
-
[scanResult],
|
|
617
|
-
import_general.NoResponseTimeoutError,
|
|
618
|
-
async () => {
|
|
619
|
-
const device = mdnsScanner.getDiscoveredOperationalDevice(this.fabric, peerNodeId);
|
|
620
|
-
return device !== void 0 ? [device] : [];
|
|
621
|
-
},
|
|
622
|
-
async (address, device) => {
|
|
623
|
-
const result2 = await this.pair(peerNodeId, address, device);
|
|
624
|
-
await this.setOperationalDeviceData(peerNodeId, address, {
|
|
625
|
-
...discoveryData,
|
|
626
|
-
...device
|
|
627
|
-
});
|
|
628
|
-
return result2;
|
|
629
|
-
}
|
|
630
|
-
);
|
|
631
|
-
return result;
|
|
632
|
-
});
|
|
633
|
-
this.#runningNodeDiscoveries.set(peerNodeId, {
|
|
634
|
-
type: requestedDiscoveryType,
|
|
635
|
-
promises: discoveryPromises,
|
|
636
|
-
timer: reconnectionPollingTimer
|
|
637
|
-
});
|
|
638
|
-
return await (0, import_general.anyPromise)(discoveryPromises).finally(() => this.#runningNodeDiscoveries.delete(peerNodeId));
|
|
639
|
-
}
|
|
640
|
-
/**
|
|
641
|
-
* Resume a device connection and establish a CASE session that was previously paired with the controller. This
|
|
642
|
-
* method will try to connect to the device using the previously used server address (if set). If that fails, the
|
|
643
|
-
* device is discovered again using its operational instance details.
|
|
644
|
-
* It returns the operational MessageChannel on success.
|
|
645
|
-
*/
|
|
646
|
-
async resume(peerNodeId, discoveryOptions) {
|
|
647
|
-
const operationalAddress = this.getLastOperationalAddress(peerNodeId);
|
|
648
|
-
try {
|
|
649
|
-
return await this.connectOrDiscoverNode(peerNodeId, operationalAddress, discoveryOptions);
|
|
650
|
-
} catch (error) {
|
|
651
|
-
if ((error instanceof import_protocol.DiscoveryError || error instanceof import_general.NoResponseTimeoutError) && this.commissionedNodes.has(peerNodeId)) {
|
|
652
|
-
logger.info(`Resume failed, remove all sessions for node ${peerNodeId}`);
|
|
653
|
-
await this.sessionManager.removeAllSessionsForNode(peerNodeId);
|
|
654
|
-
}
|
|
655
|
-
throw error;
|
|
656
|
-
}
|
|
657
|
-
}
|
|
658
|
-
/** Pair with an operational device (already commissioned) and establish a CASE session. */
|
|
659
|
-
async pair(peerNodeId, operationalServerAddress, discoveryData, expectedProcessingTimeMs) {
|
|
660
|
-
const { ip, port } = operationalServerAddress;
|
|
661
|
-
const isIpv6Address = (0, import_general.isIPv6)(ip);
|
|
662
|
-
const operationalInterface = isIpv6Address ? this.netInterfaceIpv6 : this.netInterfaceIpv4;
|
|
663
|
-
if (operationalInterface === void 0) {
|
|
664
|
-
throw new import_protocol.PairRetransmissionLimitReachedError(
|
|
665
|
-
`IPv${isIpv6Address ? "6" : "4"} interface not initialized for port ${port}. Cannot use ${ip} for pairing.`
|
|
666
|
-
);
|
|
667
|
-
}
|
|
668
|
-
const operationalChannel = await operationalInterface.openChannel(operationalServerAddress);
|
|
669
|
-
const { sessionParameters } = this.findResumptionRecordByNodeId(peerNodeId) ?? {};
|
|
670
|
-
const unsecureSession = this.sessionManager.createUnsecureSession({
|
|
671
|
-
// Use the session parameters from MDNS announcements when available and rest is assumed to be fallbacks
|
|
672
|
-
sessionParameters: {
|
|
673
|
-
idleIntervalMs: discoveryData?.SII ?? sessionParameters?.idleIntervalMs,
|
|
674
|
-
activeIntervalMs: discoveryData?.SAI ?? sessionParameters?.activeIntervalMs,
|
|
675
|
-
activeThresholdMs: discoveryData?.SAT ?? sessionParameters?.activeThresholdMs
|
|
676
|
-
},
|
|
677
|
-
isInitiator: true
|
|
678
|
-
});
|
|
679
|
-
const operationalUnsecureMessageExchange = new import_protocol.MessageChannel(operationalChannel, unsecureSession);
|
|
680
|
-
let operationalSecureSession;
|
|
681
|
-
try {
|
|
682
|
-
const exchange = this.exchangeManager.initiateExchangeWithChannel(
|
|
683
|
-
operationalUnsecureMessageExchange,
|
|
684
|
-
import_protocol.SECURE_CHANNEL_PROTOCOL_ID
|
|
685
|
-
);
|
|
686
|
-
try {
|
|
687
|
-
operationalSecureSession = await this.caseClient.pair(
|
|
688
|
-
this,
|
|
689
|
-
exchange,
|
|
690
|
-
this.fabric,
|
|
691
|
-
peerNodeId,
|
|
692
|
-
expectedProcessingTimeMs
|
|
693
|
-
);
|
|
694
|
-
} catch (e) {
|
|
695
|
-
await exchange.close();
|
|
696
|
-
throw e;
|
|
697
|
-
}
|
|
698
|
-
} catch (e) {
|
|
699
|
-
import_general.NoResponseTimeoutError.accept(e);
|
|
700
|
-
throw new import_protocol.PairRetransmissionLimitReachedError(e.message);
|
|
701
|
-
}
|
|
702
|
-
await unsecureSession.destroy();
|
|
703
|
-
const channel = new import_protocol.MessageChannel(operationalChannel, operationalSecureSession);
|
|
704
|
-
await this.channelManager.setChannel(this.fabric, peerNodeId, channel);
|
|
705
|
-
return channel;
|
|
706
|
-
}
|
|
707
280
|
isCommissioned() {
|
|
708
|
-
return this.
|
|
281
|
+
return this.peers.size > 0;
|
|
709
282
|
}
|
|
710
283
|
getCommissionedNodes() {
|
|
711
|
-
return
|
|
284
|
+
return this.peers.map((peer) => peer.address.nodeId);
|
|
712
285
|
}
|
|
713
286
|
getCommissionedNodesDetails() {
|
|
714
|
-
return
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
287
|
+
return this.peers.map((peer) => {
|
|
288
|
+
const { address, operationalAddress, discoveryData, basicInformationData } = peer;
|
|
289
|
+
return {
|
|
290
|
+
nodeId: address.nodeId,
|
|
291
|
+
operationalAddress: operationalAddress ? (0, import_general.serverAddressToString)(operationalAddress) : void 0,
|
|
718
292
|
advertisedName: discoveryData?.DN,
|
|
719
293
|
discoveryData,
|
|
720
294
|
basicInformationData
|
|
721
|
-
})
|
|
722
|
-
);
|
|
723
|
-
}
|
|
724
|
-
async setOperationalDeviceData(nodeId, operationalServerAddress, discoveryData) {
|
|
725
|
-
const nodeDetails = this.commissionedNodes.get(nodeId) ?? {};
|
|
726
|
-
nodeDetails.operationalServerAddress = operationalServerAddress;
|
|
727
|
-
if (discoveryData !== void 0) {
|
|
728
|
-
nodeDetails.discoveryData = {
|
|
729
|
-
...nodeDetails.discoveryData,
|
|
730
|
-
...discoveryData
|
|
731
295
|
};
|
|
732
|
-
}
|
|
733
|
-
this.commissionedNodes.set(nodeId, nodeDetails);
|
|
734
|
-
await this.storeCommissionedNodes();
|
|
296
|
+
});
|
|
735
297
|
}
|
|
736
298
|
async enhanceCommissionedNodeDetails(nodeId, data) {
|
|
737
|
-
const nodeDetails = this.
|
|
299
|
+
const nodeDetails = this.peers.get(this.fabric.addressOf(nodeId));
|
|
738
300
|
if (nodeDetails === void 0) {
|
|
739
301
|
throw new Error(`Node ${nodeId} is not commissioned.`);
|
|
740
302
|
}
|
|
741
303
|
const { basicInformationData } = data;
|
|
742
304
|
nodeDetails.basicInformationData = basicInformationData;
|
|
743
|
-
this.
|
|
744
|
-
await this.storeCommissionedNodes();
|
|
745
|
-
}
|
|
746
|
-
getLastOperationalAddress(nodeId) {
|
|
747
|
-
return this.commissionedNodes.get(nodeId)?.operationalServerAddress;
|
|
748
|
-
}
|
|
749
|
-
async storeCommissionedNodes() {
|
|
750
|
-
await this.nodesStorage.set("commissionedNodes", Array.from(this.commissionedNodes.entries()));
|
|
305
|
+
await this.nodesStore.save();
|
|
751
306
|
}
|
|
752
307
|
/**
|
|
753
308
|
* Connect to the device by opening a channel and creating a new CASE session if necessary.
|
|
754
309
|
* Returns a InteractionClient on success.
|
|
755
310
|
*/
|
|
756
311
|
async connect(peerNodeId, discoveryOptions) {
|
|
757
|
-
|
|
758
|
-
let channel;
|
|
759
|
-
try {
|
|
760
|
-
channel = this.channelManager.getChannel(this.fabric, peerNodeId);
|
|
761
|
-
} catch (error) {
|
|
762
|
-
import_protocol.NoChannelError.accept(error);
|
|
763
|
-
channel = await this.resume(peerNodeId, discoveryOptions);
|
|
764
|
-
}
|
|
765
|
-
return new import_protocol.InteractionClient(
|
|
766
|
-
new import_protocol.ExchangeProvider(this.exchangeManager, channel, async () => {
|
|
767
|
-
if (!this.channelManager.hasChannel(this.fabric, peerNodeId)) {
|
|
768
|
-
throw new import_protocol.RetransmissionLimitReachedError(`Device ${peerNodeId} is currently not reachable.`);
|
|
769
|
-
}
|
|
770
|
-
await this.channelManager.removeAllNodeChannels(this.fabric, peerNodeId);
|
|
771
|
-
const discoveredAddresses = this.mdnsScanner?.getDiscoveredOperationalDevice(this.fabric, peerNodeId);
|
|
772
|
-
const lastKnownAddress = this.getLastOperationalAddress(peerNodeId);
|
|
773
|
-
if (lastKnownAddress !== void 0 && discoveredAddresses !== void 0 && discoveredAddresses.addresses.some(
|
|
774
|
-
({ ip, port }) => ip === lastKnownAddress.ip && port === lastKnownAddress.port
|
|
775
|
-
)) {
|
|
776
|
-
discoveredAddresses.addresses.length = 0;
|
|
777
|
-
}
|
|
778
|
-
const operationalAddress = discoveredAddresses?.addresses[0];
|
|
779
|
-
if (operationalAddress === void 0) {
|
|
780
|
-
logger.info(
|
|
781
|
-
`Re-Discovering device failed (no address found), remove all sessions for node ${peerNodeId}`
|
|
782
|
-
);
|
|
783
|
-
await this.sessionManager.removeAllSessionsForNode(peerNodeId);
|
|
784
|
-
throw new import_protocol.RetransmissionLimitReachedError(`No operational address found for node ${peerNodeId}`);
|
|
785
|
-
}
|
|
786
|
-
if (await this.reconnectKnownAddress(peerNodeId, operationalAddress, discoveryData, 2e3) === void 0) {
|
|
787
|
-
throw new import_protocol.RetransmissionLimitReachedError(`Device ${peerNodeId} is not reachable.`);
|
|
788
|
-
}
|
|
789
|
-
return this.channelManager.getChannel(this.fabric, peerNodeId);
|
|
790
|
-
}),
|
|
791
|
-
peerNodeId
|
|
792
|
-
);
|
|
312
|
+
return this.peers.connect(this.fabric.addressOf(peerNodeId), discoveryOptions);
|
|
793
313
|
}
|
|
794
314
|
async getNextAvailableSessionId() {
|
|
795
315
|
return this.sessionManager.getNextAvailableSessionId();
|
|
@@ -798,7 +318,7 @@ class MatterController {
|
|
|
798
318
|
return this.sessionManager.findResumptionRecordById(resumptionId);
|
|
799
319
|
}
|
|
800
320
|
findResumptionRecordByNodeId(nodeId) {
|
|
801
|
-
return this.sessionManager.
|
|
321
|
+
return this.sessionManager.findResumptionRecordByAddress(this.fabric.addressOf(nodeId));
|
|
802
322
|
}
|
|
803
323
|
async saveResumptionRecord(resumptionRecord) {
|
|
804
324
|
return this.sessionManager.saveResumptionRecord(resumptionRecord);
|
|
@@ -806,19 +326,58 @@ class MatterController {
|
|
|
806
326
|
announce() {
|
|
807
327
|
}
|
|
808
328
|
async close() {
|
|
809
|
-
|
|
810
|
-
timer?.stop();
|
|
811
|
-
this.mdnsScanner?.cancelOperationalDeviceDiscovery(this.fabric, nodeId, false);
|
|
812
|
-
}
|
|
329
|
+
await this.peers.close();
|
|
813
330
|
await this.exchangeManager.close();
|
|
814
331
|
await this.sessionManager.close();
|
|
815
332
|
await this.channelManager.close();
|
|
816
|
-
await this.
|
|
817
|
-
await this.netInterfaceIpv4?.close();
|
|
818
|
-
await this.netInterfaceIpv6?.close();
|
|
333
|
+
await this.netInterfaces.close();
|
|
819
334
|
}
|
|
820
335
|
getActiveSessionInformation() {
|
|
821
336
|
return this.sessionManager.getActiveSessionInformation();
|
|
822
337
|
}
|
|
823
338
|
}
|
|
339
|
+
class CommissionedNodeStore extends import_protocol.PeerStore {
|
|
340
|
+
constructor(nodesStorage, fabric) {
|
|
341
|
+
super();
|
|
342
|
+
this.nodesStorage = nodesStorage;
|
|
343
|
+
this.fabric = fabric;
|
|
344
|
+
}
|
|
345
|
+
async loadPeers() {
|
|
346
|
+
if (!await this.nodesStorage.has("commissionedNodes")) {
|
|
347
|
+
return [];
|
|
348
|
+
}
|
|
349
|
+
const commissionedNodes = await this.nodesStorage.get("commissionedNodes");
|
|
350
|
+
return commissionedNodes.map(
|
|
351
|
+
([nodeId, { operationalServerAddress, discoveryData, basicInformationData }]) => ({
|
|
352
|
+
address: this.fabric.addressOf(nodeId),
|
|
353
|
+
operationalAddress: operationalServerAddress,
|
|
354
|
+
discoveryData,
|
|
355
|
+
basicInformationData
|
|
356
|
+
})
|
|
357
|
+
);
|
|
358
|
+
}
|
|
359
|
+
async updatePeer() {
|
|
360
|
+
return this.save();
|
|
361
|
+
}
|
|
362
|
+
async deletePeer() {
|
|
363
|
+
return this.save();
|
|
364
|
+
}
|
|
365
|
+
async save() {
|
|
366
|
+
await this.nodesStorage.set(
|
|
367
|
+
"commissionedNodes",
|
|
368
|
+
this.peers.map((peer) => {
|
|
369
|
+
const {
|
|
370
|
+
address,
|
|
371
|
+
operationalAddress: operationalServerAddress,
|
|
372
|
+
basicInformationData,
|
|
373
|
+
discoveryData
|
|
374
|
+
} = peer;
|
|
375
|
+
return [
|
|
376
|
+
address.nodeId,
|
|
377
|
+
{ operationalServerAddress, basicInformationData, discoveryData }
|
|
378
|
+
];
|
|
379
|
+
})
|
|
380
|
+
);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
824
383
|
//# sourceMappingURL=MatterController.js.map
|