@matter/protocol 0.16.8-alpha.0-20260123-dff2cae52 → 0.16.8-alpha.0-20260127-65e1b40e2
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 +4 -4
- package/dist/cjs/action/client/ClientInteraction.d.ts.map +1 -1
- package/dist/cjs/action/client/ClientInteraction.js +48 -6
- package/dist/cjs/action/client/ClientInteraction.js.map +1 -1
- package/dist/cjs/action/client/QueuedClientInteraction.d.ts +0 -1
- package/dist/cjs/action/client/QueuedClientInteraction.d.ts.map +1 -1
- package/dist/cjs/action/client/QueuedClientInteraction.js +0 -1
- package/dist/cjs/action/client/QueuedClientInteraction.js.map +1 -1
- package/dist/cjs/action/client/subscription/ClientSubscriptionHandler.d.ts.map +1 -1
- package/dist/cjs/action/client/subscription/ClientSubscriptionHandler.js +5 -2
- package/dist/cjs/action/client/subscription/ClientSubscriptionHandler.js.map +1 -1
- package/dist/cjs/action/server/AttributeWriteResponse.d.ts +1 -1
- package/dist/cjs/action/server/AttributeWriteResponse.d.ts.map +1 -1
- package/dist/cjs/action/server/AttributeWriteResponse.js +0 -6
- package/dist/cjs/action/server/AttributeWriteResponse.js.map +1 -1
- package/dist/cjs/action/server/DataResponse.d.ts +5 -0
- package/dist/cjs/action/server/DataResponse.d.ts.map +1 -1
- package/dist/cjs/action/server/DataResponse.js +7 -0
- package/dist/cjs/action/server/DataResponse.js.map +1 -1
- package/dist/cjs/action/server/ServerInteraction.js.map +1 -1
- package/dist/cjs/dcl/DclCertificateService.d.ts.map +1 -1
- package/dist/cjs/dcl/DclCertificateService.js +3 -0
- package/dist/cjs/dcl/DclCertificateService.js.map +1 -1
- package/dist/cjs/dcl/DclOtaUpdateService.d.ts.map +1 -1
- package/dist/cjs/dcl/DclOtaUpdateService.js +6 -4
- package/dist/cjs/dcl/DclOtaUpdateService.js.map +1 -1
- package/dist/cjs/interaction/InteractionMessenger.d.ts +30 -30
- package/dist/cjs/interaction/InteractionMessenger.d.ts.map +1 -1
- package/dist/cjs/interaction/InteractionMessenger.js +81 -12
- package/dist/cjs/interaction/InteractionMessenger.js.map +1 -1
- package/dist/cjs/mdns/MdnsClient.d.ts.map +1 -1
- package/dist/cjs/mdns/MdnsClient.js +163 -102
- package/dist/cjs/mdns/MdnsClient.js.map +1 -1
- package/dist/cjs/mdns/MdnsServer.d.ts +2 -0
- package/dist/cjs/mdns/MdnsServer.d.ts.map +1 -1
- package/dist/cjs/mdns/MdnsServer.js +45 -5
- package/dist/cjs/mdns/MdnsServer.js.map +1 -1
- package/dist/cjs/peer/ControllerCommissioningFlow.d.ts.map +1 -1
- package/dist/cjs/peer/ControllerCommissioningFlow.js +3 -1
- package/dist/cjs/peer/ControllerCommissioningFlow.js.map +1 -1
- package/dist/cjs/peer/Peer.d.ts +2 -1
- package/dist/cjs/peer/Peer.d.ts.map +1 -1
- package/dist/cjs/peer/Peer.js +20 -3
- package/dist/cjs/peer/Peer.js.map +1 -1
- package/dist/cjs/peer/PeerAddressStore.d.ts +1 -11
- package/dist/cjs/peer/PeerAddressStore.d.ts.map +1 -1
- package/dist/cjs/peer/PeerAddressStore.js +1 -4
- package/dist/cjs/peer/PeerAddressStore.js.map +1 -1
- package/dist/cjs/peer/PeerDescriptor.d.ts +1 -9
- package/dist/cjs/peer/PeerDescriptor.d.ts.map +1 -1
- package/dist/cjs/peer/PeerDescriptor.js +1 -6
- package/dist/cjs/peer/PeerDescriptor.js.map +1 -1
- package/dist/cjs/peer/PeerSet.d.ts +1 -1
- package/dist/cjs/peer/PeerSet.d.ts.map +1 -1
- package/dist/cjs/peer/PeerSet.js +55 -22
- package/dist/cjs/peer/PeerSet.js.map +2 -2
- package/dist/cjs/protocol/ExchangeManager.d.ts.map +1 -1
- package/dist/cjs/protocol/ExchangeManager.js +2 -2
- package/dist/cjs/protocol/ExchangeManager.js.map +1 -1
- package/dist/cjs/protocol/ExchangeProvider.d.ts.map +1 -1
- package/dist/cjs/protocol/ExchangeProvider.js +3 -3
- package/dist/cjs/protocol/ExchangeProvider.js.map +1 -1
- package/dist/cjs/protocol/MRP.d.ts +54 -0
- package/dist/cjs/protocol/MRP.d.ts.map +1 -0
- package/dist/cjs/protocol/MRP.js +96 -0
- package/dist/cjs/protocol/MRP.js.map +6 -0
- package/dist/cjs/protocol/MessageChannel.d.ts +0 -23
- package/dist/cjs/protocol/MessageChannel.d.ts.map +1 -1
- package/dist/cjs/protocol/MessageChannel.js +15 -47
- package/dist/cjs/protocol/MessageChannel.js.map +2 -2
- package/dist/cjs/protocol/MessageExchange.d.ts.map +1 -1
- package/dist/cjs/protocol/MessageExchange.js +7 -7
- package/dist/cjs/protocol/MessageExchange.js.map +1 -1
- package/dist/cjs/protocol/index.d.ts +1 -0
- package/dist/cjs/protocol/index.d.ts.map +1 -1
- package/dist/cjs/protocol/index.js +1 -0
- package/dist/cjs/protocol/index.js.map +1 -1
- package/dist/cjs/session/NodeSession.js +2 -2
- package/dist/cjs/session/NodeSession.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/case/CaseClient.d.ts.map +1 -1
- package/dist/cjs/session/case/CaseClient.js +1 -1
- package/dist/cjs/session/case/CaseClient.js.map +1 -1
- package/dist/cjs/session/case/CaseServer.d.ts.map +1 -1
- package/dist/cjs/session/case/CaseServer.js +4 -1
- package/dist/cjs/session/case/CaseServer.js.map +1 -1
- package/dist/esm/action/client/ClientInteraction.d.ts +4 -4
- package/dist/esm/action/client/ClientInteraction.d.ts.map +1 -1
- package/dist/esm/action/client/ClientInteraction.js +49 -6
- package/dist/esm/action/client/ClientInteraction.js.map +1 -1
- package/dist/esm/action/client/QueuedClientInteraction.d.ts +0 -1
- package/dist/esm/action/client/QueuedClientInteraction.d.ts.map +1 -1
- package/dist/esm/action/client/QueuedClientInteraction.js +0 -1
- package/dist/esm/action/client/QueuedClientInteraction.js.map +1 -1
- package/dist/esm/action/client/subscription/ClientSubscriptionHandler.d.ts.map +1 -1
- package/dist/esm/action/client/subscription/ClientSubscriptionHandler.js +5 -2
- package/dist/esm/action/client/subscription/ClientSubscriptionHandler.js.map +1 -1
- package/dist/esm/action/server/AttributeWriteResponse.d.ts +1 -1
- package/dist/esm/action/server/AttributeWriteResponse.d.ts.map +1 -1
- package/dist/esm/action/server/AttributeWriteResponse.js +0 -6
- package/dist/esm/action/server/AttributeWriteResponse.js.map +1 -1
- package/dist/esm/action/server/DataResponse.d.ts +5 -0
- package/dist/esm/action/server/DataResponse.d.ts.map +1 -1
- package/dist/esm/action/server/DataResponse.js +7 -0
- package/dist/esm/action/server/DataResponse.js.map +1 -1
- package/dist/esm/action/server/ServerInteraction.js.map +1 -1
- package/dist/esm/dcl/DclCertificateService.d.ts.map +1 -1
- package/dist/esm/dcl/DclCertificateService.js +3 -0
- package/dist/esm/dcl/DclCertificateService.js.map +1 -1
- package/dist/esm/dcl/DclOtaUpdateService.d.ts.map +1 -1
- package/dist/esm/dcl/DclOtaUpdateService.js +6 -4
- package/dist/esm/dcl/DclOtaUpdateService.js.map +1 -1
- package/dist/esm/interaction/InteractionMessenger.d.ts +30 -30
- package/dist/esm/interaction/InteractionMessenger.d.ts.map +1 -1
- package/dist/esm/interaction/InteractionMessenger.js +82 -12
- package/dist/esm/interaction/InteractionMessenger.js.map +1 -1
- package/dist/esm/mdns/MdnsClient.d.ts.map +1 -1
- package/dist/esm/mdns/MdnsClient.js +163 -102
- package/dist/esm/mdns/MdnsClient.js.map +1 -1
- package/dist/esm/mdns/MdnsServer.d.ts +2 -0
- package/dist/esm/mdns/MdnsServer.d.ts.map +1 -1
- package/dist/esm/mdns/MdnsServer.js +45 -5
- package/dist/esm/mdns/MdnsServer.js.map +1 -1
- package/dist/esm/peer/ControllerCommissioningFlow.d.ts.map +1 -1
- package/dist/esm/peer/ControllerCommissioningFlow.js +3 -1
- package/dist/esm/peer/ControllerCommissioningFlow.js.map +1 -1
- package/dist/esm/peer/Peer.d.ts +2 -1
- package/dist/esm/peer/Peer.d.ts.map +1 -1
- package/dist/esm/peer/Peer.js +20 -3
- package/dist/esm/peer/Peer.js.map +1 -1
- package/dist/esm/peer/PeerAddressStore.d.ts +1 -11
- package/dist/esm/peer/PeerAddressStore.d.ts.map +1 -1
- package/dist/esm/peer/PeerAddressStore.js +1 -4
- package/dist/esm/peer/PeerAddressStore.js.map +1 -1
- package/dist/esm/peer/PeerDescriptor.d.ts +1 -9
- package/dist/esm/peer/PeerDescriptor.d.ts.map +1 -1
- package/dist/esm/peer/PeerDescriptor.js +1 -6
- package/dist/esm/peer/PeerDescriptor.js.map +1 -1
- package/dist/esm/peer/PeerSet.d.ts +1 -1
- package/dist/esm/peer/PeerSet.d.ts.map +1 -1
- package/dist/esm/peer/PeerSet.js +60 -24
- package/dist/esm/peer/PeerSet.js.map +2 -2
- package/dist/esm/protocol/ExchangeManager.d.ts.map +1 -1
- package/dist/esm/protocol/ExchangeManager.js +2 -2
- package/dist/esm/protocol/ExchangeManager.js.map +1 -1
- package/dist/esm/protocol/ExchangeProvider.d.ts.map +1 -1
- package/dist/esm/protocol/ExchangeProvider.js +3 -3
- package/dist/esm/protocol/ExchangeProvider.js.map +1 -1
- package/dist/esm/protocol/MRP.d.ts +54 -0
- package/dist/esm/protocol/MRP.d.ts.map +1 -0
- package/dist/esm/protocol/MRP.js +76 -0
- package/dist/esm/protocol/MRP.js.map +6 -0
- package/dist/esm/protocol/MessageChannel.d.ts +0 -23
- package/dist/esm/protocol/MessageChannel.d.ts.map +1 -1
- package/dist/esm/protocol/MessageChannel.js +16 -54
- package/dist/esm/protocol/MessageChannel.js.map +2 -2
- package/dist/esm/protocol/MessageExchange.d.ts.map +1 -1
- package/dist/esm/protocol/MessageExchange.js +3 -3
- package/dist/esm/protocol/MessageExchange.js.map +1 -1
- package/dist/esm/protocol/index.d.ts +1 -0
- package/dist/esm/protocol/index.d.ts.map +1 -1
- package/dist/esm/protocol/index.js +1 -0
- package/dist/esm/protocol/index.js.map +1 -1
- package/dist/esm/session/NodeSession.js +2 -2
- package/dist/esm/session/NodeSession.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/case/CaseClient.d.ts.map +1 -1
- package/dist/esm/session/case/CaseClient.js +2 -2
- package/dist/esm/session/case/CaseClient.js.map +1 -1
- package/dist/esm/session/case/CaseServer.d.ts.map +1 -1
- package/dist/esm/session/case/CaseServer.js +4 -1
- package/dist/esm/session/case/CaseServer.js.map +1 -1
- package/package.json +6 -6
- package/src/action/client/ClientInteraction.ts +62 -6
- package/src/action/client/QueuedClientInteraction.ts +0 -1
- package/src/action/client/subscription/ClientSubscriptionHandler.ts +5 -2
- package/src/action/server/AttributeWriteResponse.ts +4 -16
- package/src/action/server/DataResponse.ts +8 -0
- package/src/action/server/ServerInteraction.ts +2 -2
- package/src/dcl/DclCertificateService.ts +3 -0
- package/src/dcl/DclOtaUpdateService.ts +11 -5
- package/src/interaction/InteractionMessenger.ts +113 -15
- package/src/mdns/MdnsClient.ts +216 -104
- package/src/mdns/MdnsServer.ts +79 -6
- package/src/peer/ControllerCommissioningFlow.ts +5 -1
- package/src/peer/Peer.ts +28 -5
- package/src/peer/PeerAddressStore.ts +1 -19
- package/src/peer/PeerDescriptor.ts +1 -15
- package/src/peer/PeerSet.ts +82 -35
- package/src/protocol/ExchangeManager.ts +5 -2
- package/src/protocol/ExchangeProvider.ts +3 -3
- package/src/protocol/MRP.ts +146 -0
- package/src/protocol/MessageChannel.ts +16 -101
- package/src/protocol/MessageExchange.ts +4 -3
- package/src/protocol/index.ts +1 -0
- package/src/session/NodeSession.ts +3 -3
- package/src/session/Session.ts +1 -0
- package/src/session/case/CaseClient.ts +8 -2
- package/src/session/case/CaseServer.ts +4 -0
|
@@ -19,6 +19,7 @@ import { BdxMessenger } from "#bdx/BdxMessenger.js";
|
|
|
19
19
|
import { Mark } from "#common/Mark.js";
|
|
20
20
|
import {
|
|
21
21
|
Abort,
|
|
22
|
+
AsyncIterator,
|
|
22
23
|
BasicSet,
|
|
23
24
|
Diagnostic,
|
|
24
25
|
Duration,
|
|
@@ -38,6 +39,7 @@ import { InteractionClientMessenger, MessageType } from "#interaction/Interactio
|
|
|
38
39
|
import { Subscription } from "#interaction/Subscription.js";
|
|
39
40
|
import { PeerAddress } from "#peer/PeerAddress.js";
|
|
40
41
|
import { ExchangeProvider } from "#protocol/ExchangeProvider.js";
|
|
42
|
+
import { SessionClosedError } from "#protocol/index.js";
|
|
41
43
|
import { SecureSession } from "#session/SecureSession.js";
|
|
42
44
|
import { Status, TlvAttributeReport, TlvNoResponse, TlvSubscribeResponse, TypeFromSchema } from "#types";
|
|
43
45
|
import { ClientWrite } from "./ClientWrite.js";
|
|
@@ -186,10 +188,7 @@ export class ClientInteraction<
|
|
|
186
188
|
}
|
|
187
189
|
|
|
188
190
|
/**
|
|
189
|
-
*
|
|
190
|
-
*
|
|
191
|
-
* Writes with the Matter protocol are generally not atomic, so this method only throws if the entire action fails.
|
|
192
|
-
* You must check each {@link WriteResult.AttributeStatus} to determine whether individual updates failed.
|
|
191
|
+
* Write to node attributes.
|
|
193
192
|
*/
|
|
194
193
|
async write<T extends ClientWrite>(request: T, session?: SessionT): WriteResult<T> {
|
|
195
194
|
await using context = await this.#begin("writing", request, session);
|
|
@@ -253,9 +252,9 @@ export class ClientInteraction<
|
|
|
253
252
|
}
|
|
254
253
|
|
|
255
254
|
/**
|
|
256
|
-
* Invoke
|
|
255
|
+
* Invoke a single batch of commands (internal implementation).
|
|
257
256
|
*/
|
|
258
|
-
async
|
|
257
|
+
async *#invokeSingle(request: ClientInvoke, session?: SessionT): DecodedInvokeResult {
|
|
259
258
|
await using context = await this.#begin("invoking", request, session);
|
|
260
259
|
const { checkAbort, messenger } = context;
|
|
261
260
|
|
|
@@ -358,6 +357,63 @@ export class ClientInteraction<
|
|
|
358
357
|
}
|
|
359
358
|
}
|
|
360
359
|
|
|
360
|
+
/**
|
|
361
|
+
* Split commands across multiple parallel invoke-exchanges.
|
|
362
|
+
* Results are streamed as they arrive from any batch, not buffered.
|
|
363
|
+
*/
|
|
364
|
+
async *#invokeWithSplitting(
|
|
365
|
+
request: ClientInvoke,
|
|
366
|
+
maxPathsPerInvoke: number,
|
|
367
|
+
session?: SessionT,
|
|
368
|
+
): DecodedInvokeResult {
|
|
369
|
+
// Split commands into batches
|
|
370
|
+
const allCommands = [...request.commands.entries()];
|
|
371
|
+
const batches = new Array<ClientInvoke["commands"]>();
|
|
372
|
+
|
|
373
|
+
for (let i = 0; i < allCommands.length; i += maxPathsPerInvoke) {
|
|
374
|
+
const batchEntries = allCommands.slice(i, i + maxPathsPerInvoke);
|
|
375
|
+
batches.push(new Map(batchEntries));
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
// Create async iterators for each batch and merge results as they arrive
|
|
379
|
+
const iterators = batches.map(batchCommands => {
|
|
380
|
+
const batchRequest: ClientInvoke = {
|
|
381
|
+
...request,
|
|
382
|
+
commands: batchCommands,
|
|
383
|
+
};
|
|
384
|
+
return this.#invokeSingle(batchRequest, session);
|
|
385
|
+
});
|
|
386
|
+
|
|
387
|
+
yield* AsyncIterator.merge(iterators, "One or more invoke batches failed");
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
/** Get the effective MaxPathsPerInvoke parameter from the session, or 1 as a fallback as defined by spec. */
|
|
391
|
+
get #maxPathsPerInvoke(): number {
|
|
392
|
+
try {
|
|
393
|
+
return this.session.parameters.maxPathsPerInvoke;
|
|
394
|
+
} catch (error) {
|
|
395
|
+
SessionClosedError.accept(error);
|
|
396
|
+
return 1;
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/**
|
|
401
|
+
* Invoke one or more commands.
|
|
402
|
+
*
|
|
403
|
+
* When the number of commands exceeds the peer's MaxPathsPerInvoke limit (or 1 for older nodes),
|
|
404
|
+
* commands are split across multiple parallel exchanges automatically.
|
|
405
|
+
*/
|
|
406
|
+
async *invoke(request: ClientInvoke, session?: SessionT): DecodedInvokeResult {
|
|
407
|
+
const maxPathsPerInvoke = this.#maxPathsPerInvoke;
|
|
408
|
+
const commandCount = request.commands.size;
|
|
409
|
+
|
|
410
|
+
if (commandCount > maxPathsPerInvoke) {
|
|
411
|
+
yield* this.#invokeWithSplitting(request, maxPathsPerInvoke, session);
|
|
412
|
+
} else {
|
|
413
|
+
yield* this.#invokeSingle(request, session);
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
|
|
361
417
|
/**
|
|
362
418
|
* Subscribe to attribute values and events.
|
|
363
419
|
*/
|
|
@@ -69,7 +69,6 @@ export class QueuedClientInteraction<
|
|
|
69
69
|
|
|
70
70
|
/**
|
|
71
71
|
* Write chosen attributes remotely to the node.
|
|
72
|
-
* The returned attribute writing status information is returned.
|
|
73
72
|
*/
|
|
74
73
|
override async write<T extends ClientWrite>(request: T, session?: SessionT): WriteResult<T> {
|
|
75
74
|
using _slot = await this.queue.obtainSlot();
|
|
@@ -44,7 +44,7 @@ export class ClientSubscriptionHandler implements ProtocolHandler {
|
|
|
44
44
|
// Ensure there is a subscription ID present
|
|
45
45
|
const { subscriptionId } = initialReport;
|
|
46
46
|
if (subscriptionId === undefined) {
|
|
47
|
-
logger.debug("Ignoring unsolicited data report with no subscription ID");
|
|
47
|
+
logger.debug(exchange.via, "Ignoring unsolicited data report with no subscription ID");
|
|
48
48
|
await sendInvalid(messenger, undefined);
|
|
49
49
|
return;
|
|
50
50
|
}
|
|
@@ -55,6 +55,7 @@ export class ClientSubscriptionHandler implements ProtocolHandler {
|
|
|
55
55
|
const subscription = this.#subscriptions.getPeer(session.peerAddress, subscriptionId);
|
|
56
56
|
if (subscription === undefined) {
|
|
57
57
|
logger.info(
|
|
58
|
+
exchange.via,
|
|
58
59
|
"Ignoring data report for unknown subscription ID",
|
|
59
60
|
Diagnostic.strong(Subscription.idStrOf(subscriptionId)),
|
|
60
61
|
);
|
|
@@ -72,6 +73,7 @@ export class ClientSubscriptionHandler implements ProtocolHandler {
|
|
|
72
73
|
const ending = await reports.next();
|
|
73
74
|
if (!ending.done) {
|
|
74
75
|
logger.warn(
|
|
76
|
+
exchange.via,
|
|
75
77
|
"Unexpected data reports after empty report",
|
|
76
78
|
Diagnostic.strong(Subscription.idStrOf(subscriptionId)),
|
|
77
79
|
);
|
|
@@ -125,13 +127,14 @@ async function* processReports(
|
|
|
125
127
|
for await (const report of otherReports) {
|
|
126
128
|
const { subscriptionId: reportSubscriptionId } = report;
|
|
127
129
|
if (reportSubscriptionId === undefined) {
|
|
128
|
-
logger.debug("Ignoring data report with missing subscription id");
|
|
130
|
+
logger.debug(messenger.exchange.via, "Ignoring data report with missing subscription id");
|
|
129
131
|
await sendInvalid(messenger, reportSubscriptionId);
|
|
130
132
|
continue;
|
|
131
133
|
}
|
|
132
134
|
|
|
133
135
|
if (reportSubscriptionId !== subscriptionId) {
|
|
134
136
|
logger.debug(
|
|
137
|
+
messenger.exchange.via,
|
|
135
138
|
"Ignoring data report for incorrect subscription id",
|
|
136
139
|
Diagnostic.strong(Subscription.idStrOf(reportSubscriptionId)),
|
|
137
140
|
"expected",
|
|
@@ -40,7 +40,6 @@ export class AttributeWriteResponse<
|
|
|
40
40
|
// a cache between producers that touch the same endpoint and/or cluster
|
|
41
41
|
#currentEndpoint?: EndpointProtocol;
|
|
42
42
|
#currentCluster?: ClusterProtocol;
|
|
43
|
-
#previousProcessedAttributePath?: WriteResult.ConcreteAttributePath;
|
|
44
43
|
|
|
45
44
|
// Count how many attribute status (on error) and attribute values (on success) we have emitted
|
|
46
45
|
#statusCount = 0;
|
|
@@ -52,7 +51,7 @@ export class AttributeWriteResponse<
|
|
|
52
51
|
this.#fabricIndex = session.fabric ?? FabricIndex.NO_FABRIC;
|
|
53
52
|
}
|
|
54
53
|
|
|
55
|
-
async process
|
|
54
|
+
async process({ writeRequests, suppressResponse }: Write): Promise<WriteResult.AttributeStatus[] | undefined> {
|
|
56
55
|
using _writing = this.join("writing");
|
|
57
56
|
|
|
58
57
|
const writeResponses = new Array<WriteResult.AttributeStatus>();
|
|
@@ -75,9 +74,9 @@ export class AttributeWriteResponse<
|
|
|
75
74
|
}
|
|
76
75
|
|
|
77
76
|
if (!suppressResponse) {
|
|
78
|
-
return writeResponses
|
|
77
|
+
return writeResponses;
|
|
79
78
|
}
|
|
80
|
-
return undefined
|
|
79
|
+
return undefined;
|
|
81
80
|
}
|
|
82
81
|
|
|
83
82
|
/** Guarded accessor for this.#currentEndpoint. This should never be undefined */
|
|
@@ -394,9 +393,6 @@ export class AttributeWriteResponse<
|
|
|
394
393
|
);
|
|
395
394
|
}
|
|
396
395
|
|
|
397
|
-
const previousPath = this.#previousProcessedAttributePath;
|
|
398
|
-
this.#previousProcessedAttributePath = path;
|
|
399
|
-
|
|
400
396
|
try {
|
|
401
397
|
const { tlv } = attribute;
|
|
402
398
|
if (listIndex === undefined) {
|
|
@@ -408,15 +404,7 @@ export class AttributeWriteResponse<
|
|
|
408
404
|
writeState[attributeId] = decoded;
|
|
409
405
|
await this.session.transaction?.commit();
|
|
410
406
|
} else if (listIndex === null) {
|
|
411
|
-
|
|
412
|
-
previousPath?.endpointId !== path.endpointId ||
|
|
413
|
-
previousPath?.clusterId !== path.clusterId ||
|
|
414
|
-
previousPath?.attributeId !== path.attributeId
|
|
415
|
-
) {
|
|
416
|
-
// Mimic chip sdk behavior
|
|
417
|
-
throw new StatusResponseError("ADD list action without a former REPLACE_ALL action", Status.Busy);
|
|
418
|
-
}
|
|
419
|
-
// ADD
|
|
407
|
+
// ADD - caller (InteractionServer) has already validated that this ADD is allowed
|
|
420
408
|
if (!(tlv instanceof ArraySchema)) {
|
|
421
409
|
throw new StatusResponseError(
|
|
422
410
|
`Unsupported Write path provided: listIndex === ${listIndex} but attribute is not a list`,
|
|
@@ -42,6 +42,14 @@ export abstract class DataResponse<SessionT extends InteractionSession = Interac
|
|
|
42
42
|
return this.#session;
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
+
/**
|
|
46
|
+
* Update the session for processing subsequent chunks.
|
|
47
|
+
* This allows reusing the same response instance while maintaining state across chunks.
|
|
48
|
+
*/
|
|
49
|
+
protected updateSession(session: SessionT) {
|
|
50
|
+
this.#session = session;
|
|
51
|
+
}
|
|
52
|
+
|
|
45
53
|
/**
|
|
46
54
|
* The node ID used to filter paths with node ID specified. Unsure if this is ever actually used.
|
|
47
55
|
*/
|
|
@@ -69,11 +69,11 @@ export class ServerInteraction<
|
|
|
69
69
|
// TODO - validate request
|
|
70
70
|
|
|
71
71
|
const writer = new AttributeWriteResponse(this.#node, session);
|
|
72
|
-
return await writer.process(request)
|
|
72
|
+
return (await writer.process(request)) as Awaited<WriteResult<T>>;
|
|
73
73
|
}
|
|
74
74
|
|
|
75
75
|
async *invoke(request: Invoke, session: SessionT): InvokeResult {
|
|
76
|
-
// TODO -
|
|
76
|
+
// TODO - validate request
|
|
77
77
|
|
|
78
78
|
const invoker = new CommandInvokeResponse(this.#node, session);
|
|
79
79
|
yield* invoker.process(request);
|
|
@@ -227,11 +227,17 @@ export class DclOtaUpdateService {
|
|
|
227
227
|
localUpdates[0].maxApplicableSoftwareVersion ?? localUpdates[0].softwareVersion - 1,
|
|
228
228
|
source: localUpdates[0].mode === "prod" ? "dcl-prod" : "local",
|
|
229
229
|
};
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
230
|
+
if (
|
|
231
|
+
localUpdate.softwareVersion > currentSoftwareVersion &&
|
|
232
|
+
currentSoftwareVersion >= localUpdate.minApplicableSoftwareVersion &&
|
|
233
|
+
currentSoftwareVersion <= localUpdate.maxApplicableSoftwareVersion
|
|
234
|
+
) {
|
|
235
|
+
logger.debug(`Found applicable local update`, Diagnostic.dict(localUpdate));
|
|
236
|
+
if (targetSoftwareVersion !== undefined && localUpdate.softwareVersion === targetSoftwareVersion) {
|
|
237
|
+
return localUpdate;
|
|
238
|
+
}
|
|
239
|
+
foundUpdates.push(localUpdate);
|
|
233
240
|
}
|
|
234
|
-
foundUpdates.push(localUpdate);
|
|
235
241
|
}
|
|
236
242
|
}
|
|
237
243
|
|
|
@@ -508,7 +514,7 @@ export class DclOtaUpdateService {
|
|
|
508
514
|
return false;
|
|
509
515
|
}
|
|
510
516
|
|
|
511
|
-
//
|
|
517
|
+
// The current version must be within the applicable range if specified
|
|
512
518
|
if (
|
|
513
519
|
versionInfo.minApplicableSoftwareVersion !== undefined &&
|
|
514
520
|
currentVersion < versionInfo.minApplicableSoftwareVersion
|
|
@@ -30,6 +30,7 @@ import {
|
|
|
30
30
|
TlvDataVersionFilter,
|
|
31
31
|
TlvInvokeRequest,
|
|
32
32
|
TlvInvokeResponse,
|
|
33
|
+
TlvInvokeResponseForSend,
|
|
33
34
|
TlvReadRequest,
|
|
34
35
|
TlvSchema,
|
|
35
36
|
TlvStatusResponse,
|
|
@@ -76,6 +77,7 @@ export type SubscribeRequest = TypeFromSchema<typeof TlvSubscribeRequest>;
|
|
|
76
77
|
export type SubscribeResponse = TypeFromSchema<typeof TlvSubscribeResponse>;
|
|
77
78
|
export type InvokeRequest = TypeFromSchema<typeof TlvInvokeRequest>;
|
|
78
79
|
export type InvokeResponse = TypeFromSchema<typeof TlvInvokeResponse>;
|
|
80
|
+
export type InvokeResponseForSend = TypeFromSchema<typeof TlvInvokeResponseForSend>;
|
|
79
81
|
export type TimedRequest = TypeFromSchema<typeof TlvTimedRequest>;
|
|
80
82
|
export type WriteRequest = TypeFromSchema<typeof TlvWriteRequest>;
|
|
81
83
|
export type WriteResponse = TypeFromSchema<typeof TlvWriteResponse>;
|
|
@@ -211,7 +213,12 @@ export interface InteractionRecipient {
|
|
|
211
213
|
request: ReadRequest,
|
|
212
214
|
message: Message,
|
|
213
215
|
): Promise<{ dataReport: DataReport; payload?: DataReportPayloadIterator }>;
|
|
214
|
-
handleWriteRequest(
|
|
216
|
+
handleWriteRequest(
|
|
217
|
+
exchange: MessageExchange,
|
|
218
|
+
request: WriteRequest,
|
|
219
|
+
messenger: InteractionServerMessenger,
|
|
220
|
+
message: Message,
|
|
221
|
+
): Promise<void>;
|
|
215
222
|
handleSubscribeRequest(
|
|
216
223
|
exchange: MessageExchange,
|
|
217
224
|
request: SubscribeRequest,
|
|
@@ -262,11 +269,8 @@ export class InteractionServerMessenger extends InteractionMessenger {
|
|
|
262
269
|
}
|
|
263
270
|
case MessageType.WriteRequest: {
|
|
264
271
|
const writeRequest = TlvWriteRequest.decode(message.payload);
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
if (!suppressResponse && !isGroupSession) {
|
|
268
|
-
await this.send(MessageType.WriteResponse, TlvWriteResponse.encode(writeResponse));
|
|
269
|
-
}
|
|
272
|
+
await recipient.handleWriteRequest(this.exchange, writeRequest, this, message);
|
|
273
|
+
// response is sent by the handler
|
|
270
274
|
break;
|
|
271
275
|
}
|
|
272
276
|
case MessageType.SubscribeRequest: {
|
|
@@ -278,7 +282,7 @@ export class InteractionServerMessenger extends InteractionMessenger {
|
|
|
278
282
|
}
|
|
279
283
|
const subscribeRequest = TlvSubscribeRequest.decode(message.payload);
|
|
280
284
|
await recipient.handleSubscribeRequest(this.exchange, subscribeRequest, this, message);
|
|
281
|
-
// response is sent by handler
|
|
285
|
+
// response is sent by the handler
|
|
282
286
|
break;
|
|
283
287
|
}
|
|
284
288
|
case MessageType.InvokeRequest: {
|
|
@@ -797,6 +801,60 @@ export class InteractionServerMessenger extends InteractionMessenger {
|
|
|
797
801
|
}
|
|
798
802
|
}
|
|
799
803
|
}
|
|
804
|
+
|
|
805
|
+
/**
|
|
806
|
+
* Send a WriteResponse message.
|
|
807
|
+
*/
|
|
808
|
+
async sendWriteResponse(response: WriteResponse, options?: { logContext?: string }) {
|
|
809
|
+
await this.send(MessageType.WriteResponse, TlvWriteResponse.encode(response), {
|
|
810
|
+
logContext: options?.logContext ? { for: options.logContext } : undefined,
|
|
811
|
+
});
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
/**
|
|
815
|
+
* Wait for and decode the next WriteRequest message (for chunked writes).
|
|
816
|
+
*/
|
|
817
|
+
async readNextWriteRequest(): Promise<{ writeRequest: WriteRequest; message: Message }> {
|
|
818
|
+
const message = await this.nextMessage(MessageType.WriteRequest, undefined, "WriteRequest-chunk");
|
|
819
|
+
return {
|
|
820
|
+
writeRequest: TlvWriteRequest.decode(message.payload),
|
|
821
|
+
message,
|
|
822
|
+
};
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
/**
|
|
826
|
+
* Send an intermediate InvokeResponse chunk with moreChunkedMessages=true and wait for Status.Success.
|
|
827
|
+
* Returns true if a client acknowledged, and we should continue, false if a client terminated the chunked series.
|
|
828
|
+
*/
|
|
829
|
+
async sendInvokeResponseChunk(response: InvokeResponseForSend): Promise<boolean> {
|
|
830
|
+
await this.send(
|
|
831
|
+
MessageType.InvokeResponse,
|
|
832
|
+
TlvInvokeResponseForSend.encode({
|
|
833
|
+
...response,
|
|
834
|
+
moreChunkedMessages: true,
|
|
835
|
+
}),
|
|
836
|
+
{
|
|
837
|
+
logContext: { for: "InvokeResponse-chunk" },
|
|
838
|
+
},
|
|
839
|
+
);
|
|
840
|
+
|
|
841
|
+
try {
|
|
842
|
+
await this.waitForSuccess("InvokeResponse-chunk");
|
|
843
|
+
return true; // Continue sending chunks
|
|
844
|
+
} catch (error) {
|
|
845
|
+
// Any non-success status or error terminate further transmission of InvokeResponseMessages,
|
|
846
|
+
// close the exchange, and consider the Invoke Interaction completed.
|
|
847
|
+
logger.debug("Chunked invoke response terminated by client", error);
|
|
848
|
+
return false;
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
/**
|
|
853
|
+
* Send the final InvokeResponse (without moreChunkedMessages flag).
|
|
854
|
+
*/
|
|
855
|
+
async sendInvokeResponse(response: InvokeResponseForSend) {
|
|
856
|
+
await this.send(MessageType.InvokeResponse, TlvInvokeResponseForSend.encode(response));
|
|
857
|
+
}
|
|
800
858
|
}
|
|
801
859
|
|
|
802
860
|
export class IncomingInteractionClientMessenger extends InteractionMessenger {
|
|
@@ -972,7 +1030,14 @@ export class InteractionClientMessenger extends IncomingInteractionClientMesseng
|
|
|
972
1030
|
await this.send(MessageType.SubscribeRequest, request);
|
|
973
1031
|
}
|
|
974
1032
|
|
|
975
|
-
|
|
1033
|
+
/**
|
|
1034
|
+
* Send an invoke command and handle chunked responses.
|
|
1035
|
+
* Returns a combined InvokeResponse with all responses from all chunks, or undefined if suppressResponse
|
|
1036
|
+
*/
|
|
1037
|
+
async sendInvokeCommand(
|
|
1038
|
+
invokeRequest: InvokeRequest,
|
|
1039
|
+
expectedProcessingTime?: Duration,
|
|
1040
|
+
): Promise<InvokeResponse | undefined> {
|
|
976
1041
|
if (invokeRequest.suppressResponse) {
|
|
977
1042
|
await this.requestWithSuppressedResponse(
|
|
978
1043
|
MessageType.InvokeRequest,
|
|
@@ -980,16 +1045,49 @@ export class InteractionClientMessenger extends IncomingInteractionClientMesseng
|
|
|
980
1045
|
invokeRequest,
|
|
981
1046
|
expectedProcessingTime,
|
|
982
1047
|
);
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
1048
|
+
return undefined;
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
// Send invoke request
|
|
1052
|
+
await this.send(MessageType.InvokeRequest, TlvInvokeRequest.encode(invokeRequest), {
|
|
1053
|
+
expectAckOnly: false,
|
|
1054
|
+
expectedProcessingTime,
|
|
1055
|
+
});
|
|
1056
|
+
|
|
1057
|
+
// Receive and accumulate responses from potentially multiple chunks
|
|
1058
|
+
const allInvokeResponses: InvokeResponse["invokeResponses"] = [];
|
|
1059
|
+
let finalResponse: InvokeResponse | undefined;
|
|
1060
|
+
|
|
1061
|
+
while (true) {
|
|
1062
|
+
const responseMessage = await this.nextMessage(
|
|
987
1063
|
MessageType.InvokeResponse,
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
expectedProcessingTime,
|
|
1064
|
+
{ expectedProcessingTime },
|
|
1065
|
+
"InvokeResponse",
|
|
991
1066
|
);
|
|
1067
|
+
const response = TlvInvokeResponse.decode(responseMessage.payload);
|
|
1068
|
+
|
|
1069
|
+
// Accumulate responses from this chunk
|
|
1070
|
+
if (response.invokeResponses) {
|
|
1071
|
+
allInvokeResponses.push(...response.invokeResponses);
|
|
1072
|
+
}
|
|
1073
|
+
|
|
1074
|
+
// Check if more chunks are coming
|
|
1075
|
+
if (response.moreChunkedMessages) {
|
|
1076
|
+
await this.sendStatus(Status.Success, {
|
|
1077
|
+
multipleMessageInteraction: true,
|
|
1078
|
+
logContext: { for: "InvokeResponse-chunk" },
|
|
1079
|
+
});
|
|
1080
|
+
} else {
|
|
1081
|
+
// This is the final chunk
|
|
1082
|
+
finalResponse = {
|
|
1083
|
+
...response,
|
|
1084
|
+
invokeResponses: allInvokeResponses,
|
|
1085
|
+
};
|
|
1086
|
+
break;
|
|
1087
|
+
}
|
|
992
1088
|
}
|
|
1089
|
+
|
|
1090
|
+
return finalResponse;
|
|
993
1091
|
}
|
|
994
1092
|
|
|
995
1093
|
async sendWriteCommand(writeRequest: WriteRequest) {
|