diff --git a/EmberClient/EmberClient.js b/EmberClient/EmberClient.js index 4fa9502..c1b33e9 100755 --- a/EmberClient/EmberClient.js +++ b/EmberClient/EmberClient.js @@ -73,7 +73,7 @@ class EmberClient extends EventEmitter { } } catch(e) { - winston.debug(e, root); + winston.error(e, root); if (this._callback) { this._callback(e); } @@ -88,7 +88,7 @@ class EmberClient extends EventEmitter { try { this._makeRequest(); } catch(e) { - winston.debug(e); + winston.error(e); if (this._callback != null) { this._callback(e); } @@ -140,8 +140,8 @@ class EmberClient extends EventEmitter { if (n == null) { parent.addChild(node); n = node; - } else { - n.update(node); + } else if (n.update(node)) { + n.updateSubscribers(); } const children = node.getChildren(); @@ -165,7 +165,9 @@ class EmberClient extends EventEmitter { let element = parent.getElementByPath(node.path); if (element !== null) { this.emit("value-change", node); - element.update(node); + if (element.update(node)) { + element.updateSubscribers(); + } } else { const path = node.path.split("."); @@ -344,17 +346,16 @@ class EmberClient extends EventEmitter { if (nodeElements != null && ((qnode.isMatrix() && nodeElements.length === 1 && nodeElements[0].getPath() === requestedPath) || (!qnode.isMatrix() && nodeElements.every(el => isDirectSubPathOf(el.getPath(), requestedPath))))) { - winston.debug("Received getDirectory response", node); + winston.debug("Received getDirectory response", node); this._finishRequest(); return resolve(node); // make sure the info is treated before going to next request. } else { winston.debug(node); - winston.debug(new Error(requestedPath)); + winston.error(new Error(requestedPath)); } } }; - winston.debug("Sending getDirectory", qnode); try { this._client.sendBERNode(qnode.getDirectory(callback)); } @@ -420,6 +421,9 @@ class EmberClient extends EventEmitter { // We have this part already. pos++; if (pos >= pathArray.length) { + if (callback) { + node.getDirectory(callback); + } return node; } currentNode = node; @@ -514,7 +518,7 @@ class EmberClient extends EventEmitter { return; } if (error) { - winston.debug("Received getDirectory error", error); + winston.error("Received getDirectory error", error); this._clearTimeout(); // clear the timeout now. The resolve below may take a while. this._finishRequest(); reject(error); @@ -612,7 +616,7 @@ class EmberClient extends EventEmitter { resolve(node); } }; - winston.debug('setValue sending ...', node.getPath(), value); + winston.debug('setValue sending ...', node.getPath(), value); this._client.sendBERNode(node.setValue(value)); }}); } diff --git a/EmberLib/QualifiedParameter.js b/EmberLib/QualifiedParameter.js index 3871823..2ff6d8c 100755 --- a/EmberLib/QualifiedParameter.js +++ b/EmberLib/QualifiedParameter.js @@ -36,28 +36,6 @@ class QualifiedParameter extends QualifiedElement { return r; } - /** - * - * @param {QualifiedParameter} other - */ - update(other) { - if ((other != null) && (other.contents != null)) { - if (this.contents == null) { - this.contents = other.contents; - } - else { - for (var key in other.contents) { - if (key[0] === "_") { - continue; - } - if (other.contents.hasOwnProperty(key)) { - this.contents[key] = other.contents[key]; - } - } - } - } - return; - } /** * diff --git a/EmberLib/StreamCollection.js b/EmberLib/StreamCollection.js new file mode 100755 index 0000000..4576809 --- /dev/null +++ b/EmberLib/StreamCollection.js @@ -0,0 +1,102 @@ +const BER = require("../ber"); +const StreamEntry = require("./StreamEntry"); + +class StreamCollection { + /** + * + */ + constructor() { + /** @type {Map} */ + this.elements = new Map(); + } + /** + * + * @param {StreamEntry} entry + */ + addEntry(entry) { + this.elements.set(entry.identifier, entry); + } + /** + * + * @param {StreamEntry} entry + */ + removeEntry(entry) { + this.elements.delete(entry.identifier); + } + /** + * + * @param {number} identifier + * @returns {StreamEntry} + */ + getEntry(identifier) { + return this.elements.get(identifier); + } + + /** + * @returns {StreamEntry} + */ + [Symbol.iterator]() { + return this.elements.values(); + } + + /** + * @retuns {number} + */ + size() { + return this.elements.size; + } + + /** + * + * @param {BER.Writer} ber + */ + encode(ber) { + ber.startSequence(StreamCollection.BERID); + for(let [, entry] of this.elements) { + ber.startSequence(BER.CONTEXT(0)); + entry.encode(ber); + ber.endSequence(); + } + ber.endSequence(); + } + + /** + * @returns { + * {identifier: number, value: string|number|boolean|Buffer}[] + * } + */ + toJSON() { + const js = []; + for(let [, entry] of this.elements) { + js.push(entry.toJSON()); + } + return js; + } + + /** + * @returns {number} + */ + static get BERID() { + return BER.APPLICATION(5); + } + + /** + * + * @param {BER.ExtendedReader} ber + * @returns {StreamCollection} + */ + static decode(ber) { + const streamCollection = new StreamCollection(); + const seq = ber.getSequence(this.BERID); + while (seq.remain > 0) { + const rootReader = seq.getSequence(BER.CONTEXT(0)); + while (rootReader.remain > 0) { + const entry = StreamEntry.decode(rootReader); + streamCollection.addEntry(entry); + } + } + return streamCollection; + } +} + +module.exports = StreamCollection; \ No newline at end of file diff --git a/EmberLib/StreamEntry.js b/EmberLib/StreamEntry.js new file mode 100755 index 0000000..2e6b10e --- /dev/null +++ b/EmberLib/StreamEntry.js @@ -0,0 +1,70 @@ +const BER = require("../ber"); +const Errors = require("../Errors"); + +class StreamEntry { + /** + * + * @param {number} identifier + * @param {string|number|boolean|Buffer} value + */ + constructor(identifier, value ) { + this.identifier = identifier; + this.value = value; + } + + /** + * + * @param {BER} ber + */ + encode(ber) { + ber.startSequence(StreamEntry.BERID); + if (this.identifier != null) { + ber.startSequence(BER.CONTEXT(0)); + ber.writeInt(this.identifier); + ber.endSequence(); + } + if (this.value != null) { + ber.startSequence(BER.CONTEXT(1)); + ber.writeValue(this.value); + ber.endSequence(); + } + ber.endSequence(); + } + + /** + * @returns {{ + * identifier: number, + * value: string|number + * }} + */ + toJSON() { + return { + identifier: this.identifier, + value: this.value + } + } + + static get BERID() { + return BER.APPLICATION(5); + } + + static decode(ber) { + const entry = new StreamEntry(); + const seq = ber.getSequence(this.BERID); + while(seq.remain > 0) { + const tag = seq.peek(); + const data = seq.getSequence(tag); + if(tag == BER.CONTEXT(0)) { + entry.identifier = data.readInt(); + } else if(tag == BER.CONTEXT(1)) { + entry.value = data.readValue(); + } + else { + throw new Errors.UnimplementedEmberTypeError(tag); + } + } + return entry; + } +} + +module.exports = StreamEntry; \ No newline at end of file diff --git a/EmberLib/TreeNode.js b/EmberLib/TreeNode.js index 2cb7919..69b6ebe 100755 --- a/EmberLib/TreeNode.js +++ b/EmberLib/TreeNode.js @@ -16,8 +16,7 @@ class TreeNode extends ElementInterface { _isSubscribable(callback) { return (callback != null && - ((this.isParameter() && this.isStream()) || - this.isMatrix())); + (this.isParameter() || this.isMatrix())); } _subscribe(callback) { @@ -236,7 +235,7 @@ class TreeNode extends ElementInterface { * @param {function} callback */ getDirectory(callback) { - if (this._isSubscribable(callback)) { + if (this._isSubscribable(callback) && !this.isStream()) { this._subscribe(callback); } return this.getCommand(new Command(COMMAND_GETDIRECTORY)); @@ -471,7 +470,7 @@ class TreeNode extends ElementInterface { * @param {function} callback */ subscribe(callback) { - if (this._isSubscribable(callback)) { + if (this._isSubscribable(callback) && this.isStream()) { this._subscribe(callback); } return this.getCommand(new Command(COMMAND_SUBSCRIBE)); diff --git a/EmberServer/EmberServer.js b/EmberServer/EmberServer.js index 23fb37d..741f045 100755 --- a/EmberServer/EmberServer.js +++ b/EmberServer/EmberServer.js @@ -4,8 +4,8 @@ const EmberLib = require('../EmberLib'); const JSONParser = require("./JSONParser"); const ElementHandlers = require("./ElementHandlers"); const ServerEvents = require("./ServerEvents"); -const winston = require("winston"); const Errors = require("../Errors"); +const winston = require("winston"); class TreeServer extends EventEmitter{ /** @@ -16,7 +16,7 @@ class TreeServer extends EventEmitter{ */ constructor(host, port, tree) { super(); - this._debug = false; + this._debug = true; this.timeoutValue = 2000; this.server = new S101Server(host, port); this.tree = tree; @@ -390,6 +390,7 @@ class TreeServer extends EventEmitter{ setValue(element, value, origin, key) { return new Promise(resolve => { // Change the element value if write access permitted. + winston.debug("New Setvalue request"); if (element.contents == null) { return resolve(); } @@ -398,6 +399,7 @@ class TreeServer extends EventEmitter{ (element.contents.access != null) && (element.contents.access.value > 1)) { element.contents.value = value; + winston.debug("New value ", value, "path", element.getPath()); const res = this.getResponse(element); this.updateSubscribers(element.getPath(),res, origin); } @@ -460,6 +462,7 @@ class TreeServer extends EventEmitter{ */ updateSubscribers(path, response, origin) { if (this.subscribers[path] == null) { + winston.debug("No subscribers for", path); return; } @@ -468,10 +471,12 @@ class TreeServer extends EventEmitter{ continue; // already sent the response to origin } if (this.clients.has(client)) { + winston.debug("Sending new value to", client.remoteAddress()); client.queueMessage(response); } else { // clean up subscribers - client is gone + winston.debug("deleting client"); this.subscribers[path].delete(client); } } diff --git a/EmberServer/QualifiedHandlers.js b/EmberServer/QualifiedHandlers.js index db73742..43755ff 100755 --- a/EmberServer/QualifiedHandlers.js +++ b/EmberServer/QualifiedHandlers.js @@ -68,7 +68,6 @@ class QualifiedHandlers extends MatrixHandlers { this.server.setValue(element, parameter.contents.value, client); let res = this.server.getQualifiedResponse(element); client.sendBERNode(res) - this.server.updateSubscribers(element.getPath(), res, client); } } } diff --git a/package.json b/package.json index 9e9bc19..3c39074 100755 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "node-emberplus", - "version": "2.5.6", + "version": "2.5.7", "description": "Javascript implementation of the Ember+ automation protocol", "main": "index.js", "scripts": { @@ -24,7 +24,8 @@ "long": "^3.2.0", "smart-buffer": "^3.0.3", "winston": "^2.1.1", - "winston-color": "^1.0.0" + "winston-color": "^1.0.0", + "yargs": "^15.1.0" }, "devDependencies": { "eslint": "^5.5.0",