From fdf40b8d2e7c1fc967e3c60d4949f55c1d00aa43 Mon Sep 17 00:00:00 2001 From: Ash Keel Date: Tue, 11 May 2021 11:38:38 +0200 Subject: [PATCH] Use published package for kilovolt --- frontend/package-lock.json | 162 ++++++++------- frontend/package.json | 25 +-- frontend/src/lib/strimertul-ws.ts | 319 ------------------------------ frontend/src/store/api/reducer.ts | 10 +- 4 files changed, 95 insertions(+), 421 deletions(-) delete mode 100644 frontend/src/lib/strimertul-ws.ts diff --git a/frontend/package-lock.json b/frontend/package-lock.json index eeee36b..22d876e 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1121,9 +1121,9 @@ "integrity": "sha512-ZvzKYD/Gk9HSq42jCHFlTXb3oJztspH7WTdlVU6WdW3MKk6Jja/wWhxRSpT07aDkU69pqdUl9zx6lpG6/qxO6g==" }, "@eslint/eslintrc": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.0.tgz", - "integrity": "sha512-2ZPCc+uNbjV5ERJr+aKSPRwZgKd2z11x0EgLvb1PURmUrn9QNRXFqje0Ldq454PfAVyaJYyrDvvIKSFP4NnBog==", + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.1.tgz", + "integrity": "sha512-5v7TDE9plVhvxQeWLXDTvFvJBdH6pEsdnl2g/dAptmuFEPedQ4Erq5rsDsX+mvAM610IhNaO2W5V1dOOnDKxkQ==", "dev": true, "requires": { "ajv": "^6.12.4", @@ -2273,6 +2273,14 @@ "reselect": "^4.0.0" } }, + "@strimertul/kilovolt-client": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@strimertul/kilovolt-client/-/kilovolt-client-2.0.0.tgz", + "integrity": "sha512-3CaHbXA1DPURgSVy6mdfDGM5y6H8j4kWzQRSj5V/RUziOulMc9bUKI3Hw/DLO7HCoz8rvY8gTBpKbgngzvabsw==", + "requires": { + "@billjs/event-emitter": "^1.0.3" + } + }, "@types/hoist-non-react-statics": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz", @@ -2303,9 +2311,9 @@ "dev": true }, "@types/node": { - "version": "15.0.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-15.0.1.tgz", - "integrity": "sha512-TMkXt0Ck1y0KKsGr9gJtWGjttxlZnnvDtphxUOSd0bfaR6Q1jle+sPvrzNR1urqYTWMinoKvjKfXUGsumaO1PA==" + "version": "15.0.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-15.0.2.tgz", + "integrity": "sha512-p68+a+KoxpoB47015IeYZYRrdqMUcpbK8re/zpFB8Ld46LHC1lPEbp3EXgkEhAYEcPvjJF6ZO+869SQ0aH1dcA==" }, "@types/prop-types": { "version": "15.7.3", @@ -2326,9 +2334,9 @@ } }, "@types/react": { - "version": "17.0.4", - "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.4.tgz", - "integrity": "sha512-onz2BqScSFMoTRdJUZUDD/7xrusM8hBA2Fktk2qgaTYPCgPvWnDEgkrOs8hhPUf2jfcIXkJ5yK6VfYormJS3Jw==", + "version": "17.0.5", + "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.5.tgz", + "integrity": "sha512-bj4biDB9ZJmGAYTWSKJly6bMr4BLUiBrx9ujiJEoP9XIDY9CTaPGxE5QWN/1WjpPLzYF7/jRNnV2nNxNe970sw==", "requires": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -2336,9 +2344,9 @@ } }, "@types/react-dom": { - "version": "17.0.3", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.3.tgz", - "integrity": "sha512-4NnJbCeWE+8YBzupn/YrJxZ8VnjcJq5iR1laqQ1vkpQgBiA7bwk0Rp24fxsdNinzJY2U+HHS4dJJDPdoMjdJ7w==", + "version": "17.0.4", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.4.tgz", + "integrity": "sha512-Wb6rlnPJfqbhpkvYN39y1NM/pOGGPzzIRquu0RdUMvTwgXNvASFO7pdtrtvyxGTQNb9wzBaQxXAWDdEqegZw2A==", "requires": { "@types/react": "*" } @@ -2360,13 +2368,13 @@ "integrity": "sha512-EaCxbanVeyxDRTQBkdLb3Bvl/HK7PBK6UJjsSixB0iHKoWxE5uu2Q/DgtpOhPIojN0Zl1whvOd7PoHs2P0s5eA==" }, "@typescript-eslint/eslint-plugin": { - "version": "4.22.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.22.0.tgz", - "integrity": "sha512-U8SP9VOs275iDXaL08Ln1Fa/wLXfj5aTr/1c0t0j6CdbOnxh+TruXu1p4I0NAvdPBQgoPjHsgKn28mOi0FzfoA==", + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.23.0.tgz", + "integrity": "sha512-tGK1y3KIvdsQEEgq6xNn1DjiFJtl+wn8JJQiETtCbdQxw1vzjXyAaIkEmO2l6Nq24iy3uZBMFQjZ6ECf1QdgGw==", "dev": true, "requires": { - "@typescript-eslint/experimental-utils": "4.22.0", - "@typescript-eslint/scope-manager": "4.22.0", + "@typescript-eslint/experimental-utils": "4.23.0", + "@typescript-eslint/scope-manager": "4.23.0", "debug": "^4.1.1", "functional-red-black-tree": "^1.0.1", "lodash": "^4.17.15", @@ -2376,55 +2384,55 @@ } }, "@typescript-eslint/experimental-utils": { - "version": "4.22.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.22.0.tgz", - "integrity": "sha512-xJXHHl6TuAxB5AWiVrGhvbGL8/hbiCQ8FiWwObO3r0fnvBdrbWEDy1hlvGQOAWc6qsCWuWMKdVWlLAEMpxnddg==", + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.23.0.tgz", + "integrity": "sha512-WAFNiTDnQfrF3Z2fQ05nmCgPsO5o790vOhmWKXbbYQTO9erE1/YsFot5/LnOUizLzU2eeuz6+U/81KV5/hFTGA==", "dev": true, "requires": { "@types/json-schema": "^7.0.3", - "@typescript-eslint/scope-manager": "4.22.0", - "@typescript-eslint/types": "4.22.0", - "@typescript-eslint/typescript-estree": "4.22.0", + "@typescript-eslint/scope-manager": "4.23.0", + "@typescript-eslint/types": "4.23.0", + "@typescript-eslint/typescript-estree": "4.23.0", "eslint-scope": "^5.0.0", "eslint-utils": "^2.0.0" } }, "@typescript-eslint/parser": { - "version": "4.22.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.22.0.tgz", - "integrity": "sha512-z/bGdBJJZJN76nvAY9DkJANYgK3nlRstRRi74WHm3jjgf2I8AglrSY+6l7ogxOmn55YJ6oKZCLLy+6PW70z15Q==", + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.23.0.tgz", + "integrity": "sha512-wsvjksHBMOqySy/Pi2Q6UuIuHYbgAMwLczRl4YanEPKW5KVxI9ZzDYh3B5DtcZPQTGRWFJrfcbJ6L01Leybwug==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "4.22.0", - "@typescript-eslint/types": "4.22.0", - "@typescript-eslint/typescript-estree": "4.22.0", + "@typescript-eslint/scope-manager": "4.23.0", + "@typescript-eslint/types": "4.23.0", + "@typescript-eslint/typescript-estree": "4.23.0", "debug": "^4.1.1" } }, "@typescript-eslint/scope-manager": { - "version": "4.22.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.22.0.tgz", - "integrity": "sha512-OcCO7LTdk6ukawUM40wo61WdeoA7NM/zaoq1/2cs13M7GyiF+T4rxuA4xM+6LeHWjWbss7hkGXjFDRcKD4O04Q==", + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.23.0.tgz", + "integrity": "sha512-ZZ21PCFxPhI3n0wuqEJK9omkw51wi2bmeKJvlRZPH5YFkcawKOuRMQMnI8mH6Vo0/DoHSeZJnHiIx84LmVQY+w==", "dev": true, "requires": { - "@typescript-eslint/types": "4.22.0", - "@typescript-eslint/visitor-keys": "4.22.0" + "@typescript-eslint/types": "4.23.0", + "@typescript-eslint/visitor-keys": "4.23.0" } }, "@typescript-eslint/types": { - "version": "4.22.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.22.0.tgz", - "integrity": "sha512-sW/BiXmmyMqDPO2kpOhSy2Py5w6KvRRsKZnV0c4+0nr4GIcedJwXAq+RHNK4lLVEZAJYFltnnk1tJSlbeS9lYA==", + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.23.0.tgz", + "integrity": "sha512-oqkNWyG2SLS7uTWLZf6Sr7Dm02gA5yxiz1RP87tvsmDsguVATdpVguHr4HoGOcFOpCvx9vtCSCyQUGfzq28YCw==", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "4.22.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.22.0.tgz", - "integrity": "sha512-TkIFeu5JEeSs5ze/4NID+PIcVjgoU3cUQUIZnH3Sb1cEn1lBo7StSV5bwPuJQuoxKXlzAObjYTilOEKRuhR5yg==", + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.23.0.tgz", + "integrity": "sha512-5Sty6zPEVZF5fbvrZczfmLCOcby3sfrSPu30qKoY1U3mca5/jvU5cwsPb/CO6Q3ByRjixTMIVsDkqwIxCf/dMw==", "dev": true, "requires": { - "@typescript-eslint/types": "4.22.0", - "@typescript-eslint/visitor-keys": "4.22.0", + "@typescript-eslint/types": "4.23.0", + "@typescript-eslint/visitor-keys": "4.23.0", "debug": "^4.1.1", "globby": "^11.0.1", "is-glob": "^4.0.1", @@ -2433,12 +2441,12 @@ } }, "@typescript-eslint/visitor-keys": { - "version": "4.22.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.22.0.tgz", - "integrity": "sha512-nnMu4F+s4o0sll6cBSsTeVsT4cwxB7zECK3dFxzEjPBii9xLpq4yqqsy/FU5zMfan6G60DKZSCXAa3sHJZrcYw==", + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.23.0.tgz", + "integrity": "sha512-5PNe5cmX9pSifit0H+nPoQBXdbNzi5tOEec+3riK+ku4e3er37pKxMKDH5Ct5Y4fhWxcD4spnlYjxi9vXbSpwg==", "dev": true, "requires": { - "@typescript-eslint/types": "4.22.0", + "@typescript-eslint/types": "4.23.0", "eslint-visitor-keys": "^2.0.0" } }, @@ -4309,13 +4317,13 @@ } }, "eslint": { - "version": "7.25.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.25.0.tgz", - "integrity": "sha512-TVpSovpvCNpLURIScDRB6g5CYu/ZFq9GfX2hLNIV4dSBKxIWojeDODvYl3t0k0VtMxYeR8OXPCFE5+oHMlGfhw==", + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.26.0.tgz", + "integrity": "sha512-4R1ieRf52/izcZE7AlLy56uIHHDLT74Yzz2Iv2l6kDaYvEu9x+wMB5dZArVL8SYGXSYV2YAg70FcW5Y5nGGNIg==", "dev": true, "requires": { "@babel/code-frame": "7.12.11", - "@eslint/eslintrc": "^0.4.0", + "@eslint/eslintrc": "^0.4.1", "ajv": "^6.10.0", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", @@ -4373,13 +4381,10 @@ } }, "eslint-config-prettier": { - "version": "6.15.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-6.15.0.tgz", - "integrity": "sha512-a1+kOYLR8wMGustcgAjdydMsQ2A/2ipRPwRKUmfYaSxc9ZPcrku080Ctl6zrZzZNs/U82MjSv+qKREkoq3bJaw==", - "dev": true, - "requires": { - "get-stdin": "^6.0.0" - } + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.3.0.tgz", + "integrity": "sha512-BgZuLUSeKzvlL/VUjx/Yb787VQ26RU3gGjA3iiFvdsp/2bMfVIWUVP7tjxtjS0e+HP409cPlPvNkQloz8C91ew==", + "dev": true }, "eslint-import-resolver-node": { "version": "0.3.4", @@ -4533,9 +4538,9 @@ } }, "eslint-visitor-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz", - "integrity": "sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", "dev": true }, "espree": { @@ -5003,12 +5008,6 @@ "resolved": "https://registry.npmjs.org/get-port/-/get-port-4.2.0.tgz", "integrity": "sha512-/b3jarXkH8KJoOMQc3uVGHASwGLPq3gSFJ7tgJm2diza+bydJPTGOibin2steecKeOylE8oY2JERlVWkAJO6yw==" }, - "get-stdin": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz", - "integrity": "sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==", - "dev": true - }, "get-value": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", @@ -5967,12 +5966,6 @@ "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=" }, - "lodash.flatten": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", - "integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=", - "dev": true - }, "lodash.memoize": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", @@ -8363,9 +8356,9 @@ "dev": true }, "prettier": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.2.1.tgz", - "integrity": "sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.3.0.tgz", + "integrity": "sha512-kXtO4s0Lz/DW/IJ9QdWhAf7/NmPWQXkFr/r/WkR3vyI+0v8amTDxiaQSLzs8NBlytfLWX/7uQUMIW677yLKl4w==", "dev": true }, "prettier-linter-helpers": { @@ -8894,9 +8887,9 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "sass": { - "version": "1.32.11", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.32.11.tgz", - "integrity": "sha512-O9tRcob/fegUVSIV1ihLLZcftIOh0AF1VpKgusUfLqnb2jQ0GLDwI5ivv1FYWivGv8eZ/AwntTyTzjcHu0c/qw==", + "version": "1.32.12", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.32.12.tgz", + "integrity": "sha512-zmXn03k3hN0KaiVTjohgkg98C3UowhL1/VSGdj4/VAAiMKGQOE80PFPxFP2Kyq0OUskPKcY5lImkhBKEHlypJA==", "requires": { "chokidar": ">=3.0.0 <4.0.0" } @@ -9503,14 +9496,13 @@ "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==" }, "table": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/table/-/table-6.6.0.tgz", - "integrity": "sha512-iZMtp5tUvcnAdtHpZTWLPF0M7AgiQsURR2DwmxnJwSy8I3+cY+ozzVvYha3BOLG2TB+L0CqjIz+91htuj6yCXg==", + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/table/-/table-6.7.0.tgz", + "integrity": "sha512-SAM+5p6V99gYiiy2gT5ArdzgM1dLDed0nkrWmG6Fry/bUS/m9x83BwpJUOf1Qj/x2qJd+thL6IkIx7qPGRxqBw==", "dev": true, "requires": { "ajv": "^8.0.1", "lodash.clonedeep": "^4.5.0", - "lodash.flatten": "^4.4.0", "lodash.truncate": "^4.4.2", "slice-ansi": "^4.0.0", "string-width": "^4.2.0", @@ -9518,9 +9510,9 @@ }, "dependencies": { "ajv": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.2.0.tgz", - "integrity": "sha512-WSNGFuyWd//XO8n/m/EaOlNLtO0yL8EXT/74LqT4khdhpZjP7lkj/kT5uwRmGitKEVp/Oj7ZUHeGfPtgHhQ5CA==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.3.0.tgz", + "integrity": "sha512-RYE7B5An83d7eWnDR8kbdaIFqmKCNsP16ay1hDbJEU+sa0e3H9SebskCt0Uufem6cfAVu7Col6ubcn/W+Sm8/Q==", "dev": true, "requires": { "fast-deep-equal": "^3.1.1", diff --git a/frontend/package.json b/frontend/package.json index fea9164..2625e1e 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -5,10 +5,11 @@ "@billjs/event-emitter": "^1.0.3", "@reach/router": "^1.3.4", "@reduxjs/toolkit": "^1.5.1", - "@types/node": "^15.0.0", + "@strimertul/kilovolt-client": "^2.0.0", + "@types/node": "^15.0.2", "@types/reach__router": "^1.3.7", - "@types/react": "^17.0.3", - "@types/react-dom": "^17.0.3", + "@types/react": "^17.0.5", + "@types/react-dom": "^17.0.4", "bulma": "^0.9.2", "parcel": "^2.0.0-beta.2", "react": "^17.0.2", @@ -16,7 +17,7 @@ "react-redux": "^7.2.4", "redux-devtools-extension": "^2.13.9", "redux-thunk": "^2.3.0", - "sass": "^1.32.11", + "sass": "^1.32.12", "typescript": "^4.2.4" }, "scripts": { @@ -28,15 +29,15 @@ ], "devDependencies": { "@parcel/transformer-sass": "^2.0.0-beta.2", - "@typescript-eslint/eslint-plugin": "^4.22.0", - "@typescript-eslint/parser": "^4.22.0", - "eslint": "^7.12.1", - "eslint-config-airbnb-base": "^14.2.0", - "eslint-config-prettier": "^6.15.0", - "eslint-import-resolver-typescript": "^2.3.0", + "@typescript-eslint/eslint-plugin": "^4.23.0", + "@typescript-eslint/parser": "^4.23.0", + "eslint": "^7.26.0", + "eslint-config-airbnb-base": "^14.2.1", + "eslint-config-prettier": "^8.3.0", + "eslint-import-resolver-typescript": "^2.4.0", "eslint-plugin-import": "^2.22.1", - "eslint-plugin-prettier": "^3.1.4", - "prettier": "^2.1.2", + "eslint-plugin-prettier": "^3.4.0", + "prettier": "^2.3.0", "rimraf": "^3.0.2" } } diff --git a/frontend/src/lib/strimertul-ws.ts b/frontend/src/lib/strimertul-ws.ts deleted file mode 100644 index 62d2600..0000000 --- a/frontend/src/lib/strimertul-ws.ts +++ /dev/null @@ -1,319 +0,0 @@ -import { EventEmitter } from '@billjs/event-emitter'; - -export type SubscriptionHandler = (newValue: string) => void; - -interface kvError { - ok: false; - error: string; -} - -interface kvPush { - type: 'push'; - key: string; - // eslint-disable-next-line camelcase - new_value: string; -} - -interface kvGenericResponse { - ok: true; - type: 'response'; - cmd: string; - data: string; -} - -interface kvEmptyResponse { - ok: true; - type: 'response'; - cmd: string; -} - -interface kvGet { - command: 'kget'; - data: { key: string }; -} - -interface kvSet { - command: 'kset'; - data: { key: string; data: string }; -} -interface kvSubscribe { - command: 'ksub'; - data: { key: string }; -} - -interface kvUnsubscribe { - command: 'kunsub'; - data: { key: string }; -} - -interface kvVersion { - command: 'kversion'; -} - -export type KilovoltRequest = - | kvGet - | kvSet - | kvSubscribe - | kvUnsubscribe - | kvVersion; - -type KilovoltResponse = kvGenericResponse | kvEmptyResponse; - -export type KilovoltMessage = kvError | kvPush | KilovoltResponse; - -export default class KilovoltWS extends EventEmitter { - socket!: WebSocket; - - address: string; - - pending: Record void>; - - subscriptions: Record; - - /** - * Create a new Kilovolt client instance and connect to it - * @param address Kilovolt server endpoint (including path) - */ - constructor(address = 'ws://localhost:4337/ws') { - super(); - this.address = address; - this.pending = {}; - this.subscriptions = {}; - this.connect(address); - } - - /** - * Re-connect to kilovolt server - */ - reconnect(): void { - this.connect(this.address); - } - - private connect(address: string): void { - this.socket = new WebSocket(address); - this.socket.addEventListener('open', this.open.bind(this)); - this.socket.addEventListener('message', this.received.bind(this)); - this.socket.addEventListener('close', this.closed.bind(this)); - } - - /** - * Wait for websocket connection to be established - */ - async wait(): Promise { - return new Promise((resolve) => { - if (this.socket.readyState === this.socket.OPEN) { - resolve(); - return; - } - this.once('open', () => resolve()); - }); - } - - private open() { - console.info('connected to server'); - this.fire('open'); - this.fire('stateChange', this.socket.readyState); - } - - private closed() { - console.warn('lost connection to server'); - this.fire('close'); - this.fire('stateChange', this.socket.readyState); - } - - private received(event: MessageEvent) { - const events = (event.data as string) - .split('\n') - .map((ev) => ev.trim()) - .filter((ev) => ev.length > 0); - events.forEach((ev) => { - const response: KilovoltMessage = JSON.parse(ev ?? '""'); - if ('error' in response) { - console.error('Received error from ws: ', response.error); - // TODO show in UI somehow - return; - } - switch (response.type) { - case 'response': - if (response.cmd in this.pending) { - this.pending[response.cmd](response); - delete this.pending[response.cmd]; - } else { - console.warn( - 'Received a response for an unregistered request: ', - response, - ); - } - break; - case 'push': { - if (response.key in this.subscriptions) { - this.subscriptions[response.key].forEach((fn) => - fn(response.new_value), - ); - } else { - console.warn( - 'Received subscription push with no listeners: ', - response, - ); - } - break; - } - default: - // Do nothing - } - }); - } - - /** - * Send a request to the server - * @param msg Request to send - * @returns Response from server - */ - async send(msg: KilovoltRequest): Promise { - return new Promise((resolve) => { - const payload = JSON.stringify(msg); - this.socket.send(payload); - this.pending[payload] = resolve; - }); - } - - /** - * Set a key to a specified value - * @param key Key to set - * @param data Value to set - * @returns Reply from server - */ - async putKey(key: string, data: string): Promise { - return this.send({ - command: 'kset', - data: { - key, - data, - }, - }); - } - - /** - * Set a key to the JSON representation of an object - * @param key Key to set - * @param data Object to save - * @returns Reply from server - */ - async putJSON(key: string, data: T): Promise { - return this.send({ - command: 'kset', - data: { - key, - data: JSON.stringify(data), - }, - }); - } - - /** - * Retrieve value for key - * @param key Key to retrieve - * @returns Reply from server - */ - async getKey(key: string): Promise { - const response = (await this.send({ - command: 'kget', - data: { - key, - }, - })) as kvError | kvGenericResponse; - if ('error' in response) { - throw new Error(response.error); - } - return response.data; - } - - /** - * Retrieve object from key, deserialized from JSON. - * It's your responsibility to make sure the object is actually what you expect - * @param key Key to retrieve - * @returns Reply from server - */ - async getJSON(key: string): Promise { - const response = (await this.send({ - command: 'kget', - data: { - key, - }, - })) as kvError | kvGenericResponse; - if ('error' in response) { - throw new Error(response.error); - } - return JSON.parse(response.data); - } - - /** - * Subscribe to key changes - * @param key Key to subscribe to - * @param fn Callback to call when key changes - * @returns Reply from server - */ - async subscribe( - key: string, - fn: SubscriptionHandler, - ): Promise { - if (key in this.subscriptions) { - this.subscriptions[key].push(fn); - } else { - this.subscriptions[key] = [fn]; - } - - return this.send({ - command: 'ksub', - data: { - key, - }, - }); - } - - /** - * Stop calling a callback when its related key changes - * This only - * @param key Key to unsubscribe from - * @param fn Callback to stop calling - * @returns true if a subscription was removed, false otherwise - */ - async unsubscribe(key: string, fn: SubscriptionHandler): Promise { - if (!(key in this.subscriptions)) { - // No subscriptions, just warn and return - console.warn( - `Trying to unsubscribe from key "${key}" but no subscriptions could be found!`, - ); - return false; - } - - // Get subscriber in list - const index = this.subscriptions[key].findIndex((subfn) => subfn === fn); - if (index < 0) { - // No subscriptions, just warn and return - console.warn( - `Trying to unsubscribe from key "${key}" but specified function is not in the subscribers!`, - ); - return false; - } - - // Remove subscriber from list - this.subscriptions[key].splice(index, 1); - - // Check if array is empty - if (this.subscriptions[key].length < 1) { - // Send unsubscribe - const res = (await this.send({ - command: 'kunsub', - data: { - key, - }, - })) as kvError | kvGenericResponse; - if ('error' in res) { - console.warn(`unsubscribe failed: ${res.error}`); - } - return res.ok; - } - - return true; - } -} diff --git a/frontend/src/store/api/reducer.ts b/frontend/src/store/api/reducer.ts index 14aed42..aaab73e 100644 --- a/frontend/src/store/api/reducer.ts +++ b/frontend/src/store/api/reducer.ts @@ -8,7 +8,7 @@ import { createSlice, PayloadAction, } from '@reduxjs/toolkit'; -import StrimertulWS from '../../lib/strimertul-ws'; +import KilovoltWS from '@strimertul/kilovolt-client'; // Storage const moduleConfigKey = 'stul-meta/modules'; @@ -93,7 +93,7 @@ export interface LoyaltyRedeem { } export interface APIState { - client: StrimertulWS; + client: KilovoltWS; connected: boolean; initialLoadComplete: boolean; loyalty: { @@ -179,12 +179,12 @@ function makeModule( } // eslint-disable-next-line import/no-mutable-exports, @typescript-eslint/ban-types -export let setupClientReconnect: AsyncThunk; +export let setupClientReconnect: AsyncThunk; export const createWSClient = createAsyncThunk( 'api/createClient', async (address: string, { dispatch }) => { - const client = new StrimertulWS(address); + const client = new KilovoltWS(address); await client.wait(); dispatch(setupClientReconnect(client)); return client; @@ -345,7 +345,7 @@ const apiReducer = createSlice({ setupClientReconnect = createAsyncThunk( 'api/setupClientReconnect', - async (client: StrimertulWS, { dispatch }) => { + async (client: KilovoltWS, { dispatch }) => { client.on('close', () => { setTimeout(async () => { console.info('Attempting reconnection');