1
0
Fork 0
mirror of https://git.sr.ht/~ashkeel/strimertul synced 2024-09-18 01:50:50 +00:00

Use published package for kilovolt

This commit is contained in:
Ash Keel 2021-05-11 11:38:38 +02:00
parent 7c9774432e
commit fdf40b8d2e
No known key found for this signature in database
GPG key ID: CF2CC050478BD7E5
4 changed files with 95 additions and 421 deletions

View file

@ -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",

View file

@ -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"
}
}

View file

@ -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<string, (response: KilovoltMessage) => void>;
subscriptions: Record<string, SubscriptionHandler[]>;
/**
* 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<void> {
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<KilovoltMessage> {
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<KilovoltMessage> {
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<T>(key: string, data: T): Promise<KilovoltMessage> {
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<string> {
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<T>(key: string): Promise<T> {
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<KilovoltMessage> {
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<boolean> {
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;
}
}

View file

@ -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<T>(
}
// eslint-disable-next-line import/no-mutable-exports, @typescript-eslint/ban-types
export let setupClientReconnect: AsyncThunk<void, StrimertulWS, {}>;
export let setupClientReconnect: AsyncThunk<void, KilovoltWS, {}>;
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');