@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
|
@@ -18,11 +18,9 @@ import {
|
|
|
18
18
|
StatusCode,
|
|
19
19
|
StatusResponseError,
|
|
20
20
|
TlvAny,
|
|
21
|
-
TlvAttributeReport,
|
|
22
21
|
TlvDataReport,
|
|
23
22
|
TlvDataReportForSend,
|
|
24
23
|
TlvDataVersionFilter,
|
|
25
|
-
TlvEventReport,
|
|
26
24
|
TlvInvokeRequest,
|
|
27
25
|
TlvInvokeResponse,
|
|
28
26
|
TlvReadRequest,
|
|
@@ -693,15 +691,10 @@ export class IncomingInteractionClientMessenger extends InteractionMessenger {
|
|
|
693
691
|
return message;
|
|
694
692
|
}
|
|
695
693
|
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
let subscriptionId: number | undefined;
|
|
699
|
-
const attributeValues: TypeFromSchema<typeof TlvAttributeReport>[] = [];
|
|
700
|
-
const eventValues: TypeFromSchema<typeof TlvEventReport>[] = [];
|
|
694
|
+
async readAggregateDataReport(expectedSubscriptionIds?: number[]): Promise<DataReport> {
|
|
695
|
+
let result: DataReport | undefined;
|
|
701
696
|
|
|
702
|
-
|
|
703
|
-
const dataReportMessage = await this.waitFor("DataReport", MessageType.ReportData);
|
|
704
|
-
const report = TlvDataReport.decode(dataReportMessage.payload);
|
|
697
|
+
for await (const report of this.readDataReports()) {
|
|
705
698
|
if (expectedSubscriptionIds !== undefined) {
|
|
706
699
|
if (report.subscriptionId === undefined || !expectedSubscriptionIds.includes(report.subscriptionId)) {
|
|
707
700
|
await this.sendStatus(StatusCode.InvalidSubscription, {
|
|
@@ -718,56 +711,82 @@ export class IncomingInteractionClientMessenger extends InteractionMessenger {
|
|
|
718
711
|
}
|
|
719
712
|
}
|
|
720
713
|
|
|
721
|
-
if (subscriptionId
|
|
722
|
-
subscriptionId = report.subscriptionId;
|
|
723
|
-
} else if (
|
|
724
|
-
(subscriptionId !== undefined || report.subscriptionId !== undefined) &&
|
|
725
|
-
report.subscriptionId !== subscriptionId
|
|
726
|
-
) {
|
|
714
|
+
if (result?.subscriptionId !== undefined && report.subscriptionId !== result.subscriptionId) {
|
|
727
715
|
throw new UnexpectedDataError(`Invalid subscription ID ${report.subscriptionId} received`);
|
|
728
716
|
}
|
|
729
717
|
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
718
|
+
if (!result) {
|
|
719
|
+
result = report;
|
|
720
|
+
} else {
|
|
721
|
+
if (Array.isArray(report.attributeReports)) {
|
|
722
|
+
if (!result.attributeReports) {
|
|
723
|
+
result.attributeReports = report.attributeReports;
|
|
724
|
+
} else {
|
|
725
|
+
result.attributeReports.push(...report.attributeReports);
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
if (Array.isArray(report.eventReports)) {
|
|
729
|
+
if (!result.eventReports) {
|
|
730
|
+
result.eventReports = report.eventReports;
|
|
731
|
+
} else {
|
|
732
|
+
result.eventReports.push(...report.eventReports);
|
|
733
|
+
}
|
|
734
|
+
}
|
|
746
735
|
}
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
if (result === undefined) {
|
|
739
|
+
// readDataReports should have thrown
|
|
740
|
+
throw new InternalError("No data reports loaded during read");
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
return result;
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
/**
|
|
747
|
+
* Read data reports as they come in on the wire.
|
|
748
|
+
*
|
|
749
|
+
* Data reports payloads are decoded but list attributes may be split across messages; these will require reassembly.
|
|
750
|
+
*/
|
|
751
|
+
async *readDataReports() {
|
|
752
|
+
while (true) {
|
|
753
|
+
const dataReportMessage = await this.waitFor("DataReport", MessageType.ReportData);
|
|
754
|
+
const report = TlvDataReport.decode(dataReportMessage.payload);
|
|
755
|
+
|
|
756
|
+
yield report;
|
|
747
757
|
|
|
748
758
|
if (report.moreChunkedMessages) {
|
|
749
759
|
await this.sendStatus(StatusCode.Success, {
|
|
750
760
|
multipleMessageInteraction: true,
|
|
751
|
-
logContext,
|
|
761
|
+
logContext: this.#logContextOf(report),
|
|
752
762
|
});
|
|
753
763
|
} else if (!report.suppressResponse) {
|
|
754
|
-
// We received the last message and need to send a final
|
|
764
|
+
// We received the last message and need to send a final success, but we do not need to wait for it and
|
|
755
765
|
// also don't care if it fails
|
|
756
766
|
this.sendStatus(StatusCode.Success, {
|
|
757
767
|
multipleMessageInteraction: true,
|
|
758
|
-
logContext,
|
|
759
|
-
}).catch(error =>
|
|
760
|
-
logger.info("Error while sending final Success after receiving all DataReport chunks", error),
|
|
761
|
-
);
|
|
768
|
+
logContext: this.#logContextOf(report),
|
|
769
|
+
}).catch(error => logger.info("Error sending success after final data report chunk", error));
|
|
762
770
|
}
|
|
763
771
|
|
|
764
772
|
if (!report.moreChunkedMessages) {
|
|
765
|
-
|
|
766
|
-
report.eventReports = eventValues;
|
|
767
|
-
return report;
|
|
773
|
+
break;
|
|
768
774
|
}
|
|
769
775
|
}
|
|
770
776
|
}
|
|
777
|
+
|
|
778
|
+
#logContextOf(report: DataReport) {
|
|
779
|
+
return {
|
|
780
|
+
subId: report.subscriptionId,
|
|
781
|
+
dataReportFlags: Diagnostic.asFlags({
|
|
782
|
+
empty: !report.attributeReports?.length && !report.eventReports?.length,
|
|
783
|
+
suppressResponse: report.suppressResponse,
|
|
784
|
+
moreChunkedMessages: report.moreChunkedMessages,
|
|
785
|
+
}),
|
|
786
|
+
attr: report.attributeReports?.length,
|
|
787
|
+
ev: report.eventReports?.length,
|
|
788
|
+
};
|
|
789
|
+
}
|
|
771
790
|
}
|
|
772
791
|
|
|
773
792
|
export class InteractionClientMessenger extends IncomingInteractionClientMessenger {
|
|
@@ -793,6 +812,7 @@ export class InteractionClientMessenger extends IncomingInteractionClientMesseng
|
|
|
793
812
|
return await this.exchange.send(messageType, payload, options);
|
|
794
813
|
} catch (error) {
|
|
795
814
|
if (
|
|
815
|
+
this.exchangeProvider.supportsReconnect &&
|
|
796
816
|
(error instanceof RetransmissionLimitReachedError || error instanceof ChannelNotConnectedError) &&
|
|
797
817
|
!options?.multipleMessageInteraction
|
|
798
818
|
) {
|
|
@@ -815,7 +835,7 @@ export class InteractionClientMessenger extends IncomingInteractionClientMesseng
|
|
|
815
835
|
async sendReadRequest(readRequest: ReadRequest) {
|
|
816
836
|
await this.send(MessageType.ReadRequest, this.#encodeReadingRequest(TlvReadRequest, readRequest));
|
|
817
837
|
|
|
818
|
-
return this.
|
|
838
|
+
return this.readAggregateDataReport();
|
|
819
839
|
}
|
|
820
840
|
|
|
821
841
|
#encodeReadingRequest<T extends TlvSchema<any>>(schema: T, request: TypeFromSchema<T>) {
|
|
@@ -876,7 +896,7 @@ export class InteractionClientMessenger extends IncomingInteractionClientMesseng
|
|
|
876
896
|
const request = this.#encodeReadingRequest(TlvSubscribeRequest, subscribeRequest);
|
|
877
897
|
await this.send(MessageType.SubscribeRequest, request);
|
|
878
898
|
|
|
879
|
-
const report = await this.
|
|
899
|
+
const report = await this.readAggregateDataReport();
|
|
880
900
|
const { subscriptionId } = report;
|
|
881
901
|
|
|
882
902
|
if (subscriptionId === undefined) {
|
|
@@ -227,9 +227,11 @@ export interface InteractionContext {
|
|
|
227
227
|
* Translates interactions from the Matter protocol to matter.js APIs.
|
|
228
228
|
*/
|
|
229
229
|
export class InteractionServer implements ProtocolHandler, InteractionRecipient {
|
|
230
|
+
readonly id = INTERACTION_PROTOCOL_ID;
|
|
230
231
|
#context: InteractionContext;
|
|
231
232
|
#nextSubscriptionId = Crypto.getRandomUInt32();
|
|
232
233
|
#isClosing = false;
|
|
234
|
+
#clientHandler?: ProtocolHandler;
|
|
233
235
|
readonly #subscriptionConfig: ServerSubscriptionConfig;
|
|
234
236
|
readonly #maxPathsPerInvoke;
|
|
235
237
|
|
|
@@ -244,10 +246,6 @@ export class InteractionServer implements ProtocolHandler, InteractionRecipient
|
|
|
244
246
|
});
|
|
245
247
|
}
|
|
246
248
|
|
|
247
|
-
getId() {
|
|
248
|
-
return INTERACTION_PROTOCOL_ID;
|
|
249
|
-
}
|
|
250
|
-
|
|
251
249
|
protected get isClosing() {
|
|
252
250
|
return this.#isClosing;
|
|
253
251
|
}
|
|
@@ -256,13 +254,28 @@ export class InteractionServer implements ProtocolHandler, InteractionRecipient
|
|
|
256
254
|
return this.#maxPathsPerInvoke;
|
|
257
255
|
}
|
|
258
256
|
|
|
259
|
-
async onNewExchange(exchange: MessageExchange) {
|
|
257
|
+
async onNewExchange(exchange: MessageExchange, message: Message) {
|
|
260
258
|
// Note - changes here must be copied to TransactionalInteractionServer as it does not call super() to avoid
|
|
261
259
|
// the stack frame
|
|
262
260
|
if (this.#isClosing) return; // We are closing, ignore anything newly incoming
|
|
261
|
+
|
|
262
|
+
// An incoming data report as the first message is not a valid server operation. We instead delegate to a
|
|
263
|
+
// client implementation if available
|
|
264
|
+
if (message.payloadHeader.messageType === MessageType.SubscribeRequest && this.#clientHandler) {
|
|
265
|
+
return this.#clientHandler.onNewExchange(exchange, message);
|
|
266
|
+
}
|
|
267
|
+
|
|
263
268
|
await new InteractionServerMessenger(exchange).handleRequest(this);
|
|
264
269
|
}
|
|
265
270
|
|
|
271
|
+
get clientHandler(): ProtocolHandler | undefined {
|
|
272
|
+
return this.#clientHandler;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
set clientHandler(clientHandler: ProtocolHandler) {
|
|
276
|
+
this.#clientHandler = clientHandler;
|
|
277
|
+
}
|
|
278
|
+
|
|
266
279
|
async #collectEventDataForRead(
|
|
267
280
|
{ eventRequests, eventFilters, isFabricFiltered }: ReadRequest,
|
|
268
281
|
exchange: MessageExchange,
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2022-2025 Matter.js Authors
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { MessageExchange } from "#protocol/MessageExchange.js";
|
|
8
|
+
import { ProtocolHandler } from "#protocol/ProtocolHandler.js";
|
|
9
|
+
import { Environment, Environmental, Logger, MaybePromise, Time, Timer } from "@matter/general";
|
|
10
|
+
import { INTERACTION_PROTOCOL_ID } from "@matter/types";
|
|
11
|
+
import { DataReport, IncomingInteractionClientMessenger } from "./InteractionMessenger.js";
|
|
12
|
+
|
|
13
|
+
const logger = Logger.get("SubscriptionClient");
|
|
14
|
+
|
|
15
|
+
export interface RegisteredSubscription {
|
|
16
|
+
id: number;
|
|
17
|
+
maximumPeerResponseTime: number;
|
|
18
|
+
maxIntervalS: number;
|
|
19
|
+
onData: (dataReport: DataReport) => MaybePromise<void>;
|
|
20
|
+
onTimeout?: () => void;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* A simple protocol handler that handles exchanges starting with data reports.
|
|
25
|
+
*
|
|
26
|
+
* Incoming data reports must match to a subscription registered with {@link add} or the exchange is invalid.
|
|
27
|
+
*/
|
|
28
|
+
export class SubscriptionClient implements ProtocolHandler {
|
|
29
|
+
readonly #listeners = new Map<number, (dataReport: DataReport) => MaybePromise<void>>();
|
|
30
|
+
readonly #timeouts = new Map<number, Timer>();
|
|
31
|
+
|
|
32
|
+
constructor() {}
|
|
33
|
+
|
|
34
|
+
static [Environmental.create](env: Environment) {
|
|
35
|
+
const client = new SubscriptionClient();
|
|
36
|
+
env.set(SubscriptionClient, client);
|
|
37
|
+
return client;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
readonly id = INTERACTION_PROTOCOL_ID;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Register a subscription.
|
|
44
|
+
*/
|
|
45
|
+
add(subscription: RegisteredSubscription) {
|
|
46
|
+
const { id, onData, onTimeout } = subscription;
|
|
47
|
+
|
|
48
|
+
this.#listeners.set(id, onData);
|
|
49
|
+
if (onTimeout) {
|
|
50
|
+
let timer = this.#timeouts.get(id);
|
|
51
|
+
if (timer !== undefined) {
|
|
52
|
+
timer.stop();
|
|
53
|
+
this.#timeouts.delete(id);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const maxIntervalMs = subscription.maxIntervalS * 1000 + subscription.maximumPeerResponseTime;
|
|
57
|
+
|
|
58
|
+
timer = Time.getTimer("Subscription timeout", maxIntervalMs, () => {
|
|
59
|
+
logger.info(`Subscription ${id} timed out after ${maxIntervalMs}ms`);
|
|
60
|
+
this.delete(id);
|
|
61
|
+
onTimeout();
|
|
62
|
+
}).start();
|
|
63
|
+
|
|
64
|
+
this.#timeouts.set(id, timer);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Unregister a subscription.
|
|
70
|
+
*/
|
|
71
|
+
delete(id: number) {
|
|
72
|
+
this.#listeners.delete(id);
|
|
73
|
+
const timer = this.#timeouts.get(id);
|
|
74
|
+
if (timer !== undefined) {
|
|
75
|
+
timer.stop();
|
|
76
|
+
this.#timeouts.delete(id);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async onNewExchange(exchange: MessageExchange) {
|
|
81
|
+
const messenger = new IncomingInteractionClientMessenger(exchange);
|
|
82
|
+
|
|
83
|
+
let dataReport: DataReport;
|
|
84
|
+
try {
|
|
85
|
+
// TODO Adjust this to getting packages as callback when received to handle error cases and checks outside
|
|
86
|
+
dataReport = await messenger.readAggregateDataReport([...this.#listeners.keys()]);
|
|
87
|
+
} finally {
|
|
88
|
+
messenger.close().catch(error => logger.info("Error closing client messenger", error));
|
|
89
|
+
}
|
|
90
|
+
const subscriptionId = dataReport.subscriptionId as number; // this is checked in the messenger already because we hand over allowed list
|
|
91
|
+
|
|
92
|
+
const listener = this.#listeners.get(subscriptionId);
|
|
93
|
+
const timer = this.#timeouts.get(subscriptionId);
|
|
94
|
+
|
|
95
|
+
if (timer !== undefined) {
|
|
96
|
+
timer.stop().start(); // Restart timer because we received data
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
await listener?.(dataReport);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
async close() {
|
|
103
|
+
this.#listeners.clear();
|
|
104
|
+
this.#timeouts.forEach(timer => timer.stop());
|
|
105
|
+
this.#timeouts.clear();
|
|
106
|
+
}
|
|
107
|
+
}
|
package/src/interaction/index.ts
CHANGED
|
@@ -27,11 +27,11 @@ import { ChannelStatusResponseError } from "#securechannel/index.js";
|
|
|
27
27
|
import { PaseClient } from "#session/index.js";
|
|
28
28
|
import { SessionManager } from "#session/SessionManager.js";
|
|
29
29
|
import { DiscoveryCapabilitiesBitmap, NodeId, SECURE_CHANNEL_PROTOCOL_ID, TypeFromPartialBitSchema } from "#types";
|
|
30
|
-
import { InteractionClient } from "../interaction/InteractionClient.js";
|
|
30
|
+
import { InteractionClient, InteractionClientProvider } from "../interaction/InteractionClient.js";
|
|
31
31
|
import { ExchangeManager, MessageChannel } from "../protocol/ExchangeManager.js";
|
|
32
32
|
import { DedicatedChannelExchangeProvider } from "../protocol/ExchangeProvider.js";
|
|
33
33
|
import { PeerAddress } from "./PeerAddress.js";
|
|
34
|
-
import { NodeDiscoveryType
|
|
34
|
+
import { NodeDiscoveryType } from "./PeerSet.js";
|
|
35
35
|
|
|
36
36
|
const logger = Logger.get("PeerCommissioner");
|
|
37
37
|
|
|
@@ -108,7 +108,7 @@ export interface DiscoveryAndCommissioningOptions extends CommissioningOptions {
|
|
|
108
108
|
* Interfaces {@link ControllerCommissioner} with other components.
|
|
109
109
|
*/
|
|
110
110
|
export interface ControllerCommissionerContext {
|
|
111
|
-
|
|
111
|
+
clients: InteractionClientProvider;
|
|
112
112
|
scanners: ScannerSet;
|
|
113
113
|
netInterfaces: NetInterfaceSet;
|
|
114
114
|
sessions: SessionManager;
|
|
@@ -130,7 +130,7 @@ export class ControllerCommissioner {
|
|
|
130
130
|
|
|
131
131
|
static [Environmental.create](env: Environment) {
|
|
132
132
|
const instance = new ControllerCommissioner({
|
|
133
|
-
|
|
133
|
+
clients: env.get(InteractionClientProvider),
|
|
134
134
|
scanners: env.get(ScannerSet),
|
|
135
135
|
netInterfaces: env.get(NetInterfaceSet),
|
|
136
136
|
sessions: env.get(SessionManager),
|
|
@@ -385,6 +385,7 @@ export class ControllerCommissioner {
|
|
|
385
385
|
// Use the created secure session to do the commissioning
|
|
386
386
|
new InteractionClient(
|
|
387
387
|
new DedicatedChannelExchangeProvider(this.#context.exchanges, paseSecureMessageChannel),
|
|
388
|
+
this.#context.clients.peers.subscriptionClient,
|
|
388
389
|
address,
|
|
389
390
|
),
|
|
390
391
|
this.#context.ca,
|
|
@@ -406,7 +407,7 @@ export class ControllerCommissioner {
|
|
|
406
407
|
}
|
|
407
408
|
|
|
408
409
|
// Look for the device broadcast over MDNS and do CASE pairing
|
|
409
|
-
return await this.#context.
|
|
410
|
+
return await this.#context.clients.connect(
|
|
410
411
|
address,
|
|
411
412
|
{
|
|
412
413
|
discoveryType: NodeDiscoveryType.TimedDiscovery,
|
|
@@ -422,7 +423,7 @@ export class ControllerCommissioner {
|
|
|
422
423
|
await commissioningManager.executeCommissioning();
|
|
423
424
|
} catch (error) {
|
|
424
425
|
// We might have added data for an operational address that we need to cleanup
|
|
425
|
-
await this.#context.peers.delete(address);
|
|
426
|
+
await this.#context.clients.peers.delete(address);
|
|
426
427
|
throw error;
|
|
427
428
|
} finally {
|
|
428
429
|
if (!paseSecureMessageChannel.closed) {
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2022-2025 Matter.js Authors
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { Environment, Environmental, PromiseQueue } from "@matter/general";
|
|
8
|
+
|
|
9
|
+
const CONCURRENT_QUEUED_INTERACTIONS = 4;
|
|
10
|
+
const INTERACTION_QUEUE_DELAY_MS = 100;
|
|
11
|
+
|
|
12
|
+
export class InteractionQueue extends PromiseQueue {
|
|
13
|
+
constructor() {
|
|
14
|
+
super(CONCURRENT_QUEUED_INTERACTIONS, INTERACTION_QUEUE_DELAY_MS);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
static [Environmental.create](env: Environment) {
|
|
18
|
+
const instance = new InteractionQueue();
|
|
19
|
+
env.set(InteractionQueue, instance);
|
|
20
|
+
return instance;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -18,7 +18,7 @@ export abstract class PeerAddressStore {
|
|
|
18
18
|
abstract loadPeers(): MaybePromise<Iterable<OperationalPeer>>;
|
|
19
19
|
abstract updatePeer(peer: OperationalPeer): MaybePromise<void>;
|
|
20
20
|
abstract deletePeer(address: PeerAddress): MaybePromise<void>;
|
|
21
|
-
abstract createNodeStore(address: PeerAddress):
|
|
21
|
+
abstract createNodeStore(address: PeerAddress): MaybePromise<PeerDataStore | undefined>;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
export abstract class PeerDataStore {
|