Version 6.1.3

This commit is contained in:
Chrystian Huot 2022-01-11 14:24:04 -05:00
parent 7b527b1b00
commit 2a6f721f4f
29 changed files with 829 additions and 753 deletions

View file

@ -21,6 +21,14 @@ _v6.1.2_
- Dirwatch type trunk-recorder now deletes json files without audio (when deleteAfter is set). - Dirwatch type trunk-recorder now deletes json files without audio (when deleteAfter is set).
- Add a new `docs/update-from-v5.md` document. - Add a new `docs/update-from-v5.md` document.
_v6.1.3_
- Fix concurrent config write when autopopulate is enabled (issue #77).
- Fix API in regards to audio filename and audio type (issue #78).
- Fix some calls not playing on the native app (issue #87).
- Fix migration error on mysql database (issue #88).
- Fix admin password not read from mysql.
## Version 6.0 ## Version 6.0
- Backend server rewritten in Go for better performance and ease of installation. - Backend server rewritten in Go for better performance and ease of installation.

View file

@ -24,13 +24,13 @@ Clone the official repository on your computer and start the build process.
When finished, you will find the precompiled versions for various platforms in the `dist` folder. When finished, you will find the precompiled versions for various platforms in the `dist` folder.
rdio-scanner-darwin-amd64-v6.1.2.zip rdio-scanner-darwin-amd64-v6.1.3.zip
rdio-scanner-darwin-arm64-v6.1.2.zip rdio-scanner-darwin-arm64-v6.1.3.zip
rdio-scanner-freebsd-amd64-v6.1.2.zip rdio-scanner-freebsd-amd64-v6.1.3.zip
rdio-scanner-linux-386-v6.1.2.zip rdio-scanner-linux-386-v6.1.3.zip
rdio-scanner-linux-amd64-v6.1.2.zip rdio-scanner-linux-amd64-v6.1.3.zip
rdio-scanner-linux-arm64-v6.1.2.zip rdio-scanner-linux-arm64-v6.1.3.zip
rdio-scanner-linux-arm-v6.1.2.zip rdio-scanner-linux-arm-v6.1.3.zip
rdio-scanner-windows-amd64-v6.1.2.zip rdio-scanner-windows-amd64-v6.1.3.zip
**Happy Rdio scanning !** **Happy Rdio scanning !**

View file

@ -16,8 +16,8 @@
################################################################################ ################################################################################
app := rdio-scanner app := rdio-scanner
date := 2022/01/05 date := 2022/01/11
ver := 6.1.2 ver := 6.1.3
client := $(wildcard client/*.json client/*.ts) client := $(wildcard client/*.json client/*.ts)
server := $(wildcard server/*.go) server := $(wildcard server/*.go)
@ -39,7 +39,7 @@ clean:
container: webapp linux-amd64 container: webapp linux-amd64
@podman build --platform linux/amd64,linux/arm,linux/arm64 --manifest rdio-scanner:latest . @podman build --platform linux/amd64,linux/arm,linux/arm64 --manifest rdio-scanner:latest .
@podman manifest push --format v2s2 localhost/rdio-scanner:latest docker://docker.io/chuot/rdio-scanner:latest @podman manifest push --format v2s2 --rm localhost/rdio-scanner:latest docker://docker.io/chuot/rdio-scanner:latest
dist: darwin freebsd linux windows dist: darwin freebsd linux windows

491
client/package-lock.json generated
View file

@ -1,12 +1,12 @@
{ {
"name": "rdio-scanner", "name": "rdio-scanner",
"version": "6.1.0", "version": "6.1.3",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "rdio-scanner", "name": "rdio-scanner",
"version": "6.1.0", "version": "6.1.3",
"license": "LICENSE", "license": "LICENSE",
"dependencies": { "dependencies": {
"@angular/animations": "^13.1.1", "@angular/animations": "^13.1.1",
@ -25,12 +25,12 @@
"zone.js": "~0.11.4" "zone.js": "~0.11.4"
}, },
"devDependencies": { "devDependencies": {
"@angular-devkit/build-angular": "~13.1.2", "@angular-devkit/build-angular": "^13.1.2",
"@angular/cli": "^13.1.2", "@angular/cli": "^13.1.2",
"@angular/compiler-cli": "~13.1.1", "@angular/compiler-cli": "~13.1.1",
"@types/node": "~17.0.7", "@types/node": "~17.0.8",
"@typescript-eslint/eslint-plugin": "^5.9.0", "@typescript-eslint/eslint-plugin": "^5.9.1",
"@typescript-eslint/parser": "^5.9.0", "@typescript-eslint/parser": "^5.9.1",
"ajv-keywords": "^5.1.0", "ajv-keywords": "^5.1.0",
"eslint": "^8.6.0", "eslint": "^8.6.0",
"npm-check-updates": "^12.1.0", "npm-check-updates": "^12.1.0",
@ -612,9 +612,9 @@
} }
}, },
"node_modules/@babel/compat-data": { "node_modules/@babel/compat-data": {
"version": "7.16.4", "version": "7.16.8",
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.16.4.tgz", "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.16.8.tgz",
"integrity": "sha512-1o/jo7D+kC9ZjHX5v+EHrdjl3PhxMrLSOTGsOdHJ+KL8HCaEK6ehrVL2RS6oHDZp+L7xLirLrPmQtEng769J/Q==", "integrity": "sha512-m7OkX0IdKLKPpBlJtF561YJal5y/jyI5fNfWbPxh2D/nbzzGI4qRyrD8xO2jB24u7l+5I2a43scCG2IrfjC50Q==",
"dev": true, "dev": true,
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
@ -987,14 +987,14 @@
} }
}, },
"node_modules/@babel/helper-remap-async-to-generator": { "node_modules/@babel/helper-remap-async-to-generator": {
"version": "7.16.7", "version": "7.16.8",
"resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.7.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.8.tgz",
"integrity": "sha512-C3o117GnP/j/N2OWo+oepeWbFEKRfNaay+F1Eo5Mj3A1SRjyx+qaFhm23nlipub7Cjv2azdUUiDH+VlpdwUFRg==", "integrity": "sha512-fm0gH7Flb8H51LqJHy3HJ3wnE1+qtYR2A99K06ahwrawLdOFsCEWjZOrYricXJHoPSudNKxrMBUPEIPxiIIvBw==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@babel/helper-annotate-as-pure": "^7.16.7", "@babel/helper-annotate-as-pure": "^7.16.7",
"@babel/helper-wrap-function": "^7.16.7", "@babel/helper-wrap-function": "^7.16.8",
"@babel/types": "^7.16.7" "@babel/types": "^7.16.8"
}, },
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
@ -1083,15 +1083,15 @@
} }
}, },
"node_modules/@babel/helper-wrap-function": { "node_modules/@babel/helper-wrap-function": {
"version": "7.16.7", "version": "7.16.8",
"resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.16.7.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.16.8.tgz",
"integrity": "sha512-7a9sABeVwcunnztZZ7WTgSw6jVYLzM1wua0Z4HIXm9S3/HC96WKQTkFgGEaj5W06SHHihPJ6Le6HzS5cGOQMNw==", "integrity": "sha512-8RpyRVIAW1RcDDGTA+GpPAwV22wXCfKOoM9bet6TLkGIFTkRQSkH1nMQ5Yet4MpoXe1ZwHPVtNasc2w0uZMqnw==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@babel/helper-function-name": "^7.16.7", "@babel/helper-function-name": "^7.16.7",
"@babel/template": "^7.16.7", "@babel/template": "^7.16.7",
"@babel/traverse": "^7.16.7", "@babel/traverse": "^7.16.8",
"@babel/types": "^7.16.7" "@babel/types": "^7.16.8"
}, },
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
@ -1154,9 +1154,9 @@
} }
}, },
"node_modules/@babel/parser": { "node_modules/@babel/parser": {
"version": "7.16.7", "version": "7.16.8",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.7.tgz", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.8.tgz",
"integrity": "sha512-sR4eaSrnM7BV7QPzGfEX5paG/6wrZM3I0HDzfIAK06ESvo9oy3xBuVBxE3MbQaKNhvg8g/ixjMWo2CGpzpHsDA==", "integrity": "sha512-i7jDUfrVBWc+7OKcBzEe5n7fbv3i2fWtxKzzCvOjnzSxMfWMigAhtfJ7qzZNGFNMsCCd67+uz553dYKWXPvCKw==",
"dev": true, "dev": true,
"bin": { "bin": {
"parser": "bin/babel-parser.js" "parser": "bin/babel-parser.js"
@ -1887,9 +1887,9 @@
} }
}, },
"node_modules/@babel/plugin-transform-modules-commonjs": { "node_modules/@babel/plugin-transform-modules-commonjs": {
"version": "7.16.7", "version": "7.16.8",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.16.7.tgz", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.16.8.tgz",
"integrity": "sha512-h2RP2kE7He1ZWKyAlanMZrAbdv+Acw1pA8dQZhE025WJZE2z0xzFADAinXA9fxd5bn7JnM+SdOGcndGx1ARs9w==", "integrity": "sha512-oflKPvsLT2+uKQopesJt3ApiaIS2HW+hzHFcwRNtyDGieAeC/dIHZX8buJQ2J2X1rxGPy4eRcUijm3qcSPjYcA==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@babel/helper-module-transforms": "^7.16.7", "@babel/helper-module-transforms": "^7.16.7",
@ -1940,9 +1940,9 @@
} }
}, },
"node_modules/@babel/plugin-transform-named-capturing-groups-regex": { "node_modules/@babel/plugin-transform-named-capturing-groups-regex": {
"version": "7.16.7", "version": "7.16.8",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.16.7.tgz", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.16.8.tgz",
"integrity": "sha512-kFy35VwmwIQwCjwrAQhl3+c/kr292i4KdLPKp5lPH03Ltc51qnFlIADoyPxc/6Naz3ok3WdYKg+KK6AH+D4utg==", "integrity": "sha512-j3Jw+n5PvpmhRR+mrgIh04puSANCk/T/UA3m3P1MjJkhlK906+ApHhDIqBQDdOgL/r1UYpz4GNclTXxyZrYGSw==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@babel/helper-create-regexp-features-plugin": "^7.16.7" "@babel/helper-create-regexp-features-plugin": "^7.16.7"
@ -2321,19 +2321,19 @@
} }
}, },
"node_modules/@babel/traverse": { "node_modules/@babel/traverse": {
"version": "7.16.7", "version": "7.16.8",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.16.7.tgz", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.16.8.tgz",
"integrity": "sha512-8KWJPIb8c2VvY8AJrydh6+fVRo2ODx1wYBU2398xJVq0JomuLBZmVQzLPBblJgHIGYG4znCpUZUZ0Pt2vdmVYQ==", "integrity": "sha512-xe+H7JlvKsDQwXRsBhSnq1/+9c+LlQcCK3Tn/l5sbx02HYns/cn7ibp9+RV1sIUqu7hKg91NWsgHurO9dowITQ==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@babel/code-frame": "^7.16.7", "@babel/code-frame": "^7.16.7",
"@babel/generator": "^7.16.7", "@babel/generator": "^7.16.8",
"@babel/helper-environment-visitor": "^7.16.7", "@babel/helper-environment-visitor": "^7.16.7",
"@babel/helper-function-name": "^7.16.7", "@babel/helper-function-name": "^7.16.7",
"@babel/helper-hoist-variables": "^7.16.7", "@babel/helper-hoist-variables": "^7.16.7",
"@babel/helper-split-export-declaration": "^7.16.7", "@babel/helper-split-export-declaration": "^7.16.7",
"@babel/parser": "^7.16.7", "@babel/parser": "^7.16.8",
"@babel/types": "^7.16.7", "@babel/types": "^7.16.8",
"debug": "^4.1.0", "debug": "^4.1.0",
"globals": "^11.1.0" "globals": "^11.1.0"
}, },
@ -2342,12 +2342,12 @@
} }
}, },
"node_modules/@babel/traverse/node_modules/@babel/generator": { "node_modules/@babel/traverse/node_modules/@babel/generator": {
"version": "7.16.7", "version": "7.16.8",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.16.7.tgz", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.16.8.tgz",
"integrity": "sha512-/ST3Sg8MLGY5HVYmrjOgL60ENux/HfO/CsUh7y4MalThufhE/Ff/6EibFDHi4jiDCaWfJKoqbE6oTh21c5hrRg==", "integrity": "sha512-1ojZwE9+lOXzcWdWmO6TbUzDfqLD39CmEhN8+2cX9XkDo5yW1OpgfejfliysR2AWLpMamTiOiAp/mtroaymhpw==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@babel/types": "^7.16.7", "@babel/types": "^7.16.8",
"jsesc": "^2.5.1", "jsesc": "^2.5.1",
"source-map": "^0.5.0" "source-map": "^0.5.0"
}, },
@ -2365,9 +2365,9 @@
} }
}, },
"node_modules/@babel/types": { "node_modules/@babel/types": {
"version": "7.16.7", "version": "7.16.8",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.16.7.tgz", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.16.8.tgz",
"integrity": "sha512-E8HuV7FO9qLpx6OtoGfUQ2cjIYnbFwvZWYBS+87EwtdMvmUPJSwykpovFB+8insbpF0uJcpr8KMUi64XZntZcg==", "integrity": "sha512-smN2DQc5s4M7fntyjGtyIPbRJv6wW4rU/94fmYJ7PKQuZkC0qGMHXJbg6sNGt12JmVr4k5YaptI/XtiLJBnmIg==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@babel/helper-validator-identifier": "^7.16.7", "@babel/helper-validator-identifier": "^7.16.7",
@ -2763,9 +2763,9 @@
"dev": true "dev": true
}, },
"node_modules/@types/eslint": { "node_modules/@types/eslint": {
"version": "8.2.1", "version": "8.2.2",
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.2.1.tgz", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.2.2.tgz",
"integrity": "sha512-UP9rzNn/XyGwb5RQ2fok+DzcIRIYwc16qTXse5+Smsy8MOIccCChT15KAwnsgQx4PzJkaMq4myFyZ4CL5TjhIQ==", "integrity": "sha512-nQxgB8/Sg+QKhnV8e0WzPpxjIGT3tuJDDzybkDi8ItE/IgTlHo07U0shaIjzhcvQxlq9SDRE42lsJ23uvEgJ2A==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@types/estree": "*", "@types/estree": "*",
@ -2773,9 +2773,9 @@
} }
}, },
"node_modules/@types/eslint-scope": { "node_modules/@types/eslint-scope": {
"version": "3.7.2", "version": "3.7.3",
"resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.2.tgz", "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.3.tgz",
"integrity": "sha512-TzgYCWoPiTeRg6RQYgtuW7iODtVoKu3RVL72k3WohqhjfaOLK5Mg2T4Tg1o2bSfu0vPkoI48wdQFv5b/Xe04wQ==", "integrity": "sha512-PB3ldyrcnAicT35TWPs5IcwKD8S333HMaa2VVv4+wdvebJkjWuW/xESoB8IwRcog8HYVYamb1g/R31Qv5Bx03g==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@types/eslint": "*", "@types/eslint": "*",
@ -2804,9 +2804,9 @@
"dev": true "dev": true
}, },
"node_modules/@types/node": { "node_modules/@types/node": {
"version": "17.0.7", "version": "17.0.8",
"resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.7.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.8.tgz",
"integrity": "sha512-1QUk+WAUD4t8iR+Oj+UgI8oJa6yyxaB8a8pHaC8uqM6RrS1qbL7bf3Pwl5rHv0psm2CuDErgho6v5N+G+5fwtQ==", "integrity": "sha512-YofkM6fGv4gDJq78g4j0mMuGMkZVxZDgtU0JRdx6FgiJDG+0fY0GKVolOV8WqVmEhLCXkQRjwDdKyPxJp/uucg==",
"dev": true "dev": true
}, },
"node_modules/@types/parse-json": { "node_modules/@types/parse-json": {
@ -2822,14 +2822,14 @@
"dev": true "dev": true
}, },
"node_modules/@typescript-eslint/eslint-plugin": { "node_modules/@typescript-eslint/eslint-plugin": {
"version": "5.9.0", "version": "5.9.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.9.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.9.1.tgz",
"integrity": "sha512-qT4lr2jysDQBQOPsCCvpPUZHjbABoTJW8V9ZzIYKHMfppJtpdtzszDYsldwhFxlhvrp7aCHeXD1Lb9M1zhwWwQ==", "integrity": "sha512-Xv9tkFlyD4MQGpJgTo6wqDqGvHIRmRgah/2Sjz1PUnJTawjHWIwBivUE9x0QtU2WVii9baYgavo/bHjrZJkqTw==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@typescript-eslint/experimental-utils": "5.9.0", "@typescript-eslint/experimental-utils": "5.9.1",
"@typescript-eslint/scope-manager": "5.9.0", "@typescript-eslint/scope-manager": "5.9.1",
"@typescript-eslint/type-utils": "5.9.0", "@typescript-eslint/type-utils": "5.9.1",
"debug": "^4.3.2", "debug": "^4.3.2",
"functional-red-black-tree": "^1.0.1", "functional-red-black-tree": "^1.0.1",
"ignore": "^5.1.8", "ignore": "^5.1.8",
@ -2876,15 +2876,15 @@
} }
}, },
"node_modules/@typescript-eslint/experimental-utils": { "node_modules/@typescript-eslint/experimental-utils": {
"version": "5.9.0", "version": "5.9.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-5.9.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-5.9.1.tgz",
"integrity": "sha512-ZnLVjBrf26dn7ElyaSKa6uDhqwvAi4jBBmHK1VxuFGPRAxhdi18ubQYSGA7SRiFiES3q9JiBOBHEBStOFkwD2g==", "integrity": "sha512-cb1Njyss0mLL9kLXgS/eEY53SZQ9sT519wpX3i+U457l2UXRDuo87hgKfgRazmu9/tQb0x2sr3Y0yrU+Zz0y+w==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@types/json-schema": "^7.0.9", "@types/json-schema": "^7.0.9",
"@typescript-eslint/scope-manager": "5.9.0", "@typescript-eslint/scope-manager": "5.9.1",
"@typescript-eslint/types": "5.9.0", "@typescript-eslint/types": "5.9.1",
"@typescript-eslint/typescript-estree": "5.9.0", "@typescript-eslint/typescript-estree": "5.9.1",
"eslint-scope": "^5.1.1", "eslint-scope": "^5.1.1",
"eslint-utils": "^3.0.0" "eslint-utils": "^3.0.0"
}, },
@ -2900,14 +2900,14 @@
} }
}, },
"node_modules/@typescript-eslint/parser": { "node_modules/@typescript-eslint/parser": {
"version": "5.9.0", "version": "5.9.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.9.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.9.1.tgz",
"integrity": "sha512-/6pOPz8yAxEt4PLzgbFRDpZmHnXCeZgPDrh/1DaVKOjvn/UPMlWhbx/gA96xRi2JxY1kBl2AmwVbyROUqys5xQ==", "integrity": "sha512-PLYO0AmwD6s6n0ZQB5kqPgfvh73p0+VqopQQLuNfi7Lm0EpfKyDalchpVwkE+81k5HeiRrTV/9w1aNHzjD7C4g==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@typescript-eslint/scope-manager": "5.9.0", "@typescript-eslint/scope-manager": "5.9.1",
"@typescript-eslint/types": "5.9.0", "@typescript-eslint/types": "5.9.1",
"@typescript-eslint/typescript-estree": "5.9.0", "@typescript-eslint/typescript-estree": "5.9.1",
"debug": "^4.3.2" "debug": "^4.3.2"
}, },
"engines": { "engines": {
@ -2927,13 +2927,13 @@
} }
}, },
"node_modules/@typescript-eslint/scope-manager": { "node_modules/@typescript-eslint/scope-manager": {
"version": "5.9.0", "version": "5.9.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.9.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.9.1.tgz",
"integrity": "sha512-DKtdIL49Qxk2a8icF6whRk7uThuVz4A6TCXfjdJSwOsf+9ree7vgQWcx0KOyCdk0i9ETX666p4aMhrRhxhUkyg==", "integrity": "sha512-8BwvWkho3B/UOtzRyW07ffJXPaLSUKFBjpq8aqsRvu6HdEuzCY57+ffT7QoV4QXJXWSU1+7g3wE4AlgImmQ9pQ==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@typescript-eslint/types": "5.9.0", "@typescript-eslint/types": "5.9.1",
"@typescript-eslint/visitor-keys": "5.9.0" "@typescript-eslint/visitor-keys": "5.9.1"
}, },
"engines": { "engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0" "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
@ -2944,12 +2944,12 @@
} }
}, },
"node_modules/@typescript-eslint/type-utils": { "node_modules/@typescript-eslint/type-utils": {
"version": "5.9.0", "version": "5.9.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.9.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.9.1.tgz",
"integrity": "sha512-uVCb9dJXpBrK1071ri5aEW7ZHdDHAiqEjYznF3HSSvAJXyrkxGOw2Ejibz/q6BXdT8lea8CMI0CzKNFTNI6TEQ==", "integrity": "sha512-tRSpdBnPRssjlUh35rE9ug5HrUvaB9ntREy7gPXXKwmIx61TNN7+l5YKgi1hMKxo5NvqZCfYhA5FvyuJG6X6vg==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@typescript-eslint/experimental-utils": "5.9.0", "@typescript-eslint/experimental-utils": "5.9.1",
"debug": "^4.3.2", "debug": "^4.3.2",
"tsutils": "^3.21.0" "tsutils": "^3.21.0"
}, },
@ -2991,9 +2991,9 @@
} }
}, },
"node_modules/@typescript-eslint/types": { "node_modules/@typescript-eslint/types": {
"version": "5.9.0", "version": "5.9.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.9.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.9.1.tgz",
"integrity": "sha512-mWp6/b56Umo1rwyGCk8fPIzb9Migo8YOniBGPAQDNC6C52SeyNGN4gsVwQTAR+RS2L5xyajON4hOLwAGwPtUwg==", "integrity": "sha512-SsWegWudWpkZCwwYcKoDwuAjoZXnM1y2EbEerTHho19Hmm+bQ56QG4L4jrtCu0bI5STaRTvRTZmjprWlTw/5NQ==",
"dev": true, "dev": true,
"engines": { "engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0" "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
@ -3004,13 +3004,13 @@
} }
}, },
"node_modules/@typescript-eslint/typescript-estree": { "node_modules/@typescript-eslint/typescript-estree": {
"version": "5.9.0", "version": "5.9.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.9.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.9.1.tgz",
"integrity": "sha512-kxo3xL2mB7XmiVZcECbaDwYCt3qFXz99tBSuVJR4L/sR7CJ+UNAPrYILILktGj1ppfZ/jNt/cWYbziJUlHl1Pw==", "integrity": "sha512-gL1sP6A/KG0HwrahVXI9fZyeVTxEYV//6PmcOn1tD0rw8VhUWYeZeuWHwwhnewnvEMcHjhnJLOBhA9rK4vmb8A==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@typescript-eslint/types": "5.9.0", "@typescript-eslint/types": "5.9.1",
"@typescript-eslint/visitor-keys": "5.9.0", "@typescript-eslint/visitor-keys": "5.9.1",
"debug": "^4.3.2", "debug": "^4.3.2",
"globby": "^11.0.4", "globby": "^11.0.4",
"is-glob": "^4.0.3", "is-glob": "^4.0.3",
@ -3052,12 +3052,12 @@
} }
}, },
"node_modules/@typescript-eslint/visitor-keys": { "node_modules/@typescript-eslint/visitor-keys": {
"version": "5.9.0", "version": "5.9.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.9.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.9.1.tgz",
"integrity": "sha512-6zq0mb7LV0ThExKlecvpfepiB+XEtFv/bzx7/jKSgyXTFD7qjmSu1FoiS0x3OZaiS+UIXpH2vd9O89f02RCtgw==", "integrity": "sha512-Xh37pNz9e9ryW4TVdwiFzmr4hloty8cFj8GTWMXh3Z8swGwyQWeCcNgF0hm6t09iZd6eiZmIf4zHedQVP6TVtg==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@typescript-eslint/types": "5.9.0", "@typescript-eslint/types": "5.9.1",
"eslint-visitor-keys": "^3.0.0" "eslint-visitor-keys": "^3.0.0"
}, },
"engines": { "engines": {
@ -4169,9 +4169,9 @@
} }
}, },
"node_modules/caniuse-lite": { "node_modules/caniuse-lite": {
"version": "1.0.30001296", "version": "1.0.30001298",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001296.tgz", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001298.tgz",
"integrity": "sha512-WfrtPEoNSoeATDlf4y3QvkwiELl9GyPLISV5GejTbbQRtQx4LhsXmc9IQ6XCL2d7UxCyEzToEZNMeqR79OUw8Q==", "integrity": "sha512-AcKqikjMLlvghZL/vfTHorlQsLDhGRalYf1+GmWCf5SCMziSGjRYQW/JEksj14NaYHIR6KIhrFAy0HV5C25UzQ==",
"dev": true, "dev": true,
"funding": { "funding": {
"type": "opencollective", "type": "opencollective",
@ -5435,9 +5435,9 @@
"dev": true "dev": true
}, },
"node_modules/electron-to-chromium": { "node_modules/electron-to-chromium": {
"version": "1.4.34", "version": "1.4.40",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.34.tgz", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.40.tgz",
"integrity": "sha512-B7g6Y9No9XMYk1VNrQ8KAmSEo1Iltrz/5EjOGxl1DffQAb3z/XbpHRCfYKwV8D+CPXm4Q7Xg1sceSt9osNwRIA==", "integrity": "sha512-j+eVIyQGt2EU5xPWUblhpp5P5z5xyAdRgzogBgfe2F5JGV17gr9pfzWBua6DlPL00LavbOjxubWkWkbVQe9Wlw==",
"dev": true "dev": true
}, },
"node_modules/emoji-regex": { "node_modules/emoji-regex": {
@ -6420,9 +6420,9 @@
"dev": true "dev": true
}, },
"node_modules/fast-glob": { "node_modules/fast-glob": {
"version": "3.2.7", "version": "3.2.10",
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.10.tgz",
"integrity": "sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==", "integrity": "sha512-s9nFhFnvR63wls6/kM88kQqDhMu0AfdjqouE2l5GVQPbqLgyFjjU5ry/r2yKsJxpb9Py1EYNqieFrmMaX4v++A==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.stat": "^2.0.2",
@ -6432,7 +6432,7 @@
"micromatch": "^4.0.4" "micromatch": "^4.0.4"
}, },
"engines": { "engines": {
"node": ">=8" "node": ">=8.6.0"
} }
}, },
"node_modules/fast-json-stable-stringify": { "node_modules/fast-json-stable-stringify": {
@ -6609,9 +6609,9 @@
"dev": true "dev": true
}, },
"node_modules/follow-redirects": { "node_modules/follow-redirects": {
"version": "1.14.6", "version": "1.14.7",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.6.tgz", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.7.tgz",
"integrity": "sha512-fhUl5EwSJbbl8AR+uYL2KQDxLkdSjZGR36xy46AO7cOMTrCMON6Sa28FmAnC2tRTDbd/Uuzz3aJBv7EBN7JH8A==", "integrity": "sha512-+hbxoLbFMbRKDwohX8GkTataGqO6Jb7jGwpAlwgy2bIz25XtRm7KEzJM76R1WiNT5SwZkX4Y75SwBolkpmE7iQ==",
"dev": true, "dev": true,
"funding": [ "funding": [
{ {
@ -6853,16 +6853,16 @@
} }
}, },
"node_modules/globby": { "node_modules/globby": {
"version": "11.0.4", "version": "11.1.0",
"resolved": "https://registry.npmjs.org/globby/-/globby-11.0.4.tgz", "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
"integrity": "sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==", "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"array-union": "^2.1.0", "array-union": "^2.1.0",
"dir-glob": "^3.0.1", "dir-glob": "^3.0.1",
"fast-glob": "^3.1.1", "fast-glob": "^3.2.9",
"ignore": "^5.1.4", "ignore": "^5.2.0",
"merge2": "^1.3.0", "merge2": "^1.4.1",
"slash": "^3.0.0" "slash": "^3.0.0"
}, },
"engines": { "engines": {
@ -6895,9 +6895,9 @@
} }
}, },
"node_modules/graceful-fs": { "node_modules/graceful-fs": {
"version": "4.2.8", "version": "4.2.9",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz",
"integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==",
"dev": true "dev": true
}, },
"node_modules/handle-thing": { "node_modules/handle-thing": {
@ -6987,9 +6987,9 @@
"dev": true "dev": true
}, },
"node_modules/hosted-git-info": { "node_modules/hosted-git-info": {
"version": "4.0.2", "version": "4.1.0",
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.0.2.tgz", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz",
"integrity": "sha512-c9OGXbZ3guC/xOlCg1Ci/VgWlwsqDv1yMQL1CWqXDL0hDjXuNcq0zuR4xqPSuasI3kqFDhqSyTjREz5gzq0fXg==", "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"lru-cache": "^6.0.0" "lru-cache": "^6.0.0"
@ -7479,9 +7479,9 @@
} }
}, },
"node_modules/is-core-module": { "node_modules/is-core-module": {
"version": "2.8.0", "version": "2.8.1",
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz",
"integrity": "sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw==", "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"has": "^1.0.3" "has": "^1.0.3"
@ -7779,9 +7779,9 @@
} }
}, },
"node_modules/jest-worker": { "node_modules/jest-worker": {
"version": "27.4.5", "version": "27.4.6",
"resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.4.5.tgz", "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.4.6.tgz",
"integrity": "sha512-f2s8kEdy15cv9r7q4KkzGXvlY0JTcmCbMHZBfSQDwW77REr45IDWwd0lksDFeVHH2jJ5pqb90T77XscrjeGzzg==", "integrity": "sha512-gHWJF/6Xi5CTG5QCvROr6GcmpIqNYpDJyc8A1h/DyXqH1tD6SnRCM0d3U5msV31D2LB/U+E0M+W4oyvKV44oNw==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@types/node": "*", "@types/node": "*",
@ -8716,9 +8716,9 @@
"dev": true "dev": true
}, },
"node_modules/nanoid": { "node_modules/nanoid": {
"version": "3.1.30", "version": "3.1.31",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.30.tgz", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.31.tgz",
"integrity": "sha512-zJpuPDwOv8D2zq2WRoMe1HsfZthVewpel9CAvTfc/2mBD1uUT/agc5f7GHGWXlYkFvi1mVxe4IjvP2HNrop7nQ==", "integrity": "sha512-ZivnJm0o9bb13p2Ot5CpgC2rQdzB9Uxm/mFZweqm5eMViqOJe3PV6LU2E30SiLgheesmcPrjquqraoolONSA0A==",
"dev": true, "dev": true,
"bin": { "bin": {
"nanoid": "bin/nanoid.cjs" "nanoid": "bin/nanoid.cjs"
@ -12227,9 +12227,9 @@
"dev": true "dev": true
}, },
"node_modules/selfsigned": { "node_modules/selfsigned": {
"version": "1.10.11", "version": "1.10.14",
"resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.11.tgz", "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.14.tgz",
"integrity": "sha512-aVmbPOfViZqOZPgRBT0+3u4yZFHpmnIghLMlAcb5/xhp5ZtB/RVnKhz5vl2M32CLXAqR4kha9zfhNg0Lf/sxKA==", "integrity": "sha512-lkjaiAye+wBZDCBsu5BGi0XiLRxeUlsGod5ZP924CRSEoGuZAw/f7y9RKu28rwTfiHVhdavhB0qH0INV6P1lEA==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"node-forge": "^0.10.0" "node-forge": "^0.10.0"
@ -12585,6 +12585,7 @@
"version": "0.6.0", "version": "0.6.0",
"resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.6.0.tgz", "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.6.0.tgz",
"integrity": "sha512-KXBr9d/fO/bWo97NXsPIAW1bFSBOuCnjbNTBMO7N59hsv5i9yzRDfcYwwt0l04+VqnKC+EwzvJZIP/qkuMgR/w==", "integrity": "sha512-KXBr9d/fO/bWo97NXsPIAW1bFSBOuCnjbNTBMO7N59hsv5i9yzRDfcYwwt0l04+VqnKC+EwzvJZIP/qkuMgR/w==",
"deprecated": "See https://github.com/lydell/source-map-resolve#deprecated",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"atob": "^2.1.2", "atob": "^2.1.2",
@ -14401,9 +14402,9 @@
} }
}, },
"@babel/compat-data": { "@babel/compat-data": {
"version": "7.16.4", "version": "7.16.8",
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.16.4.tgz", "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.16.8.tgz",
"integrity": "sha512-1o/jo7D+kC9ZjHX5v+EHrdjl3PhxMrLSOTGsOdHJ+KL8HCaEK6ehrVL2RS6oHDZp+L7xLirLrPmQtEng769J/Q==", "integrity": "sha512-m7OkX0IdKLKPpBlJtF561YJal5y/jyI5fNfWbPxh2D/nbzzGI4qRyrD8xO2jB24u7l+5I2a43scCG2IrfjC50Q==",
"dev": true "dev": true
}, },
"@babel/core": { "@babel/core": {
@ -14695,14 +14696,14 @@
"dev": true "dev": true
}, },
"@babel/helper-remap-async-to-generator": { "@babel/helper-remap-async-to-generator": {
"version": "7.16.7", "version": "7.16.8",
"resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.7.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.8.tgz",
"integrity": "sha512-C3o117GnP/j/N2OWo+oepeWbFEKRfNaay+F1Eo5Mj3A1SRjyx+qaFhm23nlipub7Cjv2azdUUiDH+VlpdwUFRg==", "integrity": "sha512-fm0gH7Flb8H51LqJHy3HJ3wnE1+qtYR2A99K06ahwrawLdOFsCEWjZOrYricXJHoPSudNKxrMBUPEIPxiIIvBw==",
"dev": true, "dev": true,
"requires": { "requires": {
"@babel/helper-annotate-as-pure": "^7.16.7", "@babel/helper-annotate-as-pure": "^7.16.7",
"@babel/helper-wrap-function": "^7.16.7", "@babel/helper-wrap-function": "^7.16.8",
"@babel/types": "^7.16.7" "@babel/types": "^7.16.8"
}, },
"dependencies": { "dependencies": {
"@babel/helper-annotate-as-pure": { "@babel/helper-annotate-as-pure": {
@ -14769,15 +14770,15 @@
"dev": true "dev": true
}, },
"@babel/helper-wrap-function": { "@babel/helper-wrap-function": {
"version": "7.16.7", "version": "7.16.8",
"resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.16.7.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.16.8.tgz",
"integrity": "sha512-7a9sABeVwcunnztZZ7WTgSw6jVYLzM1wua0Z4HIXm9S3/HC96WKQTkFgGEaj5W06SHHihPJ6Le6HzS5cGOQMNw==", "integrity": "sha512-8RpyRVIAW1RcDDGTA+GpPAwV22wXCfKOoM9bet6TLkGIFTkRQSkH1nMQ5Yet4MpoXe1ZwHPVtNasc2w0uZMqnw==",
"dev": true, "dev": true,
"requires": { "requires": {
"@babel/helper-function-name": "^7.16.7", "@babel/helper-function-name": "^7.16.7",
"@babel/template": "^7.16.7", "@babel/template": "^7.16.7",
"@babel/traverse": "^7.16.7", "@babel/traverse": "^7.16.8",
"@babel/types": "^7.16.7" "@babel/types": "^7.16.8"
}, },
"dependencies": { "dependencies": {
"@babel/template": { "@babel/template": {
@ -14829,9 +14830,9 @@
} }
}, },
"@babel/parser": { "@babel/parser": {
"version": "7.16.7", "version": "7.16.8",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.7.tgz", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.8.tgz",
"integrity": "sha512-sR4eaSrnM7BV7QPzGfEX5paG/6wrZM3I0HDzfIAK06ESvo9oy3xBuVBxE3MbQaKNhvg8g/ixjMWo2CGpzpHsDA==", "integrity": "sha512-i7jDUfrVBWc+7OKcBzEe5n7fbv3i2fWtxKzzCvOjnzSxMfWMigAhtfJ7qzZNGFNMsCCd67+uz553dYKWXPvCKw==",
"dev": true "dev": true
}, },
"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": {
@ -15311,9 +15312,9 @@
} }
}, },
"@babel/plugin-transform-modules-commonjs": { "@babel/plugin-transform-modules-commonjs": {
"version": "7.16.7", "version": "7.16.8",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.16.7.tgz", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.16.8.tgz",
"integrity": "sha512-h2RP2kE7He1ZWKyAlanMZrAbdv+Acw1pA8dQZhE025WJZE2z0xzFADAinXA9fxd5bn7JnM+SdOGcndGx1ARs9w==", "integrity": "sha512-oflKPvsLT2+uKQopesJt3ApiaIS2HW+hzHFcwRNtyDGieAeC/dIHZX8buJQ2J2X1rxGPy4eRcUijm3qcSPjYcA==",
"dev": true, "dev": true,
"requires": { "requires": {
"@babel/helper-module-transforms": "^7.16.7", "@babel/helper-module-transforms": "^7.16.7",
@ -15346,9 +15347,9 @@
} }
}, },
"@babel/plugin-transform-named-capturing-groups-regex": { "@babel/plugin-transform-named-capturing-groups-regex": {
"version": "7.16.7", "version": "7.16.8",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.16.7.tgz", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.16.8.tgz",
"integrity": "sha512-kFy35VwmwIQwCjwrAQhl3+c/kr292i4KdLPKp5lPH03Ltc51qnFlIADoyPxc/6Naz3ok3WdYKg+KK6AH+D4utg==", "integrity": "sha512-j3Jw+n5PvpmhRR+mrgIh04puSANCk/T/UA3m3P1MjJkhlK906+ApHhDIqBQDdOgL/r1UYpz4GNclTXxyZrYGSw==",
"dev": true, "dev": true,
"requires": { "requires": {
"@babel/helper-create-regexp-features-plugin": "^7.16.7" "@babel/helper-create-regexp-features-plugin": "^7.16.7"
@ -15620,30 +15621,30 @@
} }
}, },
"@babel/traverse": { "@babel/traverse": {
"version": "7.16.7", "version": "7.16.8",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.16.7.tgz", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.16.8.tgz",
"integrity": "sha512-8KWJPIb8c2VvY8AJrydh6+fVRo2ODx1wYBU2398xJVq0JomuLBZmVQzLPBblJgHIGYG4znCpUZUZ0Pt2vdmVYQ==", "integrity": "sha512-xe+H7JlvKsDQwXRsBhSnq1/+9c+LlQcCK3Tn/l5sbx02HYns/cn7ibp9+RV1sIUqu7hKg91NWsgHurO9dowITQ==",
"dev": true, "dev": true,
"requires": { "requires": {
"@babel/code-frame": "^7.16.7", "@babel/code-frame": "^7.16.7",
"@babel/generator": "^7.16.7", "@babel/generator": "^7.16.8",
"@babel/helper-environment-visitor": "^7.16.7", "@babel/helper-environment-visitor": "^7.16.7",
"@babel/helper-function-name": "^7.16.7", "@babel/helper-function-name": "^7.16.7",
"@babel/helper-hoist-variables": "^7.16.7", "@babel/helper-hoist-variables": "^7.16.7",
"@babel/helper-split-export-declaration": "^7.16.7", "@babel/helper-split-export-declaration": "^7.16.7",
"@babel/parser": "^7.16.7", "@babel/parser": "^7.16.8",
"@babel/types": "^7.16.7", "@babel/types": "^7.16.8",
"debug": "^4.1.0", "debug": "^4.1.0",
"globals": "^11.1.0" "globals": "^11.1.0"
}, },
"dependencies": { "dependencies": {
"@babel/generator": { "@babel/generator": {
"version": "7.16.7", "version": "7.16.8",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.16.7.tgz", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.16.8.tgz",
"integrity": "sha512-/ST3Sg8MLGY5HVYmrjOgL60ENux/HfO/CsUh7y4MalThufhE/Ff/6EibFDHi4jiDCaWfJKoqbE6oTh21c5hrRg==", "integrity": "sha512-1ojZwE9+lOXzcWdWmO6TbUzDfqLD39CmEhN8+2cX9XkDo5yW1OpgfejfliysR2AWLpMamTiOiAp/mtroaymhpw==",
"dev": true, "dev": true,
"requires": { "requires": {
"@babel/types": "^7.16.7", "@babel/types": "^7.16.8",
"jsesc": "^2.5.1", "jsesc": "^2.5.1",
"source-map": "^0.5.0" "source-map": "^0.5.0"
} }
@ -15657,9 +15658,9 @@
} }
}, },
"@babel/types": { "@babel/types": {
"version": "7.16.7", "version": "7.16.8",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.16.7.tgz", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.16.8.tgz",
"integrity": "sha512-E8HuV7FO9qLpx6OtoGfUQ2cjIYnbFwvZWYBS+87EwtdMvmUPJSwykpovFB+8insbpF0uJcpr8KMUi64XZntZcg==", "integrity": "sha512-smN2DQc5s4M7fntyjGtyIPbRJv6wW4rU/94fmYJ7PKQuZkC0qGMHXJbg6sNGt12JmVr4k5YaptI/XtiLJBnmIg==",
"dev": true, "dev": true,
"requires": { "requires": {
"@babel/helper-validator-identifier": "^7.16.7", "@babel/helper-validator-identifier": "^7.16.7",
@ -15970,9 +15971,9 @@
"dev": true "dev": true
}, },
"@types/eslint": { "@types/eslint": {
"version": "8.2.1", "version": "8.2.2",
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.2.1.tgz", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.2.2.tgz",
"integrity": "sha512-UP9rzNn/XyGwb5RQ2fok+DzcIRIYwc16qTXse5+Smsy8MOIccCChT15KAwnsgQx4PzJkaMq4myFyZ4CL5TjhIQ==", "integrity": "sha512-nQxgB8/Sg+QKhnV8e0WzPpxjIGT3tuJDDzybkDi8ItE/IgTlHo07U0shaIjzhcvQxlq9SDRE42lsJ23uvEgJ2A==",
"dev": true, "dev": true,
"requires": { "requires": {
"@types/estree": "*", "@types/estree": "*",
@ -15980,9 +15981,9 @@
} }
}, },
"@types/eslint-scope": { "@types/eslint-scope": {
"version": "3.7.2", "version": "3.7.3",
"resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.2.tgz", "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.3.tgz",
"integrity": "sha512-TzgYCWoPiTeRg6RQYgtuW7iODtVoKu3RVL72k3WohqhjfaOLK5Mg2T4Tg1o2bSfu0vPkoI48wdQFv5b/Xe04wQ==", "integrity": "sha512-PB3ldyrcnAicT35TWPs5IcwKD8S333HMaa2VVv4+wdvebJkjWuW/xESoB8IwRcog8HYVYamb1g/R31Qv5Bx03g==",
"dev": true, "dev": true,
"requires": { "requires": {
"@types/eslint": "*", "@types/eslint": "*",
@ -16011,9 +16012,9 @@
"dev": true "dev": true
}, },
"@types/node": { "@types/node": {
"version": "17.0.7", "version": "17.0.8",
"resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.7.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.8.tgz",
"integrity": "sha512-1QUk+WAUD4t8iR+Oj+UgI8oJa6yyxaB8a8pHaC8uqM6RrS1qbL7bf3Pwl5rHv0psm2CuDErgho6v5N+G+5fwtQ==", "integrity": "sha512-YofkM6fGv4gDJq78g4j0mMuGMkZVxZDgtU0JRdx6FgiJDG+0fY0GKVolOV8WqVmEhLCXkQRjwDdKyPxJp/uucg==",
"dev": true "dev": true
}, },
"@types/parse-json": { "@types/parse-json": {
@ -16029,14 +16030,14 @@
"dev": true "dev": true
}, },
"@typescript-eslint/eslint-plugin": { "@typescript-eslint/eslint-plugin": {
"version": "5.9.0", "version": "5.9.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.9.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.9.1.tgz",
"integrity": "sha512-qT4lr2jysDQBQOPsCCvpPUZHjbABoTJW8V9ZzIYKHMfppJtpdtzszDYsldwhFxlhvrp7aCHeXD1Lb9M1zhwWwQ==", "integrity": "sha512-Xv9tkFlyD4MQGpJgTo6wqDqGvHIRmRgah/2Sjz1PUnJTawjHWIwBivUE9x0QtU2WVii9baYgavo/bHjrZJkqTw==",
"dev": true, "dev": true,
"requires": { "requires": {
"@typescript-eslint/experimental-utils": "5.9.0", "@typescript-eslint/experimental-utils": "5.9.1",
"@typescript-eslint/scope-manager": "5.9.0", "@typescript-eslint/scope-manager": "5.9.1",
"@typescript-eslint/type-utils": "5.9.0", "@typescript-eslint/type-utils": "5.9.1",
"debug": "^4.3.2", "debug": "^4.3.2",
"functional-red-black-tree": "^1.0.1", "functional-red-black-tree": "^1.0.1",
"ignore": "^5.1.8", "ignore": "^5.1.8",
@ -16063,48 +16064,48 @@
} }
}, },
"@typescript-eslint/experimental-utils": { "@typescript-eslint/experimental-utils": {
"version": "5.9.0", "version": "5.9.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-5.9.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-5.9.1.tgz",
"integrity": "sha512-ZnLVjBrf26dn7ElyaSKa6uDhqwvAi4jBBmHK1VxuFGPRAxhdi18ubQYSGA7SRiFiES3q9JiBOBHEBStOFkwD2g==", "integrity": "sha512-cb1Njyss0mLL9kLXgS/eEY53SZQ9sT519wpX3i+U457l2UXRDuo87hgKfgRazmu9/tQb0x2sr3Y0yrU+Zz0y+w==",
"dev": true, "dev": true,
"requires": { "requires": {
"@types/json-schema": "^7.0.9", "@types/json-schema": "^7.0.9",
"@typescript-eslint/scope-manager": "5.9.0", "@typescript-eslint/scope-manager": "5.9.1",
"@typescript-eslint/types": "5.9.0", "@typescript-eslint/types": "5.9.1",
"@typescript-eslint/typescript-estree": "5.9.0", "@typescript-eslint/typescript-estree": "5.9.1",
"eslint-scope": "^5.1.1", "eslint-scope": "^5.1.1",
"eslint-utils": "^3.0.0" "eslint-utils": "^3.0.0"
} }
}, },
"@typescript-eslint/parser": { "@typescript-eslint/parser": {
"version": "5.9.0", "version": "5.9.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.9.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.9.1.tgz",
"integrity": "sha512-/6pOPz8yAxEt4PLzgbFRDpZmHnXCeZgPDrh/1DaVKOjvn/UPMlWhbx/gA96xRi2JxY1kBl2AmwVbyROUqys5xQ==", "integrity": "sha512-PLYO0AmwD6s6n0ZQB5kqPgfvh73p0+VqopQQLuNfi7Lm0EpfKyDalchpVwkE+81k5HeiRrTV/9w1aNHzjD7C4g==",
"dev": true, "dev": true,
"requires": { "requires": {
"@typescript-eslint/scope-manager": "5.9.0", "@typescript-eslint/scope-manager": "5.9.1",
"@typescript-eslint/types": "5.9.0", "@typescript-eslint/types": "5.9.1",
"@typescript-eslint/typescript-estree": "5.9.0", "@typescript-eslint/typescript-estree": "5.9.1",
"debug": "^4.3.2" "debug": "^4.3.2"
} }
}, },
"@typescript-eslint/scope-manager": { "@typescript-eslint/scope-manager": {
"version": "5.9.0", "version": "5.9.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.9.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.9.1.tgz",
"integrity": "sha512-DKtdIL49Qxk2a8icF6whRk7uThuVz4A6TCXfjdJSwOsf+9ree7vgQWcx0KOyCdk0i9ETX666p4aMhrRhxhUkyg==", "integrity": "sha512-8BwvWkho3B/UOtzRyW07ffJXPaLSUKFBjpq8aqsRvu6HdEuzCY57+ffT7QoV4QXJXWSU1+7g3wE4AlgImmQ9pQ==",
"dev": true, "dev": true,
"requires": { "requires": {
"@typescript-eslint/types": "5.9.0", "@typescript-eslint/types": "5.9.1",
"@typescript-eslint/visitor-keys": "5.9.0" "@typescript-eslint/visitor-keys": "5.9.1"
} }
}, },
"@typescript-eslint/type-utils": { "@typescript-eslint/type-utils": {
"version": "5.9.0", "version": "5.9.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.9.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.9.1.tgz",
"integrity": "sha512-uVCb9dJXpBrK1071ri5aEW7ZHdDHAiqEjYznF3HSSvAJXyrkxGOw2Ejibz/q6BXdT8lea8CMI0CzKNFTNI6TEQ==", "integrity": "sha512-tRSpdBnPRssjlUh35rE9ug5HrUvaB9ntREy7gPXXKwmIx61TNN7+l5YKgi1hMKxo5NvqZCfYhA5FvyuJG6X6vg==",
"dev": true, "dev": true,
"requires": { "requires": {
"@typescript-eslint/experimental-utils": "5.9.0", "@typescript-eslint/experimental-utils": "5.9.1",
"debug": "^4.3.2", "debug": "^4.3.2",
"tsutils": "^3.21.0" "tsutils": "^3.21.0"
}, },
@ -16127,19 +16128,19 @@
} }
}, },
"@typescript-eslint/types": { "@typescript-eslint/types": {
"version": "5.9.0", "version": "5.9.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.9.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.9.1.tgz",
"integrity": "sha512-mWp6/b56Umo1rwyGCk8fPIzb9Migo8YOniBGPAQDNC6C52SeyNGN4gsVwQTAR+RS2L5xyajON4hOLwAGwPtUwg==", "integrity": "sha512-SsWegWudWpkZCwwYcKoDwuAjoZXnM1y2EbEerTHho19Hmm+bQ56QG4L4jrtCu0bI5STaRTvRTZmjprWlTw/5NQ==",
"dev": true "dev": true
}, },
"@typescript-eslint/typescript-estree": { "@typescript-eslint/typescript-estree": {
"version": "5.9.0", "version": "5.9.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.9.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.9.1.tgz",
"integrity": "sha512-kxo3xL2mB7XmiVZcECbaDwYCt3qFXz99tBSuVJR4L/sR7CJ+UNAPrYILILktGj1ppfZ/jNt/cWYbziJUlHl1Pw==", "integrity": "sha512-gL1sP6A/KG0HwrahVXI9fZyeVTxEYV//6PmcOn1tD0rw8VhUWYeZeuWHwwhnewnvEMcHjhnJLOBhA9rK4vmb8A==",
"dev": true, "dev": true,
"requires": { "requires": {
"@typescript-eslint/types": "5.9.0", "@typescript-eslint/types": "5.9.1",
"@typescript-eslint/visitor-keys": "5.9.0", "@typescript-eslint/visitor-keys": "5.9.1",
"debug": "^4.3.2", "debug": "^4.3.2",
"globby": "^11.0.4", "globby": "^11.0.4",
"is-glob": "^4.0.3", "is-glob": "^4.0.3",
@ -16165,12 +16166,12 @@
} }
}, },
"@typescript-eslint/visitor-keys": { "@typescript-eslint/visitor-keys": {
"version": "5.9.0", "version": "5.9.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.9.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.9.1.tgz",
"integrity": "sha512-6zq0mb7LV0ThExKlecvpfepiB+XEtFv/bzx7/jKSgyXTFD7qjmSu1FoiS0x3OZaiS+UIXpH2vd9O89f02RCtgw==", "integrity": "sha512-Xh37pNz9e9ryW4TVdwiFzmr4hloty8cFj8GTWMXh3Z8swGwyQWeCcNgF0hm6t09iZd6eiZmIf4zHedQVP6TVtg==",
"dev": true, "dev": true,
"requires": { "requires": {
"@typescript-eslint/types": "5.9.0", "@typescript-eslint/types": "5.9.1",
"eslint-visitor-keys": "^3.0.0" "eslint-visitor-keys": "^3.0.0"
} }
}, },
@ -17043,9 +17044,9 @@
"dev": true "dev": true
}, },
"caniuse-lite": { "caniuse-lite": {
"version": "1.0.30001296", "version": "1.0.30001298",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001296.tgz", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001298.tgz",
"integrity": "sha512-WfrtPEoNSoeATDlf4y3QvkwiELl9GyPLISV5GejTbbQRtQx4LhsXmc9IQ6XCL2d7UxCyEzToEZNMeqR79OUw8Q==", "integrity": "sha512-AcKqikjMLlvghZL/vfTHorlQsLDhGRalYf1+GmWCf5SCMziSGjRYQW/JEksj14NaYHIR6KIhrFAy0HV5C25UzQ==",
"dev": true "dev": true
}, },
"canonical-path": { "canonical-path": {
@ -17994,9 +17995,9 @@
"dev": true "dev": true
}, },
"electron-to-chromium": { "electron-to-chromium": {
"version": "1.4.34", "version": "1.4.40",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.34.tgz", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.40.tgz",
"integrity": "sha512-B7g6Y9No9XMYk1VNrQ8KAmSEo1Iltrz/5EjOGxl1DffQAb3z/XbpHRCfYKwV8D+CPXm4Q7Xg1sceSt9osNwRIA==", "integrity": "sha512-j+eVIyQGt2EU5xPWUblhpp5P5z5xyAdRgzogBgfe2F5JGV17gr9pfzWBua6DlPL00LavbOjxubWkWkbVQe9Wlw==",
"dev": true "dev": true
}, },
"emoji-regex": { "emoji-regex": {
@ -18697,9 +18698,9 @@
"dev": true "dev": true
}, },
"fast-glob": { "fast-glob": {
"version": "3.2.7", "version": "3.2.10",
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.10.tgz",
"integrity": "sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==", "integrity": "sha512-s9nFhFnvR63wls6/kM88kQqDhMu0AfdjqouE2l5GVQPbqLgyFjjU5ry/r2yKsJxpb9Py1EYNqieFrmMaX4v++A==",
"dev": true, "dev": true,
"requires": { "requires": {
"@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.stat": "^2.0.2",
@ -18854,9 +18855,9 @@
"dev": true "dev": true
}, },
"follow-redirects": { "follow-redirects": {
"version": "1.14.6", "version": "1.14.7",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.6.tgz", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.7.tgz",
"integrity": "sha512-fhUl5EwSJbbl8AR+uYL2KQDxLkdSjZGR36xy46AO7cOMTrCMON6Sa28FmAnC2tRTDbd/Uuzz3aJBv7EBN7JH8A==", "integrity": "sha512-+hbxoLbFMbRKDwohX8GkTataGqO6Jb7jGwpAlwgy2bIz25XtRm7KEzJM76R1WiNT5SwZkX4Y75SwBolkpmE7iQ==",
"dev": true "dev": true
}, },
"forwarded": { "forwarded": {
@ -19023,16 +19024,16 @@
"dev": true "dev": true
}, },
"globby": { "globby": {
"version": "11.0.4", "version": "11.1.0",
"resolved": "https://registry.npmjs.org/globby/-/globby-11.0.4.tgz", "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
"integrity": "sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==", "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
"dev": true, "dev": true,
"requires": { "requires": {
"array-union": "^2.1.0", "array-union": "^2.1.0",
"dir-glob": "^3.0.1", "dir-glob": "^3.0.1",
"fast-glob": "^3.1.1", "fast-glob": "^3.2.9",
"ignore": "^5.1.4", "ignore": "^5.2.0",
"merge2": "^1.3.0", "merge2": "^1.4.1",
"slash": "^3.0.0" "slash": "^3.0.0"
} }
}, },
@ -19056,9 +19057,9 @@
} }
}, },
"graceful-fs": { "graceful-fs": {
"version": "4.2.8", "version": "4.2.9",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz",
"integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==",
"dev": true "dev": true
}, },
"handle-thing": { "handle-thing": {
@ -19127,9 +19128,9 @@
"dev": true "dev": true
}, },
"hosted-git-info": { "hosted-git-info": {
"version": "4.0.2", "version": "4.1.0",
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.0.2.tgz", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz",
"integrity": "sha512-c9OGXbZ3guC/xOlCg1Ci/VgWlwsqDv1yMQL1CWqXDL0hDjXuNcq0zuR4xqPSuasI3kqFDhqSyTjREz5gzq0fXg==", "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==",
"dev": true, "dev": true,
"requires": { "requires": {
"lru-cache": "^6.0.0" "lru-cache": "^6.0.0"
@ -19510,9 +19511,9 @@
} }
}, },
"is-core-module": { "is-core-module": {
"version": "2.8.0", "version": "2.8.1",
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz",
"integrity": "sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw==", "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==",
"dev": true, "dev": true,
"requires": { "requires": {
"has": "^1.0.3" "has": "^1.0.3"
@ -19716,9 +19717,9 @@
} }
}, },
"jest-worker": { "jest-worker": {
"version": "27.4.5", "version": "27.4.6",
"resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.4.5.tgz", "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.4.6.tgz",
"integrity": "sha512-f2s8kEdy15cv9r7q4KkzGXvlY0JTcmCbMHZBfSQDwW77REr45IDWwd0lksDFeVHH2jJ5pqb90T77XscrjeGzzg==", "integrity": "sha512-gHWJF/6Xi5CTG5QCvROr6GcmpIqNYpDJyc8A1h/DyXqH1tD6SnRCM0d3U5msV31D2LB/U+E0M+W4oyvKV44oNw==",
"dev": true, "dev": true,
"requires": { "requires": {
"@types/node": "*", "@types/node": "*",
@ -20430,9 +20431,9 @@
"dev": true "dev": true
}, },
"nanoid": { "nanoid": {
"version": "3.1.30", "version": "3.1.31",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.30.tgz", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.31.tgz",
"integrity": "sha512-zJpuPDwOv8D2zq2WRoMe1HsfZthVewpel9CAvTfc/2mBD1uUT/agc5f7GHGWXlYkFvi1mVxe4IjvP2HNrop7nQ==", "integrity": "sha512-ZivnJm0o9bb13p2Ot5CpgC2rQdzB9Uxm/mFZweqm5eMViqOJe3PV6LU2E30SiLgheesmcPrjquqraoolONSA0A==",
"dev": true "dev": true
}, },
"natural-compare": { "natural-compare": {
@ -23071,9 +23072,9 @@
"dev": true "dev": true
}, },
"selfsigned": { "selfsigned": {
"version": "1.10.11", "version": "1.10.14",
"resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.11.tgz", "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.14.tgz",
"integrity": "sha512-aVmbPOfViZqOZPgRBT0+3u4yZFHpmnIghLMlAcb5/xhp5ZtB/RVnKhz5vl2M32CLXAqR4kha9zfhNg0Lf/sxKA==", "integrity": "sha512-lkjaiAye+wBZDCBsu5BGi0XiLRxeUlsGod5ZP924CRSEoGuZAw/f7y9RKu28rwTfiHVhdavhB0qH0INV6P1lEA==",
"dev": true, "dev": true,
"requires": { "requires": {
"node-forge": "^0.10.0" "node-forge": "^0.10.0"

View file

@ -17,12 +17,12 @@
"zone.js": "~0.11.4" "zone.js": "~0.11.4"
}, },
"devDependencies": { "devDependencies": {
"@angular-devkit/build-angular": "~13.1.2", "@angular-devkit/build-angular": "^13.1.2",
"@angular/cli": "^13.1.2", "@angular/cli": "^13.1.2",
"@angular/compiler-cli": "~13.1.1", "@angular/compiler-cli": "~13.1.1",
"@types/node": "~17.0.7", "@types/node": "~17.0.8",
"@typescript-eslint/eslint-plugin": "^5.9.0", "@typescript-eslint/eslint-plugin": "^5.9.1",
"@typescript-eslint/parser": "^5.9.0", "@typescript-eslint/parser": "^5.9.1",
"ajv-keywords": "^5.1.0", "ajv-keywords": "^5.1.0",
"eslint": "^8.6.0", "eslint": "^8.6.0",
"npm-check-updates": "^12.1.0", "npm-check-updates": "^12.1.0",
@ -39,5 +39,5 @@
"build": "ng build --base-href ./ --configuration production", "build": "ng build --base-href ./ --configuration production",
"start": "ng serve" "start": "ng serve"
}, },
"version": "6.1.2" "version": "6.1.3"
} }

View file

@ -17,42 +17,45 @@
* **************************************************************************** * ****************************************************************************
*/ */
import { Injectable } from '@angular/core'; import { ApplicationRef, Injectable } from '@angular/core';
import { MatDialog } from '@angular/material/dialog'; import { MatDialog } from '@angular/material/dialog';
import { SwUpdate } from '@angular/service-worker'; import { SwUpdate, VersionEvent } from '@angular/service-worker';
import { AppUpdateComponent } from './update.component'; import { AppUpdateComponent } from './update.component';
import { concat, interval } from 'rxjs';
import { first } from 'rxjs/operators';
@Injectable() @Injectable()
export class AppUpdateService { export class AppUpdateService {
private prompted: boolean = false;
constructor( constructor(
private matDialog: MatDialog, private matDialog: MatDialog,
private swUpdate: SwUpdate, private ngAppRef: ApplicationRef,
private ngSwUpdate: SwUpdate,
) { ) {
if (swUpdate.isEnabled) { if (!ngSwUpdate.isEnabled) {
swUpdate.versionUpdates.subscribe(() => this.prompt());
setInterval(() => swUpdate.checkForUpdate(), 60 * 60 * 1000);
}
}
prompt(): void {
if (this.prompted) {
return; return;
} }
this.prompted = true concat(
this.ngAppRef.isStable.pipe(first((stable) => stable === true)),
interval(10 * 60 * 1000),
).subscribe(() => this.ngSwUpdate.checkForUpdate());
this.ngSwUpdate.versionUpdates.subscribe((event: VersionEvent) => {
if (event.type === 'VERSION_READY') {
this.prompt();
}
});
}
prompt(): void {
this.matDialog.open(AppUpdateComponent).afterClosed().subscribe((doUpdate) => { this.matDialog.open(AppUpdateComponent).afterClosed().subscribe((doUpdate) => {
if (doUpdate) { if (doUpdate) {
if (this.swUpdate.isEnabled) { if (this.ngSwUpdate.isEnabled) {
this.swUpdate.activateUpdate().then(() => document.location.reload()); this.ngSwUpdate.activateUpdate().then(() => document.location.reload());
} else { } else {
document.location.reload(); document.location.reload();
} }
} }
this.prompted = false;
}); });
} }
} }

View file

@ -16,4 +16,8 @@ A: No problem, just drop us a line at **[rdio-scanner@saubeo.solutions](mailto:r
A: First, don't use the update.js script, it won't work since the server portion of version 6 as been completely rewritten in GO. Simply unzip the archive that contains the Rdio Scanner executable and its PDF document to a new folder, then copy the database.sqlite from version 5 to the new folder that contains version 6 and make sure to rename it to _rdio-scanner.db_. A: First, don't use the update.js script, it won't work since the server portion of version 6 as been completely rewritten in GO. Simply unzip the archive that contains the Rdio Scanner executable and its PDF document to a new folder, then copy the database.sqlite from version 5 to the new folder that contains version 6 and make sure to rename it to _rdio-scanner.db_.
**Q: The web app keeps displaying a dialog telling me that a new version is available**
A: Force a refresh of the web application from the browser (usually with ctrl-shift-r) to resolve the issue. Alternatively, you can click on the icon just to the left of the URL address and select website settings, then clear all website data.
\pagebreak{} \pagebreak{}

View file

@ -42,8 +42,8 @@ ALWAYS DOWNLOAD THE LATEST VERSION OF [RDIO SCANNER](https://github.com/chuot/rd
rdio@macos ~ % mkdir rdio-scanner rdio@macos ~ % mkdir rdio-scanner
rdio@macos ~ % cd rdio-scanner rdio@macos ~ % cd rdio-scanner
rdio@macos rdio-scanner % unzip \ rdio@macos rdio-scanner % unzip \
> ~/Downloads/rdio-scanner-darwin-arm64-v6.1.2.zip > ~/Downloads/rdio-scanner-darwin-arm64-v6.1.3.zip
Archive: /Users/rdio/Downloads/rdio-scanner-darwin-arm64-v6.1.2.zip Archive: /Users/rdio/Downloads/rdio-scanner-darwin-arm64-v6.1.3.zip
inflating: rdio-scanner inflating: rdio-scanner
inflating: rdio-scanner.pdf inflating: rdio-scanner.pdf
@ -51,11 +51,11 @@ ALWAYS DOWNLOAD THE LATEST VERSION OF [RDIO SCANNER](https://github.com/chuot/rd
rdio@macos rdio-scanner % ./rdio-scanner rdio@macos rdio-scanner % ./rdio-scanner
Rdio Scanner v6.1.2 Rdio Scanner v6.1.3
---------------------------------- ----------------------------------
2022/01/05 08:38:06 server started 2022/01/11 08:38:06 server started
2022/01/05 08:38:06 main interface at http://macos.local:3000 2022/01/11 08:38:06 main interface at http://macos.local:3000
2022/01/05 08:38:06 admin interface at http://macos.local:3000/admin 2022/01/11 08:38:06 admin interface at http://macos.local:3000/admin
4. Access the administrative dashboard to finalize the configuration. 4. Access the administrative dashboard to finalize the configuration.
@ -77,11 +77,11 @@ Here we want our [Rdio Scanner](https://guthub.com/chuot/rdio-scanner) instance
rdio@macos rdio-scanner % ./rdio-scanner --listen :80 rdio@macos rdio-scanner % ./rdio-scanner --listen :80
Rdio Scanner v6.1.2 Rdio Scanner v6.1.3
---------------------------------- ----------------------------------
2022/01/05 08:48:03 server started 2022/01/11 08:48:03 server started
2022/01/05 08:48:03 main interface at http://macos.local 2022/01/11 08:48:03 main interface at http://macos.local
2022/01/05 08:48:03 admin interface at http://macos.local/admin 2022/01/11 08:48:03 admin interface at http://macos.local/admin
## Listening with SSL with self-signed certificates ## Listening with SSL with self-signed certificates
@ -90,8 +90,8 @@ It is advised to share your [Rdio Scanner](https://github.com/chuot/rdio-scanner
We can create such self-signed certificates by running [Rdio Scanner](https://github.com/chuot/rdio-scanner) with the **-ssl_create** argument. We can create such self-signed certificates by running [Rdio Scanner](https://github.com/chuot/rdio-scanner) with the **-ssl_create** argument.
rdio@macos rdio-scanner % ./rdio-scanner -ssl_create rdio@macos rdio-scanner % ./rdio-scanner -ssl_create
2022/01/05 08:49:16 generating ssl certificate files 2022/01/11 08:49:16 generating ssl certificate files
2022/01/05 08:49:17 ssl files created 2022/01/11 08:49:17 ssl files created
This has generated these files in the same folder as your [Rdio Scanner](https://github.com/chuot/rdio-scanner) executable. This has generated these files in the same folder as your [Rdio Scanner](https://github.com/chuot/rdio-scanner) executable.
@ -108,12 +108,12 @@ Now we use the self-signed server certificate to run our instance.
> -ssl_key_file server.key \ > -ssl_key_file server.key \
> -ssl_listen :443 > -ssl_listen :443
Rdio Scanner v6.1.2 Rdio Scanner v6.1.3
---------------------------------- ----------------------------------
2022/01/05 08:50:58 server started 2022/01/11 08:50:58 server started
2022/01/05 08:50:58 main interface at http://macos.local 2022/01/11 08:50:58 main interface at http://macos.local
2022/01/05 08:50:58 main interface at https://macos.local 2022/01/11 08:50:58 main interface at https://macos.local
2022/01/05 08:50:58 admin interface at https://macos.local/admin 2022/01/11 08:50:58 admin interface at https://macos.local/admin
## Save your advanced configuration to a config file ## Save your advanced configuration to a config file
@ -125,7 +125,7 @@ You don't want to have to type everytime a long list of arguments. No problem, y
> -ssl_key_file server.key \ > -ssl_key_file server.key \
> -ssl_listen :443 \ > -ssl_listen :443 \
> -config_save > -config_save
2022/01/05 08:52:24 rdio-scanner.ini file created 2022/01/11 08:52:24 rdio-scanner.ini file created
All of your parameters passed as arguments to [Rdio Scanner](https://github.com/chuot/rdio-scanner) have been saved to an INI file which has the same arguments/values list. All of your parameters passed as arguments to [Rdio Scanner](https://github.com/chuot/rdio-scanner) have been saved to an INI file which has the same arguments/values list.
@ -140,12 +140,12 @@ Then simply run [Rdio Scanner](https://github.com/chuot/rdio-scanner) without an
rdio@macos rdio-scanner % ./rdio-scanner rdio@macos rdio-scanner % ./rdio-scanner
Rdio Scanner v6.1.2 Rdio Scanner v6.1.3
---------------------------------- ----------------------------------
2022/01/05 08:54:08 server started 2022/01/11 08:54:08 server started
2022/01/05 08:54:08 main interface at http://macos.local 2022/01/11 08:54:08 main interface at http://macos.local
2022/01/05 08:54:08 main interface at https://macos.local 2022/01/11 08:54:08 main interface at https://macos.local
2022/01/05 08:54:08 admin interface at https://macos.local/admin 2022/01/11 08:54:08 admin interface at https://macos.local/admin
## Install Rdio Scanner as a service ## Install Rdio Scanner as a service

View file

@ -42,8 +42,8 @@ ALWAYS DOWNLOAD THE LATEST VERSION OF [RDIO SCANNER](https://github.com/chuot/rd
rdio@pc-freebsd:~ $ mkdir rdio-scanner rdio@pc-freebsd:~ $ mkdir rdio-scanner
rdio@pc-freebsd:~ $ cd rdio-scanner rdio@pc-freebsd:~ $ cd rdio-scanner
rdio@pc-freebsd:~/rdio-scanner $ unzip \ rdio@pc-freebsd:~/rdio-scanner $ unzip \
> ~/rdio-scanner-freebsd-amd64-v6.1.2.zip > ~/rdio-scanner-freebsd-amd64-v6.1.3.zip
Archive: ../rdio-scanner-freebsd-amd64-v6.1.2.zip Archive: ../rdio-scanner-freebsd-amd64-v6.1.3.zip
extracting: rdio-scanner extracting: rdio-scanner
extracting: rdio-scanner.pdf extracting: rdio-scanner.pdf
@ -51,11 +51,11 @@ ALWAYS DOWNLOAD THE LATEST VERSION OF [RDIO SCANNER](https://github.com/chuot/rd
rdio@pc-freebsd:~/rdio-scanner $ ./rdio-scanner rdio@pc-freebsd:~/rdio-scanner $ ./rdio-scanner
Rdio Scanner v6.1.2 Rdio Scanner v6.1.3
---------------------------------- ----------------------------------
2022/01/05 08:16:36 server started 2022/01/11 08:16:36 server started
2022/01/05 08:16:36 main interface at http://pc-freebsd:3000 2022/01/11 08:16:36 main interface at http://pc-freebsd:3000
2022/01/05 08:16:36 admin interface at http://pc-freebsd:3000/admin 2022/01/11 08:16:36 admin interface at http://pc-freebsd:3000/admin
4. Access the administrative dashboard to finalize the configuration. 4. Access the administrative dashboard to finalize the configuration.
@ -81,11 +81,11 @@ Here we want our [Rdio Scanner](https://guthub.com/chuot/rdio-scanner) instance
Password: Password:
root@pc-freebsd:/home/rdio/rdio-scanner # ./rdio-scanner -listen :80 root@pc-freebsd:/home/rdio/rdio-scanner # ./rdio-scanner -listen :80
Rdio Scanner v6.1.2 Rdio Scanner v6.1.3
---------------------------------- ----------------------------------
2022/01/05 08:19:38 server started 2022/01/11 08:19:38 server started
2022/01/05 08:19:38 main interface at http://pc-freebsd 2022/01/11 08:19:38 main interface at http://pc-freebsd
2022/01/05 08:19:38 admin interface at http://pc-freebsd/admin 2022/01/11 08:19:38 admin interface at http://pc-freebsd/admin
## Listening with SSL with self-signed certificates ## Listening with SSL with self-signed certificates
@ -94,8 +94,8 @@ It is advised to share your [Rdio Scanner](https://github.com/chuot/rdio-scanner
We can create such self-signed certificates by running [Rdio Scanner](https://github.com/chuot/rdio-scanner) with the **-ssl_create** argument. We can create such self-signed certificates by running [Rdio Scanner](https://github.com/chuot/rdio-scanner) with the **-ssl_create** argument.
rdio@pc-freebsd:~/rdio-scanner $ ./rdio-scanner -ssl_create rdio@pc-freebsd:~/rdio-scanner $ ./rdio-scanner -ssl_create
2022/01/05 10:32:17 generating ssl certificate files 2022/01/11 10:32:17 generating ssl certificate files
2022/01/05 10:32:19 ssl files created 2022/01/11 10:32:19 ssl files created
This has generated these files in the same folder as your [Rdio Scanner](https://github.com/chuot/rdio-scanner) executable. This has generated these files in the same folder as your [Rdio Scanner](https://github.com/chuot/rdio-scanner) executable.
@ -114,12 +114,12 @@ Now we use the self-signed server certificate to run our instance.
> -ssl_key_file server.key \ > -ssl_key_file server.key \
> -ssl_listen :443 > -ssl_listen :443
Rdio Scanner v6.1.2 Rdio Scanner v6.1.3
---------------------------------- ----------------------------------
2022/01/05 10:34:29 server started 2022/01/11 10:34:29 server started
2022/01/05 10:34:29 main interface at http://pc-freebsd 2022/01/11 10:34:29 main interface at http://pc-freebsd
2022/01/05 10:34:29 main interface at https://pc-freebsd 2022/01/11 10:34:29 main interface at https://pc-freebsd
2022/01/05 10:34:29 admin interface at https://pc-freebsd/admin 2022/01/11 10:34:29 admin interface at https://pc-freebsd/admin
## Save your advanced configuration to a config file ## Save your advanced configuration to a config file
@ -131,7 +131,7 @@ You don't want to have to type everytime a long list of arguments. No problem, y
> -ssl_key_file server.key \ > -ssl_key_file server.key \
> -ssl_listen :443 \ > -ssl_listen :443 \
> -config_save > -config_save
2022/01/05 10:37:00 rdio-scanner.ini file created 2022/01/11 10:37:00 rdio-scanner.ini file created
All of your parameters passed as arguments to [Rdio Scanner](https://github.com/chuot/rdio-scanner) have been saved to an INI file which has the same arguments/values list. All of your parameters passed as arguments to [Rdio Scanner](https://github.com/chuot/rdio-scanner) have been saved to an INI file which has the same arguments/values list.
@ -148,12 +148,12 @@ Then simply run [Rdio Scanner](https://github.com/chuot/rdio-scanner) without an
Password: Password:
root@pc-freebsd:/home/rdio/rdio-scanner # ./rdio-scanner root@pc-freebsd:/home/rdio/rdio-scanner # ./rdio-scanner
Rdio Scanner v6.1.2 Rdio Scanner v6.1.3
---------------------------------- ----------------------------------
2022/01/05 10:38:28 server started 2022/01/11 10:38:28 server started
2022/01/05 10:38:29 main interface at http://pc-freebsd 2022/01/11 10:38:29 main interface at http://pc-freebsd
2022/01/05 10:38:29 main interface at https://pc-freebsd 2022/01/11 10:38:29 main interface at https://pc-freebsd
2022/01/05 10:38:29 admin interface at https://pc-freebsd/admin 2022/01/11 10:38:29 admin interface at https://pc-freebsd/admin
## Install Rdio Scanner as a service ## Install Rdio Scanner as a service

View file

@ -42,8 +42,8 @@ ALWAYS DOWNLOAD THE LATEST VERSION OF [RDIO SCANNER](https://github.com/chuot/rd
[rdio@pc-linux ~]$ mkdir rdio-scanner [rdio@pc-linux ~]$ mkdir rdio-scanner
[rdio@pc-linux ~]$ cd rdio-scanner [rdio@pc-linux ~]$ cd rdio-scanner
[rdio@pc-linux rdio-scanner]$ unzip \ [rdio@pc-linux rdio-scanner]$ unzip \
> ~/Downloads/rdio-scanner-linux-amd64-v6.1.2.zip > ~/Downloads/rdio-scanner-linux-amd64-v6.1.3.zip
Archive: /home/rdio/Downloads/rdio-scanner-linux-amd64-v6.1.2.zip Archive: /home/rdio/Downloads/rdio-scanner-linux-amd64-v6.1.3.zip
inflating: rdio-scanner inflating: rdio-scanner
inflating: rdio-scanner.pdf inflating: rdio-scanner.pdf
@ -51,11 +51,11 @@ ALWAYS DOWNLOAD THE LATEST VERSION OF [RDIO SCANNER](https://github.com/chuot/rd
[rdio@pc-linux rdio-scanner]$ ./rdio-scanner [rdio@pc-linux rdio-scanner]$ ./rdio-scanner
Rdio Scanner v6.1.2 Rdio Scanner v6.1.3
---------------------------------- ----------------------------------
2022/01/05 09:11:48 server started 2022/01/11 09:11:48 server started
2022/01/05 09:11:48 main interface at http://pc-linux:3000 2022/01/11 09:11:48 main interface at http://pc-linux:3000
2022/01/05 09:11:48 admin interface at http://pc-linux:3000/admin 2022/01/11 09:11:48 admin interface at http://pc-linux:3000/admin
4. Access the administrative dashboard to finalize the configuration. 4. Access the administrative dashboard to finalize the configuration.
@ -78,11 +78,11 @@ Here we want our [Rdio Scanner](https://guthub.com/chuot/rdio-scanner) instance
[rdio@pc-linux rdio-scanner]$ sudo ./rdio-scanner -listen :80 [rdio@pc-linux rdio-scanner]$ sudo ./rdio-scanner -listen :80
[sudo] password for rdio: [sudo] password for rdio:
Rdio Scanner v6.1.2 Rdio Scanner v6.1.3
---------------------------------- ----------------------------------
2022/01/05 09:14:00 server started 2022/01/11 09:14:00 server started
2022/01/05 09:14:00 main interface at http://pc-linux 2022/01/11 09:14:00 main interface at http://pc-linux
2022/01/05 09:14:00 admin interface at http://pc-linux/admin 2022/01/11 09:14:00 admin interface at http://pc-linux/admin
## Listening with SSL with self-signed certificates ## Listening with SSL with self-signed certificates
@ -91,8 +91,8 @@ It is advised to share your [Rdio Scanner](https://github.com/chuot/rdio-scanner
We can create such self-signed certificates by running [Rdio Scanner](https://github.com/chuot/rdio-scanner) with the **-ssl_create** argument. We can create such self-signed certificates by running [Rdio Scanner](https://github.com/chuot/rdio-scanner) with the **-ssl_create** argument.
[rdio@pc-linux rdio-scanner]$ ./rdio-scanner -ssl_create [rdio@pc-linux rdio-scanner]$ ./rdio-scanner -ssl_create
2022/01/05 09:15:03 generating ssl certificate files 2022/01/11 09:15:03 generating ssl certificate files
2022/01/05 09:15:05 ssl files created 2022/01/11 09:15:05 ssl files created
This has generated these files in the same folder as your [Rdio Scanner](https://github.com/chuot/rdio-scanner) executable. This has generated these files in the same folder as your [Rdio Scanner](https://github.com/chuot/rdio-scanner) executable.
@ -110,12 +110,12 @@ Now we use the self-signed server certificate to run our instance.
> -ssl_listen :443 > -ssl_listen :443
[sudo] password for rdio: [sudo] password for rdio:
Rdio Scanner v6.1.2 Rdio Scanner v6.1.3
---------------------------------- ----------------------------------
2022/01/05 09:16:47 server started 2022/01/11 09:16:47 server started
2022/01/05 09:16:47 main interface at http://pc-linux 2022/01/11 09:16:47 main interface at http://pc-linux
2022/01/05 09:16:47 main interface at https://pc-linux 2022/01/11 09:16:47 main interface at https://pc-linux
2022/01/05 09:16:47 admin interface at https://pc-linux/admin 2022/01/11 09:16:47 admin interface at https://pc-linux/admin
## Save your advanced configuration to a config file ## Save your advanced configuration to a config file
@ -127,7 +127,7 @@ You don't want to have to type everytime a long list of arguments. No problem, y
> -ssl_key_file server.key \ > -ssl_key_file server.key \
> -ssl_listen :443 \ > -ssl_listen :443 \
> -config_save > -config_save
2022/01/05 09:19:29 rdio-scanner.ini file created 2022/01/11 09:19:29 rdio-scanner.ini file created
All of your parameters passed as arguments to [Rdio Scanner](https://github.com/chuot/rdio-scanner) have been saved to an INI file which has the same arguments/values list. All of your parameters passed as arguments to [Rdio Scanner](https://github.com/chuot/rdio-scanner) have been saved to an INI file which has the same arguments/values list.
@ -143,12 +143,12 @@ Then simply run [Rdio Scanner](https://github.com/chuot/rdio-scanner) without an
[rdio@pc-linux rdio-scanner]$ sudo ./rdio-scanner [rdio@pc-linux rdio-scanner]$ sudo ./rdio-scanner
[sudo] Mot de passe de rdio : [sudo] Mot de passe de rdio :
Rdio Scanner v6.1.2 Rdio Scanner v6.1.3
---------------------------------- ----------------------------------
2022/01/05 09:20:40 server started 2022/01/11 09:20:40 server started
2022/01/05 09:20:40 main interface at http://pc-linux 2022/01/11 09:20:40 main interface at http://pc-linux
2022/01/05 09:20:40 main interface at https://pc-linux 2022/01/11 09:20:40 main interface at https://pc-linux
2022/01/05 09:20:40 admin interface at https://pc-linux/admin 2022/01/11 09:20:40 admin interface at https://pc-linux/admin
## Install Rdio Scanner as a service ## Install Rdio Scanner as a service

View file

@ -44,7 +44,7 @@ ALWAYS DOWNLOAD THE LATEST VERSION OF [RDIO SCANNER](https://github.com/chuot/rd
C:\Users\rdio> cd rdio-scanner C:\Users\rdio> cd rdio-scanner
C:\Users\rdio\rdio-scanner> tar -xvf ^ C:\Users\rdio\rdio-scanner> tar -xvf ^
..\downloads\rdio-scanner-windows-amd64-v6.1.2.zip ..\downloads\rdio-scanner-windows-amd64-v6.1.3.zip
x rdio-scanner.exe x rdio-scanner.exe
x rdio-scanner.pdf x rdio-scanner.pdf
@ -52,11 +52,11 @@ ALWAYS DOWNLOAD THE LATEST VERSION OF [RDIO SCANNER](https://github.com/chuot/rd
C:\Users\rdio\rdio-scanner>rdio-scanner C:\Users\rdio\rdio-scanner>rdio-scanner
Rdio Scanner v6.1.2 Rdio Scanner v6.1.3
---------------------------------- ----------------------------------
2022/01/05 13:48:48 server started 2022/01/11 13:48:48 server started
2022/01/05 13:48:48 main interface at http://pc-windows:3000 2022/01/11 13:48:48 main interface at http://pc-windows:3000
2022/01/05 13:48:48 admin interface at http://pc-windows:3000/admin 2022/01/11 13:48:48 admin interface at http://pc-windows:3000/admin
4. Access the administrative dashboard to finalize the configuration. 4. Access the administrative dashboard to finalize the configuration.
@ -78,11 +78,11 @@ Here we want our [Rdio Scanner](https://guthub.com/chuot/rdio-scanner) instance
C:\Users\rdio\rdio-scanner>rdio-scanner -listen :80 C:\Users\rdio\rdio-scanner>rdio-scanner -listen :80
Rdio Scanner v6.1.2 Rdio Scanner v6.1.3
---------------------------------- ----------------------------------
2022/01/05 10:53:31 server started 2022/01/11 10:53:31 server started
2022/01/05 10:53:31 main interface at http://pc-windows 2022/01/11 10:53:31 main interface at http://pc-windows
2022/01/05 10:53:31 admin interface at http://pc-windows/admin 2022/01/11 10:53:31 admin interface at http://pc-windows/admin
## Listening with SSL with self-signed certificates ## Listening with SSL with self-signed certificates
@ -91,8 +91,8 @@ It is advised to share your [Rdio Scanner](https://github.com/chuot/rdio-scanner
We can create such self-signed certificates by running [Rdio Scanner](https://github.com/chuot/rdio-scanner) with the **-ssl_create** argument. We can create such self-signed certificates by running [Rdio Scanner](https://github.com/chuot/rdio-scanner) with the **-ssl_create** argument.
C:\Users\rdio\rdio-scanner>rdio-scanner -ssl_create C:\Users\rdio\rdio-scanner>rdio-scanner -ssl_create
2022/01/05 10:58:51 generating ssl certificate files 2022/01/11 10:58:51 generating ssl certificate files
2022/01/05 10:58:54 ssl files created 2022/01/11 10:58:54 ssl files created
This has generated these files in the same folder as your [Rdio Scanner](https://github.com/chuot/rdio-scanner) executable. This has generated these files in the same folder as your [Rdio Scanner](https://github.com/chuot/rdio-scanner) executable.
@ -109,12 +109,12 @@ Now we use the self-signed server certificate to run our instance.
-ssl_key_file server.key ^ -ssl_key_file server.key ^
-ssl_listen :443 -ssl_listen :443
Rdio Scanner v6.1.2 Rdio Scanner v6.1.3
---------------------------------- ----------------------------------
2022/01/05 11:05:43 server started 2022/01/11 11:05:43 server started
2022/01/05 11:05:43 main interface at http://pc-windows 2022/01/11 11:05:43 main interface at http://pc-windows
2022/01/05 11:05:43 main interface at https://pc-windows 2022/01/11 11:05:43 main interface at https://pc-windows
2022/01/05 11:05:43 admin interface at https://pc-windows/admin 2022/01/11 11:05:43 admin interface at https://pc-windows/admin
## Save your advanced configuration to a config file ## Save your advanced configuration to a config file
@ -126,7 +126,7 @@ You don't want to have to type everytime a long list of arguments. No problem, y
-ssl_key_file server.key ^ -ssl_key_file server.key ^
-ssl_listen :443 ^ -ssl_listen :443 ^
-config_save -config_save
2022/01/05 11:08:28 rdio-scanner.ini file created 2022/01/11 11:08:28 rdio-scanner.ini file created
All of your parameters passed as arguments to [Rdio Scanner](https://github.com/chuot/rdio-scanner) have been saved to an INI file which has the same arguments/values list. All of your parameters passed as arguments to [Rdio Scanner](https://github.com/chuot/rdio-scanner) have been saved to an INI file which has the same arguments/values list.
@ -141,12 +141,12 @@ Then simply run [Rdio Scanner](https://github.com/chuot/rdio-scanner) without an
C:\Users\rdio\rdio-scanner>rdio-scanner C:\Users\rdio\rdio-scanner>rdio-scanner
Rdio Scanner v6.1.2 Rdio Scanner v6.1.3
---------------------------------- ----------------------------------
2022/01/05 11:11:28 server started 2022/01/11 11:11:28 server started
2022/01/05 11:11:28 main interface at http://pc-windows 2022/01/11 11:11:28 main interface at http://pc-windows
2022/01/05 11:11:28 main interface at https://pc-windows 2022/01/11 11:11:28 main interface at https://pc-windows
2022/01/05 11:11:28 admin interface at https://pc-windows/admin 2022/01/11 11:11:28 admin interface at https://pc-windows/admin
\pagebreak{} \pagebreak{}

View file

@ -20,6 +20,7 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"strings" "strings"
"sync"
"time" "time"
) )
@ -124,7 +125,10 @@ func (access *Access) HasExpired() bool {
return false return false
} }
type Accesses []Access type Accesses struct {
List []*Access
mutex sync.Mutex
}
func (accesses *Accesses) FromMap(f []interface{}) { func (accesses *Accesses) FromMap(f []interface{}) {
*accesses = Accesses{} *accesses = Accesses{}
@ -132,24 +136,24 @@ func (accesses *Accesses) FromMap(f []interface{}) {
for _, r := range f { for _, r := range f {
switch m := r.(type) { switch m := r.(type) {
case map[string]interface{}: case map[string]interface{}:
access := Access{} access := &Access{}
access.FromMap(m) access.FromMap(m)
*accesses = append(*accesses, access) accesses.List = append(accesses.List, access)
} }
} }
} }
func (accesses *Accesses) GetAccess(code string) (access *Access, ok bool) { func (accesses *Accesses) GetAccess(code string) (access *Access, ok bool) {
for _, access := range *accesses { for _, access := range accesses.List {
if access.Code == code { if access.Code == code {
return &access, true return access, true
} }
} }
return nil, false return nil, false
} }
func (accesses *Accesses) IsRestricted() bool { func (accesses *Accesses) IsRestricted() bool {
return len(*accesses) > 0 return len(accesses.List) > 0
} }
func (accesses *Accesses) Read(db *Database) error { func (accesses *Accesses) Read(db *Database) error {
@ -164,7 +168,7 @@ func (accesses *Accesses) Read(db *Database) error {
t time.Time t time.Time
) )
*accesses = Accesses{} accesses.List = []*Access{}
formatError := func(err error) error { formatError := func(err error) error {
return fmt.Errorf("accesses.read: %v", err) return fmt.Errorf("accesses.read: %v", err)
@ -175,7 +179,8 @@ func (accesses *Accesses) Read(db *Database) error {
} }
for rows.Next() { for rows.Next() {
access := Access{} access := &Access{}
if err = rows.Scan(&id, &access.Code, &expiration, &access.Ident, &limit, &order, &systems); err != nil { if err = rows.Scan(&id, &access.Code, &expiration, &access.Ident, &limit, &order, &systems); err != nil {
break break
} }
@ -206,7 +211,7 @@ func (accesses *Accesses) Read(db *Database) error {
access.Systems = []interface{}{} access.Systems = []interface{}{}
} }
*accesses = append(*accesses, access) accesses.List = append(accesses.List, access)
} }
rows.Close() rows.Close()
@ -227,11 +232,13 @@ func (accesses *Accesses) Write(db *Database) error {
systems interface{} systems interface{}
) )
accesses.mutex.Lock()
formatError := func(err error) error { formatError := func(err error) error {
return fmt.Errorf("accesses.write: %v", err) return fmt.Errorf("accesses.write: %v", err)
} }
for _, access := range *accesses { for _, access := range accesses.List {
switch access.Systems { switch access.Systems {
case "*": case "*":
systems = `"*"` systems = `"*"`
@ -265,7 +272,7 @@ func (accesses *Accesses) Write(db *Database) error {
var id uint var id uint
rows.Scan(&id) rows.Scan(&id)
remove := true remove := true
for _, access := range *accesses { for _, access := range accesses.List {
if access.Id == nil || access.Id == id { if access.Id == nil || access.Id == id {
remove = false remove = false
break break
@ -294,5 +301,7 @@ func (accesses *Accesses) Write(db *Database) error {
} }
} }
accesses.mutex.Unlock()
return nil return nil
} }

View file

@ -81,30 +81,36 @@ func (admin *Admin) BroadcastConfig() {
} }
func (admin *Admin) ChangePassword(currentPassword string, newPassword string) error { func (admin *Admin) ChangePassword(currentPassword string, newPassword string) error {
if len(currentPassword) > 0 { var (
if err := bcrypt.CompareHashAndPassword([]byte(admin.Controller.Options.adminPassword), []byte(currentPassword)); err == nil { err error
var hash []byte hash []byte
if hash, err = bcrypt.GenerateFromPassword([]byte(newPassword), bcrypt.DefaultCost); err != nil { )
return err
}
admin.Controller.Options.adminPassword = string(hash) if len(newPassword) == 0 {
admin.Controller.Options.adminPasswordNeedChange = newPassword == defaults.adminPassword return errors.New("newPassword is empty")
if err := admin.Controller.Options.Write(admin.Controller.Database); err != nil {
return err
}
if err := admin.Controller.Options.Read(admin.Controller.Database); err != nil {
return err
}
LogEvent(admin.Controller.Database, LogLevelInfo, "admin password changed.")
} else {
return err
}
} }
if err = bcrypt.CompareHashAndPassword([]byte(admin.Controller.Options.adminPassword), []byte(currentPassword)); err != nil {
return err
}
if hash, err = bcrypt.GenerateFromPassword([]byte(newPassword), bcrypt.DefaultCost); err != nil {
return err
}
admin.Controller.Options.adminPassword = string(hash)
admin.Controller.Options.adminPasswordNeedChange = newPassword == defaults.adminPassword
if err := admin.Controller.Options.Write(admin.Controller.Database); err != nil {
return err
}
if err := admin.Controller.Options.Read(admin.Controller.Database); err != nil {
return err
}
LogEvent(admin.Controller.Database, LogLevelInfo, "admin password changed.")
return nil return nil
} }
@ -287,7 +293,7 @@ func (admin *Admin) GetAuthorization(r *http.Request) string {
func (admin *Admin) GetConfig() map[string]interface{} { func (admin *Admin) GetConfig() map[string]interface{} {
systems := []map[string]interface{}{} systems := []map[string]interface{}{}
for _, system := range *admin.Controller.Systems { for _, system := range admin.Controller.Systems.List {
systems = append(systems, map[string]interface{}{ systems = append(systems, map[string]interface{}{
"_id": system.RowId, "_id": system.RowId,
"autoPopulate": system.AutoPopulate, "autoPopulate": system.AutoPopulate,
@ -302,14 +308,14 @@ func (admin *Admin) GetConfig() map[string]interface{} {
} }
return map[string]interface{}{ return map[string]interface{}{
"access": *admin.Controller.Accesses, "access": admin.Controller.Accesses.List,
"apiKeys": *admin.Controller.Apikeys, "apiKeys": admin.Controller.Apikeys.List,
"dirWatch": *admin.Controller.Dirwatches, "dirWatch": admin.Controller.Dirwatches.List,
"downstreams": *admin.Controller.Downstreams, "downstreams": admin.Controller.Downstreams.List,
"groups": *admin.Controller.Groups, "groups": admin.Controller.Groups.List,
"options": *admin.Controller.Options, "options": admin.Controller.Options,
"systems": systems, "systems": systems,
"tags": *admin.Controller.Tags, "tags": admin.Controller.Tags.List,
} }
} }

View file

@ -16,16 +16,12 @@
package main package main
import ( import (
"encoding/json"
"fmt" "fmt"
"io" "io"
"mime" "mime"
"mime/multipart" "mime/multipart"
"net/http" "net/http"
"regexp"
"strconv"
"strings" "strings"
"time"
) )
const ( const (
@ -45,23 +41,8 @@ func (api *Api) CallUploadHandler(w http.ResponseWriter, r *http.Request) {
switch r.Method { switch r.Method {
case http.MethodPost: case http.MethodPost:
var ( var (
audio []byte call = NewCall()
audioName string key string
audioType string
dateTime time.Time
frequencies = []map[string]interface{}{}
frequency interface{}
key string
patches = []uint{}
source interface{}
sources = []map[string]interface{}{}
system uint
systemLabel interface{}
talkgroup uint
talkgroupGroup interface{}
talkgroupLabel interface{}
talkgroupTag interface{}
units interface{}
) )
mediaType, params, err := mime.ParseMediaType(r.Header.Get("Content-Type")) mediaType, params, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
@ -93,182 +74,15 @@ func (api *Api) CallUploadHandler(w http.ResponseWriter, r *http.Request) {
} }
switch p.FormName() { switch p.FormName() {
case "audio":
audio = b
audioName = p.FileName()
audioType = p.Header.Get("Content-Type")
case "audioName":
audioName = string(b)
case "audioType":
audioType = string(b)
case "dateTime":
if regexp.MustCompile(`^[0-9]+$`).Match(b) {
if i, err := strconv.Atoi(string(b)); err == nil {
dateTime = time.Unix(int64(i), 0).UTC()
}
} else {
dateTime, _ = time.Parse(time.RFC3339, string(b))
dateTime = dateTime.UTC()
}
case "frequencies":
var f interface{}
if err := json.Unmarshal(b, &f); err == nil {
switch v := f.(type) {
case []interface{}:
for _, f := range v {
freq := map[string]interface{}{}
switch v := f.(type) {
case map[string]interface{}:
switch v := v["errorCount"].(type) {
case float64:
freq["errorCount"] = uint(v)
}
switch v := v["freq"].(type) {
case float64:
freq["freq"] = uint(v)
}
switch v := v["len"].(type) {
case float64:
freq["len"] = uint(v)
}
switch v := v["pos"].(type) {
case float64:
freq["pos"] = uint(v)
}
switch v := v["spikeCount"].(type) {
case float64:
freq["spikeCount"] = uint(v)
}
}
frequencies = append(frequencies, freq)
}
}
}
case "frequency":
if i, err := strconv.Atoi(string(b)); err == nil {
frequency = uint(i)
}
case "key": case "key":
key = string(b) key = string(b)
default:
case "patches", "patched_talkgroups": ParseMultipartContent(call, p, b)
var f interface{}
if err := json.Unmarshal(b, &f); err == nil {
switch v := f.(type) {
case []interface{}:
for _, patch := range v {
switch v := patch.(type) {
case float64:
if v > 0 {
patches = append(patches, uint(v))
}
}
}
}
}
case "source":
if i, err := strconv.Atoi(string(b)); err == nil {
source = int(i)
}
case "sources":
var f interface{}
if err := json.Unmarshal(b, &f); err == nil {
switch v := f.(type) {
case []interface{}:
for _, f := range v {
src := map[string]interface{}{}
switch v := f.(type) {
case map[string]interface{}:
switch v := v["pos"].(type) {
case float64:
src["pos"] = uint(v)
}
switch s := v["src"].(type) {
case float64:
if s > 0 {
src["src"] = uint(s)
switch t := v["tag"].(type) {
case string:
var u Units
switch v := units.(type) {
case Units:
u = v
default:
u = Units{}
}
u.Add(int(s), t)
units = u
}
}
}
}
sources = append(sources, src)
}
}
}
case "system", "systemId":
if i, err := strconv.Atoi(string(b)); err == nil {
system = uint(i)
}
case "systemLabel":
systemLabel = string(b)
case "talkgroup", "talkgroupId":
if i, err := strconv.Atoi(string(b)); err == nil {
talkgroup = uint(i)
}
case "talkgroupGroup":
if s := string(b); len(s) > 1 {
talkgroupGroup = s
}
case "talkgroupLabel":
if s := string(b); len(s) > 1 {
talkgroupLabel = s
}
case "talkgroupTag":
if s := string(b); len(s) > 1 {
talkgroupTag = s
}
} }
} }
call := &Call{
Audio: audio,
AudioName: audioName,
AudioType: audioType,
DateTime: dateTime,
Frequencies: frequencies,
Frequency: frequency,
Patches: patches,
Source: source,
Sources: sources,
System: system,
Talkgroup: talkgroup,
systemLabel: systemLabel,
talkgroupGroup: talkgroupGroup,
talkgroupLabel: talkgroupLabel,
talkgroupTag: talkgroupTag,
units: units,
}
if call.IsValid() { if call.IsValid() {
api.HandleCall(key, call, w) api.HandleCall(key, call, w)
} else { } else {
w.WriteHeader(http.StatusExpectationFailed) w.WriteHeader(http.StatusExpectationFailed)
w.Write([]byte("Incomplete call data")) w.Write([]byte("Incomplete call data"))
@ -306,12 +120,8 @@ func (api *Api) TrunkRecorderCallUploadHandler(w http.ResponseWriter, r *http.Re
switch r.Method { switch r.Method {
case http.MethodPost: case http.MethodPost:
var ( var (
audio []byte call = NewCall()
audioName string key string
audioType string
key string
meta []byte
system uint
) )
mediaType, params, err := mime.ParseMediaType(r.Header.Get("Content-Type")) mediaType, params, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
@ -343,35 +153,33 @@ func (api *Api) TrunkRecorderCallUploadHandler(w http.ResponseWriter, r *http.Re
} }
switch p.FormName() { switch p.FormName() {
case "audio":
audio = b
audioName = p.FileName()
audioType = p.Header.Get("Content-Type")
case "key": case "key":
key = string(b) key = string(b)
case "meta": case "meta":
meta = b if err := ParseTrunkRecorderMeta(call, b); err != nil {
w.WriteHeader(http.StatusExpectationFailed)
case "system": w.Write([]byte("Invalid call data"))
if i, err := strconv.Atoi(string(b)); err == nil { return
system = uint(i)
} }
} }
} }
call := &Call{ mr = multipart.NewReader(r.Body, params["boundary"])
Audio: audio,
AudioName: audioName,
AudioType: audioType,
System: system,
}
if err := ParseTrunkRecorderMeta(call, meta); err != nil { for {
w.WriteHeader(http.StatusExpectationFailed) p, err := mr.NextPart()
w.Write([]byte("Invalid call data")) if err == io.EOF {
return break
} else if err != nil {
continue
}
b, err := io.ReadAll(p)
if err != nil {
continue
}
ParseMultipartContent(call, p, b)
} }
if call.IsValid() { if call.IsValid() {

View file

@ -20,6 +20,7 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"strings" "strings"
"sync"
"github.com/google/uuid" "github.com/google/uuid"
) )
@ -107,25 +108,28 @@ func (apikey *Apikey) HasAccess(call *Call) bool {
return false return false
} }
type Apikeys []Apikey type Apikeys struct {
List []*Apikey
mutex sync.Mutex
}
func (apikeys *Apikeys) FromMap(f []interface{}) { func (apikeys *Apikeys) FromMap(f []interface{}) {
*apikeys = Apikeys{} apikeys.List = []*Apikey{}
for _, r := range f { for _, r := range f {
switch m := r.(type) { switch m := r.(type) {
case map[string]interface{}: case map[string]interface{}:
apikey := Apikey{} apikey := &Apikey{}
apikey.FromMap(m) apikey.FromMap(m)
*apikeys = append(*apikeys, apikey) apikeys.List = append(apikeys.List, apikey)
} }
} }
} }
func (apikeys *Apikeys) GetApikey(key string) (apikey *Apikey, ok bool) { func (apikeys *Apikeys) GetApikey(key string) (apikey *Apikey, ok bool) {
for _, apikey := range *apikeys { for _, apikey := range apikeys.List {
if apikey.Key == key { if apikey.Key == key {
return &apikey, true return apikey, true
} }
} }
return nil, false return nil, false
@ -140,7 +144,7 @@ func (apikeys *Apikeys) Read(db *Database) error {
systems string systems string
) )
*apikeys = Apikeys{} apikeys.List = []*Apikey{}
formatError := func(err error) error { formatError := func(err error) error {
return fmt.Errorf("apikeys.read: %v", err) return fmt.Errorf("apikeys.read: %v", err)
@ -151,7 +155,8 @@ func (apikeys *Apikeys) Read(db *Database) error {
} }
for rows.Next() { for rows.Next() {
apikey := Apikey{} apikey := &Apikey{}
if err = rows.Scan(&id, &apikey.Disabled, &apikey.Ident, &apikey.Key, &order, &systems); err != nil { if err = rows.Scan(&id, &apikey.Disabled, &apikey.Ident, &apikey.Key, &order, &systems); err != nil {
break break
} }
@ -176,7 +181,7 @@ func (apikeys *Apikeys) Read(db *Database) error {
apikey.Systems = []interface{}{} apikey.Systems = []interface{}{}
} }
*apikeys = append(*apikeys, apikey) apikeys.List = append(apikeys.List, apikey)
} }
rows.Close() rows.Close()
@ -197,11 +202,13 @@ func (apikeys *Apikeys) Write(db *Database) error {
systems interface{} systems interface{}
) )
apikeys.mutex.Lock()
formatError := func(err error) error { formatError := func(err error) error {
return fmt.Errorf("apikeys.write %v", err) return fmt.Errorf("apikeys.write %v", err)
} }
for _, apikey := range *apikeys { for _, apikey := range apikeys.List {
switch apikey.Systems { switch apikey.Systems {
case "*": case "*":
systems = `"*"` systems = `"*"`
@ -235,7 +242,7 @@ func (apikeys *Apikeys) Write(db *Database) error {
var id uint var id uint
rows.Scan(&id) rows.Scan(&id)
remove := true remove := true
for _, apikey := range *apikeys { for _, apikey := range apikeys.List {
if apikey.Id == nil || apikey.Id == id { if apikey.Id == nil || apikey.Id == id {
remove = false remove = false
break break
@ -264,5 +271,7 @@ func (apikeys *Apikeys) Write(db *Database) error {
} }
} }
apikeys.mutex.Unlock()
return nil return nil
} }

View file

@ -43,6 +43,14 @@ type Call struct {
units interface{} units interface{}
} }
func NewCall() *Call {
return &Call{
Frequencies: []map[string]interface{}{},
Patches: []uint{},
Sources: []map[string]interface{}{},
}
}
func (call *Call) IsValid() bool { func (call *Call) IsValid() bool {
if len(call.Audio) <= 44 { if len(call.Audio) <= 44 {
return false return false

View file

@ -219,7 +219,7 @@ func (controller *Controller) IngestCall(call *Call) {
system.Label = fmt.Sprintf("System %v", call.System) system.Label = fmt.Sprintf("System %v", call.System)
} }
*controller.Systems = append(*controller.Systems, system) controller.Systems.List = append(controller.Systems.List, system)
} }
if system != nil && talkgroup == nil && (controller.Options.AutoPopulate || system.AutoPopulate) { if system != nil && talkgroup == nil && (controller.Options.AutoPopulate || system.AutoPopulate) {
@ -242,7 +242,7 @@ func (controller *Controller) IngestCall(call *Call) {
if group, ok = controller.Groups.GetGroup(groupLabel); !ok { if group, ok = controller.Groups.GetGroup(groupLabel); !ok {
group = &Group{Label: groupLabel} group = &Group{Label: groupLabel}
*controller.Groups = append(*controller.Groups, *group) controller.Groups.List = append(controller.Groups.List, group)
if err = controller.Groups.Write(controller.Database); err != nil { if err = controller.Groups.Write(controller.Database); err != nil {
logError(err) logError(err)
@ -271,7 +271,7 @@ func (controller *Controller) IngestCall(call *Call) {
if tag, ok = controller.Tags.GetTag(tagLabel); !ok { if tag, ok = controller.Tags.GetTag(tagLabel); !ok {
tag = &Tag{Label: tagLabel} tag = &Tag{Label: tagLabel}
*controller.Tags = append(*controller.Tags, *tag) controller.Tags.List = append(controller.Tags.List, tag)
if err = controller.Tags.Write(controller.Database); err != nil { if err = controller.Tags.Write(controller.Database); err != nil {
logError(err) logError(err)
@ -508,8 +508,8 @@ func (controller *Controller) ProcessMessageCommandPin(client *Client, message *
switch v := client.Access.Limit.(type) { switch v := client.Access.Limit.(type) {
case uint: case uint:
count := uint(0) count := uint(0)
for _, acc := range *controller.Accesses { for _, acc := range controller.Accesses.List {
if acc == *client.Access { if acc == client.Access {
count++ count++
} }
} }

View file

@ -206,7 +206,7 @@ func (db *Database) migration20191028144433(verbose bool) error {
} }
} else { } else {
queries = []string{ queries = []string{
"create table `rdioScannerSystems` (`id` integer primary key auto_increment, `createdAt` datetime not null, `updatedAt` datetime not null, `name` varchar(255) not null, `system` integer not null, `talkgroups` json not null default '[]')", "create table `rdioScannerSystems` (`id` integer primary key auto_increment, `createdAt` datetime not null, `updatedAt` datetime not null, `name` varchar(255) not null, `system` integer not null, `talkgroups` json not null)",
"create unique index `rdio_scanner_systems_system` on `rdioScannerSystems` (`system`)", "create unique index `rdio_scanner_systems_system` on `rdioScannerSystems` (`system`)",
} }
} }
@ -261,7 +261,7 @@ func (db *Database) migration20191220093214(verbose bool) error {
queries = []string{ queries = []string{
"alter table `rdioScannerCalls` add column `audioName` varchar(255)", "alter table `rdioScannerCalls` add column `audioName` varchar(255)",
"alter table `rdioScannerCalls` add column `audioType` varchar(255)", "alter table `rdioScannerCalls` add column `audioType` varchar(255)",
"alter table `rdioScannerSystems` add column `aliases` json not null default '[]'", "alter table `rdioScannerSystems` add column `aliases` json not null",
} }
} }
return db.migrateWithSchema("20191220093214-new-v3-tables", queries, verbose) return db.migrateWithSchema("20191220093214-new-v3-tables", queries, verbose)
@ -297,7 +297,7 @@ func (db *Database) migration20200428132918(verbose bool) error {
} else { } else {
queries = []string{ queries = []string{
"drop table `rdioScannerSystems`", "drop table `rdioScannerSystems`",
"create table `rdioScannerCalls2` (`id` integer primary key auto_increment, `audio` longblob not null, `audioName` varchar(255), `audioType` varchar(255), `dateTime` datetime not null, `frequencies` json not null default '[]', `frequency` integer, `source` integer, `sources` json not null default '[]', `system` integer not null, `talkgroup` integer not null)", "create table `rdioScannerCalls2` (`id` integer primary key auto_increment, `audio` longblob not null, `audioName` varchar(255), `audioType` varchar(255), `dateTime` datetime not null, `frequencies` json not null, `frequency` integer, `source` integer, `sources` json not null, `system` integer not null, `talkgroup` integer not null)",
"insert into `rdioScannerCalls2` select `id`, `audio`, `audioName`, `audioType`, `startTime`, `freqList`, `freq`, null, `srcList`, `system`, `talkgroup` from `rdioScannerCalls`", "insert into `rdioScannerCalls2` select `id`, `audio`, `audioName`, `audioType`, `startTime`, `freqList`, `freq`, null, `srcList`, `system`, `talkgroup` from `rdioScannerCalls`",
"drop table `rdioScannerCalls`", "drop table `rdioScannerCalls`",
"alter table `rdioScannerCalls2` rename to `rdioScannerCalls`", "alter table `rdioScannerCalls2` rename to `rdioScannerCalls`",

View file

@ -29,6 +29,7 @@ import (
"sort" "sort"
"strconv" "strconv"
"strings" "strings"
"sync"
"time" "time"
"github.com/fsnotify/fsnotify" "github.com/fsnotify/fsnotify"
@ -161,16 +162,16 @@ func (dirwatch *Dirwatch) ingestDefault(p string) error {
} }
if strings.EqualFold(path.Ext(p), ext) { if strings.EqualFold(path.Ext(p), ext) {
call := Call{ call := NewCall()
AudioName: path.Base(p),
AudioType: mime.TypeByExtension(path.Ext(p)), call.AudioName = path.Base(p)
} call.AudioType = mime.TypeByExtension(path.Ext(p))
if call.Audio, err = os.ReadFile(p); err != nil { if call.Audio, err = os.ReadFile(p); err != nil {
return err return err
} }
dirwatch.parseMask(&call) dirwatch.parseMask(call)
switch v := dirwatch.SystemId.(type) { switch v := dirwatch.SystemId.(type) {
case uint: case uint:
@ -183,7 +184,7 @@ func (dirwatch *Dirwatch) ingestDefault(p string) error {
} }
if call.IsValid() { if call.IsValid() {
dirwatch.controller.Ingest <- &call dirwatch.controller.Ingest <- call
if dirwatch.DeleteAfter { if dirwatch.DeleteAfter {
if err = os.Remove(p); err != nil { if err = os.Remove(p); err != nil {
@ -217,23 +218,23 @@ func (dirwatch *Dirwatch) ingestSdrTrunk(p string) error {
return nil return nil
} }
call := Call{ call := NewCall()
AudioName: path.Base(p),
AudioType: mime.TypeByExtension(path.Ext(p)), call.AudioName = path.Base(p)
} call.AudioType = mime.TypeByExtension(path.Ext(p))
if call.Audio, err = os.ReadFile(p); err != nil { if call.Audio, err = os.ReadFile(p); err != nil {
fmt.Println("err1") fmt.Println("err1")
return err return err
} }
if err = ParseSdrTrunkMeta(&call, dirwatch.controller); err != nil { if err = ParseSdrTrunkMeta(call, dirwatch.controller); err != nil {
fmt.Println("err2") fmt.Println("err2")
return err return err
} }
if call.IsValid() { if call.IsValid() {
dirwatch.controller.Ingest <- &call dirwatch.controller.Ingest <- call
if dirwatch.DeleteAfter { if dirwatch.DeleteAfter {
if err = os.Remove(p); err != nil { if err = os.Remove(p); err != nil {
@ -272,10 +273,10 @@ func (dirwatch *Dirwatch) ingestTrunkRecorder(p string) error {
audioName := base + ext audioName := base + ext
call := Call{ call := NewCall()
AudioName: path.Base(audioName),
AudioType: mime.TypeByExtension(path.Ext(audioName)), call.AudioName = path.Base(audioName)
} call.AudioType = mime.TypeByExtension(path.Ext(audioName))
switch v := dirwatch.SystemId.(type) { switch v := dirwatch.SystemId.(type) {
case uint: case uint:
@ -290,12 +291,12 @@ func (dirwatch *Dirwatch) ingestTrunkRecorder(p string) error {
return err return err
} }
if err = ParseTrunkRecorderMeta(&call, b); err != nil { if err = ParseTrunkRecorderMeta(call, b); err != nil {
return err return err
} }
if call.IsValid() { if call.IsValid() {
dirwatch.controller.Ingest <- &call dirwatch.controller.Ingest <- call
} }
if dirwatch.DeleteAfter { if dirwatch.DeleteAfter {
@ -428,7 +429,10 @@ func (dirwatch *Dirwatch) parseMask(call *Call) {
switch v := metaval["unit"].(type) { switch v := metaval["unit"].(type) {
case string: case string:
if i, err := strconv.Atoi(v); err == nil { if i, err := strconv.Atoi(v); err == nil {
call.Sources = map[string]interface{}{"pos": 0, "src": uint(i)} switch sources := call.Sources.(type) {
case []map[string]interface{}:
call.Sources = append(sources, map[string]interface{}{"pos": 0, "src": uint(i)})
}
} }
} }
} }
@ -530,19 +534,22 @@ func (dirwatch *Dirwatch) Stop() {
} }
} }
type Dirwatches []Dirwatch type Dirwatches struct {
List []*Dirwatch
mutex sync.Mutex
}
func (dirwatches *Dirwatches) FromMap(f []interface{}) { func (dirwatches *Dirwatches) FromMap(f []interface{}) {
dirwatches.Stop() dirwatches.Stop()
*dirwatches = Dirwatches{} dirwatches.List = []*Dirwatch{}
for _, f := range f { for _, f := range f {
switch v := f.(type) { switch v := f.(type) {
case map[string]interface{}: case map[string]interface{}:
dirwatch := Dirwatch{} dirwatch := &Dirwatch{}
dirwatch.FromMap(v) dirwatch.FromMap(v)
*dirwatches = append(*dirwatches, dirwatch) dirwatches.List = append(dirwatches.List, dirwatch)
} }
} }
} }
@ -575,7 +582,7 @@ func (dirwatches *Dirwatches) Read(db *Database) error {
} }
for rows.Next() { for rows.Next() {
dirwatch := Dirwatch{} dirwatch := &Dirwatch{}
if err = rows.Scan(&id, &delay, &dirwatch.DeleteAfter, &dirwatch.Directory, &dirwatch.Disabled, &extension, &frequency, &mask, &order, &systemId, &talkgroupId, &kind, &dirwatch.UsePolling); err != nil { if err = rows.Scan(&id, &delay, &dirwatch.DeleteAfter, &dirwatch.Directory, &dirwatch.Disabled, &extension, &frequency, &mask, &order, &systemId, &talkgroupId, &kind, &dirwatch.UsePolling); err != nil {
break break
@ -617,7 +624,7 @@ func (dirwatches *Dirwatches) Read(db *Database) error {
dirwatch.Kind = kind.String dirwatch.Kind = kind.String
} }
*dirwatches = append(*dirwatches, dirwatch) dirwatches.List = append(dirwatches.List, dirwatch)
} }
rows.Close() rows.Close()
@ -630,8 +637,8 @@ func (dirwatches *Dirwatches) Read(db *Database) error {
} }
func (dirwatches *Dirwatches) Start(controller *Controller) { func (dirwatches *Dirwatches) Start(controller *Controller) {
for i := range *dirwatches { for i := range dirwatches.List {
if err := (*dirwatches)[i].Start(controller); err != nil { if err := dirwatches.List[i].Start(controller); err != nil {
LogEvent( LogEvent(
controller.Database, controller.Database,
LogLevelError, LogLevelError,
@ -642,8 +649,8 @@ func (dirwatches *Dirwatches) Start(controller *Controller) {
} }
func (dirwatches *Dirwatches) Stop() { func (dirwatches *Dirwatches) Stop() {
for i := range *dirwatches { for i := range dirwatches.List {
(*dirwatches)[i].Stop() dirwatches.List[i].Stop()
} }
} }
@ -655,11 +662,13 @@ func (dirwatches *Dirwatches) Write(db *Database) error {
rowIds = []uint{} rowIds = []uint{}
) )
dirwatches.mutex.Lock()
formatError := func(err error) error { formatError := func(err error) error {
return fmt.Errorf("dirwatches.write: %v", err) return fmt.Errorf("dirwatches.write: %v", err)
} }
for _, dirwatch := range *dirwatches { for _, dirwatch := range dirwatches.List {
if err = db.Sql.QueryRow("select count(*) from `rdioScannerDirWatches` where `_id` = ?", dirwatch.Id).Scan(&count); err != nil { if err = db.Sql.QueryRow("select count(*) from `rdioScannerDirWatches` where `_id` = ?", dirwatch.Id).Scan(&count); err != nil {
break break
} }
@ -686,7 +695,7 @@ func (dirwatches *Dirwatches) Write(db *Database) error {
var rowId uint var rowId uint
rows.Scan(&rowId) rows.Scan(&rowId)
remove := true remove := true
for _, dirwatch := range *dirwatches { for _, dirwatch := range dirwatches.List {
if dirwatch.Id == nil || dirwatch.Id == rowId { if dirwatch.Id == nil || dirwatch.Id == rowId {
remove = false remove = false
break break
@ -715,6 +724,8 @@ func (dirwatches *Dirwatches) Write(db *Database) error {
} }
} }
dirwatches.mutex.Unlock()
return nil return nil
} }

View file

@ -25,6 +25,7 @@ import (
"net/url" "net/url"
"path" "path"
"strings" "strings"
"sync"
"time" "time"
"github.com/google/uuid" "github.com/google/uuid"
@ -321,7 +322,10 @@ func (downstream *Downstream) Send(call *Call) error {
return nil return nil
} }
type Downstreams []Downstream type Downstreams struct {
List []*Downstream
mutex sync.Mutex
}
func (downstreams *Downstreams) FromMap(f []interface{}) { func (downstreams *Downstreams) FromMap(f []interface{}) {
*downstreams = Downstreams{} *downstreams = Downstreams{}
@ -329,9 +333,9 @@ func (downstreams *Downstreams) FromMap(f []interface{}) {
for _, r := range f { for _, r := range f {
switch m := r.(type) { switch m := r.(type) {
case map[string]interface{}: case map[string]interface{}:
downstream := Downstream{} downstream := &Downstream{}
downstream.FromMap(m) downstream.FromMap(m)
*downstreams = append(*downstreams, downstream) downstreams.List = append(downstreams.List, downstream)
} }
} }
} }
@ -344,7 +348,7 @@ func (downstreams *Downstreams) Read(db *Database) error {
rows *sql.Rows rows *sql.Rows
) )
*downstreams = Downstreams{} downstreams.List = []*Downstream{}
formatError := func(err error) error { formatError := func(err error) error {
return fmt.Errorf("downstreams.read: %v", err) return fmt.Errorf("downstreams.read: %v", err)
@ -355,7 +359,7 @@ func (downstreams *Downstreams) Read(db *Database) error {
} }
for rows.Next() { for rows.Next() {
downstream := Downstream{} downstream := &Downstream{}
if err = rows.Scan(&id, &downstream.Apikey, &downstream.Disabled, &order, &downstream.Systems, &downstream.Url); err != nil { if err = rows.Scan(&id, &downstream.Apikey, &downstream.Disabled, &order, &downstream.Systems, &downstream.Url); err != nil {
break break
@ -382,7 +386,7 @@ func (downstreams *Downstreams) Read(db *Database) error {
continue continue
} }
*downstreams = append(*downstreams, downstream) downstreams.List = append(downstreams.List, downstream)
} }
rows.Close() rows.Close()
@ -395,7 +399,7 @@ func (downstreams *Downstreams) Read(db *Database) error {
} }
func (downstreams *Downstreams) Send(controller *Controller, call *Call) { func (downstreams *Downstreams) Send(controller *Controller, call *Call) {
for _, downstream := range *downstreams { for _, downstream := range downstreams.List {
logEvent := func(logLevel string, message string) { logEvent := func(logLevel string, message string) {
LogEvent( LogEvent(
controller.Database, controller.Database,
@ -423,11 +427,13 @@ func (downstreams *Downstreams) Write(db *Database) error {
systems interface{} systems interface{}
) )
downstreams.mutex.Lock()
formatError := func(err error) error { formatError := func(err error) error {
return fmt.Errorf("downstreams.write: %v", err) return fmt.Errorf("downstreams.write: %v", err)
} }
for _, downstream := range *downstreams { for _, downstream := range downstreams.List {
switch downstream.Systems { switch downstream.Systems {
case "*": case "*":
systems = `"*"` systems = `"*"`
@ -461,7 +467,7 @@ func (downstreams *Downstreams) Write(db *Database) error {
var rowId uint var rowId uint
rows.Scan(&rowId) rows.Scan(&rowId)
remove := true remove := true
for _, downstream := range *downstreams { for _, downstream := range downstreams.List {
if downstream.Id == nil || downstream.Id == rowId { if downstream.Id == nil || downstream.Id == rowId {
remove = false remove = false
break break
@ -490,5 +496,7 @@ func (downstreams *Downstreams) Write(db *Database) error {
} }
} }
downstreams.mutex.Unlock()
return nil return nil
} }

View file

@ -9,10 +9,10 @@ require (
github.com/golang-jwt/jwt/v4 v4.2.0 github.com/golang-jwt/jwt/v4 v4.2.0
github.com/google/uuid v1.3.0 github.com/google/uuid v1.3.0
github.com/gorilla/websocket v1.4.2 github.com/gorilla/websocket v1.4.2
github.com/kardianos/service v1.2.0 github.com/kardianos/service v1.2.1
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3
gopkg.in/ini.v1 v1.66.2 gopkg.in/ini.v1 v1.66.2
modernc.org/sqlite v1.14.3 modernc.org/sqlite v1.14.4
) )
require ( require (
@ -21,8 +21,8 @@ require (
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect
github.com/stretchr/testify v1.7.0 // indirect github.com/stretchr/testify v1.7.0 // indirect
golang.org/x/mod v0.5.1 // indirect golang.org/x/mod v0.5.1 // indirect
golang.org/x/net v0.0.0-20220105145211-5b0dc2dfae98 // indirect golang.org/x/net v0.0.0-20220111093109-d55c255bac03 // indirect
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect golang.org/x/sys v0.0.0-20220111092808-5a964db01320 // indirect
golang.org/x/text v0.3.7 // indirect golang.org/x/text v0.3.7 // indirect
golang.org/x/tools v0.1.8 // indirect golang.org/x/tools v0.1.8 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect

View file

@ -16,15 +16,15 @@ github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/kardianos/service v1.2.0 h1:bGuZ/epo3vrt8IPC7mnKQolqFeYJb7Cs8Rk4PSOBB/g= github.com/kardianos/service v1.2.1 h1:AYndMsehS+ywIS6RB9KOlcXzteWUzxgMgBymJD7+BYk=
github.com/kardianos/service v1.2.0/go.mod h1:CIMRFEJVL+0DS1a3Nx06NaMn4Dz63Ng6O7dl0qH0zVM= github.com/kardianos/service v1.2.1/go.mod h1:CIMRFEJVL+0DS1a3Nx06NaMn4Dz63Ng6O7dl0qH0zVM=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-sqlite3 v1.14.9 h1:10HX2Td0ocZpYEjhilsuo6WWtUqttj2Kb0KtD86/KYA= github.com/mattn/go-sqlite3 v1.14.10 h1:MLn+5bFRlWMGoSRmJour3CL1w/qL96mvipqpwQW/Sfk=
github.com/mattn/go-sqlite3 v1.14.9/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/go-sqlite3 v1.14.10/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk= github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk=
@ -47,8 +47,8 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220105145211-5b0dc2dfae98 h1:+6WJMRLHlD7X7frgp7TUZ36RnQzSf9wVVTNakEp+nqY= golang.org/x/net v0.0.0-20220111093109-d55c255bac03 h1:0FB83qp0AzVJm+0wcIlauAjJ+tNdh7jLuacRYCIVv7s=
golang.org/x/net v0.0.0-20220105145211-5b0dc2dfae98/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220111093109-d55c255bac03/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -65,8 +65,8 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20210902050250-f475640dd07b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210902050250-f475640dd07b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM= golang.org/x/sys v0.0.0-20220111092808-5a964db01320 h1:0jf+tOCoZ3LyutmCOWpVni1chK4VfFLhRsDK7MhqGRY=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220111092808-5a964db01320/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
@ -142,10 +142,8 @@ modernc.org/ccgo/v3 v3.12.73/go.mod h1:hngkB+nUUqzOf3iqsM48Gf1FZhY599qzVg1iX+BT3
modernc.org/ccgo/v3 v3.12.81/go.mod h1:p2A1duHoBBg1mFtYvnhAnQyI6vL0uw5PGYLSIgF6rYY= modernc.org/ccgo/v3 v3.12.81/go.mod h1:p2A1duHoBBg1mFtYvnhAnQyI6vL0uw5PGYLSIgF6rYY=
modernc.org/ccgo/v3 v3.12.84/go.mod h1:ApbflUfa5BKadjHynCficldU1ghjen84tuM5jRynB7w= modernc.org/ccgo/v3 v3.12.84/go.mod h1:ApbflUfa5BKadjHynCficldU1ghjen84tuM5jRynB7w=
modernc.org/ccgo/v3 v3.12.86/go.mod h1:dN7S26DLTgVSni1PVA3KxxHTcykyDurf3OgUzNqTSrU= modernc.org/ccgo/v3 v3.12.86/go.mod h1:dN7S26DLTgVSni1PVA3KxxHTcykyDurf3OgUzNqTSrU=
modernc.org/ccgo/v3 v3.12.88/go.mod h1:0MFzUHIuSIthpVZyMWiFYMwjiFnhrN5MkvBrUwON+ZM=
modernc.org/ccgo/v3 v3.12.90/go.mod h1:obhSc3CdivCRpYZmrvO88TXlW0NvoSVvdh/ccRjJYko= modernc.org/ccgo/v3 v3.12.90/go.mod h1:obhSc3CdivCRpYZmrvO88TXlW0NvoSVvdh/ccRjJYko=
modernc.org/ccgo/v3 v3.12.92/go.mod h1:5yDdN7ti9KWPi5bRVWPl8UNhpEAtCjuEE7ayQnzzqHA= modernc.org/ccgo/v3 v3.12.92/go.mod h1:5yDdN7ti9KWPi5bRVWPl8UNhpEAtCjuEE7ayQnzzqHA=
modernc.org/ccgo/v3 v3.12.95/go.mod h1:ZcLyvtocXYi8uF+9Ebm3G8EF8HNY5hGomBqthDp4eC8=
modernc.org/ccgo/v3 v3.13.1/go.mod h1:aBYVOUfIlcSnrsRVU8VRS35y2DIfpgkmVkYZ0tpIXi4= modernc.org/ccgo/v3 v3.13.1/go.mod h1:aBYVOUfIlcSnrsRVU8VRS35y2DIfpgkmVkYZ0tpIXi4=
modernc.org/ccgo/v3 v3.14.0 h1:Zr1Ny9+7r5yAiXpBdgp8XiXqkNA4ARrRphHGHVXeAp0= modernc.org/ccgo/v3 v3.14.0 h1:Zr1Ny9+7r5yAiXpBdgp8XiXqkNA4ARrRphHGHVXeAp0=
modernc.org/ccgo/v3 v3.14.0/go.mod h1:hBrkiBlUwvr5vV/ZH9YzXIp982jKE8Ek8tR1ytoAL6Q= modernc.org/ccgo/v3 v3.14.0/go.mod h1:hBrkiBlUwvr5vV/ZH9YzXIp982jKE8Ek8tR1ytoAL6Q=
@ -188,11 +186,8 @@ modernc.org/libc v1.11.82/go.mod h1:NF+Ek1BOl2jeC7lw3a7Jj5PWyHPwWD4aq3wVKxqV1fI=
modernc.org/libc v1.11.86/go.mod h1:ePuYgoQLmvxdNT06RpGnaDKJmDNEkV7ZPKI2jnsvZoE= modernc.org/libc v1.11.86/go.mod h1:ePuYgoQLmvxdNT06RpGnaDKJmDNEkV7ZPKI2jnsvZoE=
modernc.org/libc v1.11.87/go.mod h1:Qvd5iXTeLhI5PS0XSyqMY99282y+3euapQFxM7jYnpY= modernc.org/libc v1.11.87/go.mod h1:Qvd5iXTeLhI5PS0XSyqMY99282y+3euapQFxM7jYnpY=
modernc.org/libc v1.11.88/go.mod h1:h3oIVe8dxmTcchcFuCcJ4nAWaoiwzKCdv82MM0oiIdQ= modernc.org/libc v1.11.88/go.mod h1:h3oIVe8dxmTcchcFuCcJ4nAWaoiwzKCdv82MM0oiIdQ=
modernc.org/libc v1.11.90/go.mod h1:ynK5sbjsU77AP+nn61+k+wxUGRx9rOFcIqWYYMaDZ4c=
modernc.org/libc v1.11.98/go.mod h1:ynK5sbjsU77AP+nn61+k+wxUGRx9rOFcIqWYYMaDZ4c= modernc.org/libc v1.11.98/go.mod h1:ynK5sbjsU77AP+nn61+k+wxUGRx9rOFcIqWYYMaDZ4c=
modernc.org/libc v1.11.99/go.mod h1:wLLYgEiY2D17NbBOEp+mIJJJBGSiy7fLL4ZrGGZ+8jI=
modernc.org/libc v1.11.101/go.mod h1:wLLYgEiY2D17NbBOEp+mIJJJBGSiy7fLL4ZrGGZ+8jI= modernc.org/libc v1.11.101/go.mod h1:wLLYgEiY2D17NbBOEp+mIJJJBGSiy7fLL4ZrGGZ+8jI=
modernc.org/libc v1.11.104/go.mod h1:2MH3DaF/gCU8i/UBiVE1VFRos4o523M7zipmwH8SIgQ=
modernc.org/libc v1.12.0/go.mod h1:2MH3DaF/gCU8i/UBiVE1VFRos4o523M7zipmwH8SIgQ= modernc.org/libc v1.12.0/go.mod h1:2MH3DaF/gCU8i/UBiVE1VFRos4o523M7zipmwH8SIgQ=
modernc.org/libc v1.13.1/go.mod h1:npFeGWjmZTjFeWALQLrvklVmAxv4m80jnG3+xI8FdJk= modernc.org/libc v1.13.1/go.mod h1:npFeGWjmZTjFeWALQLrvklVmAxv4m80jnG3+xI8FdJk=
modernc.org/libc v1.13.2 h1:GCFjY9bmwDZ/TJC4OZOUWaNgxIxwb104C/QZrqpcVEA= modernc.org/libc v1.13.2 h1:GCFjY9bmwDZ/TJC4OZOUWaNgxIxwb104C/QZrqpcVEA=
@ -207,13 +202,13 @@ modernc.org/memory v1.0.5 h1:XRch8trV7GgvTec2i7jc33YlUI0RKVDBvZ5eZ5m8y14=
modernc.org/memory v1.0.5/go.mod h1:B7OYswTRnfGg+4tDH1t1OeUNnsy2viGTdME4tzd+IjM= modernc.org/memory v1.0.5/go.mod h1:B7OYswTRnfGg+4tDH1t1OeUNnsy2viGTdME4tzd+IjM=
modernc.org/opt v0.1.1 h1:/0RX92k9vwVeDXj+Xn23DKp2VJubL7k8qNffND6qn3A= modernc.org/opt v0.1.1 h1:/0RX92k9vwVeDXj+Xn23DKp2VJubL7k8qNffND6qn3A=
modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
modernc.org/sqlite v1.14.3 h1:psrTwgpEujgWEP3FNdsC9yNh5tSeA77U0GeWhHH4XmQ= modernc.org/sqlite v1.14.4 h1:F3DRiVZKnCLqIQ0LhEGqBLnw9LcdADciCwCIHQ8bD5g=
modernc.org/sqlite v1.14.3/go.mod h1:xMpicS1i2MJ4C8+Ap0vYBqTwYfpFvdnPE6brbFOtV2Y= modernc.org/sqlite v1.14.4/go.mod h1:LWtcO8JtBrt29KKmTqNNXDjAn36vHa/3nHvOYoVIAjc=
modernc.org/strutil v1.1.1 h1:xv+J1BXY3Opl2ALrBwyfEikFAj8pmqcpnfmuwUwcozs= modernc.org/strutil v1.1.1 h1:xv+J1BXY3Opl2ALrBwyfEikFAj8pmqcpnfmuwUwcozs=
modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw= modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw=
modernc.org/tcl v1.9.2 h1:YA87dFLOsR2KqMka371a2Xgr+YsyUwo7OmHVSv/kztw= modernc.org/tcl v1.10.0 h1:vux2MNFhSXYqD8Kq4Uc9RjWcgv2c7Atx3da3VpLPPEw=
modernc.org/tcl v1.9.2/go.mod h1:aw7OnlIoiuJgu1gwbTZtrKnGpDqH9wyH++jZcxdqNsg= modernc.org/tcl v1.10.0/go.mod h1:WzWapmP/7dHVhFoyPpEaNSVTL8xtewhouN/cqSJ5A2s=
modernc.org/token v1.0.0 h1:a0jaWiNMDhDUtqOj09wvjWWAqd3q7WpBulmL9H2egsk= modernc.org/token v1.0.0 h1:a0jaWiNMDhDUtqOj09wvjWWAqd3q7WpBulmL9H2egsk=
modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
modernc.org/z v1.2.20 h1:DyboxM1sJR2NB803j2StnbnL6jcQXz273OhHDGu8dGk= modernc.org/z v1.2.21 h1:UO0ptLQLHM2eNistCE6ofm1fMKKXk0n0IkrQly3z5HA=
modernc.org/z v1.2.20/go.mod h1:zU9FiF4PbHdOTUxw+IF8j7ArBMRPsHgq10uVPt6xTzo= modernc.org/z v1.2.21/go.mod h1:uXrObx4pGqXWIMliC5MiKuwAyMrltzwpteOFUP1PWCc=

View file

@ -20,6 +20,7 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"strings" "strings"
"sync"
) )
type Group struct { type Group struct {
@ -39,17 +40,20 @@ func (group *Group) FromMap(m map[string]interface{}) {
} }
} }
type Groups []Group type Groups struct {
List []*Group
mutex sync.Mutex
}
func (groups *Groups) FromMap(f []interface{}) { func (groups *Groups) FromMap(f []interface{}) {
*groups = Groups{} groups.List = []*Group{}
for _, r := range f { for _, r := range f {
switch m := r.(type) { switch m := r.(type) {
case map[string]interface{}: case map[string]interface{}:
group := Group{} group := &Group{}
group.FromMap(m) group.FromMap(m)
*groups = append(*groups, group) groups.List = append(groups.List, group)
} }
} }
} }
@ -57,15 +61,15 @@ func (groups *Groups) FromMap(f []interface{}) {
func (groups *Groups) GetGroup(f interface{}) (group *Group, ok bool) { func (groups *Groups) GetGroup(f interface{}) (group *Group, ok bool) {
switch v := f.(type) { switch v := f.(type) {
case uint: case uint:
for _, group := range *groups { for _, group := range groups.List {
if group.Id == v { if group.Id == v {
return &group, true return group, true
} }
} }
case string: case string:
for _, group := range *groups { for _, group := range groups.List {
if group.Label == v { if group.Label == v {
return &group, true return group, true
} }
} }
} }
@ -147,7 +151,7 @@ func (groups *Groups) Read(db *Database) error {
rows *sql.Rows rows *sql.Rows
) )
*groups = Groups{} groups.List = []*Group{}
formatError := func(err error) error { formatError := func(err error) error {
return fmt.Errorf("groups.read: %v", err) return fmt.Errorf("groups.read: %v", err)
@ -158,7 +162,7 @@ func (groups *Groups) Read(db *Database) error {
} }
for rows.Next() { for rows.Next() {
group := Group{} group := &Group{}
if err = rows.Scan(&id, &group.Label); err != nil { if err = rows.Scan(&id, &group.Label); err != nil {
break break
@ -172,7 +176,7 @@ func (groups *Groups) Read(db *Database) error {
continue continue
} }
*groups = append(*groups, group) groups.List = append(groups.List, group)
} }
rows.Close() rows.Close()
@ -192,11 +196,13 @@ func (groups *Groups) Write(db *Database) error {
rowIds = []uint{} rowIds = []uint{}
) )
groups.mutex.Lock()
formatError := func(err error) error { formatError := func(err error) error {
return fmt.Errorf("groups.write %v", err) return fmt.Errorf("groups.write %v", err)
} }
for _, group := range *groups { for _, group := range groups.List {
if err = db.Sql.QueryRow("select count(*) from `rdioScannerGroups` where `_id` = ?", group.Id).Scan(&count); err != nil { if err = db.Sql.QueryRow("select count(*) from `rdioScannerGroups` where `_id` = ?", group.Id).Scan(&count); err != nil {
break break
} }
@ -223,7 +229,7 @@ func (groups *Groups) Write(db *Database) error {
var rowId uint var rowId uint
rows.Scan(&rowId) rows.Scan(&rowId)
remove := true remove := true
for _, group := range *groups { for _, group := range groups.List {
if group.Id == nil || group.Id == rowId { if group.Id == nil || group.Id == rowId {
remove = false remove = false
break break
@ -251,6 +257,9 @@ func (groups *Groups) Write(db *Database) error {
} }
} }
} }
groups.mutex.Unlock()
return nil return nil
} }

View file

@ -68,7 +68,9 @@ sys:
} }
func (livefeedMap *LivefeedMap) IsEnabled(call *Call) bool { func (livefeedMap *LivefeedMap) IsEnabled(call *Call) bool {
if (*livefeedMap)[call.System][call.Talkgroup] { if livefeedMap == nil {
return false
} else if (*livefeedMap)[call.System][call.Talkgroup] {
return true return true
} else { } else {
switch v := call.Patches.(type) { switch v := call.Patches.(type) {

View file

@ -19,6 +19,7 @@ import (
"database/sql" "database/sql"
"encoding/json" "encoding/json"
"fmt" "fmt"
"sync"
"golang.org/x/crypto/bcrypt" "golang.org/x/crypto/bcrypt"
) )
@ -36,6 +37,7 @@ type Options struct {
TagsToggle bool `json:"tagsToggle"` TagsToggle bool `json:"tagsToggle"`
adminPassword string adminPassword string
adminPasswordNeedChange bool adminPasswordNeedChange bool
mutex sync.Mutex
secret string secret string
} }
@ -136,6 +138,11 @@ func (options *Options) Read(db *Database) error {
err = db.Sql.QueryRow("select `val` from `rdioScannerConfigs` where `key` = 'adminPassword'").Scan(&f) err = db.Sql.QueryRow("select `val` from `rdioScannerConfigs` where `key` = 'adminPassword'").Scan(&f)
if err == nil { if err == nil {
switch v := f.(type) { switch v := f.(type) {
case []uint8:
var f string
if err = json.Unmarshal(v, &f); err == nil {
options.adminPassword = f
}
case string: case string:
var f string var f string
if err = json.Unmarshal([]byte(v), &f); err == nil { if err = json.Unmarshal([]byte(v), &f); err == nil {
@ -147,6 +154,11 @@ func (options *Options) Read(db *Database) error {
err = db.Sql.QueryRow("select `val` from `rdioScannerConfigs` where `key` = 'adminPasswordNeedChange'").Scan(&f) err = db.Sql.QueryRow("select `val` from `rdioScannerConfigs` where `key` = 'adminPasswordNeedChange'").Scan(&f)
if err == nil { if err == nil {
switch v := f.(type) { switch v := f.(type) {
case []uint8:
var f bool
if err = json.Unmarshal(v, &f); err == nil {
options.adminPasswordNeedChange = f
}
case string: case string:
var f bool var f bool
if err = json.Unmarshal([]byte(v), &f); err == nil { if err = json.Unmarshal([]byte(v), &f); err == nil {
@ -238,6 +250,8 @@ func (options *Options) Write(db *Database) error {
res sql.Result res sql.Result
) )
options.mutex.Lock()
formatError := func(err error) error { formatError := func(err error) error {
return fmt.Errorf("options.write: %v", err) return fmt.Errorf("options.write: %v", err)
} }
@ -289,5 +303,7 @@ func (options *Options) Write(db *Database) error {
db.Sql.Exec("insert into `rdioScannerConfigs` (`key`, `val`) values (?, ?)", "options", string(b)) db.Sql.Exec("insert into `rdioScannerConfigs` (`key`, `val`) values (?, ?)", "options", string(b))
} }
options.mutex.Unlock()
return nil return nil
} }

View file

@ -18,6 +18,9 @@ package main
import ( import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"mime"
"mime/multipart"
"path"
"regexp" "regexp"
"strconv" "strconv"
"strings" "strings"
@ -111,6 +114,166 @@ func ParseSdrTrunkMeta(call *Call, controller *Controller) error {
return nil return nil
} }
func ParseMultipartContent(call *Call, p *multipart.Part, b []byte) {
switch p.FormName() {
case "audio":
call.Audio = b
call.AudioName = p.FileName()
case "audioName":
call.AudioName = string(b)
call.AudioType = mime.TypeByExtension(path.Ext(string(b)))
case "dateTime":
if regexp.MustCompile(`^[0-9]+$`).Match(b) {
if i, err := strconv.Atoi(string(b)); err == nil {
call.DateTime = time.Unix(int64(i), 0).UTC()
}
} else {
call.DateTime, _ = time.Parse(time.RFC3339, string(b))
call.DateTime = call.DateTime.UTC()
}
case "frequencies":
var f interface{}
if err := json.Unmarshal(b, &f); err == nil {
switch v := f.(type) {
case []interface{}:
var frequencies = []map[string]interface{}{}
for _, f := range v {
freq := map[string]interface{}{}
switch v := f.(type) {
case map[string]interface{}:
switch v := v["errorCount"].(type) {
case float64:
freq["errorCount"] = uint(v)
}
switch v := v["freq"].(type) {
case float64:
freq["freq"] = uint(v)
}
switch v := v["len"].(type) {
case float64:
freq["len"] = uint(v)
}
switch v := v["pos"].(type) {
case float64:
freq["pos"] = uint(v)
}
switch v := v["spikeCount"].(type) {
case float64:
freq["spikeCount"] = uint(v)
}
}
frequencies = append(frequencies, freq)
}
call.Frequencies = frequencies
}
}
case "frequency":
if i, err := strconv.Atoi(string(b)); err == nil {
call.Frequency = uint(i)
}
case "patches", "patched_talkgroups":
var (
f interface{}
patches = []uint{}
)
if err := json.Unmarshal(b, &f); err == nil {
switch v := f.(type) {
case []interface{}:
for _, patch := range v {
switch v := patch.(type) {
case float64:
if v > 0 {
patches = append(patches, uint(v))
}
}
}
}
call.Patches = patches
}
case "source":
if i, err := strconv.Atoi(string(b)); err == nil {
call.Source = int(i)
}
case "sources":
var (
f interface{}
units interface{}
)
if err := json.Unmarshal(b, &f); err == nil {
switch v := f.(type) {
case []interface{}:
var sources = []map[string]interface{}{}
for _, f := range v {
src := map[string]interface{}{}
switch v := f.(type) {
case map[string]interface{}:
switch v := v["pos"].(type) {
case float64:
src["pos"] = uint(v)
}
switch s := v["src"].(type) {
case float64:
if s > 0 {
src["src"] = uint(s)
switch t := v["tag"].(type) {
case string:
var u Units
switch v := units.(type) {
case Units:
u = v
default:
u = Units{}
}
u.Add(int(s), t)
units = u
}
}
}
}
sources = append(sources, src)
}
call.Sources = sources
call.units = units
}
}
case "system", "systemId":
if i, err := strconv.Atoi(string(b)); err == nil {
call.System = uint(i)
}
case "systemLabel":
call.systemLabel = string(b)
case "talkgroup", "talkgroupId":
if i, err := strconv.Atoi(string(b)); err == nil {
call.Talkgroup = uint(i)
}
case "talkgroupGroup":
if s := string(b); len(s) > 1 {
call.talkgroupGroup = s
}
case "talkgroupLabel":
if s := string(b); len(s) > 1 {
call.talkgroupLabel = s
}
case "talkgroupTag":
if s := string(b); len(s) > 1 {
call.talkgroupTag = s
}
}
}
func ParseTrunkRecorderMeta(call *Call, b []byte) error { func ParseTrunkRecorderMeta(call *Call, b []byte) error {
m := map[string]interface{}{} m := map[string]interface{}{}

View file

@ -22,6 +22,7 @@ import (
"sort" "sort"
"strconv" "strconv"
"strings" "strings"
"sync"
) )
type System struct { type System struct {
@ -85,17 +86,20 @@ func (system *System) FromMap(m map[string]interface{}) {
type SystemMap map[string]interface{} type SystemMap map[string]interface{}
type Systems []*System type Systems struct {
List []*System
mutex sync.Mutex
}
func (systems *Systems) FromMap(f []interface{}) { func (systems *Systems) FromMap(f []interface{}) {
*systems = Systems{} systems.List = []*System{}
for _, r := range f { for _, r := range f {
switch m := r.(type) { switch m := r.(type) {
case map[string]interface{}: case map[string]interface{}:
system := &System{} system := &System{}
system.FromMap(m) system.FromMap(m)
*systems = append(*systems, system) systems.List = append(systems.List, system)
} }
} }
} }
@ -103,7 +107,7 @@ func (systems *Systems) FromMap(f []interface{}) {
func (systems *Systems) GetNewSystemId() uint { func (systems *Systems) GetNewSystemId() uint {
NextId: NextId:
for i := uint(1); i < 65535; i++ { for i := uint(1); i < 65535; i++ {
for _, s := range *systems { for _, s := range systems.List {
if s.Id == i { if s.Id == i {
continue NextId continue NextId
} }
@ -116,13 +120,13 @@ NextId:
func (systems *Systems) GetSystem(f interface{}) (system *System, ok bool) { func (systems *Systems) GetSystem(f interface{}) (system *System, ok bool) {
switch v := f.(type) { switch v := f.(type) {
case uint: case uint:
for _, system := range *systems { for _, system := range systems.List {
if system.Id == v { if system.Id == v {
return system, true return system, true
} }
} }
case string: case string:
for _, system := range *systems { for _, system := range systems.List {
if system.Label == v { if system.Label == v {
return system, true return system, true
} }
@ -133,21 +137,21 @@ func (systems *Systems) GetSystem(f interface{}) (system *System, ok bool) {
func (systems *Systems) GetScopedSystems(client *Client, groups *Groups, tags *Tags, sortTalkgroups bool) *SystemsMap { func (systems *Systems) GetScopedSystems(client *Client, groups *Groups, tags *Tags, sortTalkgroups bool) *SystemsMap {
var ( var (
rawSystems = Systems{} rawSystems = []*System{}
systemsMap = SystemsMap{} systemsMap = SystemsMap{}
) )
if client.Access == nil { if client.Access == nil {
rawSystems = append(rawSystems, *systems...) rawSystems = append(rawSystems, systems.List...)
} else { } else {
switch v := client.Access.Systems.(type) { switch v := client.Access.Systems.(type) {
case nil: case nil:
rawSystems = append(rawSystems, *systems...) rawSystems = append(rawSystems, systems.List...)
case string: case string:
if v == "*" { if v == "*" {
rawSystems = append(rawSystems, *systems...) rawSystems = append(rawSystems, systems.List...)
} }
case []interface{}: case []interface{}:
@ -338,7 +342,7 @@ func (systems *Systems) Read(db *Database) error {
return err return err
} }
*systems = append(*systems, system) systems.List = append(systems.List, system)
} }
rows.Close() rows.Close()
@ -347,8 +351,8 @@ func (systems *Systems) Read(db *Database) error {
return formatError(err) return formatError(err)
} }
sort.Slice(*systems, func(i int, j int) bool { sort.Slice(systems.List, func(i int, j int) bool {
return (*systems)[i].Order < (*systems)[j].Order return systems.List[i].Order < systems.List[j].Order
}) })
return nil return nil
@ -364,11 +368,13 @@ func (systems *Systems) Write(db *Database) error {
systemIds = []uint{} systemIds = []uint{}
) )
systems.mutex.Lock()
formatError := func(err error) error { formatError := func(err error) error {
return fmt.Errorf("systems.write: %v", err) return fmt.Errorf("systems.write: %v", err)
} }
for _, system := range *systems { for _, system := range systems.List {
if len(system.Blacklists) > 0 { if len(system.Blacklists) > 0 {
blacklists = strings.Join([]string{"[", system.Blacklists.String(), "]"}, "") blacklists = strings.Join([]string{"[", system.Blacklists.String(), "]"}, "")
} else { } else {
@ -410,7 +416,7 @@ func (systems *Systems) Write(db *Database) error {
var systemId uint var systemId uint
rows.Scan(&rowId, &systemId) rows.Scan(&rowId, &systemId)
remove := true remove := true
for _, system := range *systems { for _, system := range systems.List {
if system.RowId == nil || system.RowId == rowId { if system.RowId == nil || system.RowId == rowId {
remove = false remove = false
break break
@ -456,6 +462,8 @@ func (systems *Systems) Write(db *Database) error {
} }
} }
systems.mutex.Unlock()
return nil return nil
} }

View file

@ -20,6 +20,7 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"strings" "strings"
"sync"
) )
type Tag struct { type Tag struct {
@ -39,17 +40,20 @@ func (tag *Tag) FromMap(m map[string]interface{}) {
} }
} }
type Tags []Tag type Tags struct {
List []*Tag
mutex sync.Mutex
}
func (tags *Tags) FromMap(f []interface{}) { func (tags *Tags) FromMap(f []interface{}) {
*tags = Tags{} tags.List = []*Tag{}
for _, r := range f { for _, r := range f {
switch m := r.(type) { switch m := r.(type) {
case map[string]interface{}: case map[string]interface{}:
tag := Tag{} tag := &Tag{}
tag.FromMap(m) tag.FromMap(m)
*tags = append(*tags, tag) tags.List = append(tags.List, tag)
} }
} }
} }
@ -57,15 +61,15 @@ func (tags *Tags) FromMap(f []interface{}) {
func (tags *Tags) GetTag(f interface{}) (tag *Tag, ok bool) { func (tags *Tags) GetTag(f interface{}) (tag *Tag, ok bool) {
switch v := f.(type) { switch v := f.(type) {
case uint: case uint:
for _, tag := range *tags { for _, tag := range tags.List {
if tag.Id == v { if tag.Id == v {
return &tag, true return tag, true
} }
} }
case string: case string:
for _, tag := range *tags { for _, tag := range tags.List {
if tag.Label == v { if tag.Label == v {
return &tag, true return tag, true
} }
} }
} }
@ -147,7 +151,7 @@ func (tags *Tags) Read(db *Database) error {
rows *sql.Rows rows *sql.Rows
) )
*tags = Tags{} tags.List = []*Tag{}
formatError := func(err error) error { formatError := func(err error) error {
return fmt.Errorf("tags read: %v", err) return fmt.Errorf("tags read: %v", err)
@ -158,7 +162,7 @@ func (tags *Tags) Read(db *Database) error {
} }
for rows.Next() { for rows.Next() {
tag := Tag{} tag := &Tag{}
if err = rows.Scan(&id, &tag.Label); err != nil { if err = rows.Scan(&id, &tag.Label); err != nil {
break break
@ -168,7 +172,7 @@ func (tags *Tags) Read(db *Database) error {
tag.Id = uint(id.Float64) tag.Id = uint(id.Float64)
} }
*tags = append(*tags, tag) tags.List = append(tags.List, tag)
} }
rows.Close() rows.Close()
@ -188,11 +192,13 @@ func (tags *Tags) Write(db *Database) error {
rowIds = []uint{} rowIds = []uint{}
) )
tags.mutex.Lock()
formatError := func(err error) error { formatError := func(err error) error {
return fmt.Errorf("tags write %v", err) return fmt.Errorf("tags write %v", err)
} }
for _, tag := range *tags { for _, tag := range tags.List {
if err = db.Sql.QueryRow("select count(*) from `rdioScannerTags` where `_id` = ?", tag.Id).Scan(&count); err != nil { if err = db.Sql.QueryRow("select count(*) from `rdioScannerTags` where `_id` = ?", tag.Id).Scan(&count); err != nil {
break break
} }
@ -218,7 +224,7 @@ func (tags *Tags) Write(db *Database) error {
var rowId uint var rowId uint
rows.Scan(&rowId) rows.Scan(&rowId)
remove := true remove := true
for _, tag := range *tags { for _, tag := range tags.List {
if tag.Id == nil || tag.Id == rowId { if tag.Id == nil || tag.Id == rowId {
remove = false remove = false
break break
@ -247,6 +253,8 @@ func (tags *Tags) Write(db *Database) error {
} }
} }
tags.mutex.Unlock()
return nil return nil
} }

View file

@ -15,4 +15,4 @@
package main package main
const Version = "6.1.2" const Version = "6.1.3"