node-opcua-service-filter 2.183.0 → 2.184.0
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/check_event_clause.d.ts +1 -0
- package/dist/check_event_clause.d.ts.map +1 -0
- package/dist/check_event_clause.js +23 -19
- package/dist/check_event_clause.js.map +1 -1
- package/dist/check_where_clause.d.ts +1 -0
- package/dist/check_where_clause.d.ts.map +1 -0
- package/dist/check_where_clause.js +112 -116
- package/dist/check_where_clause.js.map +1 -1
- package/dist/extract_event_field.d.ts +2 -1
- package/dist/extract_event_field.d.ts.map +1 -0
- package/dist/extract_event_field.js +14 -42
- package/dist/extract_event_field.js.map +1 -1
- package/dist/filter_context.d.ts +1 -0
- package/dist/filter_context.d.ts.map +1 -0
- package/dist/filter_context.js +1 -2
- package/dist/imports.d.ts +1 -0
- package/dist/imports.d.ts.map +1 -0
- package/dist/imports.js +1 -15
- package/dist/imports.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -26
- package/dist/index.js.map +1 -1
- package/dist/make_content_filter.d.ts +1 -0
- package/dist/make_content_filter.d.ts.map +1 -0
- package/dist/make_content_filter.js +47 -62
- package/dist/make_content_filter.js.map +1 -1
- package/dist/on_address_space/extract_event_fields.d.ts +1 -0
- package/dist/on_address_space/extract_event_fields.d.ts.map +1 -0
- package/dist/on_address_space/extract_event_fields.js +5 -8
- package/dist/on_address_space/extract_event_fields.js.map +1 -1
- package/dist/on_address_space/filter_context_on_address_space.d.ts +1 -0
- package/dist/on_address_space/filter_context_on_address_space.d.ts.map +1 -0
- package/dist/on_address_space/filter_context_on_address_space.js +21 -25
- package/dist/on_address_space/filter_context_on_address_space.js.map +1 -1
- package/dist/on_address_space/index.d.ts +1 -0
- package/dist/on_address_space/index.d.ts.map +1 -0
- package/dist/on_address_space/index.js +2 -18
- package/dist/on_address_space/index.js.map +1 -1
- package/dist/resolve_operand.d.ts +14 -0
- package/dist/resolve_operand.d.ts.map +1 -0
- package/dist/resolve_operand.js +66 -21
- package/dist/resolve_operand.js.map +1 -1
- package/dist/tools_event_filter.d.ts +1 -0
- package/dist/tools_event_filter.d.ts.map +1 -0
- package/dist/tools_event_filter.js +17 -22
- package/dist/tools_event_filter.js.map +1 -1
- package/package.json +18 -17
- package/source/check_event_clause.ts +11 -2
- package/source/check_where_clause.ts +2 -2
- package/source/extract_event_field.ts +7 -33
- package/source/resolve_operand.ts +53 -2
|
@@ -1,19 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
-
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
-
};
|
|
16
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
__exportStar(require("./extract_event_fields.js"), exports);
|
|
18
|
-
__exportStar(require("./filter_context_on_address_space.js"), exports);
|
|
1
|
+
export * from "./extract_event_fields.js";
|
|
2
|
+
export * from "./filter_context_on_address_space.js";
|
|
19
3
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../source/on_address_space/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../source/on_address_space/index.ts"],"names":[],"mappings":"AAAA,cAAc,2BAA2B,CAAC;AAC1C,cAAc,sCAAsC,CAAC"}
|
|
@@ -1,4 +1,18 @@
|
|
|
1
1
|
import { AttributeOperand, SimpleAttributeOperand } from "node-opcua-types";
|
|
2
2
|
import { Variant } from "node-opcua-variant";
|
|
3
3
|
import type { FilterContext } from "./filter_context.js";
|
|
4
|
+
/**
|
|
5
|
+
* OPC 10000-4 7.4.4.5: a SimpleAttributeOperand with an empty browsePath denotes the instance of
|
|
6
|
+
* typeDefinitionId itself, not "nothing to do". A ConditionId operand (typeDefinitionId
|
|
7
|
+
* ConditionType or a subtype, attributeId NodeId, empty browsePath) resolves to the event's own
|
|
8
|
+
* condition instance NodeId - this is what every Alarms and Conditions client sends, in both the
|
|
9
|
+
* select clause (delivery, via extractEventField) and the where clause (evaluation, via
|
|
10
|
+
* resolveOperand below). FEAT-58 taught the select-clause validation this; both consumers share
|
|
11
|
+
* this one resolution so they never drift apart again.
|
|
12
|
+
*
|
|
13
|
+
* Returns undefined when the operand does not match this shape, so the caller falls back to its
|
|
14
|
+
* normal browsePath resolution.
|
|
15
|
+
*/
|
|
16
|
+
export declare function resolveConditionIdOperand(context: FilterContext, operand: SimpleAttributeOperand): Variant | undefined;
|
|
4
17
|
export declare function resolveOperand(context: FilterContext, operand: SimpleAttributeOperand | AttributeOperand): Variant;
|
|
18
|
+
//# sourceMappingURL=resolve_operand.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve_operand.d.ts","sourceRoot":"","sources":["../source/resolve_operand.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAC5E,OAAO,EAAY,OAAO,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAOzD;;;;;;;;;;;GAWG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,aAAa,EAAE,OAAO,EAAE,sBAAsB,GAAG,OAAO,GAAG,SAAS,CA+BtH;AAYD,wBAAgB,cAAc,CAAC,OAAO,EAAE,aAAa,EAAE,OAAO,EAAE,sBAAsB,GAAG,gBAAgB,GAAG,OAAO,CAiClH"}
|
package/dist/resolve_operand.js
CHANGED
|
@@ -1,15 +1,56 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
-
const
|
|
12
|
-
|
|
1
|
+
import { AttributeIds, NodeClass } from "node-opcua-data-model";
|
|
2
|
+
import { checkDebugFlag, make_debugLog, make_warningLog } from "node-opcua-debug";
|
|
3
|
+
import { resolveNodeId, sameNodeId } from "node-opcua-nodeid";
|
|
4
|
+
import { constructBrowsePathFromQualifiedName } from "node-opcua-service-translate-browse-path";
|
|
5
|
+
import { StatusCodes } from "node-opcua-status-code";
|
|
6
|
+
import { AttributeOperand, SimpleAttributeOperand } from "node-opcua-types";
|
|
7
|
+
import { DataType, Variant } from "node-opcua-variant";
|
|
8
|
+
const warningLog = make_warningLog("FILTER");
|
|
9
|
+
const debugLog = make_debugLog("FILTER");
|
|
10
|
+
const doDebug = checkDebugFlag("FILTER");
|
|
11
|
+
const conditionTypeNodeId = resolveNodeId("ConditionType");
|
|
12
|
+
/**
|
|
13
|
+
* OPC 10000-4 7.4.4.5: a SimpleAttributeOperand with an empty browsePath denotes the instance of
|
|
14
|
+
* typeDefinitionId itself, not "nothing to do". A ConditionId operand (typeDefinitionId
|
|
15
|
+
* ConditionType or a subtype, attributeId NodeId, empty browsePath) resolves to the event's own
|
|
16
|
+
* condition instance NodeId - this is what every Alarms and Conditions client sends, in both the
|
|
17
|
+
* select clause (delivery, via extractEventField) and the where clause (evaluation, via
|
|
18
|
+
* resolveOperand below). FEAT-58 taught the select-clause validation this; both consumers share
|
|
19
|
+
* this one resolution so they never drift apart again.
|
|
20
|
+
*
|
|
21
|
+
* Returns undefined when the operand does not match this shape, so the caller falls back to its
|
|
22
|
+
* normal browsePath resolution.
|
|
23
|
+
*/
|
|
24
|
+
export function resolveConditionIdOperand(context, operand) {
|
|
25
|
+
if (operand.browsePath && operand.browsePath.length > 0) {
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
if (operand.attributeId !== AttributeIds.NodeId) {
|
|
29
|
+
return undefined;
|
|
30
|
+
}
|
|
31
|
+
// "ns=0;i=2782" => ConditionType
|
|
32
|
+
// "ns=0;i=2041" => BaseEventType
|
|
33
|
+
if (!sameNodeId(operand.typeDefinitionId, conditionTypeNodeId)) {
|
|
34
|
+
// not a ConditionType
|
|
35
|
+
// but could be on of its derived type. for instance ns=0;i=2881 => AcknowledgeableConditionType
|
|
36
|
+
if (!context.isSubtypeOf(operand.typeDefinitionId, conditionTypeNodeId)) {
|
|
37
|
+
warningLog(" ", operand.typeDefinitionId.toString());
|
|
38
|
+
warningLog(`this case is not handled yet : selectClause.typeDefinitionId = ${operand.typeDefinitionId.toString()}`);
|
|
39
|
+
warningLog(operand.toString());
|
|
40
|
+
return new Variant({ dataType: DataType.NodeId, value: context.eventSource });
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
const eventSourceTypeDefinition = context.getTypeDefinition(context.eventSource);
|
|
44
|
+
if (!eventSourceTypeDefinition) {
|
|
45
|
+
// eventSource is a EventType class
|
|
46
|
+
return new Variant();
|
|
47
|
+
}
|
|
48
|
+
if (!context.isSubtypeOf(eventSourceTypeDefinition, conditionTypeNodeId)) {
|
|
49
|
+
return new Variant();
|
|
50
|
+
}
|
|
51
|
+
// Yeh : our EventType is a Condition Type !
|
|
52
|
+
return new Variant({ dataType: DataType.NodeId, value: context.eventSource });
|
|
53
|
+
}
|
|
13
54
|
// export function readOperand(context: FilterContext, operand: SimpleAttributeOperand): Variant {
|
|
14
55
|
// // navigate to the innerNode specified by the browsePath [ QualifiedName]
|
|
15
56
|
// const browsePath = constructBrowsePathFromQualifiedName({ nodeId: context.eventSource }, operand.browsePath);
|
|
@@ -19,29 +60,33 @@ const doDebug = (0, node_opcua_debug_1.checkDebugFlag)("FILTER");
|
|
|
19
60
|
// }
|
|
20
61
|
// return context.readNodeValue(targetNode);
|
|
21
62
|
// }
|
|
22
|
-
function resolveOperand(context, operand) {
|
|
23
|
-
if (operand instanceof
|
|
24
|
-
const
|
|
63
|
+
export function resolveOperand(context, operand) {
|
|
64
|
+
if (operand instanceof SimpleAttributeOperand) {
|
|
65
|
+
const conditionIdValue = resolveConditionIdOperand(context, operand);
|
|
66
|
+
if (conditionIdValue) {
|
|
67
|
+
return conditionIdValue;
|
|
68
|
+
}
|
|
69
|
+
const browsePath = constructBrowsePathFromQualifiedName({ nodeId: context.eventSource }, operand.browsePath);
|
|
25
70
|
const target = context.browsePath(browsePath);
|
|
26
71
|
if (!target) {
|
|
27
|
-
return new
|
|
72
|
+
return new Variant({ dataType: DataType.Null });
|
|
28
73
|
// return new Variant({ dataType: DataType.StatusCode, value: StatusCodes.BadNodeIdUnknown });
|
|
29
74
|
}
|
|
30
75
|
const nodeClass = context.getNodeClass(target);
|
|
31
|
-
if (nodeClass !==
|
|
76
|
+
if (nodeClass !== NodeClass.Variable) {
|
|
32
77
|
doDebug &&
|
|
33
|
-
debugLog("resolveOperand: cannot find variable here but got nodeClass",
|
|
34
|
-
return new
|
|
78
|
+
debugLog("resolveOperand: cannot find variable here but got nodeClass", NodeClass[nodeClass], browsePath.toString());
|
|
79
|
+
return new Variant({ dataType: DataType.StatusCode, value: StatusCodes.BadNodeClassInvalid });
|
|
35
80
|
}
|
|
36
81
|
const value = context.readNodeValue(target);
|
|
37
82
|
return value;
|
|
38
83
|
}
|
|
39
84
|
else {
|
|
40
|
-
if (!(operand instanceof
|
|
85
|
+
if (!(operand instanceof AttributeOperand)) {
|
|
41
86
|
throw new Error("expecting an AttributeOperand");
|
|
42
87
|
}
|
|
43
88
|
warningLog("AttributeOperand is not yet implemented");
|
|
44
|
-
return new
|
|
89
|
+
return new Variant({ dataType: DataType.Null });
|
|
45
90
|
}
|
|
46
91
|
}
|
|
47
92
|
//# sourceMappingURL=resolve_operand.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolve_operand.js","sourceRoot":"","sources":["../source/resolve_operand.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"resolve_operand.js","sourceRoot":"","sources":["../source/resolve_operand.ts"],"names":[],"mappings":"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"}
|
|
@@ -18,3 +18,4 @@ export declare function constructSelectClause(arrayOfNames: string | string[] |
|
|
|
18
18
|
*
|
|
19
19
|
*/
|
|
20
20
|
export declare function constructEventFilter(arrayOfNames: (QualifiedNameOptions | string)[][] | (QualifiedNameOptions | string)[] | QualifiedNameOptions | string[] | string, whereClause?: ContentFilterOptions | ContentFilterElement): EventFilter;
|
|
21
|
+
//# sourceMappingURL=tools_event_filter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools_event_filter.d.ts","sourceRoot":"","sources":["../source/tools_event_filter.ts"],"names":[],"mappings":"AAIA,OAAO,EAAqC,KAAK,aAAa,EAAE,KAAK,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAEzH,OAAO,EAAiB,oBAAoB,EAAE,KAAK,oBAAoB,EAAE,WAAW,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AAUnI,wBAAgB,yBAAyB,CACrC,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,oBAAoB,GAAG,CAAC,oBAAoB,GAAG,MAAM,CAAC,EAAE,GAChF,aAAa,EAAE,CAMjB;AACD,wBAAgB,qBAAqB,CACjC,YAAY,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,oBAAoB,GAAG,CAAC,oBAAoB,GAAG,MAAM,CAAC,EAAE,GAAG,CAAC,oBAAoB,GAAG,MAAM,CAAC,EAAE,EAAE,GACjI,sBAAsB,EAAE,CA+C1B;AACD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,oBAAoB,CAChC,YAAY,EACN,CAAC,oBAAoB,GAAG,MAAM,CAAC,EAAE,EAAE,GACnC,CAAC,oBAAoB,GAAG,MAAM,CAAC,EAAE,GACjC,oBAAoB,GACpB,MAAM,EAAE,GACR,MAAM,EACZ,WAAW,CAAC,EAAE,oBAAoB,GAAG,oBAAoB,GAC1D,WAAW,CAWb"}
|
|
@@ -1,23 +1,18 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.constructSimpleBrowsePath = constructSimpleBrowsePath;
|
|
4
|
-
exports.constructSelectClause = constructSelectClause;
|
|
5
|
-
exports.constructEventFilter = constructEventFilter;
|
|
6
1
|
/**
|
|
7
2
|
* @module node-opcua-service-filter
|
|
8
3
|
*/
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
4
|
+
import { ObjectTypeIds } from "node-opcua-constants";
|
|
5
|
+
import { AttributeIds, coerceQualifiedName } from "node-opcua-data-model";
|
|
6
|
+
import { ContentFilter, ContentFilterElement, EventFilter, SimpleAttributeOperand } from "./imports.js";
|
|
12
7
|
function coerceQualifiedName2(a) {
|
|
13
8
|
if (typeof a === "string")
|
|
14
|
-
return
|
|
9
|
+
return coerceQualifiedName(a);
|
|
15
10
|
a.namespaceIndex = a.namespaceIndex || 0; // need a namespaceIndex
|
|
16
|
-
return
|
|
11
|
+
return coerceQualifiedName(a);
|
|
17
12
|
}
|
|
18
13
|
// A bare QualifiedNameOptions is accepted, and always was: the last line coerces a
|
|
19
14
|
// single non-array value. Only the signature said otherwise.
|
|
20
|
-
function constructSimpleBrowsePath(a) {
|
|
15
|
+
export function constructSimpleBrowsePath(a) {
|
|
21
16
|
if (typeof a === "string") {
|
|
22
17
|
return constructSimpleBrowsePath(a.split("."));
|
|
23
18
|
}
|
|
@@ -25,7 +20,7 @@ function constructSimpleBrowsePath(a) {
|
|
|
25
20
|
return a.map(coerceQualifiedName2);
|
|
26
21
|
return [coerceQualifiedName2(a)];
|
|
27
22
|
}
|
|
28
|
-
function constructSelectClause(arrayOfNames) {
|
|
23
|
+
export function constructSelectClause(arrayOfNames) {
|
|
29
24
|
if (!Array.isArray(arrayOfNames)) {
|
|
30
25
|
return constructSelectClause([arrayOfNames]);
|
|
31
26
|
}
|
|
@@ -53,19 +48,19 @@ function constructSelectClause(arrayOfNames) {
|
|
|
53
48
|
// browsePath[] QualifiedName empty
|
|
54
49
|
// attributeId IntegerId Id of the NodeId Attribute
|
|
55
50
|
//
|
|
56
|
-
return new
|
|
57
|
-
attributeId:
|
|
51
|
+
return new SimpleAttributeOperand({
|
|
52
|
+
attributeId: AttributeIds.NodeId,
|
|
58
53
|
browsePath: null,
|
|
59
54
|
indexRange: undefined, // NumericRange
|
|
60
|
-
typeDefinitionId:
|
|
55
|
+
typeDefinitionId: ObjectTypeIds.ConditionType // i=2782
|
|
61
56
|
});
|
|
62
57
|
}
|
|
63
58
|
else
|
|
64
|
-
return new
|
|
65
|
-
attributeId:
|
|
59
|
+
return new SimpleAttributeOperand({
|
|
60
|
+
attributeId: AttributeIds.Value,
|
|
66
61
|
browsePath,
|
|
67
62
|
indexRange: undefined, // NumericRange
|
|
68
|
-
typeDefinitionId:
|
|
63
|
+
typeDefinitionId: ObjectTypeIds.BaseEventType // i=2041
|
|
69
64
|
});
|
|
70
65
|
});
|
|
71
66
|
return selectClauses;
|
|
@@ -85,12 +80,12 @@ function constructSelectClause(arrayOfNames) {
|
|
|
85
80
|
* constructEventFilter([ ["SourceName",{namespaceIndex:2 , "MyData"} ]]);
|
|
86
81
|
*
|
|
87
82
|
*/
|
|
88
|
-
function constructEventFilter(arrayOfNames, whereClause) {
|
|
83
|
+
export function constructEventFilter(arrayOfNames, whereClause) {
|
|
89
84
|
const selectClauses = constructSelectClause(arrayOfNames);
|
|
90
|
-
if (whereClause instanceof
|
|
91
|
-
whereClause = new
|
|
85
|
+
if (whereClause instanceof ContentFilterElement) {
|
|
86
|
+
whereClause = new ContentFilter({ elements: [whereClause] });
|
|
92
87
|
}
|
|
93
|
-
const filter = new
|
|
88
|
+
const filter = new EventFilter({
|
|
94
89
|
selectClauses,
|
|
95
90
|
whereClause
|
|
96
91
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tools_event_filter.js","sourceRoot":"","sources":["../source/tools_event_filter.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"tools_event_filter.js","sourceRoot":"","sources":["../source/tools_event_filter.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "node-opcua-service-filter",
|
|
3
|
-
"
|
|
3
|
+
"type": "module",
|
|
4
|
+
"version": "2.184.0",
|
|
4
5
|
"description": "pure nodejs OPCUA SDK - module service-filter",
|
|
5
6
|
"main": "./dist/index.js",
|
|
6
7
|
"types": "./dist/index.d.ts",
|
|
@@ -14,23 +15,23 @@
|
|
|
14
15
|
"node": ">=22.13.0"
|
|
15
16
|
},
|
|
16
17
|
"dependencies": {
|
|
17
|
-
"node-opcua-address-space-base": "2.
|
|
18
|
-
"node-opcua-assert": "2.
|
|
19
|
-
"node-opcua-basic-types": "2.
|
|
20
|
-
"node-opcua-constants": "2.
|
|
21
|
-
"node-opcua-data-model": "2.
|
|
22
|
-
"node-opcua-data-value": "2.
|
|
23
|
-
"node-opcua-debug": "2.
|
|
24
|
-
"node-opcua-extension-object": "2.
|
|
25
|
-
"node-opcua-nodeid": "2.
|
|
26
|
-
"node-opcua-service-translate-browse-path": "2.
|
|
27
|
-
"node-opcua-status-code": "2.
|
|
28
|
-
"node-opcua-types": "2.
|
|
29
|
-
"node-opcua-variant": "2.
|
|
18
|
+
"node-opcua-address-space-base": "2.184.0",
|
|
19
|
+
"node-opcua-assert": "2.184.0",
|
|
20
|
+
"node-opcua-basic-types": "2.184.0",
|
|
21
|
+
"node-opcua-constants": "2.184.0",
|
|
22
|
+
"node-opcua-data-model": "2.184.0",
|
|
23
|
+
"node-opcua-data-value": "2.184.0",
|
|
24
|
+
"node-opcua-debug": "2.184.0",
|
|
25
|
+
"node-opcua-extension-object": "2.184.0",
|
|
26
|
+
"node-opcua-nodeid": "2.184.0",
|
|
27
|
+
"node-opcua-service-translate-browse-path": "2.184.0",
|
|
28
|
+
"node-opcua-status-code": "2.184.0",
|
|
29
|
+
"node-opcua-types": "2.184.0",
|
|
30
|
+
"node-opcua-variant": "2.184.0"
|
|
30
31
|
},
|
|
31
32
|
"devDependencies": {
|
|
32
|
-
"node-opcua-numeric-range": "2.
|
|
33
|
-
"node-opcua-packet-analyzer": "2.
|
|
33
|
+
"node-opcua-numeric-range": "2.184.0",
|
|
34
|
+
"node-opcua-packet-analyzer": "2.184.0"
|
|
34
35
|
},
|
|
35
36
|
"author": "Etienne Rossignon",
|
|
36
37
|
"license": "MIT",
|
|
@@ -47,7 +48,7 @@
|
|
|
47
48
|
"internet of things"
|
|
48
49
|
],
|
|
49
50
|
"homepage": "http://node-opcua.github.io/",
|
|
50
|
-
"gitHead": "
|
|
51
|
+
"gitHead": "441a5c63e3a4202eb8de8597acac77a3a49248b7",
|
|
51
52
|
"files": [
|
|
52
53
|
"dist",
|
|
53
54
|
"source"
|
|
@@ -22,7 +22,7 @@ export function checkSelectClause(parentNode: BaseNode, selectClause: SimpleAttr
|
|
|
22
22
|
//
|
|
23
23
|
const addressSpace = parentNode.addressSpace;
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
/* c8 ignore next */
|
|
26
26
|
if (selectClause.typeDefinitionId.isEmpty()) {
|
|
27
27
|
return StatusCodes.Good;
|
|
28
28
|
}
|
|
@@ -34,11 +34,20 @@ export function checkSelectClause(parentNode: BaseNode, selectClause: SimpleAttr
|
|
|
34
34
|
}
|
|
35
35
|
// ... and that node must be an ObjectType (an EventType)
|
|
36
36
|
if (eventTypeNode.nodeClass !== NodeClass.ObjectType) {
|
|
37
|
-
|
|
37
|
+
/* c8 ignore next */
|
|
38
38
|
doDebug && debugLog(" checkSelectClause", eventTypeNode.toString());
|
|
39
39
|
return StatusCodes.BadTypeMismatch;
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
+
// OPC 10000-4 7.4.4.5: an empty browsePath does not mean "nothing to do" here - it denotes the
|
|
43
|
+
// instance of typeDefinitionId itself (e.g. the ConditionId of an Alarms and Conditions event).
|
|
44
|
+
// typeDefinitionId has already been checked above to resolve to an existing EventType, so the
|
|
45
|
+
// operand is valid and must be reported Good; it is extractEventField's job, at delivery time, to
|
|
46
|
+
// resolve it against the actual event instance.
|
|
47
|
+
if (!selectClause.browsePath || selectClause.browsePath.length === 0) {
|
|
48
|
+
return StatusCodes.Good;
|
|
49
|
+
}
|
|
50
|
+
|
|
42
51
|
// navigate to the innerNode specified by the browsePath [ QualifiedName]
|
|
43
52
|
const browsePath = constructBrowsePathFromQualifiedName(eventTypeNode, selectClause.browsePath);
|
|
44
53
|
const browsePathResult = addressSpace.browsePath(browsePath);
|
|
@@ -89,12 +89,12 @@ function evaluateOperand<TIn, T>(
|
|
|
89
89
|
}
|
|
90
90
|
|
|
91
91
|
function checkOfType(filterContext: FilterContext, ofType: ExtensionObject | null): boolean {
|
|
92
|
-
|
|
92
|
+
/* c8 ignore next */
|
|
93
93
|
if (!ofType || !(ofType instanceof LiteralOperand)) {
|
|
94
94
|
warningLog("checkOfType : unsupported case ! ofType is not a LiteralOperand , ofType = ", ofType?.toString());
|
|
95
95
|
return false;
|
|
96
96
|
}
|
|
97
|
-
|
|
97
|
+
/* c8 ignore next */
|
|
98
98
|
if (ofType.value.dataType !== DataType.NodeId) {
|
|
99
99
|
warningLog(`invalid operand type (expecting NodeId); got ${DataType[ofType.value.dataType]}`);
|
|
100
100
|
return false;
|
|
@@ -1,14 +1,8 @@
|
|
|
1
1
|
import { assert } from "node-opcua-assert";
|
|
2
|
-
import { AttributeIds } from "node-opcua-data-model";
|
|
3
|
-
import { make_warningLog } from "node-opcua-debug";
|
|
4
|
-
import { resolveNodeId, sameNodeId } from "node-opcua-nodeid";
|
|
5
2
|
import { SimpleAttributeOperand } from "node-opcua-types";
|
|
6
|
-
import {
|
|
3
|
+
import type { Variant } from "node-opcua-variant";
|
|
7
4
|
import type { FilterContext } from "./filter_context.js";
|
|
8
|
-
import { resolveOperand } from "./resolve_operand.js";
|
|
9
|
-
|
|
10
|
-
const warningLog = make_warningLog("FILTER");
|
|
11
|
-
const conditionTypeNodeId = resolveNodeId("ConditionType");
|
|
5
|
+
import { resolveConditionIdOperand, resolveOperand } from "./resolve_operand.js";
|
|
12
6
|
|
|
13
7
|
/**
|
|
14
8
|
*
|
|
@@ -19,31 +13,11 @@ export function extractEventField(context: FilterContext, operand: SimpleAttribu
|
|
|
19
13
|
|
|
20
14
|
operand.browsePath = operand.browsePath || [];
|
|
21
15
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
// but could be on of its derived type. for instance ns=0;i=2881 => AcknowledgeableConditionType
|
|
28
|
-
if (!context.isSubtypeOf(operand.typeDefinitionId, conditionTypeNodeId)) {
|
|
29
|
-
warningLog(" ", operand.typeDefinitionId.toString());
|
|
30
|
-
warningLog(`this case is not handled yet : selectClause.typeDefinitionId = ${operand.typeDefinitionId.toString()}`);
|
|
31
|
-
warningLog(operand.toString());
|
|
32
|
-
return new Variant({ dataType: DataType.NodeId, value: context.eventSource });
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
const eventSourceTypeDefinition = context.getTypeDefinition(context.eventSource);
|
|
37
|
-
if (!eventSourceTypeDefinition) {
|
|
38
|
-
// eventSource is a EventType class
|
|
39
|
-
return new Variant();
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
if (!context.isSubtypeOf(eventSourceTypeDefinition, conditionTypeNodeId)) {
|
|
43
|
-
return new Variant();
|
|
44
|
-
}
|
|
45
|
-
// Yeh : our EventType is a Condition Type !
|
|
46
|
-
return new Variant({ dataType: DataType.NodeId, value: context.eventSource });
|
|
16
|
+
// the ConditionId shape (empty browsePath, attributeId NodeId) is resolved the same way here
|
|
17
|
+
// (delivery) and in resolveOperand (where-clause evaluation) - see resolveConditionIdOperand.
|
|
18
|
+
const conditionIdValue = resolveConditionIdOperand(context, operand);
|
|
19
|
+
if (conditionIdValue) {
|
|
20
|
+
return conditionIdValue;
|
|
47
21
|
}
|
|
48
22
|
return resolveOperand(context, operand);
|
|
49
23
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { NodeClass } from "node-opcua-data-model";
|
|
1
|
+
import { AttributeIds, NodeClass } from "node-opcua-data-model";
|
|
2
2
|
import { checkDebugFlag, make_debugLog, make_warningLog } from "node-opcua-debug";
|
|
3
|
-
import type
|
|
3
|
+
import { type NodeId, resolveNodeId, sameNodeId } from "node-opcua-nodeid";
|
|
4
4
|
import { constructBrowsePathFromQualifiedName } from "node-opcua-service-translate-browse-path";
|
|
5
5
|
import { StatusCodes } from "node-opcua-status-code";
|
|
6
6
|
import { AttributeOperand, SimpleAttributeOperand } from "node-opcua-types";
|
|
@@ -10,6 +10,52 @@ import type { FilterContext } from "./filter_context.js";
|
|
|
10
10
|
const warningLog = make_warningLog("FILTER");
|
|
11
11
|
const debugLog = make_debugLog("FILTER");
|
|
12
12
|
const doDebug = checkDebugFlag("FILTER");
|
|
13
|
+
const conditionTypeNodeId = resolveNodeId("ConditionType");
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* OPC 10000-4 7.4.4.5: a SimpleAttributeOperand with an empty browsePath denotes the instance of
|
|
17
|
+
* typeDefinitionId itself, not "nothing to do". A ConditionId operand (typeDefinitionId
|
|
18
|
+
* ConditionType or a subtype, attributeId NodeId, empty browsePath) resolves to the event's own
|
|
19
|
+
* condition instance NodeId - this is what every Alarms and Conditions client sends, in both the
|
|
20
|
+
* select clause (delivery, via extractEventField) and the where clause (evaluation, via
|
|
21
|
+
* resolveOperand below). FEAT-58 taught the select-clause validation this; both consumers share
|
|
22
|
+
* this one resolution so they never drift apart again.
|
|
23
|
+
*
|
|
24
|
+
* Returns undefined when the operand does not match this shape, so the caller falls back to its
|
|
25
|
+
* normal browsePath resolution.
|
|
26
|
+
*/
|
|
27
|
+
export function resolveConditionIdOperand(context: FilterContext, operand: SimpleAttributeOperand): Variant | undefined {
|
|
28
|
+
if (operand.browsePath && operand.browsePath.length > 0) {
|
|
29
|
+
return undefined;
|
|
30
|
+
}
|
|
31
|
+
if (operand.attributeId !== AttributeIds.NodeId) {
|
|
32
|
+
return undefined;
|
|
33
|
+
}
|
|
34
|
+
// "ns=0;i=2782" => ConditionType
|
|
35
|
+
// "ns=0;i=2041" => BaseEventType
|
|
36
|
+
if (!sameNodeId(operand.typeDefinitionId, conditionTypeNodeId)) {
|
|
37
|
+
// not a ConditionType
|
|
38
|
+
// but could be on of its derived type. for instance ns=0;i=2881 => AcknowledgeableConditionType
|
|
39
|
+
if (!context.isSubtypeOf(operand.typeDefinitionId, conditionTypeNodeId)) {
|
|
40
|
+
warningLog(" ", operand.typeDefinitionId.toString());
|
|
41
|
+
warningLog(`this case is not handled yet : selectClause.typeDefinitionId = ${operand.typeDefinitionId.toString()}`);
|
|
42
|
+
warningLog(operand.toString());
|
|
43
|
+
return new Variant({ dataType: DataType.NodeId, value: context.eventSource });
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const eventSourceTypeDefinition = context.getTypeDefinition(context.eventSource);
|
|
48
|
+
if (!eventSourceTypeDefinition) {
|
|
49
|
+
// eventSource is a EventType class
|
|
50
|
+
return new Variant();
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (!context.isSubtypeOf(eventSourceTypeDefinition, conditionTypeNodeId)) {
|
|
54
|
+
return new Variant();
|
|
55
|
+
}
|
|
56
|
+
// Yeh : our EventType is a Condition Type !
|
|
57
|
+
return new Variant({ dataType: DataType.NodeId, value: context.eventSource });
|
|
58
|
+
}
|
|
13
59
|
|
|
14
60
|
// export function readOperand(context: FilterContext, operand: SimpleAttributeOperand): Variant {
|
|
15
61
|
// // navigate to the innerNode specified by the browsePath [ QualifiedName]
|
|
@@ -23,6 +69,11 @@ const doDebug = checkDebugFlag("FILTER");
|
|
|
23
69
|
|
|
24
70
|
export function resolveOperand(context: FilterContext, operand: SimpleAttributeOperand | AttributeOperand): Variant {
|
|
25
71
|
if (operand instanceof SimpleAttributeOperand) {
|
|
72
|
+
const conditionIdValue = resolveConditionIdOperand(context, operand);
|
|
73
|
+
if (conditionIdValue) {
|
|
74
|
+
return conditionIdValue;
|
|
75
|
+
}
|
|
76
|
+
|
|
26
77
|
const browsePath = constructBrowsePathFromQualifiedName({ nodeId: context.eventSource }, operand.browsePath);
|
|
27
78
|
|
|
28
79
|
const target: NodeId | null = context.browsePath(browsePath);
|