diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 0000000..294210d
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,507 @@
+{
+ "name": "red-briq-nodes",
+ "version": "0.2.4",
+ "lockfileVersion": 1,
+ "requires": true,
+ "dependencies": {
+ "@xmpp/jid": {
+ "version": "0.0.2",
+ "resolved": "https://registry.npmjs.org/@xmpp/jid/-/jid-0.0.2.tgz",
+ "integrity": "sha1-DVKMqdWNr8gzZlVk/+YvMyoxZ/I="
+ },
+ "@xmpp/streamparser": {
+ "version": "0.0.6",
+ "resolved": "https://registry.npmjs.org/@xmpp/streamparser/-/streamparser-0.0.6.tgz",
+ "integrity": "sha1-EYAz6p23yGoctGED8mnr/3n28eo=",
+ "requires": {
+ "@xmpp/xml": "^0.1.3",
+ "inherits": "^2.0.3",
+ "ltx": "^2.5.0"
+ }
+ },
+ "@xmpp/xml": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/@xmpp/xml/-/xml-0.1.3.tgz",
+ "integrity": "sha1-HxQ5nlPkGWiFWGmPbGLnHjmoam4=",
+ "requires": {
+ "inherits": "^2.0.3",
+ "ltx": "^2.6.2"
+ }
+ },
+ "ajv": {
+ "version": "6.12.0",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.0.tgz",
+ "integrity": "sha512-D6gFiFA0RRLyUbvijN74DWAjXSFxWKaWP7mldxkVhyhAV3+SWA9HEJPHQ2c9soIeTFJqcSdFDGFgdqs1iUU2Hw==",
+ "requires": {
+ "fast-deep-equal": "^3.1.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ }
+ },
+ "asn1": {
+ "version": "0.2.4",
+ "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
+ "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==",
+ "requires": {
+ "safer-buffer": "~2.1.0"
+ }
+ },
+ "assert-plus": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
+ "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
+ },
+ "asynckit": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+ "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
+ },
+ "aws-sign2": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
+ "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg="
+ },
+ "aws4": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.9.1.tgz",
+ "integrity": "sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug=="
+ },
+ "backoff": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/backoff/-/backoff-2.3.0.tgz",
+ "integrity": "sha1-7nx+OAk/kuRyhZ22NedlJFT8Ieo="
+ },
+ "bcrypt-pbkdf": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
+ "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=",
+ "requires": {
+ "tweetnacl": "^0.14.3"
+ }
+ },
+ "browser-request": {
+ "version": "0.3.3",
+ "resolved": "https://registry.npmjs.org/browser-request/-/browser-request-0.3.3.tgz",
+ "integrity": "sha1-ns5bWsqJopkyJC4Yv5M975h2zBc="
+ },
+ "caseless": {
+ "version": "0.12.0",
+ "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
+ "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw="
+ },
+ "combined-stream": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
+ "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
+ "requires": {
+ "delayed-stream": "~1.0.0"
+ }
+ },
+ "core-util-is": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
+ "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
+ },
+ "dashdash": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
+ "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
+ "requires": {
+ "assert-plus": "^1.0.0"
+ }
+ },
+ "debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "delayed-stream": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+ "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
+ },
+ "denque": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/denque/-/denque-1.4.1.tgz",
+ "integrity": "sha512-OfzPuSZKGcgr96rf1oODnfjqBFmr1DVoc/TrItj3Ohe0Ah1C5WX5Baquw/9U9KovnQ88EqmJbD66rKYUQYN1tQ=="
+ },
+ "ecc-jsbn": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
+ "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=",
+ "requires": {
+ "jsbn": "~0.1.0",
+ "safer-buffer": "^2.1.0"
+ }
+ },
+ "extend": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
+ "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
+ },
+ "extsprintf": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
+ "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU="
+ },
+ "fast-deep-equal": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz",
+ "integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA=="
+ },
+ "fast-json-stable-stringify": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
+ "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="
+ },
+ "forever-agent": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
+ "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE="
+ },
+ "form-data": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
+ "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
+ "requires": {
+ "asynckit": "^0.4.0",
+ "combined-stream": "^1.0.6",
+ "mime-types": "^2.1.12"
+ }
+ },
+ "getpass": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
+ "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
+ "requires": {
+ "assert-plus": "^1.0.0"
+ }
+ },
+ "har-schema": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
+ "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI="
+ },
+ "har-validator": {
+ "version": "5.1.3",
+ "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz",
+ "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==",
+ "requires": {
+ "ajv": "^6.5.5",
+ "har-schema": "^2.0.0"
+ }
+ },
+ "hash-base": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz",
+ "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=",
+ "requires": {
+ "inherits": "^2.0.1",
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "http-signature": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
+ "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=",
+ "requires": {
+ "assert-plus": "^1.0.0",
+ "jsprim": "^1.2.2",
+ "sshpk": "^1.7.0"
+ }
+ },
+ "inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
+ },
+ "is-typedarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
+ "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo="
+ },
+ "isstream": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
+ "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo="
+ },
+ "jsbn": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
+ "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM="
+ },
+ "json-schema": {
+ "version": "0.2.3",
+ "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
+ "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM="
+ },
+ "json-schema-traverse": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
+ },
+ "json-stringify-safe": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
+ "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus="
+ },
+ "jsprim": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
+ "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
+ "requires": {
+ "assert-plus": "1.0.0",
+ "extsprintf": "1.3.0",
+ "json-schema": "0.2.3",
+ "verror": "1.10.0"
+ }
+ },
+ "lodash.assign": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz",
+ "integrity": "sha1-DZnzzNem0mHRm9rrkkUAXShYCOc="
+ },
+ "ltx": {
+ "version": "2.9.2",
+ "resolved": "https://registry.npmjs.org/ltx/-/ltx-2.9.2.tgz",
+ "integrity": "sha512-llB7HflFhlfsYYT1SAe80elCBO5C20ryLdwPB/A/BZk38hhVeZztDlWQ9uTyvKNPX4aK6sA+JfS1f/mfzp5cxA==",
+ "requires": {
+ "inherits": "^2.0.4"
+ }
+ },
+ "md5.js": {
+ "version": "1.3.5",
+ "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz",
+ "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==",
+ "requires": {
+ "hash-base": "^3.0.0",
+ "inherits": "^2.0.1",
+ "safe-buffer": "^5.1.2"
+ }
+ },
+ "mime-db": {
+ "version": "1.43.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.43.0.tgz",
+ "integrity": "sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ=="
+ },
+ "mime-types": {
+ "version": "2.1.26",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.26.tgz",
+ "integrity": "sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ==",
+ "requires": {
+ "mime-db": "1.43.0"
+ }
+ },
+ "minimist": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
+ "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
+ },
+ "node-xmpp-client": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/node-xmpp-client/-/node-xmpp-client-3.2.0.tgz",
+ "integrity": "sha1-r0Un3wzFq9JpDLohOcwezcgeoYk=",
+ "requires": {
+ "browser-request": "^0.3.3",
+ "debug": "^2.2.0",
+ "md5.js": "^1.3.3",
+ "minimist": "^1.2.0",
+ "node-xmpp-core": "^5.0.9",
+ "request": "^2.65.0",
+ "ws": "^1.1.1"
+ }
+ },
+ "node-xmpp-core": {
+ "version": "5.0.9",
+ "resolved": "https://registry.npmjs.org/node-xmpp-core/-/node-xmpp-core-5.0.9.tgz",
+ "integrity": "sha1-XCjCjtsfs/i+uixnYHd2E/SPNCo=",
+ "requires": {
+ "@xmpp/jid": "^0.0.2",
+ "@xmpp/streamparser": "^0.0.6",
+ "@xmpp/xml": "^0.1.3",
+ "debug": "^2.2.0",
+ "inherits": "^2.0.1",
+ "lodash.assign": "^4.0.0",
+ "node-xmpp-tls-connect": "^1.0.1",
+ "reconnect-core": "https://github.com/dodo/reconnect-core/tarball/merged"
+ }
+ },
+ "node-xmpp-tls-connect": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/node-xmpp-tls-connect/-/node-xmpp-tls-connect-1.0.1.tgz",
+ "integrity": "sha1-kazkOsJrE4hhsr5HjfnfGdYdxcM="
+ },
+ "oauth-sign": {
+ "version": "0.9.0",
+ "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
+ "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ=="
+ },
+ "options": {
+ "version": "0.0.6",
+ "resolved": "https://registry.npmjs.org/options/-/options-0.0.6.tgz",
+ "integrity": "sha1-7CLTEoBrtT5zF3Pnza788cZDEo8="
+ },
+ "performance-now": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
+ "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
+ },
+ "psl": {
+ "version": "1.8.0",
+ "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz",
+ "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ=="
+ },
+ "punycode": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
+ "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
+ },
+ "qbox": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/qbox/-/qbox-0.1.7.tgz",
+ "integrity": "sha1-6A8NxdCfhp2IghaMP2asjdKEDwI="
+ },
+ "qs": {
+ "version": "6.5.2",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
+ "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA=="
+ },
+ "reconnect-core": {
+ "version": "https://github.com/dodo/reconnect-core/tarball/merged",
+ "integrity": "sha512-wZK/v5ZaNaSUs2Wnwh2YSX/Jqv6bQHKNEwojdzV11tByKziR9ikOssf5tvUhx+8/oCBz6AakOFAjZuqPoiRHJQ==",
+ "requires": {
+ "backoff": "~2.3.0"
+ }
+ },
+ "request": {
+ "version": "2.88.2",
+ "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz",
+ "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==",
+ "requires": {
+ "aws-sign2": "~0.7.0",
+ "aws4": "^1.8.0",
+ "caseless": "~0.12.0",
+ "combined-stream": "~1.0.6",
+ "extend": "~3.0.2",
+ "forever-agent": "~0.6.1",
+ "form-data": "~2.3.2",
+ "har-validator": "~5.1.3",
+ "http-signature": "~1.2.0",
+ "is-typedarray": "~1.0.0",
+ "isstream": "~0.1.2",
+ "json-stringify-safe": "~5.0.1",
+ "mime-types": "~2.1.19",
+ "oauth-sign": "~0.9.0",
+ "performance-now": "^2.1.0",
+ "qs": "~6.5.2",
+ "safe-buffer": "^5.1.2",
+ "tough-cookie": "~2.5.0",
+ "tunnel-agent": "^0.6.0",
+ "uuid": "^3.3.2"
+ }
+ },
+ "safe-buffer": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz",
+ "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg=="
+ },
+ "safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
+ },
+ "simple-xmpp": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/simple-xmpp/-/simple-xmpp-1.3.1.tgz",
+ "integrity": "sha512-o0wGVlI8Q4o0qTz6Kylbo1QPOMVn+DA/vyHHZecqcQ+LK4ZWGe3wtRON9QjHAkSyxB36PoagmiUz4pHADau8Mw==",
+ "requires": {
+ "node-xmpp-client": "^3.0.0",
+ "qbox": "0.1.x"
+ }
+ },
+ "sshpk": {
+ "version": "1.16.1",
+ "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz",
+ "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==",
+ "requires": {
+ "asn1": "~0.2.3",
+ "assert-plus": "^1.0.0",
+ "bcrypt-pbkdf": "^1.0.0",
+ "dashdash": "^1.12.0",
+ "ecc-jsbn": "~0.1.1",
+ "getpass": "^0.1.1",
+ "jsbn": "~0.1.0",
+ "safer-buffer": "^2.0.2",
+ "tweetnacl": "~0.14.0"
+ }
+ },
+ "tough-cookie": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",
+ "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==",
+ "requires": {
+ "psl": "^1.1.28",
+ "punycode": "^2.1.1"
+ }
+ },
+ "tunnel-agent": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
+ "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
+ "requires": {
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "tweetnacl": {
+ "version": "0.14.5",
+ "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
+ "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q="
+ },
+ "ultron": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz",
+ "integrity": "sha1-rOEWq1V80Zc4ak6I9GhTeMiy5Po="
+ },
+ "uri-js": {
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",
+ "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==",
+ "requires": {
+ "punycode": "^2.1.0"
+ }
+ },
+ "uuid": {
+ "version": "3.4.0",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
+ "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
+ },
+ "verror": {
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
+ "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
+ "requires": {
+ "assert-plus": "^1.0.0",
+ "core-util-is": "1.0.2",
+ "extsprintf": "^1.2.0"
+ }
+ },
+ "ws": {
+ "version": "1.1.5",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-1.1.5.tgz",
+ "integrity": "sha512-o3KqipXNUdS7wpQzBHSe180lBGO60SoK0yVo3CYJgb2MkobuWuBX6dhkYP5ORCLd55y+SaflMOV5fqAB53ux4w==",
+ "requires": {
+ "options": ">=0.0.5",
+ "ultron": "1.0.x"
+ }
+ }
+ }
+}
diff --git a/package.json b/package.json
index 3e32aa3..cbca5f3 100644
--- a/package.json
+++ b/package.json
@@ -1,21 +1,26 @@
{
- "name" : "node-red-node-xmpp",
- "version" : "0.2.4",
- "description" : "A Node-RED node to talk to an XMPP server",
- "dependencies" : {
- "simple-xmpp" : "^1.3.1"
+ "name": "red-briq-nodes",
+ "version": "0.2.4",
+ "description": "A Node-RED node to talk to an XMPP server",
+ "dependencies": {
+ "denque": "^1.4.1",
+ "simple-xmpp": "^1.3.1"
},
- "repository" : {
- "type":"git",
- "url":"https://github.com/node-red/node-red-nodes/tree/master/social/xmpp"
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/node-red/node-red-nodes/tree/master/social/xmpp"
},
"license": "Apache-2.0",
- "keywords": [ "node-red", "xmpp" ],
- "node-red" : {
- "nodes" : {
- "xmpp": "92-xmpp.js",
- "my-debounce": "my-debounce.js",
- "command-parse": "command-parse.js"
+ "keywords": [
+ "node-red",
+ "xmpp"
+ ],
+ "node-red": {
+ "nodes": {
+ "xmpp": "red/xmpp/92-xmpp.js",
+ "my-debounce": "red/my-debounce/my-debounce.js",
+ "command-parse": "red/command-parse/command-parse.js",
+ "briq-tcp": "red/tcp/tcp.js"
}
},
"author": {
diff --git a/command-parse.html b/red/command-parse/command-parse.html
similarity index 100%
rename from command-parse.html
rename to red/command-parse/command-parse.html
diff --git a/command-parse.js b/red/command-parse/command-parse.js
similarity index 100%
rename from command-parse.js
rename to red/command-parse/command-parse.js
diff --git a/my-debounce.html b/red/my-debounce/my-debounce.html
similarity index 100%
rename from my-debounce.html
rename to red/my-debounce/my-debounce.html
diff --git a/my-debounce.js b/red/my-debounce/my-debounce.js
similarity index 100%
rename from my-debounce.js
rename to red/my-debounce/my-debounce.js
diff --git a/red/tcp/locales/en-US/tcp.json b/red/tcp/locales/en-US/tcp.json
new file mode 100644
index 0000000..6737b61
--- /dev/null
+++ b/red/tcp/locales/en-US/tcp.json
@@ -0,0 +1,57 @@
+{
+ "tcpin": {
+ "label": {
+ "type": "Type",
+ "output": "Output",
+ "port": "port",
+ "host": "at host",
+ "payload": "payload(s)",
+ "delimited": "delimited by",
+ "close-connection": "Close connection after each message is sent?",
+ "decode-base64": "Decode Base64 message?",
+ "server": "Server",
+ "return": "Return",
+ "ms": "ms",
+ "chars": "chars"
+ },
+ "type": {
+ "listen": "Listen on",
+ "connect": "Connect to",
+ "reply": "Reply to TCP"
+ },
+ "output": {
+ "stream": "stream of",
+ "single": "single",
+ "buffer": "Buffer",
+ "string": "String",
+ "base64": "Base64 String"
+ },
+ "return": {
+ "timeout": "after a fixed timeout of",
+ "character": "when character received is",
+ "number": "a fixed number of chars",
+ "never": "never - keep connection open",
+ "immed": "immediately - don't wait for reply"
+ },
+ "status": {
+ "connecting": "connecting to __host__:__port__",
+ "connected": "connected to __host__:__port__",
+ "listening-port": "listening on port __port__",
+ "stopped-listening": "stopped listening on port",
+ "connection-from": "connection from __host__:__port__",
+ "connection-closed": "connection closed from __host__:__port__",
+ "connections": "__count__ connection",
+ "connections_plural": "__count__ connections"
+ },
+ "errors": {
+ "connection-lost": "connection lost to __host__:__port__",
+ "timeout": "timeout closed socket port __port__",
+ "cannot-listen": "unable to listen on port __port__, error: __error__",
+ "error": "error: __error__",
+ "socket-error": "socket error from __host__:__port__",
+ "no-host": "Host and/or port not set",
+ "connect-timeout": "connect timeout",
+ "connect-fail": "connect failed"
+ }
+ }
+}
\ No newline at end of file
diff --git a/red/tcp/tcp.html b/red/tcp/tcp.html
new file mode 100644
index 0000000..af5cfd6
--- /dev/null
+++ b/red/tcp/tcp.html
@@ -0,0 +1,286 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/red/tcp/tcp.js b/red/tcp/tcp.js
new file mode 100644
index 0000000..e92ea48
--- /dev/null
+++ b/red/tcp/tcp.js
@@ -0,0 +1,715 @@
+/**
+ * Copyright JS Foundation and other contributors, http://js.foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+module.exports = function(RED) {
+ "use strict";
+ var reconnectTime = RED.settings.socketReconnectTime||10000;
+ var socketTimeout = RED.settings.socketTimeout||null;
+ const msgQueueSize = RED.settings.tcpMsgQueueSize || 1000;
+ const Denque = require('denque');
+ var net = require('net');
+
+ var connectionPool = {};
+
+ /**
+ * Enqueue `item` in `queue`
+ * @param {Denque} queue - Queue
+ * @param {*} item - Item to enqueue
+ * @private
+ * @returns {Denque} `queue`
+ */
+ const enqueue = (queue, item) => {
+ // drop msgs from front of queue if size is going to be exceeded
+ if (queue.length === msgQueueSize) { queue.shift(); }
+ queue.push(item);
+ return queue;
+ };
+
+ /**
+ * Shifts item off front of queue
+ * @param {Deque} queue - Queue
+ * @private
+ * @returns {*} Item previously at front of queue
+ */
+ const dequeue = queue => queue.shift();
+
+ function TcpIn(n) {
+ RED.nodes.createNode(this,n);
+ this.host = n.host;
+ this.port = n.port * 1;
+ this.topic = n.topic;
+ this.stream = (!n.datamode||n.datamode=='stream'); /* stream,single*/
+ this.datatype = n.datatype||'buffer'; /* buffer,utf8,base64 */
+ this.newline = (n.newline||"").replace("\\n","\n").replace("\\r","\r");
+ this.base64 = n.base64;
+ this.server = (typeof n.server == 'boolean')?n.server:(n.server == "server");
+ this.closing = false;
+ this.connected = false;
+ var node = this;
+ var count = 0;
+
+ if (!node.server) {
+ var buffer = null;
+ var client;
+ var reconnectTimeout;
+ var end = false;
+ var setupTcpClient = function() {
+ node.log(RED._("tcpin.status.connecting",{host:node.host,port:node.port}));
+ node.status({fill:"grey",shape:"dot",text:"common.status.connecting"});
+ var id = (1+Math.random()*4294967295).toString(16);
+ client = net.connect(node.port, node.host, function() {
+ buffer = (node.datatype == 'buffer') ? Buffer.alloc(0) : "";
+ node.connected = true;
+ node.log(RED._("tcpin.status.connected",{host:node.host,port:node.port}));
+ node.status({fill:"green",shape:"dot",text:"common.status.connected"});
+ });
+ client.setKeepAlive(true,120000);
+ connectionPool[id] = client;
+
+ client.on('data', function (data) {
+ if (node.datatype != 'buffer') {
+ data = data.toString(node.datatype);
+ }
+ if (node.stream) {
+ var msg;
+ if ((node.datatype) === "utf8" && node.newline !== "") {
+ buffer = buffer+data;
+ var parts = buffer.split(node.newline);
+ for (var i = 0; i 0)) {
+ var msg = {topic:node.topic, payload:buffer};
+ msg._session = {type:"tcp",id:id};
+ if (buffer.length !== 0) {
+ end = true; // only ask for fast re-connect if we actually got something
+ node.send(msg);
+ }
+ buffer = null;
+ }
+ });
+ client.on('close', function() {
+ delete connectionPool[id];
+ node.connected = false;
+ node.status({fill:"red",shape:"ring",text:"common.status.disconnected"});
+ if (!node.closing) {
+ if (end) { // if we were asked to close then try to reconnect once very quick.
+ end = false;
+ reconnectTimeout = setTimeout(setupTcpClient, 20);
+ }
+ else {
+ node.log(RED._("tcpin.errors.connection-lost",{host:node.host,port:node.port}));
+ reconnectTimeout = setTimeout(setupTcpClient, reconnectTime);
+ }
+ } else {
+ if (node.doneClose) { node.doneClose(); }
+ }
+ });
+ client.on('error', function(err) {
+ node.log(err);
+ });
+ }
+ setupTcpClient();
+
+ this.on('close', function(done) {
+ node.doneClose = done;
+ this.closing = true;
+ if (client) { client.destroy(); }
+ clearTimeout(reconnectTimeout);
+ if (!node.connected) { done(); }
+ });
+ }
+ else {
+ var server = net.createServer(function (socket) {
+ socket.setKeepAlive(true,120000);
+ if (socketTimeout !== null) { socket.setTimeout(socketTimeout); }
+ var id = (1+Math.random()*4294967295).toString(16);
+ var fromi;
+ var fromp;
+ connectionPool[id] = socket;
+ count++;
+ node.status({
+ text:RED._("tcpin.status.connections",{count:count}),
+ event:"connect",
+ ip:socket.remoteAddress,
+ port:socket.remotePort,
+ _session: {type:"tcp",id:id}
+ });
+
+ var buffer = (node.datatype == 'buffer') ? Buffer.alloc(0) : "";
+ socket.on('data', function (data) {
+ if (node.datatype != 'buffer') {
+ data = data.toString(node.datatype);
+ }
+ if (node.stream) {
+ var msg;
+ if ((typeof data) === "string" && node.newline !== "") {
+ buffer = buffer+data;
+ var parts = buffer.split(node.newline);
+ for (var i = 0; i 0) {
+ var msg = {topic:node.topic, payload:buffer, ip:fromi, port:fromp};
+ msg._session = {type:"tcp",id:id};
+ node.send(msg);
+ }
+ buffer = null;
+ }
+ });
+ socket.on('timeout', function() {
+ node.log(RED._("tcpin.errors.timeout",{port:node.port}));
+ socket.end();
+ });
+ socket.on('close', function() {
+ delete connectionPool[id];
+ count--;
+ node.status({
+ text:RED._("tcpin.status.connections",{count:count}),
+ event:"disconnect",
+ ip:socket.remoteAddress,
+ port:socket.remotePort,
+ _session: {type:"tcp",id:id}
+
+ });
+ });
+ socket.on('error',function(err) {
+ node.log(err);
+ });
+ });
+
+ server.on('error', function(err) {
+ if (err) {
+ node.error(RED._("tcpin.errors.cannot-listen",{port:node.port,error:err.toString()}));
+ }
+ });
+
+ server.listen(node.port, function(err) {
+ if (err) {
+ node.error(RED._("tcpin.errors.cannot-listen",{port:node.port,error:err.toString()}));
+ } else {
+ node.log(RED._("tcpin.status.listening-port",{port:node.port}));
+ node.on('close', function() {
+ for (var c in connectionPool) {
+ if (connectionPool.hasOwnProperty(c)) {
+ connectionPool[c].end();
+ connectionPool[c].unref();
+ }
+ }
+ node.closing = true;
+ server.close();
+ node.log(RED._("tcpin.status.stopped-listening",{port:node.port}));
+ });
+ }
+ });
+ }
+ }
+ RED.nodes.registerType("briq tcp in",TcpIn);
+
+
+ function TcpOut(n) {
+ RED.nodes.createNode(this,n);
+ this.host = n.host;
+ this.port = n.port * 1;
+ this.base64 = n.base64;
+ this.doend = n.end || false;
+ this.beserver = n.beserver;
+ this.name = n.name;
+ this.closing = false;
+ this.connected = false;
+ var node = this;
+
+ if (!node.beserver||node.beserver=="client") {
+ var reconnectTimeout;
+ var client = null;
+ var end = false;
+
+ var setupTcpClient = function() {
+ node.log(RED._("tcpin.status.connecting",{host:node.host,port:node.port}));
+ node.status({fill:"grey",shape:"dot",text:"common.status.connecting"});
+ client = net.connect(node.port, node.host, function() {
+ node.connected = true;
+ node.log(RED._("tcpin.status.connected",{host:node.host,port:node.port}));
+ node.status({fill:"green",shape:"dot",text:"common.status.connected"});
+ });
+ client.setKeepAlive(true,120000);
+ client.on('error', function (err) {
+ node.log(RED._("tcpin.errors.error",{error:err.toString()}));
+ });
+ client.on('end', function (err) {
+ node.status({});
+ node.connected = false;
+ });
+ client.on('close', function() {
+ node.status({fill:"red",shape:"ring",text:"common.status.disconnected"});
+ node.connected = false;
+ client.destroy();
+ if (!node.closing) {
+ if (end) {
+ end = false;
+ reconnectTimeout = setTimeout(setupTcpClient,20);
+ }
+ else {
+ node.log(RED._("tcpin.errors.connection-lost",{host:node.host,port:node.port}));
+ reconnectTimeout = setTimeout(setupTcpClient,reconnectTime);
+ }
+ } else {
+ if (node.doneClose) { node.doneClose(); }
+ }
+ });
+ }
+ setupTcpClient();
+
+ node.on("input", function(msg,nodeSend,nodeDone) {
+ if (node.connected && msg.payload != null) {
+ if (Buffer.isBuffer(msg.payload)) {
+ client.write(msg.payload);
+ } else if (typeof msg.payload === "string" && node.base64) {
+ client.write(Buffer.from(msg.payload,'base64'));
+ } else {
+ client.write(Buffer.from(""+msg.payload));
+ }
+ if (node.doend === true) {
+ end = true;
+ if (client) { node.status({}); client.destroy(); }
+ }
+ }
+ nodeDone();
+ });
+
+ node.on("close", function(done) {
+ node.doneClose = done;
+ this.closing = true;
+ if (client) { client.destroy(); }
+ clearTimeout(reconnectTimeout);
+ if (!node.connected) { done(); }
+ });
+
+ }
+ else if (node.beserver == "reply") {
+ node.on("input",function(msg, nodeSend, nodeDone) {
+ if (msg._session && msg._session.type == "tcp") {
+ var client = connectionPool[msg._session.id];
+ if (client) {
+ if (Buffer.isBuffer(msg.payload)) {
+ client.write(msg.payload);
+ } else if (typeof msg.payload === "string" && node.base64) {
+ client.write(Buffer.from(msg.payload,'base64'));
+ } else {
+ client.write(Buffer.from(""+msg.payload));
+ }
+ }
+ }
+ else {
+ for (var i in connectionPool) {
+ if (Buffer.isBuffer(msg.payload)) {
+ connectionPool[i].write(msg.payload);
+ } else if (typeof msg.payload === "string" && node.base64) {
+ connectionPool[i].write(Buffer.from(msg.payload,'base64'));
+ } else {
+ connectionPool[i].write(Buffer.from(""+msg.payload));
+ }
+ }
+ }
+ nodeDone();
+ });
+ }
+ else {
+ var connectedSockets = [];
+ node.status({text:RED._("tcpin.status.connections",{count:0})});
+ var server = net.createServer(function (socket) {
+ socket.setKeepAlive(true,120000);
+ if (socketTimeout !== null) { socket.setTimeout(socketTimeout); }
+ node.log(RED._("tcpin.status.connection-from",{host:socket.remoteAddress, port:socket.remotePort}));
+ connectedSockets.push(socket);
+ node.status({text:RED._("tcpin.status.connections",{count:connectedSockets.length})});
+ socket.on('timeout', function() {
+ node.log(RED._("tcpin.errors.timeout",{port:node.port}));
+ socket.end();
+ });
+ socket.on('close',function() {
+ node.log(RED._("tcpin.status.connection-closed",{host:socket.remoteAddress, port:socket.remotePort}));
+ connectedSockets.splice(connectedSockets.indexOf(socket),1);
+ node.status({text:RED._("tcpin.status.connections",{count:connectedSockets.length})});
+ });
+ socket.on('error',function() {
+ node.log(RED._("tcpin.errors.socket-error",{host:socket.remoteAddress, port:socket.remotePort}));
+ connectedSockets.splice(connectedSockets.indexOf(socket),1);
+ node.status({text:RED._("tcpin.status.connections",{count:connectedSockets.length})});
+ });
+ });
+
+ node.on("input", function(msg, nodeSend, nodeDone) {
+ if (msg.payload != null) {
+ var buffer;
+ if (Buffer.isBuffer(msg.payload)) {
+ buffer = msg.payload;
+ } else if (typeof msg.payload === "string" && node.base64) {
+ buffer = Buffer.from(msg.payload,'base64');
+ } else {
+ buffer = Buffer.from(""+msg.payload);
+ }
+ for (var i = 0; i < connectedSockets.length; i += 1) {
+ if (node.doend === true) { connectedSockets[i].end(buffer); }
+ else { connectedSockets[i].write(buffer); }
+ }
+ }
+ nodeDone();
+ });
+
+ server.on('error', function(err) {
+ if (err) {
+ node.error(RED._("tcpin.errors.cannot-listen",{port:node.port,error:err.toString()}));
+ }
+ });
+
+ server.listen(node.port, function(err) {
+ if (err) {
+ node.error(RED._("tcpin.errors.cannot-listen",{port:node.port,error:err.toString()}));
+ } else {
+ node.log(RED._("tcpin.status.listening-port",{port:node.port}));
+ node.on('close', function() {
+ for (var c in connectedSockets) {
+ if (connectedSockets.hasOwnProperty(c)) {
+ connectedSockets[c].end();
+ connectedSockets[c].unref();
+ }
+ }
+ server.close();
+ node.log(RED._("tcpin.status.stopped-listening",{port:node.port}));
+ });
+ }
+ });
+ }
+ }
+ RED.nodes.registerType("briq tcp out",TcpOut);
+
+
+ function TcpGet(n) {
+ RED.nodes.createNode(this,n);
+ this.server = n.server;
+ this.port = Number(n.port);
+ this.out = n.out;
+ this.splitc = n.splitc;
+
+ if (this.out === "immed") { this.splitc = -1; this.out = "time"; }
+ if (this.out !== "char") { this.splitc = Number(this.splitc); }
+ else {
+ if (this.splitc[0] == '\\') {
+ this.splitc = parseInt(this.splitc.replace("\\n",0x0A).replace("\\r",0x0D).replace("\\t",0x09).replace("\\e",0x1B).replace("\\f",0x0C).replace("\\0",0x00));
+ } // jshint ignore:line
+ if (typeof this.splitc == "string") {
+ if (this.splitc.substr(0,2) == "0x") {
+ this.splitc = parseInt(this.splitc);
+ }
+ else {
+ this.splitc = this.splitc.charCodeAt(0);
+ }
+ } // jshint ignore:line
+ }
+
+ var node = this;
+
+ var clients = {};
+
+ this.on("input", function(msg, nodeSend, nodeDone) {
+ var i = 0;
+ if ((!Buffer.isBuffer(msg.payload)) && (typeof msg.payload !== "string")) {
+ msg.payload = msg.payload.toString();
+ }
+
+ var host = node.server || msg.host;
+ var port = node.port || msg.port;
+
+ // Store client information independently
+ // the clients object will have:
+ // clients[id].client, clients[id].msg, clients[id].timeout
+ var connection_id = host + ":" + port;
+ if (connection_id !== node.last_id) {
+ node.status({});
+ node.last_id = connection_id;
+ }
+ clients[connection_id] = clients[connection_id] || {
+ msgQueue: new Denque(),
+ connected: false,
+ connecting: false
+ };
+ enqueue(clients[connection_id].msgQueue, {msg:msg,nodeSend:nodeSend, nodeDone: nodeDone});
+ clients[connection_id].lastMsg = msg;
+
+ if (!clients[connection_id].connecting && !clients[connection_id].connected) {
+ var buf;
+ if (this.out == "count") {
+ if (this.splitc === 0) { buf = Buffer.alloc(1); }
+ else { buf = Buffer.alloc(this.splitc); }
+ }
+ else { buf = Buffer.alloc(65536); } // set it to 64k... hopefully big enough for most TCP packets.... but only hopefully
+
+ clients[connection_id].client = net.Socket();
+ if (socketTimeout !== null) { clients[connection_id].client.setTimeout(socketTimeout);}
+
+ if (host && port) {
+ clients[connection_id].connecting = true;
+ clients[connection_id].client.connect(port, host, function() {
+ //node.log(RED._("tcpin.errors.client-connected"));
+ node.status({fill:"green",shape:"dot",text:"common.status.connected"});
+ if (clients[connection_id] && clients[connection_id].client) {
+ clients[connection_id].connected = true;
+ clients[connection_id].connecting = false;
+ let event;
+ while (event = dequeue(clients[connection_id].msgQueue)) {
+ clients[connection_id].client.write(event.msg.payload);
+ event.nodeDone();
+ }
+ if (node.out === "time" && node.splitc < 0) {
+ clients[connection_id].connected = clients[connection_id].connecting = false;
+ clients[connection_id].client.end();
+ delete clients[connection_id];
+ node.status({});
+ }
+ }
+ });
+ }
+ else {
+ node.warn(RED._("tcpin.errors.no-host"));
+ }
+
+ clients[connection_id].client.on('data', function(data) {
+ if (node.out === "sit") { // if we are staying connected just send the buffer
+ if (clients[connection_id]) {
+ const msg = clients[connection_id].lastMsg || {};
+ msg.payload = data;
+ nodeSend(RED.util.cloneMessage(msg));
+ }
+ }
+ // else if (node.splitc === 0) {
+ // clients[connection_id].msg.payload = data;
+ // node.send(clients[connection_id].msg);
+ // }
+ else {
+ for (var j = 0; j < data.length; j++ ) {
+ if (node.out === "time") {
+ if (clients[connection_id]) {
+ // do the timer thing
+ if (clients[connection_id].timeout) {
+ i += 1;
+ buf[i] = data[j];
+ }
+ else {
+ clients[connection_id].timeout = setTimeout(function () {
+ if (clients[connection_id]) {
+ clients[connection_id].timeout = null;
+ const msg = clients[connection_id].lastMsg || {};
+ msg.payload = Buffer.alloc(i+1);
+ buf.copy(msg.payload,0,0,i+1);
+ nodeSend(msg);
+ if (clients[connection_id].client) {
+ node.status({});
+ clients[connection_id].client.destroy();
+ delete clients[connection_id];
+ }
+ }
+ }, node.splitc);
+ i = 0;
+ buf[0] = data[j];
+ }
+ }
+ }
+ // count bytes into a buffer...
+ else if (node.out == "count") {
+ buf[i] = data[j];
+ i += 1;
+ if ( i >= node.splitc) {
+ if (clients[connection_id]) {
+ const msg = clients[connection_id].lastMsg || {};
+ msg.payload = Buffer.alloc(i);
+ buf.copy(msg.payload,0,0,i);
+ nodeSend(msg);
+ if (clients[connection_id].client) {
+ node.status({});
+ clients[connection_id].client.destroy();
+ delete clients[connection_id];
+ }
+ i = 0;
+ }
+ }
+ }
+ // look for a char
+ else {
+ buf[i] = data[j];
+ i += 1;
+ if (data[j] == node.splitc) {
+ if (clients[connection_id]) {
+ const msg = clients[connection_id].lastMsg || {};
+ msg.payload = Buffer.alloc(i);
+ buf.copy(msg.payload,0,0,i);
+ nodeSend(msg);
+ if (clients[connection_id].client) {
+ node.status({});
+ clients[connection_id].client.destroy();
+ delete clients[connection_id];
+ }
+ i = 0;
+ }
+ }
+ }
+ }
+ }
+ });
+
+ clients[connection_id].client.on('end', function() {
+ //console.log("END");
+ node.status({fill:"grey",shape:"ring",text:"common.status.disconnected"});
+ if (clients[connection_id] && clients[connection_id].client) {
+ clients[connection_id].connected = clients[connection_id].connecting = false;
+ clients[connection_id].client = null;
+ }
+ });
+
+ clients[connection_id].client.on('close', function() {
+ //console.log("CLOSE");
+ if (clients[connection_id]) {
+ clients[connection_id].connected = clients[connection_id].connecting = false;
+ }
+
+ var anyConnected = false;
+
+ for (var client in clients) {
+ if (clients[client].connected) {
+ anyConnected = true;
+ break;
+ }
+ }
+ if (node.doneClose && !anyConnected) {
+ clients = {};
+ node.doneClose();
+ }
+ });
+
+ clients[connection_id].client.on('error', function() {
+ //console.log("ERROR");
+ node.status({fill:"red",shape:"ring",text:"common.status.error"});
+ node.error(RED._("tcpin.errors.connect-fail") + " " + connection_id, msg);
+ if (clients[connection_id] && clients[connection_id].client) {
+ clients[connection_id].client.destroy();
+ delete clients[connection_id];
+ }
+ });
+
+ clients[connection_id].client.on('timeout',function() {
+ //console.log("TIMEOUT");
+ if (clients[connection_id]) {
+ clients[connection_id].connected = clients[connection_id].connecting = false;
+ node.status({fill:"grey",shape:"dot",text:"tcpin.errors.connect-timeout"});
+ //node.warn(RED._("tcpin.errors.connect-timeout"));
+ if (clients[connection_id].client) {
+ clients[connection_id].connecting = true;
+ clients[connection_id].client.connect(port, host, function() {
+ clients[connection_id].connected = true;
+ clients[connection_id].connecting = false;
+ node.status({fill:"green",shape:"dot",text:"common.status.connected"});
+ });
+ }
+ }
+ });
+ }
+ else if (!clients[connection_id].connecting && clients[connection_id].connected) {
+ if (clients[connection_id] && clients[connection_id].client) {
+ let event = dequeue(clients[connection_id].msgQueue)
+ clients[connection_id].client.write(event.msg.payload);
+ event.nodeDone();
+ }
+ }
+ });
+
+ this.on("close", function(done) {
+ node.doneClose = done;
+ for (var cl in clients) {
+ if (clients[cl].hasOwnProperty("client")) {
+ clients[cl].client.destroy();
+ }
+ }
+ node.status({});
+
+ // this is probably not necessary and may be removed
+ var anyConnected = false;
+ for (var c in clients) {
+ if (clients[c].connected) {
+ anyConnected = true;
+ break;
+ }
+ }
+ if (!anyConnected) { clients = {}; }
+ done();
+ });
+
+ }
+ RED.nodes.registerType("briq tcp request",TcpGet);
+ function TcpClose(n) {
+ RED.nodes.createNode(this,n);
+ this.name = n.name;
+ var node = this;
+
+ node.on("input",function(msg, nodeSend, nodeDone) {
+ if (msg._session && msg._session.type == "tcp") {
+ var client = connectionPool[msg._session.id];
+ if (client) {
+ client.destroy();
+ }
+ }
+ nodeDone();
+ });
+ }
+ RED.nodes.registerType("briq tcp close", TcpClose);
+}
\ No newline at end of file
diff --git a/92-xmpp.html b/red/xmpp/92-xmpp.html
similarity index 100%
rename from 92-xmpp.html
rename to red/xmpp/92-xmpp.html
diff --git a/92-xmpp.js b/red/xmpp/92-xmpp.js
similarity index 100%
rename from 92-xmpp.js
rename to red/xmpp/92-xmpp.js