@matter/protocol 0.17.3 → 0.17.4-alpha.0-20260623-5647634fc
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 +2 -0
- package/dist/cjs/action/client/ClientInteraction.d.ts.map +1 -1
- package/dist/cjs/action/client/ClientInteraction.js +6 -4
- package/dist/cjs/action/client/ClientInteraction.js.map +1 -1
- package/dist/cjs/peer/Peer.d.ts +10 -1
- package/dist/cjs/peer/Peer.d.ts.map +1 -1
- package/dist/cjs/peer/Peer.js +15 -5
- package/dist/cjs/peer/Peer.js.map +1 -1
- package/dist/cjs/peer/PeerAddressMonitor.d.ts +19 -1
- package/dist/cjs/peer/PeerAddressMonitor.d.ts.map +1 -1
- package/dist/cjs/peer/PeerAddressMonitor.js +99 -65
- package/dist/cjs/peer/PeerAddressMonitor.js.map +1 -1
- package/dist/cjs/peer/PeerExchangeProvider.d.ts +5 -1
- package/dist/cjs/peer/PeerExchangeProvider.d.ts.map +1 -1
- package/dist/cjs/peer/PeerExchangeProvider.js +3 -0
- package/dist/cjs/peer/PeerExchangeProvider.js.map +1 -1
- package/dist/cjs/peer/PeerTimingParameters.d.ts +2 -2
- package/dist/cjs/peer/PeerTimingParameters.d.ts.map +1 -1
- package/dist/cjs/peer/PeerTimingParameters.js +2 -2
- package/dist/cjs/peer/PeerTimingParameters.js.map +1 -1
- package/dist/cjs/protocol/ExchangeProvider.d.ts +11 -0
- package/dist/cjs/protocol/ExchangeProvider.d.ts.map +1 -1
- package/dist/cjs/protocol/ExchangeProvider.js +8 -0
- package/dist/cjs/protocol/ExchangeProvider.js.map +1 -1
- package/dist/esm/action/client/ClientInteraction.d.ts +2 -0
- package/dist/esm/action/client/ClientInteraction.d.ts.map +1 -1
- package/dist/esm/action/client/ClientInteraction.js +6 -4
- package/dist/esm/action/client/ClientInteraction.js.map +1 -1
- package/dist/esm/peer/Peer.d.ts +10 -1
- package/dist/esm/peer/Peer.d.ts.map +1 -1
- package/dist/esm/peer/Peer.js +15 -5
- package/dist/esm/peer/Peer.js.map +1 -1
- package/dist/esm/peer/PeerAddressMonitor.d.ts +19 -1
- package/dist/esm/peer/PeerAddressMonitor.d.ts.map +1 -1
- package/dist/esm/peer/PeerAddressMonitor.js +100 -65
- package/dist/esm/peer/PeerAddressMonitor.js.map +1 -1
- package/dist/esm/peer/PeerExchangeProvider.d.ts +5 -1
- package/dist/esm/peer/PeerExchangeProvider.d.ts.map +1 -1
- package/dist/esm/peer/PeerExchangeProvider.js +3 -0
- package/dist/esm/peer/PeerExchangeProvider.js.map +1 -1
- package/dist/esm/peer/PeerTimingParameters.d.ts +2 -2
- package/dist/esm/peer/PeerTimingParameters.d.ts.map +1 -1
- package/dist/esm/peer/PeerTimingParameters.js +3 -3
- package/dist/esm/peer/PeerTimingParameters.js.map +1 -1
- package/dist/esm/protocol/ExchangeProvider.d.ts +11 -0
- package/dist/esm/protocol/ExchangeProvider.d.ts.map +1 -1
- package/dist/esm/protocol/ExchangeProvider.js +8 -0
- package/dist/esm/protocol/ExchangeProvider.js.map +1 -1
- package/package.json +5 -5
- package/src/action/client/ClientInteraction.ts +7 -4
- package/src/peer/Peer.ts +20 -8
- package/src/peer/PeerAddressMonitor.ts +127 -92
- package/src/peer/PeerExchangeProvider.ts +5 -1
- package/src/peer/PeerTimingParameters.ts +5 -5
- package/src/protocol/ExchangeProvider.ts +12 -0
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
6
|
import {
|
|
7
|
+
Abort,
|
|
7
8
|
ChannelType,
|
|
8
9
|
Diagnostic,
|
|
9
10
|
isIpNetworkChannel,
|
|
@@ -14,6 +15,7 @@ import {
|
|
|
14
15
|
} from "@matter/general";
|
|
15
16
|
import { PeerUnresponsiveError } from "./PeerCommunicationError.js";
|
|
16
17
|
const logger = Logger.get("PeerAddressMonitor");
|
|
18
|
+
const PROBE_MAX_RETRANSMISSIONS = 2;
|
|
17
19
|
class PeerAddressMonitor {
|
|
18
20
|
#peer;
|
|
19
21
|
#abort;
|
|
@@ -22,9 +24,8 @@ class PeerAddressMonitor {
|
|
|
22
24
|
#cooldownMax;
|
|
23
25
|
#trackWork;
|
|
24
26
|
#probing;
|
|
25
|
-
// Fibonacci backoff state — resets
|
|
27
|
+
// Fibonacci backoff state — grows on each successful probe, resets only on a real reachability scare
|
|
26
28
|
#lastProbeAt;
|
|
27
|
-
#lastProbedIp;
|
|
28
29
|
#fibPrev = 0;
|
|
29
30
|
#fibCurr = 0;
|
|
30
31
|
constructor(peer, stabilizationDelay, probeCooldown, abort, trackWork) {
|
|
@@ -34,13 +35,7 @@ class PeerAddressMonitor {
|
|
|
34
35
|
this.#cooldownMax = probeCooldown.maximum;
|
|
35
36
|
this.#trackWork = trackWork;
|
|
36
37
|
this.#timer = Time.getTimer("address check stabilization", stabilizationDelay, () => {
|
|
37
|
-
|
|
38
|
-
this.#probing = this.#check().finally(() => {
|
|
39
|
-
this.#probing = void 0;
|
|
40
|
-
this.schedule();
|
|
41
|
-
});
|
|
42
|
-
this.#trackWork(this.#probing);
|
|
43
|
-
}
|
|
38
|
+
this.#trackWork(this.verifyReachability({ reason: "address-change", abort: this.#abort }));
|
|
44
39
|
});
|
|
45
40
|
}
|
|
46
41
|
/**
|
|
@@ -59,79 +54,119 @@ class PeerAddressMonitor {
|
|
|
59
54
|
stop() {
|
|
60
55
|
this.#timer.stop();
|
|
61
56
|
}
|
|
62
|
-
|
|
57
|
+
/**
|
|
58
|
+
* Tear down: stop the timer and await any in-flight run so teardown does not race a probe. The
|
|
59
|
+
* caller is expected to have aborted the peer first, so the in-flight run unwinds promptly.
|
|
60
|
+
*/
|
|
61
|
+
async close() {
|
|
62
|
+
this.#timer.stop();
|
|
63
|
+
await this.#probing;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Verify the peer is reachable, driving recovery. Coalesces concurrent triggers into one run.
|
|
67
|
+
*
|
|
68
|
+
* An `address-change` run probes the current address then walks discovered alternates (migrating in
|
|
69
|
+
* place on success); a `session-suspect` run only probes the current address and never walks alternates.
|
|
70
|
+
* Returns `true` if the session is usable afterward (current address answered, or an alternate
|
|
71
|
+
* answered and the session migrated); `false` if no address answered and the session was closed.
|
|
72
|
+
*/
|
|
73
|
+
async verifyReachability(options) {
|
|
74
|
+
if (this.#probing === void 0) {
|
|
75
|
+
this.#probing = this.#run(options.reason).finally(() => {
|
|
76
|
+
this.#probing = void 0;
|
|
77
|
+
if (options.reason === "address-change") {
|
|
78
|
+
this.schedule();
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
const run = this.#probing;
|
|
83
|
+
return options.abort !== void 0 && options.abort !== this.#abort ? await Abort.race(options.abort, run) ?? false : run;
|
|
84
|
+
}
|
|
85
|
+
async #run(reason) {
|
|
86
|
+
const abort = this.#abort;
|
|
63
87
|
const session = this.#peer.newestSession();
|
|
64
88
|
const interaction = this.#peer.interaction;
|
|
65
89
|
if (!session || !interaction) {
|
|
66
|
-
return;
|
|
90
|
+
return false;
|
|
67
91
|
}
|
|
68
92
|
const channel = session.channel.transportChannel;
|
|
69
|
-
if (!isIpNetworkChannel(channel)) {
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
|
-
if (channel.type === ChannelType.TCP) {
|
|
73
|
-
return;
|
|
93
|
+
if (!isIpNetworkChannel(channel) || channel.type === ChannelType.TCP) {
|
|
94
|
+
return true;
|
|
74
95
|
}
|
|
75
96
|
const currentAddress = channel.networkAddress;
|
|
76
|
-
const currentIp = currentAddress.ip;
|
|
77
97
|
const discoveredAddresses = this.#peer.service.addresses;
|
|
78
|
-
if (
|
|
79
|
-
return;
|
|
80
|
-
}
|
|
81
|
-
if (discoveredAddresses.has(currentAddress)) {
|
|
82
|
-
return;
|
|
83
|
-
}
|
|
84
|
-
const via = session.via;
|
|
85
|
-
if (currentIp !== this.#lastProbedIp) {
|
|
98
|
+
if (reason === "session-suspect") {
|
|
86
99
|
this.#resetBackoff();
|
|
87
100
|
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
101
|
+
if (reason === "address-change") {
|
|
102
|
+
const stillDiscovered = [...discoveredAddresses].some((addr) => ServerAddress.isEqual(addr, currentAddress));
|
|
103
|
+
if (!discoveredAddresses.size || stillDiscovered) {
|
|
104
|
+
return true;
|
|
105
|
+
}
|
|
106
|
+
const lastKnownGood = Timestamp(Math.max(this.#lastProbeAt ?? 0, session.activeTimestamp));
|
|
107
|
+
if (lastKnownGood > 0 && Timestamp.delta(lastKnownGood) < this.#currentCooldown) {
|
|
108
|
+
return true;
|
|
109
|
+
}
|
|
110
|
+
logger.info(
|
|
111
|
+
session.via,
|
|
112
|
+
"Session address",
|
|
113
|
+
Diagnostic.strong(ServerAddress.urlFor(currentAddress)),
|
|
114
|
+
"no longer in mDNS results, probing"
|
|
115
|
+
);
|
|
116
|
+
this.#lastProbeAt = Time.nowMs;
|
|
92
117
|
}
|
|
93
|
-
logger.info(
|
|
94
|
-
via,
|
|
95
|
-
"Session address",
|
|
96
|
-
Diagnostic.strong(ServerAddress.urlFor(currentAddress)),
|
|
97
|
-
"no longer in mDNS results, probing"
|
|
98
|
-
);
|
|
99
|
-
this.#lastProbeAt = Time.nowMs;
|
|
100
|
-
this.#lastProbedIp = currentIp;
|
|
101
118
|
const network = this.#peer.network;
|
|
102
119
|
const probeNetwork = network.probeAddress ?? network;
|
|
103
|
-
if (await interaction.probe({
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
120
|
+
if (await interaction.probe({
|
|
121
|
+
network: probeNetwork.id,
|
|
122
|
+
abort,
|
|
123
|
+
suppressPeerLoss: true,
|
|
124
|
+
maxRetransmissions: PROBE_MAX_RETRANSMISSIONS
|
|
125
|
+
})) {
|
|
126
|
+
if (reason === "address-change") {
|
|
127
|
+
this.#advanceBackoff();
|
|
110
128
|
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
129
|
+
return true;
|
|
130
|
+
}
|
|
131
|
+
if (reason === "address-change") {
|
|
132
|
+
for (const ipAddress of discoveredAddresses) {
|
|
133
|
+
if (abort.aborted) {
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
136
|
+
if (ServerAddress.isEqual(ipAddress, currentAddress)) {
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
const address = { ...ipAddress, type: "udp" };
|
|
140
|
+
if (await interaction.probe({
|
|
141
|
+
network: probeNetwork.id,
|
|
142
|
+
abort,
|
|
143
|
+
addressOverride: address,
|
|
144
|
+
suppressPeerLoss: true,
|
|
145
|
+
maxRetransmissions: PROBE_MAX_RETRANSMISSIONS
|
|
146
|
+
})) {
|
|
147
|
+
logger.info(
|
|
148
|
+
session.via,
|
|
149
|
+
"Discovered address reachable, migrating session to",
|
|
150
|
+
Diagnostic.strong(ServerAddress.urlFor(address))
|
|
151
|
+
);
|
|
152
|
+
session.channel.networkAddress = address;
|
|
153
|
+
interaction.subscriptions.closeForPeer(this.#peer.address);
|
|
154
|
+
this.#resetBackoff();
|
|
155
|
+
return true;
|
|
156
|
+
}
|
|
127
157
|
}
|
|
158
|
+
this.#resetBackoff();
|
|
128
159
|
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
160
|
+
if (abort.aborted) {
|
|
161
|
+
return false;
|
|
162
|
+
}
|
|
163
|
+
logger.info(session.via, "All probes failed, closing session");
|
|
164
|
+
try {
|
|
165
|
+
await session.handlePeerLoss({ cause: new PeerUnresponsiveError() });
|
|
166
|
+
} catch (error) {
|
|
167
|
+
logger.warn(session.via, "Error closing unreachable session", error);
|
|
132
168
|
}
|
|
133
|
-
|
|
134
|
-
await session.handlePeerLoss({ cause: new PeerUnresponsiveError() });
|
|
169
|
+
return false;
|
|
135
170
|
}
|
|
136
171
|
/** Current cooldown duration based on Fibonacci position. */
|
|
137
172
|
get #currentCooldown() {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/peer/PeerAddressMonitor.ts"],
|
|
4
|
-
"mappings": "AAAA;AAAA;AAAA;AAAA;AAAA;
|
|
4
|
+
"mappings": "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",
|
|
5
5
|
"names": []
|
|
6
6
|
}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
6
|
import { PeerAddress } from "#peer/PeerAddress.js";
|
|
7
|
-
import { ExchangeProvider, NewExchangeOptions } from "#protocol/ExchangeProvider.js";
|
|
7
|
+
import { ExchangeProvider, NewExchangeOptions, type ReachabilityReason } from "#protocol/ExchangeProvider.js";
|
|
8
8
|
import type { MessageExchange } from "#protocol/MessageExchange.js";
|
|
9
9
|
import { ChannelType, Duration } from "@matter/general";
|
|
10
10
|
import { Peer } from "./Peer.js";
|
|
@@ -23,6 +23,10 @@ export declare class PeerExchangeProvider extends ExchangeProvider {
|
|
|
23
23
|
*/
|
|
24
24
|
get channelType(): ChannelType;
|
|
25
25
|
connect(options?: NewExchangeOptions): Promise<void>;
|
|
26
|
+
verifyReachability(options: {
|
|
27
|
+
reason: ReachabilityReason;
|
|
28
|
+
abort?: AbortSignal;
|
|
29
|
+
}): Promise<boolean>;
|
|
26
30
|
initiateExchange(options?: NewExchangeOptions): Promise<MessageExchange>;
|
|
27
31
|
maximumPeerResponseTime(expectedProcessingTime?: Duration, includeMaximumSendingTime?: boolean): Duration;
|
|
28
32
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PeerExchangeProvider.d.ts","sourceRoot":"","sources":["../../../src/peer/PeerExchangeProvider.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"PeerExchangeProvider.d.ts","sourceRoot":"","sources":["../../../src/peer/PeerExchangeProvider.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,KAAK,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AAC9G,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAEpE,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAiB,MAAM,iBAAiB,CAAC;AAEvE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAErD;;GAEG;AACH,qBAAa,oBAAqB,SAAQ,gBAAgB;;IAItD,YAAY,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,cAAc,CAAC,OAAO,EAKtD;IAED,IAAI,iBAAiB,WAEpB;IAED,IAAI,WAAW,gBAEd;IAED;;;OAGG;IACH,IAAI,WAAW,gBAMd;IAEc,OAAO,CAAC,OAAO,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CASlE;IAEQ,kBAAkB,CAAC,OAAO,EAAE;QAAE,MAAM,EAAE,kBAAkB,CAAC;QAAC,KAAK,CAAC,EAAE,WAAW,CAAA;KAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAE1G;IAEc,gBAAgB,CAAC,OAAO,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,eAAe,CAAC,CAwEtF;IAEQ,uBAAuB,CAAC,sBAAsB,CAAC,EAAE,QAAQ,EAAE,yBAAyB,CAAC,EAAE,OAAO,GAAG,QAAQ,CAQjH;CACJ"}
|
|
@@ -44,6 +44,9 @@ class PeerExchangeProvider extends ExchangeProvider {
|
|
|
44
44
|
preferredTransport: options?.preferredTransport
|
|
45
45
|
});
|
|
46
46
|
}
|
|
47
|
+
verifyReachability(options) {
|
|
48
|
+
return this.#peer.verifyReachability(options);
|
|
49
|
+
}
|
|
47
50
|
async initiateExchange(options) {
|
|
48
51
|
const abort = options?.abort;
|
|
49
52
|
const isGroup = PeerAddress.isGroup(this.#peer.address);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/peer/PeerExchangeProvider.ts"],
|
|
4
|
-
"mappings": "AAAA;AAAA;AAAA;AAAA;AAAA;AAMA,SAAS,mBAAmB;AAC5B,SAAS,
|
|
4
|
+
"mappings": "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",
|
|
5
5
|
"names": []
|
|
6
6
|
}
|
|
@@ -91,11 +91,11 @@ export interface PeerTimingParameters {
|
|
|
91
91
|
*/
|
|
92
92
|
addressChangeStabilizationDelay: Duration;
|
|
93
93
|
/**
|
|
94
|
-
* Probe cooldown range for address-change probes
|
|
94
|
+
* Probe cooldown range for address-change probes.
|
|
95
95
|
*
|
|
96
96
|
* When mDNS keeps reporting the session IP as gone but probes succeed, the cooldown grows
|
|
97
97
|
* using a Fibonacci-like sequence from {@link minimum} to {@link maximum}. The cooldown
|
|
98
|
-
* resets
|
|
98
|
+
* resets on a probe failure or a subscription-liveness scare, not on a mere address change.
|
|
99
99
|
*
|
|
100
100
|
* Probes are also suppressed while the session is actively receiving data — the cooldown
|
|
101
101
|
* is measured from whichever is more recent: the last probe or the last received message.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PeerTimingParameters.d.ts","sourceRoot":"","sources":["../../../src/peer/PeerTimingParameters.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,QAAQ,
|
|
1
|
+
{"version":3,"file":"PeerTimingParameters.d.ts","sourceRoot":"","sources":["../../../src/peer/PeerTimingParameters.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,QAAQ,EAA0D,MAAM,iBAAiB,CAAC;AAEnG;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACjC;;;;;OAKG;IACH,wBAAwB,EAAE,QAAQ,CAAC;IAEnC;;;;OAIG;IACH,oCAAoC,EAAE,QAAQ,CAAC;IAE/C;;;;OAIG;IACH,sBAAsB,EAAE,QAAQ,CAAC;IAEjC;;;;;;;OAOG;IACH,sBAAsB,EAAE,QAAQ,CAAC;IAEjC;;;;OAIG;IACH,mBAAmB,EAAE,QAAQ,CAAC;IAE9B;;;;OAIG;IACH,wBAAwB,EAAE,QAAQ,CAAC;IAEnC;;;;;OAKG;IACH,oBAAoB,EAAE,QAAQ,CAAC;IAE/B;;;;;OAKG;IACH,sBAAsB,EAAE,MAAM,CAAC;IAE/B;;;;;;;OAOG;IACH,oBAAoB,EAAE,QAAQ,CAAC;IAE/B;;;;;OAKG;IACH,mBAAmB,EAAE;QACjB,mEAAmE;QACnE,aAAa,EAAE,QAAQ,CAAC;QAExB,gFAAgF;QAChF,OAAO,EAAE,QAAQ,CAAC;KACrB,CAAC;IAEF;;;;;OAKG;IACH,+BAA+B,EAAE,QAAQ,CAAC;IAE1C;;;;;;;;;OASG;IACH,0BAA0B,EAAE;QACxB,wEAAwE;QACxE,OAAO,EAAE,QAAQ,CAAC;QAElB,wDAAwD;QACxD,OAAO,EAAE,QAAQ,CAAC;KACrB,CAAC;CACL;AAQD,wBAAgB,oBAAoB,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC,oBAAoB,CAAC,wBAiB3E;AAED,yBAAiB,oBAAoB,CAAC,CAAC;IACnC;;;;;OAKG;IACH,SAAgB,KAAK,CAAC,IAAI,EAAE,oBAAoB,EAAE,SAAS,EAAE,OAAO,CAAC,oBAAoB,CAAC,GAAG,oBAAoB,CAIhH;IAKM,MAAM,QAAQ,EAAE,oBAsBtB,CAAC;CACL"}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Copyright 2022-2026 Matter.js Authors
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
|
-
import { merge as mergeObjects, Millis, Minutes, Seconds } from "@matter/general";
|
|
6
|
+
import { Hours, merge as mergeObjects, Millis, Minutes, Seconds } from "@matter/general";
|
|
7
7
|
const complete = /* @__PURE__ */ Symbol("complete-timing-parameters");
|
|
8
8
|
function PeerTimingParameters(options) {
|
|
9
9
|
if (options && options[complete]) {
|
|
@@ -47,8 +47,8 @@ function PeerTimingParameters(options) {
|
|
|
47
47
|
},
|
|
48
48
|
addressChangeStabilizationDelay: Seconds(10),
|
|
49
49
|
addressChangeProbeCooldown: {
|
|
50
|
-
minimum: Minutes(
|
|
51
|
-
maximum:
|
|
50
|
+
minimum: Minutes(10),
|
|
51
|
+
maximum: Hours(24)
|
|
52
52
|
}
|
|
53
53
|
};
|
|
54
54
|
})(PeerTimingParameters || (PeerTimingParameters = {}));
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/peer/PeerTimingParameters.ts"],
|
|
4
|
-
"mappings": "AAAA;AAAA;AAAA;AAAA;AAAA;AAMA,SAAmB,SAAS,cAAc,QAAQ,SAAS,eAAe;
|
|
4
|
+
"mappings": "AAAA;AAAA;AAAA;AAAA;AAAA;AAMA,SAAmB,OAAO,SAAS,cAAc,QAAQ,SAAS,eAAe;AAuHjF,MAAM,WAAW,uBAAO,4BAA4B;AAM7C,SAAS,qBAAqB,SAAyC;AAC1E,MAAI,WAAY,QAAqB,QAAQ,GAAG;AAC5C,WAAO;AAAA,EACX;AAEA,QAAM,SAAS,EAAE,GAAG,qBAAqB,SAAS;AAClD,MAAI,SAAS;AACT,eAAW,OAAO,OAAO,KAAK,OAAO,GAAG;AACpC,YAAM,QAAS,QAAoC,GAAG;AACtD,UAAI,UAAU,QAAW;AACrB,eAAO,GAAG,IAAI;AAAA,MAClB;AAAA,IACJ;AAAA,EACJ;AACA,SAAO,QAAQ,IAAI;AAEnB,SAAO;AACX;AAAA,CAEO,CAAUA,0BAAV;AAOI,WAAS,MAAM,MAA4B,WAAgE;AAC9G,UAAM,SAAS,aAAa,MAAM,SAAS;AAC3C,WAAO,QAAQ,IAAI;AACnB,WAAO;AAAA,EACX;AAJO,EAAAA,sBAAS;AAMhB,QAAM,iCAAiC,QAAQ,CAAC;AAGzC,EAAMA,sBAAA,WAAiC;AAAA,IAC1C,0BAA0B,QAAQ,EAAE;AAAA,IACpC,sCAAsC;AAAA;AAAA;AAAA,IAItC,wBAAwB,QAAQ,EAAE;AAAA,IAClC,wBAAwB,QAAQ,EAAE;AAAA,IAClC,qBAAqB,QAAQ,CAAC;AAAA,IAC9B,0BAA0B,QAAQ,CAAC;AAAA,IACnC,sBAAsB,QAAQ,CAAC;AAAA,IAC/B,wBAAwB;AAAA,IACxB,sBAAsB,OAAO,iCAAiC,CAAC;AAAA,IAC/D,qBAAqB;AAAA,MACjB,eAAe,QAAQ,EAAE;AAAA,MACzB,SAAS,QAAQ,EAAE;AAAA,IACvB;AAAA,IACA,iCAAiC,QAAQ,EAAE;AAAA,IAC3C,4BAA4B;AAAA,MACxB,SAAS,QAAQ,EAAE;AAAA,MACnB,SAAS,MAAM,EAAE;AAAA,IACrB;AAAA,EACJ;AAAA,GAtCa;",
|
|
5
5
|
"names": ["PeerTimingParameters"]
|
|
6
6
|
}
|
|
@@ -50,6 +50,8 @@ export interface NewExchangeOptions extends Omit<InteractionSettings, "transacti
|
|
|
50
50
|
*/
|
|
51
51
|
preferredTransport?: ChannelType;
|
|
52
52
|
}
|
|
53
|
+
/** Why a reachability check was requested. Gates entry conditions, not the probe mechanics. */
|
|
54
|
+
export type ReachabilityReason = "address-change" | "session-suspect";
|
|
53
55
|
/**
|
|
54
56
|
* Interface for obtaining a message exchange with a specific peer.
|
|
55
57
|
*/
|
|
@@ -74,6 +76,15 @@ export declare abstract class ExchangeProvider {
|
|
|
74
76
|
* The default implementation is a no-op (already connected).
|
|
75
77
|
*/
|
|
76
78
|
connect(_options?: NewExchangeOptions): Promise<void>;
|
|
79
|
+
/**
|
|
80
|
+
* Verify the peer is reachable, driving recovery (alternate-address migration or session close).
|
|
81
|
+
*
|
|
82
|
+
* The default reports reachable; only peer-backed providers have a reachability authority and override this.
|
|
83
|
+
*/
|
|
84
|
+
verifyReachability(_options: {
|
|
85
|
+
reason: ReachabilityReason;
|
|
86
|
+
abort?: AbortSignal;
|
|
87
|
+
}): Promise<boolean>;
|
|
77
88
|
}
|
|
78
89
|
/**
|
|
79
90
|
* Manages an exchange over an established channel.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ExchangeProvider.d.ts","sourceRoot":"","sources":["../../../src/protocol/ExchangeProvider.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AACrE,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAC/D,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAE/D,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAI1E;;GAEG;AACH,MAAM,WAAW,kBAAmB,SAAQ,IAAI,CAAC,mBAAmB,EAAE,aAAa,CAAC;IAChF;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;;;;OAKG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;;OAGG;IACH,kBAAkB,CAAC,EAAE,QAAQ,CAAC;IAE9B;;;OAGG;IACH,eAAe,CAAC,EAAE,gBAAgB,CAAC;IAEnC;;;OAGG;IACH,sBAAsB,CAAC,EAAE,OAAO,CAAC;IAEjC,wGAAwG;IACxG,iBAAiB,CAAC,EAAE,WAAW,CAAC;IAEhC;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,WAAW,CAAC;CACpC;AAED;;GAEG;AACH,8BAAsB,gBAAgB;IACtB,SAAS,CAAC,QAAQ,CAAC,eAAe,EAAE,eAAe;IAA/D,YAA+B,eAAe,EAAE,eAAe,EAAI;IAEnE,QAAQ,CAAC,uBAAuB,CAAC,sBAAsB,CAAC,EAAE,QAAQ,EAAE,yBAAyB,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;IACnH,QAAQ,CAAC,gBAAgB,CAAC,OAAO,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;IAClF,QAAQ,CAAC,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC;IAC3C,QAAQ,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,WAAW,CAAC;IAC5C,QAAQ,CAAC,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAE7C;;;;;OAKG;IACH,IAAI,OAAO,IAAI,aAAa,GAAG,SAAS,CAEvC;IAED;;;;OAIG;IACG,OAAO,CAAC,QAAQ,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAG;
|
|
1
|
+
{"version":3,"file":"ExchangeProvider.d.ts","sourceRoot":"","sources":["../../../src/protocol/ExchangeProvider.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AACrE,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAC/D,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAE/D,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAI1E;;GAEG;AACH,MAAM,WAAW,kBAAmB,SAAQ,IAAI,CAAC,mBAAmB,EAAE,aAAa,CAAC;IAChF;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;;;;OAKG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;;OAGG;IACH,kBAAkB,CAAC,EAAE,QAAQ,CAAC;IAE9B;;;OAGG;IACH,eAAe,CAAC,EAAE,gBAAgB,CAAC;IAEnC;;;OAGG;IACH,sBAAsB,CAAC,EAAE,OAAO,CAAC;IAEjC,wGAAwG;IACxG,iBAAiB,CAAC,EAAE,WAAW,CAAC;IAEhC;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,WAAW,CAAC;CACpC;AAED,+FAA+F;AAC/F,MAAM,MAAM,kBAAkB,GAAG,gBAAgB,GAAG,iBAAiB,CAAC;AAEtE;;GAEG;AACH,8BAAsB,gBAAgB;IACtB,SAAS,CAAC,QAAQ,CAAC,eAAe,EAAE,eAAe;IAA/D,YAA+B,eAAe,EAAE,eAAe,EAAI;IAEnE,QAAQ,CAAC,uBAAuB,CAAC,sBAAsB,CAAC,EAAE,QAAQ,EAAE,yBAAyB,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;IACnH,QAAQ,CAAC,gBAAgB,CAAC,OAAO,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;IAClF,QAAQ,CAAC,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC;IAC3C,QAAQ,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,WAAW,CAAC;IAC5C,QAAQ,CAAC,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAE7C;;;;;OAKG;IACH,IAAI,OAAO,IAAI,aAAa,GAAG,SAAS,CAEvC;IAED;;;;OAIG;IACG,OAAO,CAAC,QAAQ,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAG;IAE9D;;;;OAIG;IACG,kBAAkB,CAAC,QAAQ,EAAE;QAAE,MAAM,EAAE,kBAAkB,CAAC;QAAC,KAAK,CAAC,EAAE,WAAW,CAAA;KAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAExG;CACJ;AAED;;GAEG;AACH,qBAAa,gCAAiC,SAAQ,gBAAgB;;IAGlE,YAAY,eAAe,EAAE,eAAe,EAAE,OAAO,EAAE,aAAa,EAGnE;IAED,IAAI,iBAAiB,WAEpB;IAEK,gBAAgB,CAAC,OAAO,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,eAAe,CAAC,CAM7E;IAED,IAAI,WAAW,gBAEd;IAED,IAAa,OAAO,kBAEnB;IAED,uBAAuB,CACnB,sBAAsB,WAAuC,EAC7D,yBAAyB,CAAC,EAAE,OAAO,YAOtC;IAED,IAAI,WAAW;;;kBAId;CACJ"}
|
|
@@ -27,6 +27,14 @@ class ExchangeProvider {
|
|
|
27
27
|
*/
|
|
28
28
|
async connect(_options) {
|
|
29
29
|
}
|
|
30
|
+
/**
|
|
31
|
+
* Verify the peer is reachable, driving recovery (alternate-address migration or session close).
|
|
32
|
+
*
|
|
33
|
+
* The default reports reachable; only peer-backed providers have a reachability authority and override this.
|
|
34
|
+
*/
|
|
35
|
+
async verifyReachability(_options) {
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
30
38
|
}
|
|
31
39
|
class DedicatedChannelExchangeProvider extends ExchangeProvider {
|
|
32
40
|
#session;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/protocol/ExchangeProvider.ts"],
|
|
4
|
-
"mappings": "AAAA;AAAA;AAAA;AAAA;AAAA;AASA,SAAS,mBAAmB;AAG5B,SAAS,+BAA+B;AACxC,SAAS,WAAW;
|
|
4
|
+
"mappings": "AAAA;AAAA;AAAA;AAAA;AAAA;AASA,SAAS,mBAAmB;AAG5B,SAAS,+BAA+B;AACxC,SAAS,WAAW;AAwDb,MAAe,iBAAiB;AAAA,EACnC,YAA+B,iBAAkC;AAAlC;AAAA,EAAmC;AAAA,EAAnC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAc/B,IAAI,UAAqC;AACrC,WAAO;AAAA,EACX;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,QAAQ,UAA8C;AAAA,EAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAO7D,MAAM,mBAAmB,UAAiF;AACtG,WAAO;AAAA,EACX;AACJ;AAKO,MAAM,yCAAyC,iBAAiB;AAAA,EACnE;AAAA,EAEA,YAAY,iBAAkC,SAAwB;AAClE,UAAM,eAAe;AACrB,SAAK,WAAW;AAAA,EACpB;AAAA,EAEA,IAAI,oBAAoB;AACpB,WAAO,KAAK,SAAS,WAAW;AAAA,EACpC;AAAA,EAEA,MAAM,iBAAiB,SAAwD;AAG3E,WAAO,KAAK,gBAAgB,2BAA2B,KAAK,UAAU,yBAAyB;AAAA,MAC3F,wBAAwB,SAAS;AAAA,IACrC,CAAC;AAAA,EACL;AAAA,EAEA,IAAI,cAAc;AACd,WAAO,KAAK,SAAS,QAAQ,iBAAiB;AAAA,EAClD;AAAA,EAEA,IAAa,UAAU;AACnB,WAAO,KAAK;AAAA,EAChB;AAAA,EAEA,wBACI,yBAAyB,IAAI,kCAC7B,2BACF;AACE,WAAO,KAAK,gBAAgB;AAAA,MACxB,KAAK;AAAA,MACL;AAAA,MACA;AAAA,IACJ;AAAA,EACJ;AAAA,EAEA,IAAI,cAAc;AACd,QAAI,YAAY,GAAG,KAAK,QAAQ,GAAG;AAC/B,aAAO,KAAK,SAAS;AAAA,IACzB;AAAA,EACJ;AACJ;",
|
|
5
5
|
"names": []
|
|
6
6
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@matter/protocol",
|
|
3
|
-
"version": "0.17.
|
|
3
|
+
"version": "0.17.4-alpha.0-20260623-5647634fc",
|
|
4
4
|
"description": "Low-level APIs for Matter interaction",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"iot",
|
|
@@ -35,12 +35,12 @@
|
|
|
35
35
|
"#*": "./src/*"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@matter/general": "0.17.
|
|
39
|
-
"@matter/model": "0.17.
|
|
40
|
-
"@matter/types": "0.17.
|
|
38
|
+
"@matter/general": "0.17.4-alpha.0-20260623-5647634fc",
|
|
39
|
+
"@matter/model": "0.17.4-alpha.0-20260623-5647634fc",
|
|
40
|
+
"@matter/types": "0.17.4-alpha.0-20260623-5647634fc"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
|
-
"@matter/testing": "0.17.
|
|
43
|
+
"@matter/testing": "0.17.4-alpha.0-20260623-5647634fc"
|
|
44
44
|
},
|
|
45
45
|
"files": [
|
|
46
46
|
"dist/**/*",
|
|
@@ -299,6 +299,7 @@ export class ClientInteraction<
|
|
|
299
299
|
await messenger.sendReadRequest(Read({ fabricFilter: false }), {
|
|
300
300
|
abort,
|
|
301
301
|
suppressPeerLoss: options?.suppressPeerLoss,
|
|
302
|
+
maxRetransmissions: options?.maxRetransmissions,
|
|
302
303
|
});
|
|
303
304
|
for await (const _report of messenger.readDataReports({ abort }));
|
|
304
305
|
logger.info(
|
|
@@ -968,12 +969,11 @@ export class ClientInteraction<
|
|
|
968
969
|
abort: session?.abort,
|
|
969
970
|
retries: this.#sustainRetries,
|
|
970
971
|
read,
|
|
971
|
-
// TCP has 1:1 session-connection binding plus OS keep-alive — the session is
|
|
972
|
-
// evicted when the connection drops, so no liveness probe is needed.
|
|
973
972
|
probe: abort =>
|
|
974
973
|
this.#exchangeProvider.channelType === ChannelType.TCP
|
|
975
|
-
?
|
|
976
|
-
|
|
974
|
+
? // TCP evicts the session when its connection drops, so no liveness probe is needed.
|
|
975
|
+
Promise.resolve(true)
|
|
976
|
+
: this.#exchangeProvider.verifyReachability({ reason: "session-suspect", abort }),
|
|
977
977
|
});
|
|
978
978
|
} else {
|
|
979
979
|
subscription = await subscribe(request);
|
|
@@ -1143,6 +1143,9 @@ export interface ClientProbeOptions {
|
|
|
1143
1143
|
|
|
1144
1144
|
/** Suppress peer-loss reporting so the session stays alive even if the probe fails. */
|
|
1145
1145
|
suppressPeerLoss?: boolean;
|
|
1146
|
+
|
|
1147
|
+
/** Cap MRP transmission attempts for this probe (default: MRP.MAX_TRANSMISSIONS). */
|
|
1148
|
+
maxRetransmissions?: number;
|
|
1146
1149
|
}
|
|
1147
1150
|
|
|
1148
1151
|
async function* readChunks(messenger: InteractionClientMessenger, abort: Abort) {
|
package/src/peer/Peer.ts
CHANGED
|
@@ -9,7 +9,7 @@ import type { NodeProtocol } from "#action/protocols.js";
|
|
|
9
9
|
import { DiscoveryData } from "#common/Scanner.js";
|
|
10
10
|
import { getOperationalDeviceQname } from "#mdns/MdnsConsts.js";
|
|
11
11
|
import { PeerAddress } from "#peer/PeerAddress.js";
|
|
12
|
-
import type { ExchangeProvider } from "#protocol/ExchangeProvider.js";
|
|
12
|
+
import type { ExchangeProvider, ReachabilityReason } from "#protocol/ExchangeProvider.js";
|
|
13
13
|
import type { NodeSession } from "#session/NodeSession.js";
|
|
14
14
|
import { SessionParameters } from "#session/SessionParameters.js";
|
|
15
15
|
import {
|
|
@@ -142,7 +142,8 @@ export class Peer {
|
|
|
142
142
|
}
|
|
143
143
|
} else {
|
|
144
144
|
tagUdp(channel.networkAddress);
|
|
145
|
-
|
|
145
|
+
// MessageChannel.networkAddressChanged survives socket swaps; the transport channel's does not.
|
|
146
|
+
session.channel.networkAddressChanged.on(tagUdp);
|
|
146
147
|
}
|
|
147
148
|
}
|
|
148
149
|
}
|
|
@@ -150,9 +151,8 @@ export class Peer {
|
|
|
150
151
|
// Remove session and detach listener when destroyed
|
|
151
152
|
session.closing.on(() => {
|
|
152
153
|
this.#sessions.delete(session);
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
channel.networkAddressChanged.off(tagUdp);
|
|
154
|
+
if (isIpNetworkChannel(session.channel.transportChannel)) {
|
|
155
|
+
session.channel.networkAddressChanged.off(tagUdp);
|
|
156
156
|
}
|
|
157
157
|
});
|
|
158
158
|
|
|
@@ -488,11 +488,11 @@ export class Peer {
|
|
|
488
488
|
|
|
489
489
|
this.#observers.close();
|
|
490
490
|
|
|
491
|
-
// Cancel pending address check
|
|
492
|
-
this.#addressMonitor?.stop();
|
|
493
|
-
|
|
494
491
|
this.#abort(new ClosedError("Peer closed"));
|
|
495
492
|
|
|
493
|
+
// Stop the address monitor and await any in-flight reachability run (the abort above makes it unwind).
|
|
494
|
+
await this.#addressMonitor?.close();
|
|
495
|
+
|
|
496
496
|
for (const session of this.#context.sessions.sessionsFor(this.address)) {
|
|
497
497
|
await session.initiateClose();
|
|
498
498
|
}
|
|
@@ -552,6 +552,18 @@ export class Peer {
|
|
|
552
552
|
return this.#addressMonitor;
|
|
553
553
|
}
|
|
554
554
|
|
|
555
|
+
/**
|
|
556
|
+
* Verify this peer is reachable, driving recovery via the address monitor.
|
|
557
|
+
*
|
|
558
|
+
* Returns `true` if the session is usable afterward, `false` if it was closed.
|
|
559
|
+
*/
|
|
560
|
+
async verifyReachability(options: { reason: ReachabilityReason; abort?: AbortSignal }): Promise<boolean> {
|
|
561
|
+
if (!this.hasSession) {
|
|
562
|
+
return false;
|
|
563
|
+
}
|
|
564
|
+
return this.#addressCheck.verifyReachability(options);
|
|
565
|
+
}
|
|
566
|
+
|
|
555
567
|
#initiateConnection(options?: Peer.ConnectOptions) {
|
|
556
568
|
if (this.#connecting) {
|
|
557
569
|
if (options?.kick) {
|