@matter/node 0.13.0 → 0.13.1-alpha.0-20250501-80c86b03e
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/behavior/context/server/OnlineContext.d.ts.map +1 -1
- package/dist/cjs/behavior/context/server/OnlineContext.js +6 -3
- package/dist/cjs/behavior/context/server/OnlineContext.js.map +1 -1
- package/dist/cjs/behavior/system/controller/ControllerBehavior.js +2 -1
- package/dist/cjs/behavior/system/controller/ControllerBehavior.js.map +1 -1
- package/dist/cjs/behavior/system/network/ServerNetworkRuntime.d.ts.map +1 -1
- package/dist/cjs/behavior/system/network/ServerNetworkRuntime.js +7 -7
- package/dist/cjs/behavior/system/network/ServerNetworkRuntime.js.map +1 -1
- package/dist/cjs/behavior/system/subscription/SubscriptionBehavior.d.ts +2 -3
- package/dist/cjs/behavior/system/subscription/SubscriptionBehavior.d.ts.map +1 -1
- package/dist/cjs/behavior/system/subscription/SubscriptionBehavior.js.map +1 -1
- package/dist/cjs/node/server/InteractionServer.d.ts +84 -0
- package/dist/cjs/node/server/InteractionServer.d.ts.map +1 -0
- package/dist/cjs/node/server/InteractionServer.js +1326 -0
- package/dist/cjs/node/server/InteractionServer.js.map +6 -0
- package/dist/cjs/node/server/ProtocolService.d.ts.map +1 -1
- package/dist/cjs/node/server/ProtocolService.js +9 -8
- package/dist/cjs/node/server/ProtocolService.js.map +2 -2
- package/dist/cjs/node/server/index.d.ts +1 -1
- package/dist/cjs/node/server/index.d.ts.map +1 -1
- package/dist/cjs/node/server/index.js +1 -1
- package/dist/cjs/node/server/index.js.map +1 -1
- package/dist/esm/behavior/context/server/OnlineContext.d.ts.map +1 -1
- package/dist/esm/behavior/context/server/OnlineContext.js +6 -3
- package/dist/esm/behavior/context/server/OnlineContext.js.map +1 -1
- package/dist/esm/behavior/system/controller/ControllerBehavior.js +1 -1
- package/dist/esm/behavior/system/controller/ControllerBehavior.js.map +1 -1
- package/dist/esm/behavior/system/network/ServerNetworkRuntime.d.ts.map +1 -1
- package/dist/esm/behavior/system/network/ServerNetworkRuntime.js +2 -3
- package/dist/esm/behavior/system/network/ServerNetworkRuntime.js.map +1 -1
- package/dist/esm/behavior/system/subscription/SubscriptionBehavior.d.ts +2 -3
- package/dist/esm/behavior/system/subscription/SubscriptionBehavior.d.ts.map +1 -1
- package/dist/esm/behavior/system/subscription/SubscriptionBehavior.js.map +1 -1
- package/dist/esm/node/server/InteractionServer.d.ts +84 -0
- package/dist/esm/node/server/InteractionServer.d.ts.map +1 -0
- package/dist/esm/node/server/InteractionServer.js +1348 -0
- package/dist/esm/node/server/InteractionServer.js.map +6 -0
- package/dist/esm/node/server/ProtocolService.d.ts.map +1 -1
- package/dist/esm/node/server/ProtocolService.js +9 -8
- package/dist/esm/node/server/ProtocolService.js.map +1 -1
- package/dist/esm/node/server/index.d.ts +1 -1
- package/dist/esm/node/server/index.d.ts.map +1 -1
- package/dist/esm/node/server/index.js +1 -1
- package/package.json +7 -7
- package/src/behavior/context/server/OnlineContext.ts +9 -4
- package/src/behavior/system/controller/ControllerBehavior.ts +1 -1
- package/src/behavior/system/network/ServerNetworkRuntime.ts +4 -7
- package/src/behavior/system/subscription/SubscriptionBehavior.ts +2 -3
- package/src/node/server/InteractionServer.ts +1757 -0
- package/src/node/server/ProtocolService.ts +10 -8
- package/src/node/server/index.ts +1 -1
- package/dist/cjs/node/server/TransactionalInteractionServer.d.ts +0 -57
- package/dist/cjs/node/server/TransactionalInteractionServer.d.ts.map +0 -1
- package/dist/cjs/node/server/TransactionalInteractionServer.js +0 -334
- package/dist/cjs/node/server/TransactionalInteractionServer.js.map +0 -6
- package/dist/esm/node/server/TransactionalInteractionServer.d.ts +0 -57
- package/dist/esm/node/server/TransactionalInteractionServer.d.ts.map +0 -1
- package/dist/esm/node/server/TransactionalInteractionServer.js +0 -322
- package/dist/esm/node/server/TransactionalInteractionServer.js.map +0 -6
- package/src/node/server/TransactionalInteractionServer.ts +0 -413
|
@@ -1,413 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @license
|
|
3
|
-
* Copyright 2022-2025 Matter.js Authors
|
|
4
|
-
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { ActionContext } from "#behavior/context/ActionContext.js";
|
|
8
|
-
import { ActionTracer } from "#behavior/context/ActionTracer.js";
|
|
9
|
-
import { NodeActivity } from "#behavior/context/NodeActivity.js";
|
|
10
|
-
import { OfflineContext } from "#behavior/context/server/OfflineContext.js";
|
|
11
|
-
import { OnlineContext } from "#behavior/context/server/OnlineContext.js";
|
|
12
|
-
import { AccessControlCluster } from "#clusters/access-control";
|
|
13
|
-
import { Endpoint } from "#endpoint/Endpoint.js";
|
|
14
|
-
import { EndpointLifecycle } from "#endpoint/properties/EndpointLifecycle.js";
|
|
15
|
-
import { EndpointServer } from "#endpoint/server/EndpointServer.js";
|
|
16
|
-
import { Diagnostic, InternalError, Logger, MaybePromise } from "#general";
|
|
17
|
-
import {
|
|
18
|
-
AccessControl,
|
|
19
|
-
AccessDeniedError,
|
|
20
|
-
AnyAttributeServer,
|
|
21
|
-
AnyEventServer,
|
|
22
|
-
AttributePath,
|
|
23
|
-
AttributeServer,
|
|
24
|
-
CommandPath,
|
|
25
|
-
CommandServer,
|
|
26
|
-
EndpointInterface,
|
|
27
|
-
EventPath,
|
|
28
|
-
ExchangeManager,
|
|
29
|
-
InteractionContext,
|
|
30
|
-
InteractionEndpointStructure,
|
|
31
|
-
InteractionServer,
|
|
32
|
-
InteractionServerMessenger,
|
|
33
|
-
Message,
|
|
34
|
-
MessageExchange,
|
|
35
|
-
MessageType,
|
|
36
|
-
SessionManager,
|
|
37
|
-
WriteRequest,
|
|
38
|
-
WriteResponse,
|
|
39
|
-
} from "#protocol";
|
|
40
|
-
import { StatusCode, StatusResponseError, TlvEventFilter, TypeFromSchema } from "#types";
|
|
41
|
-
import { AccessControlServer } from "../../behaviors/access-control/AccessControlServer.js";
|
|
42
|
-
import { ServerNode } from "../ServerNode.js";
|
|
43
|
-
|
|
44
|
-
const logger = Logger.get("TransactionalInteractionServer");
|
|
45
|
-
|
|
46
|
-
const activityKey = Symbol("activity");
|
|
47
|
-
|
|
48
|
-
interface WithActivity {
|
|
49
|
-
[activityKey]?: NodeActivity.Activity;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
const AclClusterId = AccessControlCluster.id;
|
|
53
|
-
const AclAttributeId = AccessControlCluster.attributes.acl.id;
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Wire up an InteractionServer that initializes an InvocationContext earlier than the cluster API supports.
|
|
57
|
-
*
|
|
58
|
-
* This is necessary for attributes because the ClusterServer attribute APIs are synchronous while transaction
|
|
59
|
-
* management is asynchronous.
|
|
60
|
-
*
|
|
61
|
-
* It's not necessary for command handling because that API is entirely async. We do it here, however, just for the
|
|
62
|
-
* sake of consistency.
|
|
63
|
-
*
|
|
64
|
-
* This could be integrated directly into InteractionServer but this further refactoring is probably warranted there
|
|
65
|
-
* regardless. This keeps the touch light for now.
|
|
66
|
-
*/
|
|
67
|
-
export class TransactionalInteractionServer extends InteractionServer {
|
|
68
|
-
#endpointStructure: InteractionEndpointStructure;
|
|
69
|
-
#changeListener: (type: EndpointLifecycle.Change, endpoint: Endpoint) => void;
|
|
70
|
-
#node: ServerNode;
|
|
71
|
-
#activity: NodeActivity;
|
|
72
|
-
#newActivityBlocked = false;
|
|
73
|
-
#aclServer?: AccessControlServer;
|
|
74
|
-
#aclUpdateIsDelayedInExchange = new Set<MessageExchange>();
|
|
75
|
-
|
|
76
|
-
static async create(node: ServerNode, sessions: SessionManager) {
|
|
77
|
-
const structure = new InteractionEndpointStructure();
|
|
78
|
-
|
|
79
|
-
return new TransactionalInteractionServer(node, {
|
|
80
|
-
sessions,
|
|
81
|
-
structure,
|
|
82
|
-
subscriptionOptions: node.state.network.subscriptionOptions,
|
|
83
|
-
maxPathsPerInvoke: node.state.basicInformation.maxPathsPerInvoke,
|
|
84
|
-
initiateExchange: (address, protocolId) =>
|
|
85
|
-
node.env.get(ExchangeManager).initiateExchange(address, protocolId),
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
constructor(node: ServerNode, context: InteractionContext) {
|
|
90
|
-
super(context);
|
|
91
|
-
|
|
92
|
-
const { structure } = context;
|
|
93
|
-
|
|
94
|
-
this.#activity = node.env.get(NodeActivity);
|
|
95
|
-
|
|
96
|
-
this.#node = node;
|
|
97
|
-
this.#endpointStructure = structure;
|
|
98
|
-
|
|
99
|
-
// TODO - rewrite element lookup so we don't need to build the secondary endpoint structure cache
|
|
100
|
-
this.#updateStructure();
|
|
101
|
-
this.#changeListener = (type, endpoint) => {
|
|
102
|
-
switch (type) {
|
|
103
|
-
case EndpointLifecycle.Change.ServersChanged:
|
|
104
|
-
EndpointServer.forEndpoint(endpoint).updateServers();
|
|
105
|
-
this.#updateStructure();
|
|
106
|
-
break;
|
|
107
|
-
|
|
108
|
-
case EndpointLifecycle.Change.PartsReady:
|
|
109
|
-
case EndpointLifecycle.Change.ClientsChanged:
|
|
110
|
-
case EndpointLifecycle.Change.Destroyed:
|
|
111
|
-
this.#updateStructure();
|
|
112
|
-
break;
|
|
113
|
-
}
|
|
114
|
-
};
|
|
115
|
-
|
|
116
|
-
node.lifecycle.changed.on(this.#changeListener);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
async [Symbol.asyncDispose]() {
|
|
120
|
-
this.#node.lifecycle.changed.off(this.#changeListener);
|
|
121
|
-
await this.close();
|
|
122
|
-
this.#endpointStructure.close();
|
|
123
|
-
await EndpointServer.forEndpoint(this.#node)[Symbol.asyncDispose]();
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
blockNewActivity() {
|
|
127
|
-
this.#newActivityBlocked = true;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
override async onNewExchange(exchange: MessageExchange, message: Message) {
|
|
131
|
-
// When closing, ignore anything newly incoming
|
|
132
|
-
if (this.#newActivityBlocked || this.isClosing) {
|
|
133
|
-
return;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
// An incoming data report as the first message is not a valid server operation. We instead delegate to a
|
|
137
|
-
// client implementation if available
|
|
138
|
-
if (message.payloadHeader.messageType === MessageType.ReportData && this.clientHandler) {
|
|
139
|
-
return this.clientHandler.onNewExchange(exchange, message);
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
// Activity tracking. This provides diagnostic information and prevents the server from shutting down whilst
|
|
143
|
-
// the exchange is active
|
|
144
|
-
using activity = this.#activity.begin(`session#${exchange.session.id.toString(16)}`);
|
|
145
|
-
(exchange as WithActivity)[activityKey] = activity;
|
|
146
|
-
|
|
147
|
-
// Delegate to InteractionServerMessenger
|
|
148
|
-
return new InteractionServerMessenger(exchange)
|
|
149
|
-
.handleRequest(this)
|
|
150
|
-
.finally(() => delete (exchange as WithActivity)[activityKey]);
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
get aclServer() {
|
|
154
|
-
if (this.#aclServer !== undefined) {
|
|
155
|
-
return this.#aclServer;
|
|
156
|
-
}
|
|
157
|
-
const aclServer = this.#node.act(agent => agent.get(AccessControlServer));
|
|
158
|
-
if (MaybePromise.is(aclServer)) {
|
|
159
|
-
throw new InternalError("AccessControlServer should already be initialized.");
|
|
160
|
-
}
|
|
161
|
-
return (this.#aclServer = aclServer);
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
protected override readAttribute(
|
|
165
|
-
path: AttributePath,
|
|
166
|
-
attribute: AnyAttributeServer<any>,
|
|
167
|
-
exchange: MessageExchange,
|
|
168
|
-
fabricFiltered: boolean,
|
|
169
|
-
message: Message,
|
|
170
|
-
offline = false,
|
|
171
|
-
) {
|
|
172
|
-
const readAttribute = () => super.readAttribute(path, attribute, exchange, fabricFiltered, message, offline);
|
|
173
|
-
|
|
174
|
-
const endpoint = this.#endpointStructure.getEndpoint(path.endpointId);
|
|
175
|
-
if (!endpoint) {
|
|
176
|
-
throw new InternalError("Endpoint not found for ACL check. This should never happen.");
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
const result = offline
|
|
180
|
-
? OfflineContext.act("offline-read", this.#activity, readAttribute)
|
|
181
|
-
: OnlineContext({
|
|
182
|
-
activity: (exchange as WithActivity)[activityKey],
|
|
183
|
-
fabricFiltered,
|
|
184
|
-
message,
|
|
185
|
-
exchange,
|
|
186
|
-
tracer: this.#tracer,
|
|
187
|
-
actionType: ActionTracer.ActionType.Read,
|
|
188
|
-
node: this.#node,
|
|
189
|
-
}).act(readAttribute);
|
|
190
|
-
|
|
191
|
-
if (MaybePromise.is(result)) {
|
|
192
|
-
throw new InternalError("Reads should not return a promise.");
|
|
193
|
-
}
|
|
194
|
-
return result;
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
/**
|
|
198
|
-
* Reads the attributes for the given endpoint.
|
|
199
|
-
* This can currently only be used for subscriptions because errors are ignored!
|
|
200
|
-
*/
|
|
201
|
-
protected override readEndpointAttributesForSubscription(
|
|
202
|
-
attributes: { path: AttributePath; attribute: AnyAttributeServer<any> }[],
|
|
203
|
-
exchange: MessageExchange,
|
|
204
|
-
fabricFiltered: boolean,
|
|
205
|
-
message: Message,
|
|
206
|
-
offline = false,
|
|
207
|
-
) {
|
|
208
|
-
const readAttributes = () => {
|
|
209
|
-
const result = new Array<{
|
|
210
|
-
path: AttributePath;
|
|
211
|
-
attribute: AnyAttributeServer<unknown>;
|
|
212
|
-
value: any;
|
|
213
|
-
version: number;
|
|
214
|
-
}>();
|
|
215
|
-
for (const { path, attribute } of attributes) {
|
|
216
|
-
try {
|
|
217
|
-
const value = super.readAttribute(path, attribute, exchange, fabricFiltered, message, offline);
|
|
218
|
-
result.push({ path, attribute, value: value.value, version: value.version });
|
|
219
|
-
} catch (error) {
|
|
220
|
-
if (StatusResponseError.is(error, StatusCode.UnsupportedAccess)) {
|
|
221
|
-
logger.warn(
|
|
222
|
-
`Permission denied reading attribute ${this.#endpointStructure.resolveAttributeName(path)}`,
|
|
223
|
-
);
|
|
224
|
-
} else {
|
|
225
|
-
logger.warn(
|
|
226
|
-
`Error reading attribute ${this.#endpointStructure.resolveAttributeName(path)}:`,
|
|
227
|
-
error,
|
|
228
|
-
);
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
return result;
|
|
233
|
-
};
|
|
234
|
-
|
|
235
|
-
const result = offline
|
|
236
|
-
? OfflineContext.act("offline-read", this.#activity, readAttributes)
|
|
237
|
-
: OnlineContext({
|
|
238
|
-
activity: (exchange as WithActivity)[activityKey],
|
|
239
|
-
fabricFiltered,
|
|
240
|
-
message,
|
|
241
|
-
exchange,
|
|
242
|
-
tracer: this.#tracer,
|
|
243
|
-
actionType: ActionTracer.ActionType.Read,
|
|
244
|
-
node: this.#node,
|
|
245
|
-
}).act(readAttributes);
|
|
246
|
-
if (MaybePromise.is(result)) {
|
|
247
|
-
throw new InternalError("Online read should not return a promise.");
|
|
248
|
-
}
|
|
249
|
-
return result;
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
protected override async readEvent(
|
|
253
|
-
path: EventPath,
|
|
254
|
-
eventFilters: TypeFromSchema<typeof TlvEventFilter>[] | undefined,
|
|
255
|
-
event: AnyEventServer<any, any>,
|
|
256
|
-
exchange: MessageExchange,
|
|
257
|
-
fabricFiltered: boolean,
|
|
258
|
-
message: Message,
|
|
259
|
-
) {
|
|
260
|
-
const readEvent = (context: ActionContext) => {
|
|
261
|
-
if (
|
|
262
|
-
context.authorityAt(event.readAcl, {
|
|
263
|
-
endpoint: path.endpointId,
|
|
264
|
-
cluster: path.clusterId,
|
|
265
|
-
} as AccessControl.Location) !== AccessControl.Authority.Granted
|
|
266
|
-
) {
|
|
267
|
-
throw new AccessDeniedError(
|
|
268
|
-
`Access to ${path.endpointId}/${Diagnostic.hex(path.clusterId)} denied on ${exchange.session.name}.`,
|
|
269
|
-
);
|
|
270
|
-
}
|
|
271
|
-
return super.readEvent(path, eventFilters, event, exchange, fabricFiltered, message);
|
|
272
|
-
};
|
|
273
|
-
|
|
274
|
-
return OnlineContext({
|
|
275
|
-
activity: (exchange as WithActivity)[activityKey],
|
|
276
|
-
fabricFiltered,
|
|
277
|
-
message,
|
|
278
|
-
exchange,
|
|
279
|
-
tracer: this.#tracer,
|
|
280
|
-
actionType: ActionTracer.ActionType.Read,
|
|
281
|
-
node: this.#node,
|
|
282
|
-
}).act(readEvent);
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
override async handleWriteRequest(
|
|
286
|
-
exchange: MessageExchange,
|
|
287
|
-
writeRequest: WriteRequest,
|
|
288
|
-
message: Message,
|
|
289
|
-
): Promise<WriteResponse> {
|
|
290
|
-
let result: WriteResponse;
|
|
291
|
-
try {
|
|
292
|
-
result = await super.handleWriteRequest(exchange, writeRequest, message);
|
|
293
|
-
} catch (error) {
|
|
294
|
-
if (this.#aclUpdateIsDelayedInExchange.has(exchange)) {
|
|
295
|
-
// Unlikely to get there at all, but make sure we handle it best we can for now
|
|
296
|
-
this.#aclUpdateIsDelayedInExchange.delete(exchange);
|
|
297
|
-
|
|
298
|
-
if (this.#aclUpdateIsDelayedInExchange.size === 0) {
|
|
299
|
-
// only that one ACl change in flight, so we can reset the delayed ACL
|
|
300
|
-
this.aclServer.resetDelayedAccessControlList();
|
|
301
|
-
} else {
|
|
302
|
-
// TODO: we should restore the delayed data just for this errored fabric?
|
|
303
|
-
logger.error("One of multiple concurrent ACL writes failed, unhandled case for now.");
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
throw error;
|
|
307
|
-
}
|
|
308
|
-
// We delayed the ACL update during this write transaction, so we need to update it now that anything is written
|
|
309
|
-
if (this.#aclUpdateIsDelayedInExchange.has(exchange)) {
|
|
310
|
-
this.#aclUpdateIsDelayedInExchange.delete(exchange);
|
|
311
|
-
|
|
312
|
-
if (this.#aclUpdateIsDelayedInExchange.size === 0) {
|
|
313
|
-
// Committing the ACL changes in case of an unhandled exception might be dangerous, but we do it anyway
|
|
314
|
-
this.aclServer.aclUpdateDelayed = false;
|
|
315
|
-
} else {
|
|
316
|
-
logger.info("Multiple concurrent ACL writes, waiting for all to finish.");
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
return result;
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
protected override async writeAttribute(
|
|
324
|
-
path: AttributePath,
|
|
325
|
-
attribute: AttributeServer<any>,
|
|
326
|
-
value: any,
|
|
327
|
-
exchange: MessageExchange,
|
|
328
|
-
message: Message,
|
|
329
|
-
endpoint: EndpointInterface,
|
|
330
|
-
timed = false,
|
|
331
|
-
isListWrite?: boolean,
|
|
332
|
-
) {
|
|
333
|
-
const writeAttribute = () =>
|
|
334
|
-
super.writeAttribute(path, attribute, value, exchange, message, endpoint, timed, isListWrite);
|
|
335
|
-
|
|
336
|
-
if (path.endpointId === 0 && path.clusterId === AclClusterId && path.attributeId === AclAttributeId) {
|
|
337
|
-
// This is a hack to prevent the ACL from updating while we are in the middle of a write transaction
|
|
338
|
-
// and is needed because Acl should not become effective during writing of the ACL itself.
|
|
339
|
-
this.aclServer.aclUpdateDelayed = true;
|
|
340
|
-
this.#aclUpdateIsDelayedInExchange.add(exchange);
|
|
341
|
-
} else {
|
|
342
|
-
// Ok it seems that acl was written, but we now write another path, so we can update Acl attribute now
|
|
343
|
-
if (this.#aclUpdateIsDelayedInExchange.has(exchange)) {
|
|
344
|
-
this.#aclUpdateIsDelayedInExchange.delete(exchange);
|
|
345
|
-
|
|
346
|
-
if (this.#aclUpdateIsDelayedInExchange.size === 0) {
|
|
347
|
-
this.aclServer.aclUpdateDelayed = false;
|
|
348
|
-
} else {
|
|
349
|
-
logger.info("Multiple concurrent ACL writes, waiting for all to finish.");
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
return OnlineContext({
|
|
355
|
-
activity: (exchange as WithActivity)[activityKey],
|
|
356
|
-
timed,
|
|
357
|
-
message,
|
|
358
|
-
exchange,
|
|
359
|
-
fabricFiltered: true,
|
|
360
|
-
tracer: this.#tracer,
|
|
361
|
-
actionType: ActionTracer.ActionType.Write,
|
|
362
|
-
node: this.#node,
|
|
363
|
-
}).act(writeAttribute);
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
protected override async invokeCommand(
|
|
367
|
-
path: CommandPath,
|
|
368
|
-
command: CommandServer<any, any>,
|
|
369
|
-
exchange: MessageExchange,
|
|
370
|
-
commandFields: any,
|
|
371
|
-
message: Message,
|
|
372
|
-
endpoint: EndpointInterface,
|
|
373
|
-
timed = false,
|
|
374
|
-
) {
|
|
375
|
-
const invokeCommand = (context: ActionContext) => {
|
|
376
|
-
if (
|
|
377
|
-
context.authorityAt(command.invokeAcl, {
|
|
378
|
-
endpoint: endpoint.number,
|
|
379
|
-
cluster: path.clusterId,
|
|
380
|
-
} as AccessControl.Location) !== AccessControl.Authority.Granted
|
|
381
|
-
) {
|
|
382
|
-
throw new AccessDeniedError(
|
|
383
|
-
`Access to ${endpoint.number}/${Diagnostic.hex(path.clusterId)} denied on ${exchange.session.name}.`,
|
|
384
|
-
);
|
|
385
|
-
}
|
|
386
|
-
return super.invokeCommand(path, command, exchange, commandFields, message, endpoint, timed);
|
|
387
|
-
};
|
|
388
|
-
|
|
389
|
-
return OnlineContext({
|
|
390
|
-
activity: (exchange as WithActivity)[activityKey],
|
|
391
|
-
command: true,
|
|
392
|
-
timed,
|
|
393
|
-
message,
|
|
394
|
-
exchange,
|
|
395
|
-
tracer: this.#tracer,
|
|
396
|
-
actionType: ActionTracer.ActionType.Invoke,
|
|
397
|
-
node: this.#node,
|
|
398
|
-
}).act(invokeCommand);
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
get #tracer() {
|
|
402
|
-
if (this.#node.env.has(ActionTracer)) {
|
|
403
|
-
return this.#node.env.get(ActionTracer);
|
|
404
|
-
}
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
#updateStructure() {
|
|
408
|
-
if (this.#node.lifecycle.isPartsReady) {
|
|
409
|
-
const server = EndpointServer.forEndpoint(this.#node);
|
|
410
|
-
this.#endpointStructure.initializeFromEndpoint(server);
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
}
|