@tier0/node-opc-da 1.0.7

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.
@@ -0,0 +1,447 @@
1
+ //@ts-check
2
+ /*
3
+ Copyright: (c) 2019, Guilherme Francescon Cittolin <gfcittolin@gmail.com>
4
+ GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt)
5
+ */
6
+
7
+ const constants = require('./constants.js');
8
+ const EnumString = require('./enumString.js');
9
+ const OPCCommon = require('./opcCommon.js');
10
+ const OPCBrowser = require('./opcBrowser.js');
11
+ const OPCItemIO = require('./opcItemIO.js');
12
+ const OPCItemProperties = require('./opcItemProperties');
13
+ const OPCGroupStateManager = require('./opcGroupStateManager');
14
+ const filetime = require('./filetime');
15
+ const util = require('util');
16
+ const debug = util.debuglog('node-opca-da');
17
+ const events = require('events');
18
+ const { CallBuilder, ComString, ComValue, Flags, Pointer, Struct, Types } = require('node-dcom');
19
+
20
+ const groupCache = new WeakMap();
21
+
22
+ /**
23
+ * @typedef {import('./opcGroupStateManager').GroupProperties} GroupProperties
24
+ */
25
+
26
+ /**
27
+ * @typedef {object} GroupStatus
28
+ * @property {Date} startTime
29
+ * @property {Date} currentTime
30
+ * @property {Date} lastUpdateTime
31
+ * @property {number} serverState
32
+ * @property {number} groupCount
33
+ * @property {number} bandWidth
34
+ * @property {number} majorVersion
35
+ * @property {number} minorVersion
36
+ * @property {number} buildNumber
37
+ * @property {number} reserved
38
+ * @property {string} vendorInfo
39
+ */
40
+
41
+ /**
42
+ * Represents an OPC Server
43
+ */
44
+ class OPCServer extends events.EventEmitter {
45
+
46
+ /**
47
+ *
48
+ * @param {object} [opts]
49
+ * @param {object} [opts.groupDefaults]
50
+ * @param {boolean} [opts.groupDefaults.active=true]
51
+ * @param {number} [opts.groupDefaults.updateRate=1000]
52
+ * @param {number} [opts.groupDefaults.timeBias=60]
53
+ * @param {number} [opts.groupDefaults.deadband=0]
54
+ * @param {number} [opts.defaultLocale=1033]
55
+ */
56
+ constructor(opts) {
57
+ debug("Creating OPCServer...");
58
+ //TODO - default values for addGroup
59
+ super();
60
+ opts = opts || {};
61
+ this._defaultLocale = opts.defaultLocale || 1033;
62
+
63
+ let def = opts.groupDefaults || {};
64
+ this._groupDef = {
65
+ active: !!(def.active !== undefined ? def.active : true),
66
+ updateRate: !isNaN(def.updateRate) ? def.updateRate : 1000,
67
+ timeBias: !isNaN(def.timeBias) ? def.timeBias : 60,
68
+ deadband: !isNaN(def.deadband) ? def.deadband : 0,
69
+ }
70
+
71
+ this._comObj = null;
72
+ this._opcCommon = null;
73
+ this._opcBrowser = null;
74
+ this._opcItemIO = null;
75
+ this._opcItemProperties = null;
76
+ }
77
+
78
+ /**
79
+ *
80
+ * @param {*} unknown
81
+ * @returns {Promise<void>}
82
+ */
83
+ async init(unknown) {
84
+ debug("Initing OPCServer...")
85
+ if (this._comObj) throw new Error("Already initialized");
86
+
87
+ if (!unknown) throw new Error("OPCServer init failed. No COM Server given.");
88
+
89
+ this._comObj = await unknown.queryInterface(constants.iid.IOPCServer_IID);
90
+
91
+ // now that we have the comObj, we can get the events emitted
92
+ this._comObj.on('disconnected', function(){
93
+ this.emit('disconnected');
94
+ });
95
+ debug("OPCServer inited successfully");
96
+ }
97
+
98
+ /**
99
+ * @returns {Promise<void>}
100
+ */
101
+ async end() {
102
+ debug("Ending OPCServer...")
103
+ if (!this._comObj) return;
104
+
105
+ let obj = this._comObj;
106
+ let opcCommon = this._opcCommon;
107
+ let opcBrowser = this._opcBrowser;
108
+ let opcItemIO = this._opcItemIO;
109
+ let opcItemProperties = this._opcItemProperties;
110
+ this._comObj = null;
111
+ this._opcCommon = null;
112
+ this._opcBrowser = null;
113
+ this._opcItemIO = null;
114
+ this._opcItemProperties = null;
115
+
116
+ //TODO maybe paralelize this with Promise.all
117
+ if (opcCommon) await opcCommon.end();
118
+ if (opcBrowser) await opcBrowser.end();
119
+ if (opcItemIO) await opcItemIO.end();
120
+ if (opcItemProperties) await opcItemProperties.end();
121
+ await obj.release();
122
+ debug("OPCServer successfully ended.");
123
+ }
124
+
125
+ /**
126
+ *
127
+ * @param {String} name the group name
128
+ * @param {GroupProperties} [opts]
129
+ * @returns {Promise<?>}
130
+ * @opNum 0
131
+ */
132
+ async addGroup(name, opts) {
133
+ debug("Adding new group \"" + name + "\"...");
134
+ if (!this._comObj) throw new Error("Not initialized");
135
+
136
+ opts = opts || {
137
+ active: this._groupDef.active,
138
+ updateRate: this._groupDef.updateRate,
139
+ clientHandle: Math.trunc(Math.random() * 0xFFFFFFFF),
140
+ timeBias: this._groupDef.timeBias,
141
+ deadband: this._groupDef.deadband,
142
+ localeID: this._defaultLocale
143
+ };
144
+
145
+ let active = opts.active !== undefined ? opts.active : this._groupDef.active;
146
+ let updateRate = !isNaN(opts.updateRate) ? opts.updateRate : this._groupDef.updateRate;
147
+ let clientHandle = !isNaN(opts.clientHandle) ? opts.clientHandle : Math.trunc(Math.random() * 0xFFFFFFFF);
148
+ let timeBias = !isNaN(opts.timeBias) ? opts.timeBias : this._groupDef.timeBias;
149
+ let deadband = !isNaN(opts.deadband) ? opts.deadband : this._groupDef.deadband;
150
+ let localeID = !isNaN(opts.localeID) ? opts.localeID : this._defaultLocale;
151
+
152
+ let timeBiasCV = new ComValue(timeBias, Types.INTEGER);
153
+ let deadbandCV = new ComValue(deadband, Types.FLOAT);
154
+
155
+ let callObject = new CallBuilder(true);
156
+ callObject.setOpnum(0);
157
+
158
+ callObject.addInParamAsString(name, Flags.FLAG_REPRESENTATION_STRING_LPWSTR);
159
+ callObject.addInParamAsInt(active ? 1 : 0, Flags.FLAG_NULL);
160
+ callObject.addInParamAsInt(updateRate, Flags.FLAG_NULL);
161
+ callObject.addInParamAsInt(clientHandle, Flags.FLAG_NULL);
162
+ callObject.addInParamAsPointer(new Pointer(timeBiasCV), Flags.FLAG_NULL);
163
+ callObject.addInParamAsPointer(new Pointer(deadbandCV), Flags.FLAG_NULL);
164
+ callObject.addInParamAsInt(localeID, Flags.FLAG_NULL);
165
+ callObject.addOutParamAsType(Types.INTEGER, Flags.FLAG_NULL);
166
+ callObject.addOutParamAsType(Types.INTEGER, Flags.FLAG_NULL);
167
+ callObject.addInParamAsUUID(constants.iid.IOPCGroupStateMgt_IID, Flags.FLAG_NULL);
168
+ callObject.addOutParamAsType(Types.COMOBJECT, Flags.FLAG_NULL);
169
+
170
+ let resultObj = await this._comObj.call(callObject);
171
+
172
+ let hresult = resultObj.hresult;
173
+ let result = resultObj.getResults();
174
+ if (hresult != 0) {
175
+ if (result.lenght == 0)
176
+ throw new Error(String(hresult));
177
+ else {
178
+ if (hresult == 0x0004000D) {
179
+ this.emit('opc_s_unsuportedrate');
180
+ }
181
+ }
182
+ }
183
+
184
+ let group = new OPCGroupStateManager();
185
+ await group.init(result[2].getValue());
186
+ groupCache.set(group, clientHandle);
187
+ debug(name + " added successfully.");
188
+ return group;
189
+ }
190
+
191
+ /**
192
+ *
193
+ * @param {number} error
194
+ * @param {number} [localeID]
195
+ * @returns {Promise<?>} a descriptive string for the error code
196
+ * @opNum 1
197
+ */
198
+ async getErrorString(error, localeID) {
199
+ if (!this._comObj) throw new Error("Not initialized");
200
+
201
+ let callObject = new CallBuilder(true);
202
+ callObject.setOpnum(1);
203
+
204
+ localeID = localeID || this._defaultLocale;
205
+
206
+ let outString = new ComValue(new ComString(Flags.FLAG_REPRESENTATION_STRING_LPWSTR), Types.COMSTRING);
207
+
208
+ callObject.addInParamAsInt(error, Flags.FLAG_NULL);
209
+ callObject.addInParamAsInt(localeID, Flags.FLAG_NULL);
210
+ callObject.addOutParamAsObject(outString, Flags.FLAG_NULL);
211
+ //callObject.addOutParamAsObject(new Pointer(new ComString(Flags.FLAG_REPRESENTATION_STRING_LPWSTR)), Flags.FLAG_NULL);
212
+
213
+ let resultObj = await this._comObj.call(callObject);
214
+
215
+ let hresult = resultObj.hresult;
216
+ let result = resultObj.getResults();
217
+ if (hresult != 0) {
218
+ if (result.lenght == 0)
219
+ throw new Error(String(hresult));
220
+ else
221
+ debug(new Error(String(hresult)));
222
+ }
223
+
224
+ return result[0].getString();
225
+ //return result[0].getReferent().getString();
226
+ }
227
+
228
+ /**
229
+ *
230
+ * @param {string} name
231
+ * @returns {Promise<OPCGroupStateManager>}
232
+ * @opNum 2
233
+ */
234
+ async getGroupByName(name) {
235
+ debug("Getting group \"" + name + "\"...");
236
+ if (!this._comObj) throw new Error("Not initialized");
237
+
238
+ let callObject = new CallBuilder(true);
239
+ callObject.setOpnum(2);
240
+
241
+ callObject.addInParamAsString(name, Flags.FLAG_REPRESENTATION_STRING_LPWSTR);
242
+ callObject.addInParamAsUUID(constants.iid.IOPCGroupStateMgt_IID, Flags.FLAG_NULL);
243
+ callObject.addOutParamAsType(Types.COMOBJECT, Flags.FLAG_NULL);
244
+
245
+ let resultObj = await this._comObj.call(callObject);
246
+
247
+ let hresult = resultObj.hresult;
248
+ let result = resultObj.getResults();
249
+ if (hresult != 0) {
250
+ if (result.lenght == 0)
251
+ throw new Error(String(hresult));
252
+ else
253
+ debug(new Error(String(hresult)));
254
+ }
255
+
256
+ let group = new OPCGroupStateManager();
257
+ await group.init(result[0]);
258
+ debug("Successfully get request for group \"" + name +"\".");
259
+ return group;
260
+ }
261
+
262
+ /**
263
+ * @returns {Promise<GroupStatus>} the server status
264
+ * @opNum 3
265
+ */
266
+ async getStatus() {
267
+ debug("Querying server for status information..");
268
+ if (!this._comObj) throw new Error("Not initialized");
269
+
270
+ let statusStruct = new Struct();
271
+ statusStruct.addMember(new ComValue(filetime.getStruct(), Types.STRUCT)); //startTime
272
+ statusStruct.addMember(new ComValue(filetime.getStruct(), Types.STRUCT)); //currentTime
273
+ statusStruct.addMember(new ComValue(filetime.getStruct(), Types.STRUCT)); //lastUpdate
274
+ statusStruct.addMember(new ComValue(null, Types.SHORT)); //serverState
275
+ statusStruct.addMember(new ComValue(null, Types.INTEGER)); //groupCount
276
+ statusStruct.addMember(new ComValue(null, Types.INTEGER)); //bandwidth
277
+ statusStruct.addMember(new ComValue(null, Types.SHORT)); //majorVersion
278
+ statusStruct.addMember(new ComValue(null, Types.SHORT)); //minorVersion
279
+ statusStruct.addMember(new ComValue(null, Types.SHORT)); //buildNumber
280
+ statusStruct.addMember(new ComValue(null, Types.SHORT)); //reserved
281
+ let vendorInfoCV = new ComValue(new ComString(Flags.FLAG_REPRESENTATION_STRING_LPWSTR), Types.COMSTRING);
282
+ statusStruct.addMember(new ComValue(new Pointer(vendorInfoCV), Types.POINTER)); //vendorInfo
283
+
284
+ let statusStructPointer = new Pointer(new ComValue(statusStruct, Types.STRUCT));
285
+
286
+ let callObject = new CallBuilder(true);
287
+ callObject.setOpnum(3);
288
+ callObject.addOutParamAsObject(new ComValue(statusStructPointer, Types.POINTER), Flags.FLAG_NULL);
289
+
290
+ let resultObj = await this._comObj.call(callObject);
291
+
292
+ let hresult = resultObj.hresult;
293
+ let result = resultObj.getResults();
294
+ if (hresult != 0) {
295
+ if (result.lenght == 0)
296
+ throw new Error(String(hresult));
297
+ else
298
+ debug(new Error(String(hresult)));
299
+ }
300
+
301
+ let resStruct = result[0].getValue().getReferent();
302
+
303
+ debug("Server Status information obtained.");
304
+ return {
305
+ startTime: filetime.fromStruct(resStruct.getMember(0).getValue()).getDate(),
306
+ currentTime: filetime.fromStruct(resStruct.getMember(1).getValue()).getDate(),
307
+ lastUpdateTime: filetime.fromStruct(resStruct.getMember(2).getValue()).getDate(),
308
+ serverState: resStruct.getMember(3).getValue(),
309
+ groupCount: resStruct.getMember(4).getValue(),
310
+ bandWidth: resStruct.getMember(5).getValue(),
311
+ majorVersion: resStruct.getMember(6).getValue(),
312
+ minorVersion: resStruct.getMember(7).getValue(),
313
+ buildNumber: resStruct.getMember(8).getValue(),
314
+ reserved: resStruct.getMember(9).getValue(),
315
+ vendorInfo: resStruct.getMember(10).getValue().getReferent().getString()
316
+ };
317
+ }
318
+
319
+ /**
320
+ *
321
+ * @param {OPCGroupStateManager|number} handle
322
+ * @param {boolean} [force=false]
323
+ * @returns {Promise<?>}
324
+ * @opNum 4
325
+ */
326
+ async removeGroup(handle, force) {
327
+ debug("Removing group \"" + name + "\"...");
328
+ if (!this._comObj) throw new Error("Not initialized");
329
+
330
+ if (handle instanceof OPCGroupStateManager) {
331
+ handle = groupCache.get(handle);
332
+ }
333
+ if (typeof handle != 'number') {
334
+ throw new Error("Cannot find handle for the provided group");
335
+ }
336
+
337
+ let callObject = new CallBuilder(true);
338
+ callObject.setOpnum(4);
339
+
340
+ callObject.addInParamAsInt(handle, Flags.FLAG_NULL);
341
+ callObject.addInParamAsInt(force ? 1 : 0, Flags.FLAG_NULL);
342
+
343
+ await this._comObj.call(callObject);
344
+ debug("Group \"" + name + "\" successfully removed.");
345
+ }
346
+
347
+ /**
348
+ *
349
+ * @param {number} scope an OPC scope
350
+ * @returns {Promise<string[]>}
351
+ * @opNum 5
352
+ */
353
+ async getGroups(scope) {
354
+ debug("Querying OPCServer for a list of available groups...");
355
+ if (!this._comObj) throw new Error("Not initialized");
356
+
357
+ let callObject = new CallBuilder(true);
358
+ callObject.setOpnum(5);
359
+
360
+ callObject.addInParamAsShort(scope, Flags.FLAG_NULL);
361
+ callObject.addInParamAsUUID(constants.iid.IEnumString_IID, Flags.FLAG_NULL);
362
+ callObject.addOutParamAsType(Types.COMOBJECT, Flags.FLAG_NULL);
363
+
364
+ let resultObj = await this._comObj.call(callObject);
365
+
366
+ let hresult = resultObj.hresult;
367
+ let result = resultObj.getResults();
368
+ if (hresult != 0) {
369
+ if (result.lenght == 0)
370
+ throw new Error(String(hresult));
371
+ else
372
+ debug("No groups were found");
373
+ }
374
+
375
+ let enumStr = new EnumString();
376
+ await enumStr.init(result[0].getValue());
377
+ let res = await enumStr.asArray();
378
+ await enumStr.end(hresult);
379
+ debug("Group list successfully obtained.");
380
+ return res;
381
+ }
382
+
383
+ // ------
384
+
385
+ /**
386
+ * @returns {Promise<OPCCommon>} an OPCCommon instance of this server
387
+ */
388
+ async getCommon() {
389
+ if (!this._comObj) throw new Error("Not initialized");
390
+
391
+ if (!this._opcCommon) {
392
+ let opcCommon = new OPCCommon(); //TODO pass comObj handle
393
+ await opcCommon.init(this._comObj);
394
+ this._opcCommon = opcCommon;
395
+ }
396
+ return this._opcCommon;
397
+ }
398
+
399
+ /**
400
+ * @returns {Promise<OPCBrowser>} an OPCBrowser instance of this server
401
+ */
402
+ async getBrowser() {
403
+ debug("Creating a browser instance...");
404
+ if (!this._comObj) throw new Error("Not initialized");
405
+
406
+ if (!this._opcBrowser) {
407
+ let opcBrowser = new OPCBrowser(); //TODO pass comObj handle
408
+ await opcBrowser.init(this._comObj);
409
+ this._opcBrowser = opcBrowser;
410
+ }
411
+ debug("Browser instance succesfully created.");
412
+ return this._opcBrowser;
413
+ }
414
+
415
+ /**
416
+ * @returns {Promise<OPCItemIO>} an OPCBrowser insance of this server
417
+ */
418
+ async getItemIO() {
419
+ debug("Creating an ItemIO instance...");
420
+ if (!this._comObj) throw new Error("Not initialized");
421
+
422
+ if (!this._opcItemIO) {
423
+ let opcItemIO = new OPCItemIO(); //TODO pass comObj handle
424
+ await opcItemIO.init(this._comObj);
425
+ this._opcItemIO = opcItemIO;
426
+ }
427
+ debug("ItemIO instance successfully created.");
428
+ return this._opcItemIO;
429
+ }
430
+
431
+ /**
432
+ * @returns {Promise<OPCItemProperties>} an OPCBrowser insance of this server
433
+ */
434
+ async getItemProperties() {
435
+ if (!this._comObj) throw new Error("Not initialized");
436
+
437
+ if (!this._opcItemProperties) {
438
+ let opcItemProperties = new OPCItemProperties(); //TODO pass comObj handle
439
+ await opcItemProperties.init(this._comObj);
440
+ this._opcItemProperties = opcItemProperties;
441
+ }
442
+ return this._opcItemProperties;
443
+ }
444
+
445
+ }
446
+
447
+ module.exports = OPCServer;
@@ -0,0 +1,213 @@
1
+ //@ts-check
2
+ /*
3
+ Copyright: (c) 2019, Guilherme Francescon Cittolin <gfcittolin@gmail.com>
4
+ GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt)
5
+ */
6
+
7
+ const constants = require('./constants.js');
8
+ const filetime = require('./filetime');
9
+ const util = require('util');
10
+ const dcom = require('node-dcom');
11
+ const debug = util.debuglog('node-opc-da');
12
+
13
+ const { CallBuilder, ComArray, ComValue, Flags, Pointer, Struct, Variant, Types } = require('node-dcom');
14
+
15
+ /**
16
+ * Represents an OPC Sync IO Object
17
+ */
18
+ class OPCSyncIO {
19
+
20
+ constructor() {
21
+ this._comObj = null;
22
+ }
23
+
24
+ /**
25
+ *
26
+ * @param {*} unknown
27
+ * @returns {Promise<?>}
28
+ */
29
+ async init(unknown) {
30
+ debug("Initing OPCSyncIO...");
31
+ if (this._comObj) throw new Error("Already initialized");
32
+
33
+ this._comObj = await unknown.queryInterface(constants.iid.IOPCSyncIO_IID);
34
+
35
+ debug("OPCSyncIO successfully initted.");
36
+ }
37
+
38
+ async end() {
39
+ debug("Destroying OPCSyncIO...");
40
+ if (!this._comObj) return;
41
+
42
+ let obj = this._comObj;
43
+ this._comObj = null;
44
+ await obj.release();
45
+ debug("OPCSyncIO successfully destroyed.");
46
+ }
47
+
48
+ /**
49
+ *
50
+ * @param {number} source
51
+ * @param {number[]} handles an array of server handles
52
+ * @returns {Promise<object[]>}
53
+ * @opNum 0
54
+ */
55
+ async read(source, handles) {
56
+ debug("Reading " + handles.length + " items from " + source + ":");
57
+ for (let i = 0; i < handles.length; i++) {
58
+ debug("Item Handle: " + handles[i]);
59
+ }
60
+
61
+ if (!this._comObj) throw new Error("Not initialized");
62
+
63
+ if (!(handles.length > 0)) return [];
64
+
65
+ // TODO maybe we can have a single static instance of this,
66
+ // without the need to instantiate one every call. To be tested
67
+ let itemStateStruct = new Struct();
68
+ itemStateStruct.addMember(new ComValue(null, Types.INTEGER));
69
+ itemStateStruct.addMember(new ComValue(filetime.getStruct(), Types.STRUCT));
70
+ itemStateStruct.addMember(new ComValue(null, Types.SHORT));
71
+ itemStateStruct.addMember(new ComValue(null, Types.SHORT));
72
+ itemStateStruct.addMember(new ComValue(null, Types.VARIANT));
73
+
74
+ let callObject = new CallBuilder(true);
75
+ callObject.setOpnum(0);
76
+
77
+ callObject.addInParamAsShort(source, Flags.FLAG_NULL);
78
+ callObject.addInParamAsInt(handles.length, Flags.FLAG_NULL);
79
+
80
+ let temporaryHandles = new Array();
81
+ for (let i = 0; i < handles.length; i++)
82
+ temporaryHandles.push(new ComValue(handles[i], Types.INTEGER));
83
+ callObject.addInParamAsArray(new ComArray(new ComValue(temporaryHandles, Types.INTEGER), true), Flags.FLAG_NULL);
84
+
85
+ let resStructArray = new ComArray(new ComValue(itemStateStruct, Types.STRUCT), null, 1, true)
86
+ let errCodesArray = new ComArray(new ComValue(null, Types.INTEGER), null, 1, true)
87
+ callObject.addOutParamAsObject(new ComValue(new Pointer(new ComValue(resStructArray, Types.COMARRAY)), Types.POINTER), Flags.FLAG_NULL);
88
+ callObject.addOutParamAsObject(new ComValue(new Pointer(new ComValue(errCodesArray, Types.COMARRAY)), Types.POINTER), Flags.FLAG_NULL);
89
+
90
+ let resultObj = await this._comObj.call(callObject);
91
+
92
+ let hresult = resultObj.hresult;
93
+ let result = resultObj.getResults();
94
+ if (hresult != 0) {
95
+ if (result.lenght == 0)
96
+ throw new Error(String(hresult));
97
+ else
98
+ throw new Error(String(hresult));
99
+ }
100
+ let results = result[0].getValue().getReferent().getArrayInstance();
101
+ let errorCodes = result[1].getValue().getReferent().getArrayInstance();
102
+
103
+ let res = [];
104
+ let failed = [];
105
+ for (let i = 0; i < handles.length; i++) {
106
+ let resObj = {
107
+ errorCode: errorCodes[i].getValue(),
108
+ clientHandle: results[i].getValue().getMember(0).getValue(),
109
+ timestamp: filetime.fromStruct(results[i].getValue().getMember(1).getValue()).getDate(),
110
+ quality: results[i].getValue().getMember(2).getValue(),
111
+ reserved: results[i].getValue().getMember(3).getValue(),
112
+ value: this.extractValue(results[i])
113
+ };
114
+ res.push(resObj);
115
+ if (errorCodes[i].getValue() != 0) {
116
+ failed.push([resObj.clientHandle, resObj.errorCode]);
117
+ }
118
+ }
119
+
120
+ debug("Successfully read " + (res.length - failed.length) + " items.");
121
+ if (failed.length > 0) {
122
+ debug("The following items were not added: ");
123
+ for (let i = 0; i < failed.length; i++) {
124
+ debug("Item: " + failed[i][0] + " ErrorCode: " + failed[i][1]);
125
+ }
126
+ }
127
+ return res;
128
+ }
129
+
130
+ extractValue(item){
131
+ // first we decapsulate from the Struct
132
+ item = (!item.getValue().getMember(4).getValue().member.getValue().referent.isArray) ?
133
+ item.getValue().getMember(4).getValue().member.getValue().referent.obj.getValue() :
134
+ item.getValue().getMember(4).getValue().member.getValue().referent.getArray(0).memberArray;
135
+
136
+ if (item == null) return item;
137
+
138
+ if (item instanceof dcom.ComString ||
139
+ item .constructor.name == "ComString") {
140
+ if (item.member) {
141
+ item = item.member._obj.referent._obj;
142
+ }
143
+ // in case is a common string
144
+ if (item instanceof dcom.Pointer ||
145
+ item.constructor.type == "Pointer") {
146
+ item = item.referent._obj;
147
+ }
148
+ } else if (item instanceof dcom.ComValue ||
149
+ item.constructor.name == "ComValue") {
150
+ item = item._obj;
151
+ } else if (item instanceof Array) {
152
+ for (let i = 0; i < item.length; i++) {
153
+ if (item[i]._type == 23){
154
+ item[i] = item[i]._obj.member._obj.referent._obj;
155
+ } else {
156
+ item[i] = item[i]._obj;
157
+ }
158
+ }
159
+ }
160
+ return item;
161
+ }
162
+
163
+ /**
164
+ *
165
+ * @param {object[]} writes
166
+ * @param {number} writes[].handle
167
+ * @param {number} writes[].type
168
+ * @param {*} writes[].value
169
+ * @returns {Promise<number[]>} error codes
170
+ * @opNum 1
171
+ */
172
+ async write(writes) {
173
+ if (!this._comObj) throw new Error("Not initialized");
174
+
175
+ if (!(writes.length > 0)) return [];
176
+
177
+ let handles = [];
178
+ let values = [];
179
+ for (const write of writes) {
180
+ var valVariant = new Variant.Variant(new ComValue(write.value, write.type));
181
+
182
+ if(Array.isArray(write.value) && write.type == Types.BOOLEAN) {
183
+ valVariant.setFlag(Flags.FLAG_REPRESENTATION_VARIANT_BOOL);
184
+ }
185
+ handles.push(new ComValue(write.handle, Types.INTEGER));
186
+ values.push(new ComValue(valVariant, Types.VARIANT));
187
+ }
188
+
189
+ let callObject = new CallBuilder(true);
190
+ callObject.setOpnum(1);
191
+
192
+ callObject.addInParamAsInt(writes.length, Flags.FLAG_NULL);
193
+ callObject.addInParamAsArray(new ComArray(new ComValue(handles, Types.INTEGER), true), Flags.FLAG_NULL);
194
+ callObject.addInParamAsArray(new ComArray(new ComValue(values, Types.VARIANT), true), Flags.FLAG_NULL);
195
+ let errCodesArray = new ComArray(new ComValue(null, Types.INTEGER), null, 1, true)
196
+ callObject.addOutParamAsObject(new ComValue(new Pointer(new ComValue(errCodesArray, Types.COMARRAY)), Types.POINTER), Flags.FLAG_NULL);
197
+
198
+ let resultObj = await this._comObj.call(callObject);
199
+
200
+ let hresult = resultObj.hresult;
201
+ let result = resultObj.getResults();
202
+ if (hresult != 0) {
203
+ if (result.lenght == 0)
204
+ throw new Error(String(hresult));
205
+ else
206
+ debug(new Error(String(hresult)));
207
+ }
208
+
209
+ return result[0].getValue().getReferent().getArrayInstance();
210
+ }
211
+ }
212
+
213
+ module.exports = OPCSyncIO;