diff --git a/.gitignore b/.gitignore index a1d9c9d..18c77ae 100644 --- a/.gitignore +++ b/.gitignore @@ -132,3 +132,4 @@ dist com.zoton2.example.streamDeckPlugin DistributionTool.exe streamdeck-plugin-vue/com.zoton2.example.sdPlugin +.idea/ diff --git a/package-lock.json b/package-lock.json index 616fbae..bfc82a3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "license": "MIT", "dependencies": { "@types/ws": "^8.2.2", - "ws": "^8.4.0" + "socket.io": "^4.7.4" }, "devDependencies": { "@types/node": "^16.11.19", @@ -261,6 +261,11 @@ "node": ">=8" } }, + "node_modules/@socket.io/component-emitter": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", + "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==" + }, "node_modules/@stroncium/procfs": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/@stroncium/procfs/-/procfs-1.2.1.tgz", @@ -294,6 +299,19 @@ "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==", "dev": true }, + "node_modules/@types/cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==" + }, + "node_modules/@types/cors": { + "version": "2.8.17", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz", + "integrity": "sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/json-schema": { "version": "7.0.9", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", @@ -515,6 +533,18 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/acorn": { "version": "8.7.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", @@ -691,6 +721,14 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, + "node_modules/base64id": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", + "engines": { + "node": "^4.5.0 || >= 5.9" + } + }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -850,6 +888,26 @@ "integrity": "sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==", "dev": true }, + "node_modules/cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/create-require": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", @@ -874,7 +932,6 @@ "version": "4.3.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "dev": true, "dependencies": { "ms": "2.1.2" }, @@ -990,6 +1047,34 @@ "once": "^1.4.0" } }, + "node_modules/engine.io": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.4.tgz", + "integrity": "sha512-KdVSDKhVKyOi+r5uEabrDLZw2qXStVvCsEB/LN3mw4WFi6Gx50jTyuxYVCwAAC0U46FdnzP/ScKRBTXb/NiEOg==", + "dependencies": { + "@types/cookie": "^0.4.1", + "@types/cors": "^2.8.12", + "@types/node": ">=10.0.0", + "accepts": "~1.3.4", + "base64id": "2.0.0", + "cookie": "~0.4.1", + "cors": "~2.8.5", + "debug": "~4.3.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.11.0" + }, + "engines": { + "node": ">=10.2.0" + } + }, + "node_modules/engine.io-parser": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.2.tgz", + "integrity": "sha512-RcyUFKA93/CXH20l4SoVvzZfrSDMOTUS3bWVpTt2FuFP+XYrL8i8oonHP7WInRyVHXh0n/ORtoeiE1os+8qkSw==", + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/enquirer": { "version": "2.3.6", "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", @@ -2280,6 +2365,25 @@ "node": ">=8.6" } }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/mimic-fn": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", @@ -2380,8 +2484,7 @@ "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/natural-compare": { "version": "1.4.0", @@ -2389,6 +2492,14 @@ "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/normalize-package-data": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", @@ -2416,6 +2527,14 @@ "node": ">=8" } }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/object-inspect": { "version": "1.12.0", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz", @@ -3069,6 +3188,43 @@ "node": ">=8" } }, + "node_modules/socket.io": { + "version": "4.7.4", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.7.4.tgz", + "integrity": "sha512-DcotgfP1Zg9iP/dH9zvAQcWrE0TtbMVwXmlV4T4mqsvY+gw+LqUGPfx2AoVyRk0FLME+GQhufDMyacFmw7ksqw==", + "dependencies": { + "accepts": "~1.3.4", + "base64id": "~2.0.0", + "cors": "~2.8.5", + "debug": "~4.3.2", + "engine.io": "~6.5.2", + "socket.io-adapter": "~2.5.2", + "socket.io-parser": "~4.2.4" + }, + "engines": { + "node": ">=10.2.0" + } + }, + "node_modules/socket.io-adapter": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.2.tgz", + "integrity": "sha512-87C3LO/NOMc+eMcpcxUBebGjkpMDkNBS9tf7KJqcDsmL936EChtVva71Dw2q4tQcuVC+hAUy4an2NO/sYXmwRA==", + "dependencies": { + "ws": "~8.11.0" + } + }, + "node_modules/socket.io-parser": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", + "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/spdx-correct": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", @@ -3528,6 +3684,14 @@ "spdx-expression-parse": "^3.0.0" } }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -3575,9 +3739,9 @@ "dev": true }, "node_modules/ws": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.4.0.tgz", - "integrity": "sha512-IHVsKe2pjajSUIl4KYMQOdlyliovpEPquKkqbwswulszzI7r0SfQrxnXdWAEqOlDCLrVSJzo+O1hAwdog2sKSQ==", + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", + "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", "engines": { "node": ">=10.0.0" }, @@ -3838,6 +4002,11 @@ "execa": "^2.0.1" } }, + "@socket.io/component-emitter": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", + "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==" + }, "@stroncium/procfs": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/@stroncium/procfs/-/procfs-1.2.1.tgz", @@ -3868,6 +4037,19 @@ "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==", "dev": true }, + "@types/cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==" + }, + "@types/cors": { + "version": "2.8.17", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz", + "integrity": "sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==", + "requires": { + "@types/node": "*" + } + }, "@types/json-schema": { "version": "7.0.9", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", @@ -4000,6 +4182,15 @@ "eslint-visitor-keys": "^3.0.0" } }, + "accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "requires": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + } + }, "acorn": { "version": "8.7.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", @@ -4122,6 +4313,11 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, + "base64id": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==" + }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -4237,6 +4433,20 @@ "integrity": "sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==", "dev": true }, + "cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==" + }, + "cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "requires": { + "object-assign": "^4", + "vary": "^1" + } + }, "create-require": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", @@ -4258,7 +4468,6 @@ "version": "4.3.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "dev": true, "requires": { "ms": "2.1.2" } @@ -4341,6 +4550,28 @@ "once": "^1.4.0" } }, + "engine.io": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.4.tgz", + "integrity": "sha512-KdVSDKhVKyOi+r5uEabrDLZw2qXStVvCsEB/LN3mw4WFi6Gx50jTyuxYVCwAAC0U46FdnzP/ScKRBTXb/NiEOg==", + "requires": { + "@types/cookie": "^0.4.1", + "@types/cors": "^2.8.12", + "@types/node": ">=10.0.0", + "accepts": "~1.3.4", + "base64id": "2.0.0", + "cookie": "~0.4.1", + "cors": "~2.8.5", + "debug": "~4.3.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.11.0" + } + }, + "engine.io-parser": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.2.tgz", + "integrity": "sha512-RcyUFKA93/CXH20l4SoVvzZfrSDMOTUS3bWVpTt2FuFP+XYrL8i8oonHP7WInRyVHXh0n/ORtoeiE1os+8qkSw==" + }, "enquirer": { "version": "2.3.6", "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", @@ -5309,6 +5540,19 @@ "picomatch": "^2.2.3" } }, + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" + }, + "mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "requires": { + "mime-db": "1.52.0" + } + }, "mimic-fn": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", @@ -5386,8 +5630,7 @@ "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "natural-compare": { "version": "1.4.0", @@ -5395,6 +5638,11 @@ "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, + "negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" + }, "normalize-package-data": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", @@ -5416,6 +5664,11 @@ "path-key": "^3.0.0" } }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==" + }, "object-inspect": { "version": "1.12.0", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz", @@ -5843,6 +6096,37 @@ "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true }, + "socket.io": { + "version": "4.7.4", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.7.4.tgz", + "integrity": "sha512-DcotgfP1Zg9iP/dH9zvAQcWrE0TtbMVwXmlV4T4mqsvY+gw+LqUGPfx2AoVyRk0FLME+GQhufDMyacFmw7ksqw==", + "requires": { + "accepts": "~1.3.4", + "base64id": "~2.0.0", + "cors": "~2.8.5", + "debug": "~4.3.2", + "engine.io": "~6.5.2", + "socket.io-adapter": "~2.5.2", + "socket.io-parser": "~4.2.4" + } + }, + "socket.io-adapter": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.2.tgz", + "integrity": "sha512-87C3LO/NOMc+eMcpcxUBebGjkpMDkNBS9tf7KJqcDsmL936EChtVva71Dw2q4tQcuVC+hAUy4an2NO/sYXmwRA==", + "requires": { + "ws": "~8.11.0" + } + }, + "socket.io-parser": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", + "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", + "requires": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1" + } + }, "spdx-correct": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", @@ -6174,6 +6458,11 @@ "spdx-expression-parse": "^3.0.0" } }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==" + }, "which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -6209,9 +6498,9 @@ "dev": true }, "ws": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.4.0.tgz", - "integrity": "sha512-IHVsKe2pjajSUIl4KYMQOdlyliovpEPquKkqbwswulszzI7r0SfQrxnXdWAEqOlDCLrVSJzo+O1hAwdog2sKSQ==", + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", + "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", "requires": {} }, "xdg-basedir": { diff --git a/package.json b/package.json index 266239e..7cf7d30 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ }, "dependencies": { "@types/ws": "^8.2.2", - "ws": "^8.4.0" + "socket.io": "^4.7.4" }, "devDependencies": { "@types/node": "^16.11.19", diff --git a/src/index.ts b/src/index.ts index 7d08a28..3c4c7ab 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,43 +1,42 @@ import { EventEmitter } from 'stream'; -import * as url from 'url'; import * as util from 'util'; -import ws from 'ws'; +import { Server } from 'socket.io'; +import type { SocketId } from 'socket.io-adapter'; import { ButtonLocations, ButtonObject, EventReceive } from '../types'; /* eslint-disable max-len */ interface StreamDeck { - on(event: 'open', listener: () => void): this; - on(event: 'init', listener: () => void): this; - on(event: 'error', listener: (err: Error) => void): this; - on(event: 'close', listener: (code: number, reason: string) => void): this; + on(event: 'open', listener: (socketId: SocketId) => void): this; + on(event: 'init', listener: (socketId: SocketId) => void): this; + on(event: 'error', listener: (socketId: SocketId, err: Error) => void): this; + on(event: 'close', listener: (socketId: SocketId, code: number, reason: string) => void): this; - on(event: 'message', listener: (data: { [k: string]: unknown }) => void): this; + on(event: 'message', listener: (socketId: SocketId, data: { [k: string]: unknown }) => void): this; // Currently a blanket definition for all events, can be expanded in the future. - on(event: 'didReceiveSettings', listener: (data: { [k: string]: unknown }) => void): this; - on(event: 'didReceiveGlobalSettings', listener: (data: { [k: string]: unknown }) => void): this; - on(event: 'keyDown', listener: (data: EventReceive.KeyDown) => void): this; - on(event: 'keyUp', listener: (data: EventReceive.KeyUp) => void): this; - on(event: 'willAppear', listener: (data: { [k: string]: unknown }) => void): this; - on(event: 'willDisappear', listener: (data: { [k: string]: unknown }) => void): this; - on(event: 'titleParametersDidChange', listener: (data: { [k: string]: unknown }) => void): this; - on(event: 'deviceDidConnect', listener: (data: { [k: string]: unknown }) => void): this; - on(event: 'deviceDidDisconnect', listener: (data: { [k: string]: unknown }) => void): this; - on(event: 'applicationDidLaunch', listener: (data: { [k: string]: unknown }) => void): this; - on(event: 'applicationDidTerminate', listener: (data: { [k: string]: unknown }) => void): this; - on(event: 'systemDidWakeUp', listener: (data: { [k: string]: unknown }) => void): this; - on(event: 'propertyInspectorDidAppear', listener: (data: { [k: string]: unknown }) => void): this; - on(event: 'propertyInspectorDidDisappear', listener: (data: { [k: string]: unknown }) => void): this; - on(event: 'sendToPlugin', listener: (data: { [k: string]: unknown }) => void): this; + on(event: 'didReceiveSettings', listener: (socketId: SocketId, data: { [k: string]: unknown }) => void): this; + on(event: 'didReceiveGlobalSettings', listener: (socketId: SocketId, data: { [k: string]: unknown }) => void): this; + on(event: 'keyDown', listener: (socketId: SocketId, data: EventReceive.KeyDown) => void): this; + on(event: 'keyUp', listener: (socketId: SocketId, data: EventReceive.KeyUp) => void): this; + on(event: 'willAppear', listener: (socketId: SocketId, data: { [k: string]: unknown }) => void): this; + on(event: 'willDisappear', listener: (socketId: SocketId, data: { [k: string]: unknown }) => void): this; + on(event: 'titleParametersDidChange', listener: (socketId: SocketId, data: { [k: string]: unknown }) => void): this; + on(event: 'deviceDidConnect', listener: (socketId: SocketId, data: { [k: string]: unknown }) => void): this; + on(event: 'deviceDidDisconnect', listener: (socketId: SocketId, data: { [k: string]: unknown }) => void): this; + on(event: 'applicationDidLaunch', listener: (socketId: SocketId, data: { [k: string]: unknown }) => void): this; + on(event: 'applicationDidTerminate', listener: (socketId: SocketId, data: { [k: string]: unknown }) => void): this; + on(event: 'systemDidWakeUp', listener: (socketId: SocketId, data: { [k: string]: unknown }) => void): this; + on(event: 'propertyInspectorDidAppear', listener: (socketId: SocketId, data: { [k: string]: unknown }) => void): this; + on(event: 'propertyInspectorDidDisappear', listener: (socketId: SocketId, data: { [k: string]: unknown }) => void): this; + on(event: 'sendToPlugin', listener: (socketId: SocketId, data: { [k: string]: unknown }) => void): this; } /* eslint-enable */ class StreamDeck extends EventEmitter { - wss: ws.Server | undefined; - wsConnection: ws | undefined; - pluginUUID: string | undefined; + wss: Server | undefined; debug = false; - buttonLocations: ButtonLocations = {}; - init = 0; // Can be 0, 1 or 2 depending on what initialisation step we are at. + buttonLocations: Map = new Map(); + // Can be 0, 1 or 2 depending on what initialisation step we are at. + initStates = new Map(); private log = { /* eslint-disable no-console */ @@ -65,53 +64,52 @@ class StreamDeck extends EventEmitter { this.wss.close(); // If server is already active, close it this.wss.removeAllListeners(); } - this.wss = new ws.Server({ port: opts.port }); // Create WebSocket server + this.wss = new Server(opts.port); // Create WebSocket server this.debug = opts.debug || false; this.log.debug('WebSocket server created on port %s', opts.port); - // Triggered when client connects. - this.wss.on('connection', (socket, req) => { - this.log.debug('WebSocket client connected'); - - // Get key from request query. - if (!req.url) return; - const { query } = url.parse(req.url, true); - const { key } = query; + this.wss.use((socket, next) => { + const { key } = socket.handshake.auth; if (key) this.log.debug('WebSocket client used key %s', key); // Disconnect client if key invalid. if (!key || key !== opts.key) { this.log.debug('WebSocket client connection refused due to incorrect key'); - socket.close(); - return; + socket.disconnect(true); + return next(new Error('Key is invalid')); } - // Disconnect client if one is already connected. - if (this.wsConnection && this.wsConnection.readyState !== 3) { - this.log.debug('WebSocket client connection refused due to more than 1 connection'); - socket.close(); - return; - } + return next(); + }); - this.wsConnection = socket; - this.emit('open'); + // Triggered when client connects. + this.wss.on('connection', (socket) => { + this.log.debug('WebSocket client connected'); + + this.initStates.set(socket.id, 0); + + this.emit('open', socket.id); socket.on('message', (message) => { const msg = JSON.parse(message.toString()); if (msg.type === 'init') { - this.log.debug('WebSocket received plugin UUID: %s', msg.data.pluginUUID); - this.pluginUUID = msg.data.pluginUUID; - if (this.init < 2) { - this.init += 1; - if (this.init >= 2) this.emit('init'); + // Use plugin message.data.pluginUUID instead (somehow, it's not set anywhere else) + let initState = this.initStates.get(socket.id) || 0; + this.log.debug('WebSocket received plugin UUID: %s', socket.id); + if (initState < 2) { + initState += 1; + this.initStates.set(socket.id, initState); + if (initState >= 2) this.emit('init', socket.id); } } if (msg.type === 'buttonLocationsUpdated') { + let initState = this.initStates.get(socket.id) || 0; this.log.debug('WebSocket received updated button locations'); - this.buttonLocations = msg.data.buttonLocations; - if (this.init < 2) { - this.init += 1; - if (this.init >= 2) this.emit('init'); + this.buttonLocations.set(socket.id, msg.data.buttonLocations); + if (initState < 2) { + initState += 1; + this.initStates.set(socket.id, initState); + if (initState >= 2) this.emit('init', socket.id); } } if (msg.type === 'rawSD') { @@ -119,14 +117,14 @@ class StreamDeck extends EventEmitter { 'WebSocket received raw Stream Deck message:\n%s', util.inspect(msg.data, { depth: null }), ); - this.emit(msg.data.event, msg.data); - this.emit('message', msg.data); + this.emit(msg.data.event, socket.id, msg.data); + this.emit('message', socket.id, msg.data); } }); socket.on('error', (err) => { this.log.debug('WebSocket client connection error (%s)', err); - this.emit('error', err); + this.emit('error', socket.id, err); }); socket.once('close', (code, reason) => { @@ -134,40 +132,46 @@ class StreamDeck extends EventEmitter { 'WebSocket client connection closed (%s)', `${code}${(reason) ? `, ${reason}` : ''}`, ); - this.buttonLocations = {}; - this.pluginUUID = undefined; - this.wsConnection = undefined; - this.init = 0; + this.buttonLocations.delete(socket.id); + this.initStates.delete(socket.id); socket.removeAllListeners(); - this.emit('close', code, reason); + this.emit('close', socket.id, code, reason); }); }); } /** - * Gets the buttonLocations object as received from the Stream Deck plugin. + * Gets all buttonLocations object as received from the Stream Deck plugin. */ - getButtonLocations(): ButtonLocations { + getButtonLocations(): Map { return this.buttonLocations; } + /** + * Gets the buttonLocations object as received from the Stream Deck plugin. + */ + getButtonLocationsFor(socket: SocketId): ButtonLocations { + return this.buttonLocations.get(socket) || {}; + } + /** * Gets the pluginUUID if set. + * @deprecated */ getPluginUUID(): string | undefined { - return this.pluginUUID; + return undefined; } /** * Sends message to the Stream Deck WebSocket connection. - * as documented on https://developer.elgato.com/documentation/stream-deck/sdk/events-sent/ + * as documented on https://docs.elgato.com/sdk/plugins/events-sent * Data will be stringified for you. * Will return true/false depending on if message was able to be sent. * @param data Object formatted to send to the Stream Deck WebSocket connection. */ send(data: { [k: string]: unknown }): boolean { - if (this.wsConnection && this.wsConnection.readyState === 1) { - this.wsConnection.send(JSON.stringify(data)); + if (this.wss) { + this.wss.send(JSON.stringify(data)); return true; } return false; @@ -176,8 +180,8 @@ class StreamDeck extends EventEmitter { /** * Get raw WebSocket connection to the plugin backend if available. */ - getWSConnection(): ws | undefined { - return this.wsConnection; + getSocket(): Server | undefined { + return this.wss; } /** @@ -186,16 +190,20 @@ class StreamDeck extends EventEmitter { */ findButtonsWithAction(action: string): ButtonObject[] { const buttons: ButtonObject[] = []; - Object.keys(this.buttonLocations).forEach((device) => { - Object.keys(this.buttonLocations[device]).forEach((row) => { - Object.keys(this.buttonLocations[device][row]).forEach((column) => { - const button = this.buttonLocations[device][row][column]; - if (button && button.action === action) { - buttons.push(button); - } + + for (const location of this.buttonLocations.values()) { + Object.keys(location).forEach((device) => { + Object.keys(location[device]).forEach((row) => { + Object.keys(location[device][row]).forEach((column) => { + const button = location[device][row][column]; + if (button && button.action === action) { + buttons.push(button); + } + }); }); }); - }); + } + return buttons; } diff --git a/streamdeck-plugin-vue/compile.sh b/streamdeck-plugin-vue/compile.sh new file mode 100755 index 0000000..9c8fae7 --- /dev/null +++ b/streamdeck-plugin-vue/compile.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +if [ -L "./Release" ]; then + mkdir "./Release" +fi + +npm run build + +rm ./Release/com.zoton2.example.sdPlugin > /dev/null 2>&1 + +zip -r ./Release/com.zoton2.example.sdPlugin.zip com.zoton2.example.sdPlugin/ + +mv ./Release/com.zoton2.example.sdPlugin.zip ./Release/com.zoton2.example.streamDeckPlugin + +read -p "Press any key to continue..." diff --git a/streamdeck-plugin-vue/package-lock.json b/streamdeck-plugin-vue/package-lock.json index e8eeec9..2f0ddf6 100644 --- a/streamdeck-plugin-vue/package-lock.json +++ b/streamdeck-plugin-vue/package-lock.json @@ -6,6 +6,7 @@ "": { "dependencies": { "events": "^3.3.0", + "socket.io-client": "^4.7.4", "vue": "^2.6.14", "vue-class-component": "^7.2.6", "vue-property-decorator": "^9.1.2" @@ -230,6 +231,11 @@ "node": ">= 8" } }, + "node_modules/@socket.io/component-emitter": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", + "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==" + }, "node_modules/@soda/friendly-errors-webpack-plugin": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/@soda/friendly-errors-webpack-plugin/-/friendly-errors-webpack-plugin-1.8.1.tgz", @@ -3940,7 +3946,6 @@ "version": "4.3.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "dev": true, "dependencies": { "ms": "2.1.2" }, @@ -4562,6 +4567,46 @@ "once": "^1.4.0" } }, + "node_modules/engine.io-client": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.5.3.tgz", + "integrity": "sha512-9Z0qLB0NIisTRt1DZ/8U2k12RJn8yls/nXMZLn+/N8hANT3TcYjKFKcwbw5zFQiN4NTde3TSY9zb79e1ij6j9Q==", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.11.0", + "xmlhttprequest-ssl": "~2.0.0" + } + }, + "node_modules/engine.io-client/node_modules/ws": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", + "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/engine.io-parser": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.2.tgz", + "integrity": "sha512-RcyUFKA93/CXH20l4SoVvzZfrSDMOTUS3bWVpTt2FuFP+XYrL8i8oonHP7WInRyVHXh0n/ORtoeiE1os+8qkSw==", + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/enhanced-resolve": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-0.9.1.tgz", @@ -8708,8 +8753,7 @@ "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/multicast-dns": { "version": "6.2.3", @@ -11877,6 +11921,32 @@ "node": ">=0.10.0" } }, + "node_modules/socket.io-client": { + "version": "4.7.4", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.7.4.tgz", + "integrity": "sha512-wh+OkeF0rAVCrABWQBaEjLfb7DVPotMbu0cgWgyR0v6eA4EoVnAwcIeIbcdTE3GT/H3kbdLl7OoH2+asoDRIIg==", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.2", + "engine.io-client": "~6.5.2", + "socket.io-parser": "~4.2.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/socket.io-parser": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", + "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/sockjs": { "version": "0.3.24", "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", @@ -15139,6 +15209,14 @@ "async-limiter": "~1.0.0" } }, + "node_modules/xmlhttprequest-ssl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz", + "integrity": "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", @@ -15479,6 +15557,11 @@ "fastq": "^1.6.0" } }, + "@socket.io/component-emitter": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", + "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==" + }, "@soda/friendly-errors-webpack-plugin": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/@soda/friendly-errors-webpack-plugin/-/friendly-errors-webpack-plugin-1.8.1.tgz", @@ -18481,7 +18564,6 @@ "version": "4.3.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "dev": true, "requires": { "ms": "2.1.2" } @@ -18977,6 +19059,31 @@ "once": "^1.4.0" } }, + "engine.io-client": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.5.3.tgz", + "integrity": "sha512-9Z0qLB0NIisTRt1DZ/8U2k12RJn8yls/nXMZLn+/N8hANT3TcYjKFKcwbw5zFQiN4NTde3TSY9zb79e1ij6j9Q==", + "requires": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.11.0", + "xmlhttprequest-ssl": "~2.0.0" + }, + "dependencies": { + "ws": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", + "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", + "requires": {} + } + } + }, + "engine.io-parser": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.2.tgz", + "integrity": "sha512-RcyUFKA93/CXH20l4SoVvzZfrSDMOTUS3bWVpTt2FuFP+XYrL8i8oonHP7WInRyVHXh0n/ORtoeiE1os+8qkSw==" + }, "enhanced-resolve": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-0.9.1.tgz", @@ -22227,8 +22334,7 @@ "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "multicast-dns": { "version": "6.2.3", @@ -24835,6 +24941,26 @@ } } }, + "socket.io-client": { + "version": "4.7.4", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.7.4.tgz", + "integrity": "sha512-wh+OkeF0rAVCrABWQBaEjLfb7DVPotMbu0cgWgyR0v6eA4EoVnAwcIeIbcdTE3GT/H3kbdLl7OoH2+asoDRIIg==", + "requires": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.2", + "engine.io-client": "~6.5.2", + "socket.io-parser": "~4.2.4" + } + }, + "socket.io-parser": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", + "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", + "requires": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1" + } + }, "sockjs": { "version": "0.3.24", "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", @@ -27490,6 +27616,11 @@ "async-limiter": "~1.0.0" } }, + "xmlhttprequest-ssl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz", + "integrity": "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==" + }, "xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", diff --git a/streamdeck-plugin-vue/package.json b/streamdeck-plugin-vue/package.json index 21801a4..8fd01d6 100644 --- a/streamdeck-plugin-vue/package.json +++ b/streamdeck-plugin-vue/package.json @@ -6,6 +6,7 @@ }, "dependencies": { "events": "^3.3.0", + "socket.io-client": "^4.7.4", "vue": "^2.6.14", "vue-class-component": "^7.2.6", "vue-property-decorator": "^9.1.2" diff --git a/streamdeck-plugin-vue/public/manifest.json b/streamdeck-plugin-vue/public/manifest.json index 7d8654c..040e782 100644 --- a/streamdeck-plugin-vue/public/manifest.json +++ b/streamdeck-plugin-vue/public/manifest.json @@ -16,7 +16,6 @@ } ], "Author": "zoton2", - "Category": "node-streamdeck-util", "CodePath": "backend.html", "Description": "Barebones plugin to be used with node-streamdeck-util.", "Name": "node-streamdeck-util", @@ -42,4 +41,4 @@ "Software": { "MinimumVersion": "5" } -} \ No newline at end of file +} diff --git a/streamdeck-plugin-vue/src/backend/backend.ts b/streamdeck-plugin-vue/src/backend/backend.ts index 0a6e6b8..d37bf00 100644 --- a/streamdeck-plugin-vue/src/backend/backend.ts +++ b/streamdeck-plugin-vue/src/backend/backend.ts @@ -1,4 +1,5 @@ import { EventEmitter } from 'events'; +import { io, Socket } from 'socket.io-client'; /* eslint-disable max-len, @typescript-eslint/no-explicit-any */ interface Backend { @@ -8,8 +9,7 @@ interface Backend { class Backend extends EventEmitter { sdWS!: WebSocket; - serverWS!: WebSocket; - serverWSReconnTimeout!: number; + serverWS!: Socket; connectSocketData: { inPort?: string, inPluginUUID?: string, @@ -148,37 +148,37 @@ class Backend extends EventEmitter { */ connectToServerWS(): void { if (this.serverWS) this.serverWS.close(); // Close current connection if one is active. - clearTimeout(this.serverWSReconnTimeout); - this.serverWS = new WebSocket(`${this.globalSettings.url}/?key=${this.globalSettings.key}`); + this.serverWS = io(this.globalSettings.url!, { + auth: { + key: this.globalSettings.key, + }, + }); console.info( 'Connecting to node-streamdeck-util server using %s and key %s', this.globalSettings.url, this.globalSettings.key, ); - this.serverWS.addEventListener('error', (e) => { + this.serverWS.on('connect_error', (e) => { console.warn('Error occured on the node-streamdeck-util server connection:', e); }); // Initalise node-streamdeck-util server connection. - this.serverWS.addEventListener('open', () => { + this.serverWS.on('connect', () => { console.info('Connection to node-streamdeck-util server successful'); this.sendToServerWS('init', { pluginUUID: this.connectSocketData.inPluginUUID }); this.sendToServerWS('buttonLocationsUpdated', { buttonLocations: this.buttonLocations }); this.toggleBackendConnectionStatus(true); - }, { once: true }); + }); - this.serverWS.addEventListener('close', (e) => { - console.warn('Connection to node-streamdeck-util server closed (%s)', e.code); + this.serverWS.on('disconnect', (e) => { + console.warn('Connection to node-streamdeck-util server closed (%s)', e); this.toggleBackendConnectionStatus(false); - clearTimeout(this.serverWSReconnTimeout); - this.serverWSReconnTimeout = setTimeout(() => { this.connectToServerWS(); }, 5000); - }, { once: true }); + }); // Relays any messages sent from the node-streamdeck-util server to the main socket. - this.serverWS.addEventListener('message', (e) => { - const { data } = e; + this.serverWS.on('message', (data) => { this.sendToSDWS(data); }); } @@ -187,7 +187,7 @@ class Backend extends EventEmitter { * Helper function to send messages to the node-streamdeck-util server if connection is ready. */ sendToServerWS(type: string, data: unknown): void { - if (this.serverWS && this.serverWS.readyState === 1) { + if (this.serverWS && this.serverWS.connected) { this.serverWS.send(JSON.stringify({ type, data })); } } diff --git a/test/server.ts b/test/server.ts index 252f667..e44848f 100644 --- a/test/server.ts +++ b/test/server.ts @@ -14,28 +14,29 @@ sd.listen({ }); // When the connection between the plugin and this instance is open. -sd.on('open', () => { - console.log('open'); +sd.on('open', (socketId) => { + console.log('open (socket %s)', socketId); }); // If the connection between the plugin and this instance is closed. -sd.on('close', (code, reason) => { - console.log('close: %s, %s', code, reason); +sd.on('close', (socketId, code, reason) => { + console.log('close: %s, %s (socket %s)', code, reason, socketId); }); // If there are any errors on the connection between the plugin and this instance. -sd.on('error', (err) => { - console.log('error:'); +sd.on('error', (socketId, err) => { + console.log('error (socket %s):', socketId); console.log(err); }); // Listens for the Stream Deck's events. -sd.on('message', (msg) => { - console.log('message:'); +sd.on('message', (socketId, msg) => { + console.log('message (socket %s):', socketId); console.log(msg); var buttonLocations = sd.getButtonLocations(); // object, see below - var pluginUUID = sd.getPluginUUID(); // sometimes needed as context when sending messages + + console.log(buttonLocations); // Send a message back to the Stream Deck application; the send function stringifies it for you. /* sd.send({ @@ -47,7 +48,12 @@ sd.on('message', (msg) => { }); // You can directly listen for Stream Deck's events by their name if you want to. -sd.on('keyDown', (msg) => { - console.log('keyDown:'); +sd.on('keyDown', (socketId, msg) => { + console.log('keyDown (socket %s):', socketId); console.log(msg); + + sd.send({ + "event": "showOk", + "context": msg.context, + }); });