From f6eb4e6dd60205558cc26f5e3f9b1c313ec82efb Mon Sep 17 00:00:00 2001 From: Mathias Wagner Date: Sun, 19 May 2024 15:28:24 +0200 Subject: [PATCH 01/39] Added the cloudflare speedtest dependency to the package.json --- package-lock.json | 258 +++++++++++++++++++++++++++++++++++++++++----- package.json | 1 + 2 files changed, 232 insertions(+), 27 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9e3e316d..93631b98 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,7 @@ "name": "myspeed", "version": "1.0.8", "dependencies": { + "@cloudflare/speedtest": "^1.3.0", "axios": "^1.6.8", "bcrypt": "^5.1.1", "cron-validator": "^1.3.1", @@ -38,6 +39,19 @@ "node": ">=6.9.0" } }, + "node_modules/@cloudflare/speedtest": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@cloudflare/speedtest/-/speedtest-1.3.0.tgz", + "integrity": "sha512-/uXLCVbKcdj/ueD7/StCO/+RC/aTfHo9pBDO9GSD8kRl7oaIdMs9xC4QkPM8EvYGa3OrbVQLXTp/PLNkwt3gNg==", + "dependencies": { + "d3-scale": "^4.0.2", + "isomorphic-fetch": "^3.0.0", + "lodash.memoize": "^4.1.2" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/@gar/promisify": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", @@ -94,25 +108,6 @@ "node": ">=10" } }, - "node_modules/@mapbox/node-pre-gyp/node_modules/node-fetch": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, "node_modules/@mapbox/node-pre-gyp/node_modules/nopt": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", @@ -811,6 +806,81 @@ "resolved": "https://registry.npmjs.org/cron-validator/-/cron-validator-1.3.1.tgz", "integrity": "sha512-C1HsxuPCY/5opR55G5/WNzyEGDWFVG+6GLrA+fW/sCTcP6A6NTjUP2AK7B8n2PyFs90kDG2qzwm8LMheADku6A==" }, + "node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-format": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", + "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "dependencies": { + "d3-time": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/date-fns": { "version": "2.30.0", "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", @@ -1669,6 +1739,14 @@ "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" }, + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "engines": { + "node": ">=12" + } + }, "node_modules/ip": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.1.tgz", @@ -1768,11 +1846,25 @@ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "optional": true }, + "node_modules/isomorphic-fetch": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-3.0.0.tgz", + "integrity": "sha512-qvUtwJ3j6qwsF3jLxkZ72qCgjMysPzDfeV240JHiGZsANBYd+EEuu35v7dfrJ9Up0Ak07D7GGSkGhCHTqg/5wA==", + "dependencies": { + "node-fetch": "^2.6.1", + "whatwg-fetch": "^3.4.1" + } + }, "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==" + }, "node_modules/long": { "version": "5.2.3", "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz", @@ -2145,6 +2237,25 @@ "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.0.0.tgz", "integrity": "sha512-CvkDw2OEnme7ybCykJpVcKH+uAOLV2qLqiyla128dN9TkEWfrYmxG6C2boDe5KcNQqZF3orkqzGgOMvZ/JNekA==" }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, "node_modules/node-gyp": { "version": "8.4.1", "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-8.4.1.tgz", @@ -3462,6 +3573,11 @@ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" }, + "node_modules/whatwg-fetch": { + "version": "3.6.20", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.20.tgz", + "integrity": "sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==" + }, "node_modules/whatwg-url": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", @@ -3593,6 +3709,16 @@ "regenerator-runtime": "^0.13.11" } }, + "@cloudflare/speedtest": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@cloudflare/speedtest/-/speedtest-1.3.0.tgz", + "integrity": "sha512-/uXLCVbKcdj/ueD7/StCO/+RC/aTfHo9pBDO9GSD8kRl7oaIdMs9xC4QkPM8EvYGa3OrbVQLXTp/PLNkwt3gNg==", + "requires": { + "d3-scale": "^4.0.2", + "isomorphic-fetch": "^3.0.0", + "lodash.memoize": "^4.1.2" + } + }, "@gar/promisify": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", @@ -3640,14 +3766,6 @@ "wide-align": "^1.1.2" } }, - "node-fetch": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", - "requires": { - "whatwg-url": "^5.0.0" - } - }, "nopt": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", @@ -4181,6 +4299,60 @@ "resolved": "https://registry.npmjs.org/cron-validator/-/cron-validator-1.3.1.tgz", "integrity": "sha512-C1HsxuPCY/5opR55G5/WNzyEGDWFVG+6GLrA+fW/sCTcP6A6NTjUP2AK7B8n2PyFs90kDG2qzwm8LMheADku6A==" }, + "d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "requires": { + "internmap": "1 - 2" + } + }, + "d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==" + }, + "d3-format": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", + "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==" + }, + "d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "requires": { + "d3-color": "1 - 3" + } + }, + "d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "requires": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + } + }, + "d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "requires": { + "d3-array": "2 - 3" + } + }, + "d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "requires": { + "d3-time": "1 - 3" + } + }, "date-fns": { "version": "2.30.0", "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", @@ -4820,6 +4992,11 @@ "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" }, + "internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==" + }, "ip": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.1.tgz", @@ -4898,11 +5075,25 @@ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "optional": true }, + "isomorphic-fetch": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-3.0.0.tgz", + "integrity": "sha512-qvUtwJ3j6qwsF3jLxkZ72qCgjMysPzDfeV240JHiGZsANBYd+EEuu35v7dfrJ9Up0Ak07D7GGSkGhCHTqg/5wA==", + "requires": { + "node-fetch": "^2.6.1", + "whatwg-fetch": "^3.4.1" + } + }, "lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, + "lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==" + }, "long": { "version": "5.2.3", "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz", @@ -5177,6 +5368,14 @@ "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.0.0.tgz", "integrity": "sha512-CvkDw2OEnme7ybCykJpVcKH+uAOLV2qLqiyla128dN9TkEWfrYmxG6C2boDe5KcNQqZF3orkqzGgOMvZ/JNekA==" }, + "node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "requires": { + "whatwg-url": "^5.0.0" + } + }, "node-gyp": { "version": "8.4.1", "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-8.4.1.tgz", @@ -6146,6 +6345,11 @@ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" }, + "whatwg-fetch": { + "version": "3.6.20", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.20.tgz", + "integrity": "sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==" + }, "whatwg-url": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", diff --git a/package.json b/package.json index 483ea82c..02383781 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,7 @@ "dev": "concurrently --kill-others-on-fail \"npm run server\" \"npm run client\"" }, "dependencies": { + "@cloudflare/speedtest": "^1.3.0", "axios": "^1.6.8", "bcrypt": "^5.1.1", "cron-validator": "^1.3.1", From 72dc1052826b50b40aec22437ad6edd387a0e216 Mon Sep 17 00:00:00 2001 From: Mathias Wagner Date: Sun, 19 May 2024 15:29:42 +0200 Subject: [PATCH 02/39] Added binaries for LibreSpeed to the binaries.js config --- server/config/binaries.js | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/server/config/binaries.js b/server/config/binaries.js index d20223db..29c17a81 100644 --- a/server/config/binaries.js +++ b/server/config/binaries.js @@ -1,5 +1,5 @@ -module.exports.version = "1.2.0"; -module.exports.list = [ +module.exports.ooklaVersion = "1.2.0"; +module.exports.ooklaList = [ // MacOS {os: 'darwin', arch: 'x64', suffix: 'macosx-x86_64.tgz'}, @@ -14,4 +14,28 @@ module.exports.list = [ // FreeBSD {os: 'freebsd', arch: 'x64', suffix: 'freebsd12-x86_64.pkg'} +]; + +module.exports.libreVersion = "1.0.10"; +module.exports.libreList = [ + // MacOS + {os: 'darwin', arch: 'x64', suffix: 'darwin_amd64.tar.gz'}, + {os: 'darwin', arch: 'arm64', suffix: 'darwin_arm64.tar.gz'}, + + // Windows + {os: 'win32', arch: 'x64', suffix: 'windows_amd64.zip'}, + {os: 'win32', arch: 'ia32', suffix: 'windows_386.zip'}, + {os: 'win32', arch: 'arm64', suffix: 'windows_arm64.zip'}, + + // Linux + {os: 'linux', arch: 'x64', suffix: 'linux_amd64.tar.gz'}, + {os: 'linux', arch: 'ia32', suffix: 'linux_386.tar.gz'}, + {os: 'linux', arch: 'arm', suffix: 'linux_armv7.tar.gz'}, + {os: 'linux', arch: 'arm64', suffix: 'linux_arm64.tar.gz'}, + + // FreeBSD + {os: 'freebsd', arch: 'x64', suffix: 'freebsd_amd64.tar.gz'}, + {os: 'freebsd', arch: 'ia32', suffix: 'freebsd_386.tar.gz'}, + {os: 'freebsd', arch: 'arm', suffix: 'freebsd_armv7.tar.gz'}, + {os: 'freebsd', arch: 'arm64', suffix: 'freebsd_arm64.tar.gz'} ] \ No newline at end of file From f6f879da560bbeb1f399c4df2be9daa99a4b8a13 Mon Sep 17 00:00:00 2001 From: Mathias Wagner Date: Sun, 19 May 2024 15:29:57 +0200 Subject: [PATCH 03/39] Added the serverId to the Speedtests.js model --- server/models/Speedtests.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/server/models/Speedtests.js b/server/models/Speedtests.js index 4394f7ce..190f3ded 100644 --- a/server/models/Speedtests.js +++ b/server/models/Speedtests.js @@ -7,6 +7,10 @@ module.exports = db.define("speedtests", { primaryKey: true, autoIncrement: true, }, + serverId: { + type: Sequelize.INTEGER, + defaultValue: 0 + }, ping: { type: Sequelize.INTEGER, allowNull: false From 664323467656d2fce4fac5b05f43d27ac831da52 Mon Sep 17 00:00:00 2001 From: Mathias Wagner Date: Sun, 19 May 2024 15:30:54 +0200 Subject: [PATCH 04/39] Migrated serverId -> ooklaId,libreId (depending on provider) --- server/routes/config.js | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/server/routes/config.js b/server/routes/config.js index 328e0895..9f55e069 100644 --- a/server/routes/config.js +++ b/server/routes/config.js @@ -7,10 +7,8 @@ const password = require('../middlewares/password'); app.get("/", password(true), async (req, res) => { let configValues = {}; (await config.listAll()).forEach(row => { - if (row.key !== "password" && !(req.viewMode && ["serverId", "cron", "passwordLevel"].includes(row.key))) + if (row.key !== "password" && !(req.viewMode && ["ooklaId", "libreId", "cron", "passwordLevel"].includes(row.key))) configValues[row.key] = row.value; - if (process.env.PREVIEW_MODE === "true" && row.key === "acceptOoklaLicense") - configValues[row.key] = true; }); configValues['viewMode'] = req.viewMode; configValues['previewMode'] = process.env.PREVIEW_MODE === "true"; @@ -31,8 +29,8 @@ app.patch("/:key", password(false), async (req, res) => { if (req.params.key === "passwordLevel" && !["none", "read"].includes(req.body.value)) return res.status(400).json({message: "You need to provide either none or read-access"}); - if (req.params.key === "acceptOoklaLicense" && typeof req.body.value !== "boolean") - return res.status(400).json({message: "You need to provide a boolean value"}); + if (req.params.key === "provider" && !["ookla", "libre", "cloudflare"].includes(req.body.value)) + return res.status(400).json({message: "You need to provide a valid provider"}); if (req.params.key === "ping") req.body.value = req.body.value.toString().split(".")[0]; @@ -45,9 +43,6 @@ app.patch("/:key", password(false), async (req, res) => { if (!await config.updateValue(req.params.key, req.body.value.toString())) return res.status(404).json({message: "The provided key does not exist"}); - if (process.env.PREVIEW_MODE === "true" && req.params.key === "acceptOoklaLicense") - return res.status(403).json({message: "You can't change the Ookla license acceptance in preview mode"}); - if (process.env.PREVIEW_MODE === "true" && (req.params.key === "password" || req.params.key === "passwordLevel")) return res.status(403).json({message: "You can't change the password in preview mode"}); From ae7099f6e0e237448768dc24c9995ca169b46bee Mon Sep 17 00:00:00 2001 From: Mathias Wagner Date: Sun, 19 May 2024 15:31:05 +0200 Subject: [PATCH 05/39] Integrated providers into the speedtests.js route --- server/routes/speedtests.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/server/routes/speedtests.js b/server/routes/speedtests.js index ee5b9560..961c5d88 100644 --- a/server/routes/speedtests.js +++ b/server/routes/speedtests.js @@ -22,8 +22,7 @@ app.get("/statistics", password(true), async (req, res) => { app.post("/run", password(false), async (req, res) => { if (pauseController.currentState) return res.status(410).json({message: "The speedtests are currently paused"}); - if (await config.getValue("acceptOoklaLicense") === "false") - return res.status(410).json({message: "You need to accept the ookla license first"}); + if (await config.getValue("provider") === "none") return res.status(410).json({message: "No provider selected"}); let speedtest = await testTask.create("custom"); if (speedtest !== undefined) return res.status(409).json({message: "An speedtest is already running"}); res.json({message: "Speedtest successfully created"}); From 6a2b16f903e0d01d0d4f82d096fa17a08f99ed67 Mon Sep 17 00:00:00 2001 From: Mathias Wagner Date: Sun, 19 May 2024 15:31:53 +0200 Subject: [PATCH 06/39] Created the servers.js controller --- server/controller/servers.js | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 server/controller/servers.js diff --git a/server/controller/servers.js b/server/controller/servers.js new file mode 100644 index 00000000..27d9102e --- /dev/null +++ b/server/controller/servers.js @@ -0,0 +1,34 @@ +const fs = require("fs"); +let ooklaServers; +let libreServers; + +module.exports.getLibreServers = () => { + if (libreServers) return libreServers; + + if (fs.existsSync("./data/servers/librespeed.json")) { + libreServers = fs.readFileSync("./data/servers/librespeed.json"); + libreServers = JSON.parse(libreServers); + + return libreServers; + } + + return []; +} + +module.exports.getOoklaServers = () => { + if (ooklaServers) return ooklaServers; + + if (fs.existsSync("./data/servers/ookla.json")) { + ooklaServers = fs.readFileSync("./data/servers/ookla.json"); + ooklaServers = JSON.parse(ooklaServers); + + return ooklaServers; + } + + return []; +} + +module.exports.getByMode = (mode) => { + if (mode === "ookla") return this.getOoklaServers(); + if (mode === "libre") return this.getLibreServers(); +} \ No newline at end of file From 668b99de020361529d189ad86ef719503f9f0f60 Mon Sep 17 00:00:00 2001 From: Mathias Wagner Date: Sun, 19 May 2024 15:32:09 +0200 Subject: [PATCH 07/39] Implemented the new servers.js controller into the system.js routes --- server/routes/system.js | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/server/routes/system.js b/server/routes/system.js index da5b3f0f..d00627f1 100644 --- a/server/routes/system.js +++ b/server/routes/system.js @@ -2,10 +2,8 @@ const app = require('express').Router(); const version = require('../../package.json').version; const remote_url = "https://api.github.com/repos/gnmyt/myspeed/releases/latest"; const axios = require('axios'); -const fs = require("fs"); const password = require('../middlewares/password'); - -let servers; +const serverController = require('../controller/servers'); app.get("/version", password(false), async (req, res) => { if (process.env.PREVIEW_MODE === "true") return res.json({local: version, remote: "0"}); @@ -17,15 +15,11 @@ app.get("/version", password(false), async (req, res) => { } }); -app.get("/server", password(false), (req, res) => { - if (servers) return res.json(JSON.parse(servers)); +app.get("/server/:provider", password(false), (req, res) => { + if (!["ookla", "libre"].includes(req.params.provider)) + return res.status(400).json({message: "Invalid provider"}); - if (fs.existsSync("./data/servers.json")) { - servers = fs.readFileSync("./data/servers.json"); - return res.json(JSON.parse(servers)); - } else { - return res.json([]); - } + res.json(serverController.getByMode(req.params.provider)); }); module.exports = app; \ No newline at end of file From 4280e277a26f03f1b161406dd37979cd605d3841 Mon Sep 17 00:00:00 2001 From: Mathias Wagner Date: Sun, 19 May 2024 15:32:20 +0200 Subject: [PATCH 08/39] Added new defaults to the config.js --- server/controller/config.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/server/controller/config.js b/server/controller/config.js index f5878d67..43e47282 100644 --- a/server/controller/config.js +++ b/server/controller/config.js @@ -6,10 +6,11 @@ const configDefaults = { download: "100", upload: "50", cron: "0 * * * *", - serverId: "none", + provider: "none", + ooklaId: "none", + libreId: "none", password: "none", - passwordLevel: "none", - acceptOoklaLicense: "false" + passwordLevel: "none" } module.exports.insertDefaults = async () => { @@ -27,7 +28,6 @@ module.exports.listAll = async () => { } module.exports.getValue = async (key) => { - if (process.env.PREVIEW_MODE === "true" && key === "acceptOoklaLicense") return true; return (await config.findByPk(key)).value; } From 87c8bb0aee2285d61acdf107417da9f561817e70 Mon Sep 17 00:00:00 2001 From: Mathias Wagner Date: Sun, 19 May 2024 15:32:42 +0200 Subject: [PATCH 09/39] Implemented the serverId into the speedtests.js controller --- server/controller/speedtests.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/controller/speedtests.js b/server/controller/speedtests.js index 1b44554e..78588f56 100644 --- a/server/controller/speedtests.js +++ b/server/controller/speedtests.js @@ -2,8 +2,8 @@ const tests = require('../models/Speedtests'); const {Op, Sequelize} = require("sequelize"); const {mapFixed, mapRounded, calculateTestAverages} = require("../util/helpers"); -module.exports.create = async (ping, download, upload, time, type = "auto", error = null) => { - return (await tests.create({ping, download, upload, error, type, time})).id; +module.exports.create = async (ping, download, upload, time, serverId, type = "auto", error = null) => { + return (await tests.create({ping, download, upload, error, serverId, type, time})).id; } module.exports.getOne = async (id) => { From e724f1dac4aecefe498b942064d406836bb82a4d Mon Sep 17 00:00:00 2001 From: Mathias Wagner Date: Sun, 19 May 2024 15:33:06 +0200 Subject: [PATCH 10/39] Implemented the new provider system into the speedtest.js task --- server/tasks/speedtest.js | 72 ++++++++++++++++++++++++++++++--------- 1 file changed, 56 insertions(+), 16 deletions(-) diff --git a/server/tasks/speedtest.js b/server/tasks/speedtest.js index 68ef69e7..7a64708b 100644 --- a/server/tasks/speedtest.js +++ b/server/tasks/speedtest.js @@ -2,14 +2,12 @@ const speedTest = require('../util/speedtest'); const tests = require('../controller/speedtests'); const config = require('../controller/config'); const controller = require("../controller/recommendations"); +const parseData = require('../util/providers/parseData'); let {setState, sendRunning, sendError, sendFinished} = require("./integrations"); +const serverController = require("../controller/servers"); let isRunning = false; -const roundSpeed = (bytes, elapsed) => { - return Math.round((bytes * 8 / elapsed) / 10) / 100; -} - const setRunning = (running, sendRequest = true) => { isRunning = running; @@ -35,25 +33,69 @@ const createRecommendations = async () => { } } +module.exports.executeCloudflare = async () => { + try { + const {default: SpeedTest} = await import('@cloudflare/speedtest'); + + // This needs to be disabled because of a library issue + // See https://github.com/cloudflare/speedtest/issues/17 + console.warn = () => {}; + + const startTime = new Date().getTime(); + return await new Promise(resolve => { + const speedTest = new SpeedTest(); + speedTest.onFinish = results => { + resolve({...results.getSummary(), elapsed: new Date().getTime() - startTime}); + } + }); + } catch (error) { + console.error('Error loading SpeedTest module:', error); + } +} + module.exports.run = async (retryAuto = false) => { setRunning(true); - let serverId = await config.getValue("serverId"); + let mode = await config.getValue("provider"); + + if (mode === "none") { + setRunning(false); + throw {message: "No provider selected"}; + } + + let serverId = mode === "cloudflare" ? 0 : await config.getValue(mode + "Id"); if (serverId === "none") serverId = undefined; - let speedtest = await (retryAuto ? speedTest() : speedTest(serverId)); + let speedtest; + if (mode === "cloudflare") { + speedtest = await this.executeCloudflare(); + } else { + speedtest = await (retryAuto ? speedTest(mode) : speedTest(mode, serverId)); + } + + if (serverId === undefined && mode === "ookla") { + serverId = speedtest.server.id; + await config.updateValue("ooklaId", speedtest.server.id); + } + + if (serverId === undefined && mode === "libre") { + let server = Object.entries(serverController.getLibreServers()) + .filter(([key, value]) => value === speedtest.server.name)[0][0]; - if (serverId === undefined) - await config.updateValue("serverId", speedtest.server.id); + serverId = parseInt(server); + + if (server) await config.updateValue("libreId", server); + } if (Object.keys(speedtest).length === 0) throw {message: "No response, even after trying again, test timed out."}; - return speedtest; + return {...speedtest, serverId} } module.exports.create = async (type = "auto", retried = false) => { - if (await config.getValue("acceptOoklaLicense") === 'false') return; + const mode = await config.getValue("provider"); + if (mode === "none") return 400; if (isRunning && !retried) return 500; try { @@ -69,18 +111,16 @@ module.exports.create = async (type = "auto", retried = false) => { test = await this.run(retried); } - let ping = Math.round(test.ping.latency); - let download = roundSpeed(test.download.bytes, test.download.elapsed); - let upload = roundSpeed(test.upload.bytes, test.upload.elapsed); - let time = Math.round((test.download.elapsed + test.upload.elapsed) / 1000); - let testResult = await tests.create(ping, download, upload, time, type); + let {ping, download, upload, time} = await parseData.parseData(mode, test); + + let testResult = await tests.create(ping, download, upload, time, test.serverId, type); console.log(`Test #${testResult} was executed successfully in ${time}s. 🏓 ${ping} ⬇ ${download}️ ⬆ ${upload}️`); createRecommendations().then(() => ""); setRunning(false); sendFinished({ping, download, upload, time}).then(() => ""); } catch (e) { if (!retried) return this.create(type, true); - let testResult = await tests.create(-1, -1, -1, null, type, e.message); + let testResult = await tests.create(-1, -1, -1, null, 0, type, e.message); await sendError(e.message); setRunning(false, false); console.log(`Test #${testResult} was not executed successfully. Please try reconnecting to the internet or restarting the software: ` + e.message); From 32c8e05703a68d870f0ccfb7ed2cca0c9c8dfd66 Mon Sep 17 00:00:00 2001 From: Mathias Wagner Date: Sun, 19 May 2024 15:33:34 +0200 Subject: [PATCH 11/39] Implemented the libre cli loader --- server/util/providers/loadLibre.js | 49 ++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 server/util/providers/loadLibre.js diff --git a/server/util/providers/loadLibre.js b/server/util/providers/loadLibre.js new file mode 100644 index 00000000..68bad02f --- /dev/null +++ b/server/util/providers/loadLibre.js @@ -0,0 +1,49 @@ +const fs = require('fs'); +const {get} = require('https'); +const decompress = require("decompress"); +const {file} = require("tmp"); +const decompressTarGz = require('decompress-targz'); +const decompressUnzip = require('decompress-unzip'); +const binaries = require('../../config/binaries'); + +const binaryRegex = /librespeed-cli(.exe)?$/; +const binaryDirectory = __dirname + "/../../../bin/"; +const binaryPath = `${binaryDirectory}/librespeed-cli` + (process.platform === "win32" ? ".exe" : ""); + +const downloadPath = `https://github.com/librespeed/speedtest-cli/releases/download/v${binaries.libreVersion}/librespeed-cli_${binaries.libreVersion}_`; + +module.exports.fileExists = async () => fs.existsSync(binaryPath); + +module.exports.downloadFile = async () => { + const binary = binaries.libreList.find(b => b.os === process.platform && b.arch === process.arch); + + if (!binary) + throw new Error(`Your platform (${process.platform}-${process.arch}) is not supported by the LibreSpeed CLI`); + + await new Promise((resolve) => { + file({postfix: binary.suffix}, async (err, path) => { + const location = await new Promise((resolve) => get(downloadPath + binary.suffix, (res) => { + resolve(res.headers.location); + })); + + get(location, async resp => { + resp.pipe(fs.createWriteStream(path)).on('finish', async () => { + await decompress(path, binaryDirectory, { + plugins: [decompressTarGz(), decompressUnzip()], + filter: file => binaryRegex.test(file.path), + map: file => { + file.path = "librespeed-cli" + (process.platform === "win32" ? ".exe" : ""); + return file; + } + }); + resolve(); + }); + }); + }); + }); +} + +module.exports.load = async () => { + if (!await this.fileExists()) + await this.downloadFile(); +} \ No newline at end of file From baabfeb60b002e419ac144eaaea374b234b40dd1 Mon Sep 17 00:00:00 2001 From: Mathias Wagner Date: Sun, 19 May 2024 15:33:47 +0200 Subject: [PATCH 12/39] Moved the ookla cli loader --- server/util/providers/loadOokla.js | 45 ++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 server/util/providers/loadOokla.js diff --git a/server/util/providers/loadOokla.js b/server/util/providers/loadOokla.js new file mode 100644 index 00000000..a34dc9eb --- /dev/null +++ b/server/util/providers/loadOokla.js @@ -0,0 +1,45 @@ +const fs = require('fs'); +const {get} = require('https'); +const decompress = require("decompress"); +const {file} = require("tmp"); +const decompressTarGz = require('decompress-targz'); +const decompressUnzip = require('decompress-unzip'); +const binaries = require('../../config/binaries'); + +const binaryRegex = /speedtest(.exe)?$/; +const binaryDirectory = __dirname + "/../../../bin/"; +const binaryPath = `${binaryDirectory}/ookla` + (process.platform === "win32" ? ".exe" : ""); + +const downloadPath = `https://install.speedtest.net/app/cli/ookla-speedtest-${binaries.ooklaVersion}-`; + +module.exports.fileExists = async () => fs.existsSync(binaryPath); + +module.exports.downloadFile = async () => { + const binary = binaries.ooklaList.find(b => b.os === process.platform && b.arch === process.arch); + + if (!binary) + throw new Error(`Your platform (${process.platform}-${process.arch}) is not supported by the Speedtest CLI`); + + await new Promise((resolve) => { + file({postfix: binary.suffix}, async (err, path) => { + get(downloadPath + binary.suffix, async resp => { + resp.pipe(fs.createWriteStream(path)).on('finish', async () => { + await decompress(path, binaryDirectory, { + plugins: [decompressTarGz(), decompressUnzip()], + filter: file => binaryRegex.test(file.path), + map: file => { + file.path = "speedtest" + (process.platform === "win32" ? ".exe" : ""); + return file; + } + }); + resolve(); + }); + }); + }); + }); +} + +module.exports.load = async () => { + if (!await this.fileExists()) + await this.downloadFile(); +} \ No newline at end of file From 7143965093b7c6394807adf9e4e2796b750c2a74 Mon Sep 17 00:00:00 2001 From: Mathias Wagner Date: Sun, 19 May 2024 15:33:57 +0200 Subject: [PATCH 13/39] Created a data parser for all 3 providers --- server/util/providers/parseData.js | 38 ++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 server/util/providers/parseData.js diff --git a/server/util/providers/parseData.js b/server/util/providers/parseData.js new file mode 100644 index 00000000..140515b1 --- /dev/null +++ b/server/util/providers/parseData.js @@ -0,0 +1,38 @@ +const roundSpeed = (bytes, elapsed) => { + return Math.round((bytes * 8 / elapsed) / 10) / 100; +} + +module.exports.parseOokla = (test) => { + let ping = Math.round(test.ping.latency); + let download = roundSpeed(test.download.bytes, test.download.elapsed); + let upload = roundSpeed(test.upload.bytes, test.upload.elapsed); + let time = Math.round((test.download.elapsed + test.upload.elapsed) / 1000); + + return {ping, download, upload, time}; +} + +module.exports.parseLibre = (test) => { + return {ping: test.ping, upload: test.upload, download: test.download, time: Math.round(test.elapsed / 1000)}; +} + +module.exports.parseCloudflare = async (test) => { + let ping = Math.round(test.latency); + let download = Math.round(test.download / 10000) / 100; + let upload = Math.round(test.upload / 10000) / 100; + let time = Math.round(test.elapsed / 1000); + + return {ping, download, upload, time}; +} + +module.exports.parseData = (provider, data) => { + switch (provider) { + case "ookla": + return this.parseOokla(data); + case "libre": + return this.parseLibre(data); + case "cloudflare": + return this.parseCloudflare(data); + default: + throw {message: "Invalid provider"}; + } +} \ No newline at end of file From f3fa8d3ba96277eb999ff87fb93f1b63fa62c288 Mon Sep 17 00:00:00 2001 From: Mathias Wagner Date: Sun, 19 May 2024 15:34:11 +0200 Subject: [PATCH 14/39] Added the data/servers folder to the createFolders.js util --- server/util/createFolders.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/util/createFolders.js b/server/util/createFolders.js index 7c6e525a..7d26cff7 100644 --- a/server/util/createFolders.js +++ b/server/util/createFolders.js @@ -1,6 +1,6 @@ const fs = require('fs'); -const neededFolder = ["data", "bin", "data/logs"]; +const neededFolder = ["data", "bin", "data/logs", "data/servers"]; neededFolder.forEach(folder => { if (!fs.existsSync(folder)) { From d86ef952827106e23896dedaa19f646406953afb Mon Sep 17 00:00:00 2001 From: Mathias Wagner Date: Sun, 19 May 2024 15:34:30 +0200 Subject: [PATCH 15/39] Implemented both the libre & ookla provider in the loadCli.js util --- server/util/loadCli.js | 46 ++++-------------------------------------- 1 file changed, 4 insertions(+), 42 deletions(-) diff --git a/server/util/loadCli.js b/server/util/loadCli.js index 80741a72..aaf3a8ba 100644 --- a/server/util/loadCli.js +++ b/server/util/loadCli.js @@ -1,45 +1,7 @@ -const fs = require('fs'); -const {get} = require('https'); -const decompress = require("decompress"); -const {file} = require("tmp"); -const decompressTarGz = require('decompress-targz'); -const decompressUnzip = require('decompress-unzip'); -const binaries = require('../config/binaries'); - -const binaryRegex = /speedtest(.exe)?$/; -const binaryDirectory = __dirname + "/../../bin/"; -const binaryPath = `${binaryDirectory}/speedtest` + (process.platform === "win32" ? ".exe" : ""); - -const downloadPath = `https://install.speedtest.net/app/cli/ookla-speedtest-${binaries.version}-`; - -module.exports.fileExists = async () => fs.existsSync(binaryPath); - -module.exports.downloadFile = async () => { - const binary = binaries.list.find(b => b.os === process.platform && b.arch === process.arch); - - if (!binary) - throw new Error(`Your platform (${process.platform}-${process.arch}) is not supported by the Speedtest CLI`); - - await new Promise((resolve) => { - file({postfix: binary.suffix}, async (err, path) => { - get(downloadPath + binary.suffix, async resp => { - resp.pipe(fs.createWriteStream(path)).on('finish', async () => { - await decompress(path, binaryDirectory, { - plugins: [decompressTarGz(), decompressUnzip()], - filter: file => binaryRegex.test(file.path), - map: file => { - file.path = "speedtest" + (process.platform === "win32" ? ".exe" : ""); - return file; - } - }); - resolve(); - }); - }); - }); - }); -} +const libreProvider = require('./providers/loadLibre'); +const ooklaProvider = require('./providers/loadOokla'); module.exports.load = async () => { - if (!await this.fileExists()) - await this.downloadFile(); + await libreProvider.load(); + await ooklaProvider.load(); } \ No newline at end of file From 3f00efa517d3bbe6e53a5103b8ce2f1d9f26a145 Mon Sep 17 00:00:00 2001 From: Mathias Wagner Date: Sun, 19 May 2024 15:34:58 +0200 Subject: [PATCH 16/39] The loadServers.js util now loads the nearest ookla & librespeed servers --- server/util/loadServers.js | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/server/util/loadServers.js b/server/util/loadServers.js index 9742ec2c..8a3e6e30 100644 --- a/server/util/loadServers.js +++ b/server/util/loadServers.js @@ -1,7 +1,8 @@ const axios = require('axios'); const fs = require('fs'); -if (!fs.existsSync("data/servers.json")) { +// Load servers from ookla +if (!fs.existsSync("data/servers/ookla.json")) { let servers = {}; try { axios.get("https://www.speedtest.net/api/js/servers?limit=20") @@ -12,13 +13,33 @@ if (!fs.existsSync("data/servers.json")) { }); try { - fs.writeFileSync("data/servers.json", JSON.stringify(servers, null, 4)); + fs.writeFileSync("data/servers/ookla.json", JSON.stringify(servers, null, 4)); } catch (e) { - console.error("Could not save servers file") + console.error("Could not save servers file"); } }); } catch (e) { console.error("Could not get servers"); } - } + +// Load servers from librespeed +if (!fs.existsSync("data/servers/librespeed.json")) { + let servers = {}; + try { + axios.get("https://librespeed.org/backend-servers/servers.php") + .then(res => res.data) + .then(data => { + data?.forEach(row => { + servers[row.id] = row.name; + }); + try { + fs.writeFileSync("data/servers/librespeed.json", JSON.stringify(servers, null, 4)); + } catch (e) { + console.error("Could not save servers file"); + } + }); + } catch (e) { + console.error("Could not get servers"); + } +} \ No newline at end of file From e13b3f0e1247e45343de259bd75091b40d9323d5 Mon Sep 17 00:00:00 2001 From: Mathias Wagner Date: Sun, 19 May 2024 15:35:12 +0200 Subject: [PATCH 17/39] Implemented librespeed into the speedtest.js util --- server/util/speedtest.js | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/server/util/speedtest.js b/server/util/speedtest.js index 3adbd7cb..9c59c74e 100644 --- a/server/util/speedtest.js +++ b/server/util/speedtest.js @@ -1,34 +1,46 @@ const {spawn} = require('child_process'); -module.exports = async (serverId, binary_path = './bin/speedtest' + (process.platform === "win32" ? ".exe" : "")) => { - const args = ['--accept-license', '--accept-gdpr', '--format=jsonl']; - if (serverId) args.push(`--server-id=${serverId}`); +module.exports = async (mode, serverId) => { + const binaryPath = mode === "ookla" ? './bin/speedtest' + (process.platform === "win32" ? ".exe" : "") + : './bin/librespeed-cli' + (process.platform === "win32" ? ".exe" : ""); + + const startTime = new Date().getTime(); + let args; + + if (mode === "ookla") { + args = ['--accept-license', '--accept-gdpr', '--format=json']; + if (serverId) args.push(`--server-id=${serverId}`); + } else { + args = ['--json', '--duration=5']; + if (serverId) args.push(`--server=${serverId}`); + } let result = {}; - const process = spawn(binary_path, args, {windowsHide: true}); + const testProcess = spawn(binaryPath, args, {windowsHide: true}); - process.stdout.on('data', (buffer) => { + testProcess.stdout.on('data', (buffer) => { const line = buffer.toString().replace("\n", ""); - if (!line.startsWith("{")) return; + if (!(line.startsWith("{") || line.startsWith("["))) return; let data = {}; try { data = JSON.parse(line); + if (line.startsWith("[")) data = data[0]; } catch (e) { data.error = e.message; } if (data.error) result.error = data.error; - if (data.type === "result") result = data; + if ((mode === "ookla" && data.type === "result") || mode === "libre") result = data; }); await new Promise((resolve, reject) => { - process.on('error', e => reject({message: e})); - process.on('exit', resolve); + testProcess.on('error', e => reject({message: e})); + testProcess.on('exit', resolve); }); if (result.error) throw new Error(result.error); - return result; + return {...result, elapsed: new Date().getTime() - startTime}; } \ No newline at end of file From 25cffa6521ce5ce7b1fd83bed144b0e7cc540083 Mon Sep 17 00:00:00 2001 From: Mathias Wagner Date: Sun, 19 May 2024 15:35:35 +0200 Subject: [PATCH 18/39] Updated the authentication message in the server index.js --- server/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/index.js b/server/index.js index 6e6a79d5..d5f38334 100755 --- a/server/index.js +++ b/server/index.js @@ -59,8 +59,8 @@ const run = async () => { } db.authenticate().then(() => { - console.log("Successfully connected to the database file"); - run().then(undefined); + console.log("Successfully connected to the database " + (process.env.DB_TYPE === "mysql" ? "server" : "file")); + run().then(undefined); }).catch(err => { console.error("Could not open the database file. Maybe it is damaged?: " + err.message); process.exit(111); From 38838504a446c550532b6336e63ffd4dc7552b2a Mon Sep 17 00:00:00 2001 From: Mathias Wagner Date: Sun, 19 May 2024 15:36:01 +0200 Subject: [PATCH 19/39] Removed the license check from the ConfigContext.jsx --- client/src/common/contexts/Config/ConfigContext.jsx | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/client/src/common/contexts/Config/ConfigContext.jsx b/client/src/common/contexts/Config/ConfigContext.jsx index bc6e73f4..13af6498 100644 --- a/client/src/common/contexts/Config/ConfigContext.jsx +++ b/client/src/common/contexts/Config/ConfigContext.jsx @@ -1,14 +1,13 @@ import React, {createContext, useContext, useEffect, useState} from "react"; import {InputDialogContext} from "../InputDialog"; import {request} from "@/common/utils/RequestUtil"; -import {acceptDialog, apiErrorDialog, passwordRequiredDialog} from "@/common/contexts/Config/dialog"; +import {apiErrorDialog, passwordRequiredDialog} from "@/common/contexts/Config/dialog"; export const ConfigContext = createContext({}); export const ConfigProvider = (props) => { const [config, setConfig] = useState({}); const [setDialog] = useContext(InputDialogContext); - const [dialogShown, setDialogShown] = useState(false); const reloadConfig = () => { request("/config").then(async res => { @@ -32,13 +31,6 @@ export const ConfigProvider = (props) => { const checkConfig = async () => (await request("/config")).json(); - useEffect(() => { - if (config.acceptOoklaLicense !== undefined && config.acceptOoklaLicense === "false" && !dialogShown) { - setDialogShown(true); - setDialog(acceptDialog()); - } - }, [config]); - useEffect(reloadConfig, []); return ( From 11d5776aab86d95ae4bc561066cd0702dd45de65 Mon Sep 17 00:00:00 2001 From: Mathias Wagner Date: Sun, 19 May 2024 15:37:36 +0200 Subject: [PATCH 20/39] Removed the acceptDialog from the dialog.jsx --- client/src/common/contexts/Config/dialog.jsx | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/client/src/common/contexts/Config/dialog.jsx b/client/src/common/contexts/Config/dialog.jsx index 168d80a1..bed3ddd3 100644 --- a/client/src/common/contexts/Config/dialog.jsx +++ b/client/src/common/contexts/Config/dialog.jsx @@ -1,11 +1,4 @@ -import {patchRequest} from "@/common/utils/RequestUtil"; import {t} from "i18next"; -import {Trans} from "react-i18next"; - -const OOKLA_ABOUT_URL = "https://www.speedtest.net/about"; -const OOKLA_TERMS_URL = OOKLA_ABOUT_URL + "/terms"; -const OOKLA_EULA_URL = OOKLA_ABOUT_URL + "/eula"; -const OOKLA_PRIVACY_URL = OOKLA_ABOUT_URL + "/privacy"; export const passwordRequiredDialog = () => ({ title: t("dialog.password.title"), @@ -26,13 +19,4 @@ export const apiErrorDialog = () => ({ buttonText: t("dialog.retry"), disableCloseButton: true, onSuccess: () => window.location.reload() -}); - -export const acceptDialog = () => ({ - title: t("dialog.accept.title"), - description: , EULA: , - Privacy: , Terms: }}>dialog.accept.description, - buttonText: t("dialog.accept.button"), - disableCloseButton: true, - onSuccess: () => patchRequest("/config/acceptOoklaLicense", {value: true}) }); \ No newline at end of file From f68e72557eb9ca37086fb357c8cd592f46216ab4 Mon Sep 17 00:00:00 2001 From: Mathias Wagner Date: Sun, 19 May 2024 15:37:44 +0200 Subject: [PATCH 21/39] Removed the accept translations from the en.json --- client/public/assets/locales/en.json | 5 ----- 1 file changed, 5 deletions(-) diff --git a/client/public/assets/locales/en.json b/client/public/assets/locales/en.json index 9e5ed747..1b3cf540 100644 --- a/client/public/assets/locales/en.json +++ b/client/public/assets/locales/en.json @@ -15,11 +15,6 @@ "wrong": "The password you entered is incorrect", "unlock": "Unlock" }, - "accept": { - "title": "We need your permission", - "description": "We use services from Ookla. By clicking Accept, you acknowledge that you have read and agree to Ookla's EULA, Privacy Statement and Terms of Use.", - "button": "Accept" - }, "api": { "title": "API not reachable", "description": "MySpeed could not reach the API of this instance. Please try again later." From 3a7076d9de8484a8498cdd1d3a5b65305846690f Mon Sep 17 00:00:00 2001 From: Mathias Wagner Date: Sun, 19 May 2024 15:39:30 +0200 Subject: [PATCH 22/39] Removed unused parameter in the speedtest.js task --- server/tasks/speedtest.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/tasks/speedtest.js b/server/tasks/speedtest.js index 7a64708b..4d4bd848 100644 --- a/server/tasks/speedtest.js +++ b/server/tasks/speedtest.js @@ -81,7 +81,7 @@ module.exports.run = async (retryAuto = false) => { if (serverId === undefined && mode === "libre") { let server = Object.entries(serverController.getLibreServers()) - .filter(([key, value]) => value === speedtest.server.name)[0][0]; + .filter(([, value]) => value === speedtest.server.name)[0][0]; serverId = parseInt(server); From 3e709ac602612f1327ab61ee8ed113c9172f0c58 Mon Sep 17 00:00:00 2001 From: Mathias Wagner Date: Sun, 19 May 2024 16:04:47 +0200 Subject: [PATCH 23/39] Fixed a bug in the speedtest.js task --- server/tasks/speedtest.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/server/tasks/speedtest.js b/server/tasks/speedtest.js index 4d4bd848..31ffd609 100644 --- a/server/tasks/speedtest.js +++ b/server/tasks/speedtest.js @@ -83,9 +83,10 @@ module.exports.run = async (retryAuto = false) => { let server = Object.entries(serverController.getLibreServers()) .filter(([, value]) => value === speedtest.server.name)[0][0]; - serverId = parseInt(server); - - if (server) await config.updateValue("libreId", server); + if (server) { + serverId = parseInt(server); + await config.updateValue("libreId", server); + } } if (Object.keys(speedtest).length === 0) throw {message: "No response, even after trying again, test timed out."}; From de1cab9994f9624c66e087d007945a7dd7b59d5c Mon Sep 17 00:00:00 2001 From: Mathias Wagner Date: Sun, 19 May 2024 16:05:01 +0200 Subject: [PATCH 24/39] Added NaN checks to the config.js route --- server/routes/config.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/server/routes/config.js b/server/routes/config.js index 9f55e069..3dd45cef 100644 --- a/server/routes/config.js +++ b/server/routes/config.js @@ -26,6 +26,10 @@ app.patch("/:key", password(false), async (req, res) => { if ((req.params.key === "ping" || req.params.key === "download" || req.params.key === "upload") && isNaN(req.body.value)) return res.status(400).json({message: "You need to provide a number in order to change this"}); + if ((req.params.key === "ooklaId" || req.params.key === "libreId") && isNaN(req.body.value)) + return res.status(400).json({message: "You need to provide a number in order to change this"}); + + if (req.params.key === "passwordLevel" && !["none", "read"].includes(req.body.value)) return res.status(400).json({message: "You need to provide either none or read-access"}); From 3992fece1744006dd73fd95253ce4b4ad77ae5cd Mon Sep 17 00:00:00 2001 From: Mathias Wagner Date: Sun, 19 May 2024 17:03:07 +0200 Subject: [PATCH 25/39] Fixed a bug in the config.js controller --- server/controller/config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/controller/config.js b/server/controller/config.js index 43e47282..d0a00600 100644 --- a/server/controller/config.js +++ b/server/controller/config.js @@ -28,7 +28,7 @@ module.exports.listAll = async () => { } module.exports.getValue = async (key) => { - return (await config.findByPk(key)).value; + return (await config.findByPk(key))?.value; } module.exports.updateValue = async (key, newValue) => { From 826a10123c553b9049963770a9ef2e99fea82903 Mon Sep 17 00:00:00 2001 From: Mathias Wagner Date: Sun, 19 May 2024 20:21:24 +0200 Subject: [PATCH 26/39] Added extended error handling to the speedtest.js util --- server/util/speedtest.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/server/util/speedtest.js b/server/util/speedtest.js index 9c59c74e..c2cdbe07 100644 --- a/server/util/speedtest.js +++ b/server/util/speedtest.js @@ -19,6 +19,13 @@ module.exports = async (mode, serverId) => { const testProcess = spawn(binaryPath, args, {windowsHide: true}); + testProcess.stderr.on('data', (buffer) => { + result.error = buffer.toString(); + if (buffer.toString().includes("Too many requests")) { + result.error = "Too many requests. Please try again later"; + } + }); + testProcess.stdout.on('data', (buffer) => { const line = buffer.toString().replace("\n", ""); if (!(line.startsWith("{") || line.startsWith("["))) return; From ba2a5bd37c5723c3ae36e46ba5c4fc9ce940fc6a Mon Sep 17 00:00:00 2001 From: Mathias Wagner Date: Sun, 19 May 2024 20:23:54 +0200 Subject: [PATCH 27/39] Fixed a bug in the speedtest.js task --- server/tasks/speedtest.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/server/tasks/speedtest.js b/server/tasks/speedtest.js index 31ffd609..59fcc852 100644 --- a/server/tasks/speedtest.js +++ b/server/tasks/speedtest.js @@ -74,22 +74,22 @@ module.exports.run = async (retryAuto = false) => { speedtest = await (retryAuto ? speedTest(mode) : speedTest(mode, serverId)); } - if (serverId === undefined && mode === "ookla") { - serverId = speedtest.server.id; - await config.updateValue("ooklaId", speedtest.server.id); + if (mode === "ookla" && speedtest.server) { + if (serverId === undefined) await config.updateValue("ooklaId", speedtest.server?.id); + serverId = speedtest.server?.id; } - if (serverId === undefined && mode === "libre") { + if (mode === "libre" && speedtest.server) { let server = Object.entries(serverController.getLibreServers()) .filter(([, value]) => value === speedtest.server.name)[0][0]; if (server) { + if (serverId === undefined) await config.updateValue("libreId", server); serverId = parseInt(server); - await config.updateValue("libreId", server); } } - if (Object.keys(speedtest).length === 0) throw {message: "No response, even after trying again, test timed out."}; + if (Object.keys(speedtest).length <= 1) throw {message: "No response, even after trying again, test timed out."}; return {...speedtest, serverId} } From e9fa2fe366919a07031ba51ea3374cbc4d070fc1 Mon Sep 17 00:00:00 2001 From: Mathias Wagner Date: Sun, 19 May 2024 20:24:07 +0200 Subject: [PATCH 28/39] Implemented support for "none" in the config.js route --- server/routes/config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/routes/config.js b/server/routes/config.js index 3dd45cef..89d13a14 100644 --- a/server/routes/config.js +++ b/server/routes/config.js @@ -26,7 +26,7 @@ app.patch("/:key", password(false), async (req, res) => { if ((req.params.key === "ping" || req.params.key === "download" || req.params.key === "upload") && isNaN(req.body.value)) return res.status(400).json({message: "You need to provide a number in order to change this"}); - if ((req.params.key === "ooklaId" || req.params.key === "libreId") && isNaN(req.body.value)) + if ((req.params.key === "ooklaId" || req.params.key === "libreId") && (isNaN(req.body.value) && req.body.value !== "none")) return res.status(400).json({message: "You need to provide a number in order to change this"}); From 6ddf0a3abe5a26bdbc857d6fb7599eaf1867cc67 Mon Sep 17 00:00:00 2001 From: Mathias Wagner Date: Sun, 19 May 2024 20:24:31 +0200 Subject: [PATCH 29/39] Updated the LanguageDialog styles.sass --- client/src/common/components/LanguageDialog/styles.sass | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/client/src/common/components/LanguageDialog/styles.sass b/client/src/common/components/LanguageDialog/styles.sass index 57d6a60c..462e858b 100644 --- a/client/src/common/components/LanguageDialog/styles.sass +++ b/client/src/common/components/LanguageDialog/styles.sass @@ -22,7 +22,7 @@ border-radius: 0.5rem &:hover - background-color: $light-gray + background-color: $darker-gray img width: 2rem @@ -38,6 +38,9 @@ background-color: $light-gray color: $white + &:hover + background-color: $light-gray + @media screen and (max-height: 425px) .language-chooser-dialog height: 15rem From 15676f1a05800bce53133f0ada98859b924ec042 Mon Sep 17 00:00:00 2001 From: Mathias Wagner Date: Sun, 19 May 2024 20:25:44 +0200 Subject: [PATCH 30/39] Updated the cloudflare.webp asset --- .../ProviderDialog/assets/img/cloudflare.webp | Bin 0 -> 2362 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 client/src/common/components/ProviderDialog/assets/img/cloudflare.webp diff --git a/client/src/common/components/ProviderDialog/assets/img/cloudflare.webp b/client/src/common/components/ProviderDialog/assets/img/cloudflare.webp new file mode 100644 index 0000000000000000000000000000000000000000..c72b453e096a8b6fe997fcf071d47ad0d217e8e9 GIT binary patch literal 2362 zcmV-A3B~qONk&F82><|BMM6+kP&il$0000G0001E003hE06|PpNaXeeb6=}PtN{E!~~#O`MK<8QFC`U&1YI- z0M%(Z&8wDu77{U;-&z*wEPEzFtF{fEVHBl#e)(YxWUzJ`? zcCNBGTayZ6bUatcPI&w3;fzhb5T)e#i^ECBkHlH)M+YsRKM?1w9~{Iyz7c1h-#n;! zyi#uIB06`wILLYYN7*F+le1R<4|*=Z$?pLuza7E(7sLTL))7b=!H+zGbqJe|V7DRo z2!9PB|3BCWb{#?)!FG;dO(Tfw2&SJSKo~#)l-~{<{AOU~CxFmX08n=OKZ#xZCz4ZK z7H<31#!aq*G0S+Hn9c8mnBv3CYyL!NDLziD=Fft0I`QSoNxng5wBc(pK8lJf9g`YJ zY-Usqh0BJ@qD)Ry7voVvJxs$y$3+4^_Vfy##-Rg(>H=qyMpWLr_-$CEmy+MDv ze~177*fHn<`)}#3`;G8t`;+^d?P34_AOZ;z(sDV;DPg_XKHVTtZ^A(-s(D9Rp;AA*yoYFn{M5jV*irj0pQdS&TkN%RmR&Iv(M`@B)^bjq2hhkb=e%fy zOt}|=hZR>E4?s#Yw>o-%{8^btEbdO_JHN!xvw61-iuHaXaHLxUhwD(PWhVJp-~a&r z^e4;u!C}*aVUgvCFF2dMnlX_2Egl^XDBD*_b(GZX#i8e2*=*Ozn#ykCTqP6e*Rr>R zoY#+~ZOStdo3JUV*_b*wkB+TJukaLkxyX+expIUN zukU$^BtF|o$>L2y(3(g|&i^1kttW=k04k>7v3y?9^)38En7n7y+Gyk)Vc66OTV{DE z%S;Y{aF%Qa%N+u;KltCDw5Tl6HB_`a0c^os;d`yxpi^t!r#h7>P`>JIc{b8ufabZ`2jb{c@qC)oRsc zK^|!#ar|{*3D(FM2k6C~uJxQ}z(Xi%LQRs-rB{o_JWEqM3N+3;%&YcNHBwQh`HUd7Vw6O?hN;5&ibJ8y8*8{NHY~td-{t;f{SC&NuZ0&6$ z<608(3I00y-xy-en)sQ5Az!r<5?UVMO`~d|JMM=0u&Ewfwf3K@I`7)#-Ag9Dr zJD^2ch8FRCcCx}y`&YIGUK)*5`;3nj?eJ0824$__a)wn-KL?*67)EcQmQCi^B#eR) z3Uz%`AXDdx1ef2GokSDO^BQnnIdc=Mj-NIhhS0oheyOA}=^cV3b5e?r2X; zUtSSeyiS9_HA^;VCPFrv%YtN*;1i&Kc$c!KD$%ViHB6Kz{%DDR|dhfrqU+>I$cyt?f#d9nP*TnSUWWqWI$@fslk; zAH+})I|y0R3jMzEuMjENLV*0)`E=n&;!*vtDkZEhbB$Tv0%Ub8k2@i~WJ@mdQq`epTAjJn}F((wf8vFL_ZcT|BHD=`%R~oBW=K$DbqXXE)o{Y!A6FexF|=vSnvQn zLSg^^GuBHE=I)_O16I=5z7tTtLymD0DLiqiTkIR|=!SExUNSQmFs;*PIcD`yFa-CP z`I3pITSNEEY=xDi;5)6ifFNt4=`24UiQio}47e|<3VH(9Cy<5|regubSp>CwKi=F3 gTK}{sW(X6yuJP46BJVpfS9!I)F*)tz0000004hp^@&Et; literal 0 HcmV?d00001 From 15553f58753bbbc1a4b2b9f949be5cfc04a8cac8 Mon Sep 17 00:00:00 2001 From: Mathias Wagner Date: Sun, 19 May 2024 20:25:49 +0200 Subject: [PATCH 31/39] Updated the libre.webp asset --- .../ProviderDialog/assets/img/libre.webp | Bin 0 -> 3344 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 client/src/common/components/ProviderDialog/assets/img/libre.webp diff --git a/client/src/common/components/ProviderDialog/assets/img/libre.webp b/client/src/common/components/ProviderDialog/assets/img/libre.webp new file mode 100644 index 0000000000000000000000000000000000000000..8d18f39e8d6e133aa46565bb3f72b6ea571d0661 GIT binary patch literal 3344 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 at$Gi_d*_M^^=wJCg*SANdGpTz0002oiEoAg literal 0 HcmV?d00001 From a6b0d760b85a34ff6bc58442af08dc0486c0374a Mon Sep 17 00:00:00 2001 From: Mathias Wagner Date: Sun, 19 May 2024 20:25:54 +0200 Subject: [PATCH 32/39] Updated the ookla.webp asset --- .../ProviderDialog/assets/img/ookla.webp | Bin 0 -> 2344 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 client/src/common/components/ProviderDialog/assets/img/ookla.webp diff --git a/client/src/common/components/ProviderDialog/assets/img/ookla.webp b/client/src/common/components/ProviderDialog/assets/img/ookla.webp new file mode 100644 index 0000000000000000000000000000000000000000..39f781a593bb785cac13e633ba15951718cffff4 GIT binary patch literal 2344 zcmV+@3D@>gNk&E>2><|BMM6+kP&il$0000G0001E003hE06|PpNW%gE00EF|+qUX9 z$8Z&pWVVLhP#0!SI@3?Epa?T}W|vOI%*H?!I=2cI*z)v;~lY!;Ax!}+3QNm5_;u2mRD;6ss;8ONi#0xb29+&ps zC}9?SLi0J;`4JiQ6V1md5s1Ib;ofE8RdB!+VU6!c)ITYVsH+@uHw(?q zLFa{Jc#XUy)p#jV_eTn!4`Aixj_uqklkT{(m3*=%s_jg@dE)YU$FIA{>$dz z9siw1can&h51l8PXf}sGk7yabHAGeTE>V;hpPQ^IzM+&1u7g>NY)S?bL%#UAWS!2W{1QPS+u$&Jq&MVIka z5v|3yjA$OdIYiNJbbdxeC()fIB66V1{V&yr?X%@SI)H5t1pt!1#mbR-H?%POPr5i!7LRu$P z$yc91+Ota8wirps1s`Slw17k%byuFdGf3R{@_so6${7hgwpWI(X(W1-{kdrFd`1!u z+xSGJXDiJlsd3>oLDV}A6G?1H-}6N~|DjAqvRkr``?YYNv8NJ7HhcLcuNvNv`|{d( zF$6WrnwDR*`)qCNmCn|xQ#*@XS*av009H^qAT|a70I(eZodGIj0Av6@Z7`HaBqE|A zCG(v4fDMUf4ar!57$6X>-m>&69)CscgZuS(AM7|=+PiiuA@LogcjaEdADn##Kicw- z^(XAVz-RKW>c92-4*utR9RAWCdu#B+=FzeSW=Dpp^R__(Nr7e+3GTkHNShS|$~6Mc zvuv!|Zq0`|;pPhjBL(Hi3a-N1v17h?hr@p1$u+ELyMu%26)EbezeVFolQY8Is3QGv#P^6a3QYY5rG8=l;U9KV2* z_z_w_kt3x{AkB*$14e~xyP4L2|7>gvI;ORqAms$ z=9SZ5?S62cjWXr{ZGx5`Jm(N#x2}%ZP0B>6+-aWRg_rMsu-s2&K*jzq$U{8`!}`{^ ze+;~jV@rvr3PX`~qXegkF4GVZNf43wcKVHpD^>aB@;}$!@=`B@2Pi&2?5IRo(>7cN zx4pUd@xoL8COkXm^y1$)3wFEyKWS^xx^@P)aIo*%;$G8KHM1_j153R(Z06m%90I~$ zieaNWw{JkZj=!hGw#hPek0*Ml098bT5G+Wy7q9vzmwBQ^npnw5-|y6Ky8aT@!#miE zL|TI{EV#ZwyC6X9V$bJ&=tUN6*rC>h^h>z$3DPM zgy`o8UaKyXB9LHPYYU9%`oJG-KppAE*XGV8=fgkzl`{3Q4f);w23YXJa2)w2<9QC= zMQ?{MvFpQ_=O3!~jbhBRBC?tOPIS^yQ;DBJTT+-QC@P~EzTb_49j&$NN>GK@DjBD8d?D{ojTXRL~l$+1}lz4QQwXm}xun3#(7^eN%;E zTIAsA|9%>uXu128hi#{Nr$32Q&OF_#W2bkOL)L#E^D6E5byyyuAM0Jq`GjvvEw@^0 zY=G2+NgNc|C5H=lt=Jv^phQnl4Wi-#5ylpXo%p0_xJ%u8AA6M$r2&C5RweM-E&olJG$Q~NjgR(0AB@|Ni$VcUTMZhF zXbItP#-AFSzlkA36KiAl#S5(k#nI4zJ-eU!<>umriZeVDh5Umta&%cQ_{tpmwO>L< z9-r+JVj!7 zO4W?Dj-J^)#iid0X)&ICGT;rg0V7W@JzpnO$*oznM8!G^f^xKU?zqI1rrEmX=OOGftZ{&!bwbZozN33`4 z|MvuSYoz3t;NFZ8L*a(?&l_e2KE*1s|F4;_x9a_TV`A``@vKDiswrz}@IST5BVLRC zdCxR|{3MW|xWFg2-e;G>QR;4{)JZ0>PQFX)9(B Date: Sun, 19 May 2024 20:26:21 +0200 Subject: [PATCH 33/39] Created the ProviderDialog.jsx --- .../ProviderDialog/ProviderDialog.jsx | 138 ++++++++++++++++++ 1 file changed, 138 insertions(+) create mode 100644 client/src/common/components/ProviderDialog/ProviderDialog.jsx diff --git a/client/src/common/components/ProviderDialog/ProviderDialog.jsx b/client/src/common/components/ProviderDialog/ProviderDialog.jsx new file mode 100644 index 00000000..bd79c505 --- /dev/null +++ b/client/src/common/components/ProviderDialog/ProviderDialog.jsx @@ -0,0 +1,138 @@ +import {DialogContext, DialogProvider} from "@/common/contexts/Dialog"; +import {t} from "i18next"; +import {FontAwesomeIcon} from "@fortawesome/react-fontawesome"; +import {faClose} from "@fortawesome/free-solid-svg-icons"; +import "./styles.sass"; +import React, {useContext, useEffect, useState} from "react"; +import OoklaImage from "./assets/img/ookla.webp"; +import LibreImage from "./assets/img/libre.webp"; +import CloudflareImage from "./assets/img/cloudflare.webp"; +import {jsonRequest, patchRequest} from "@/common/utils/RequestUtil"; +import {Trans} from "react-i18next"; +import {ConfigContext} from "@/common/contexts/Config"; + +const providers = [ + {id: "ookla", name: "Ookla", image: OoklaImage}, + {id: "libre", name: "LibreSpeed", image: LibreImage}, + {id: "cloudflare", name: "Cloudflare", image: CloudflareImage} +] + + +export const Dialog = () => { + const close = useContext(DialogContext); + const [config, reloadConfig] = useContext(ConfigContext); + const [provider, setProvider] = useState(config.provider || "ookla"); + + const [licenseAccepted, setLicenseAccepted] = useState(false); + const [licenseError, setLicenseError] = useState(false); + + const [ooklaServers, setOoklaServers] = useState({}); + const [libreServers, setLibreServers] = useState({}); + + const [serverId, setServerId] = useState("none"); + + useEffect(() => { + jsonRequest("/info/server/ookla").then((response) => { + setOoklaServers(response); + }); + jsonRequest("/info/server/libre").then((response) => { + setLibreServers(response); + }); + }, []); + + useEffect(() => { + if (config[provider + "Id"]) setServerId(config[provider + "Id"]); + }, [provider]); + + useEffect(() => { + if (serverId === "") setServerId("none"); + }, [serverId]); + + const update = async () => { + if (provider === "ookla" && !licenseAccepted) { + setLicenseError(true); + return; + } + + await patchRequest("/config/provider", {value: provider}); + + if (serverId !== config[provider + "Id"] && provider !== "cloudflare") { + await patchRequest("/config/" + provider + "Id", {value: serverId}); + } + + reloadConfig(); + + close(); + } + + return ( + <> +
+

{t("update.provider_title")}

+ close()}/> +
+
+
+ {providers.map((current, index) => ( +
setProvider(current.id)}> + {current.name}/ +

{current.name}

+
+ ))} +
+ {provider !== "cloudflare" &&
+
+

{t("dialog.provider.server")}

+ +
+
+

{t("dialog.provider.server_id")}

+ setServerId(e.target.value)}/> +
+
} + {provider === "cloudflare" &&
+

{t("dialog.provider.cloudflare_note")}

+
} +
+
+ + ) +} + +export const ProviderDialog = (props) => { + return ( + <> + + + + + ) +} \ No newline at end of file From 6884b7ae43a61bda77e5670b164e7d29afcb431a Mon Sep 17 00:00:00 2001 From: Mathias Wagner Date: Sun, 19 May 2024 20:26:26 +0200 Subject: [PATCH 34/39] Created the ProviderDialog index.js --- client/src/common/components/ProviderDialog/index.js | 1 + 1 file changed, 1 insertion(+) create mode 100644 client/src/common/components/ProviderDialog/index.js diff --git a/client/src/common/components/ProviderDialog/index.js b/client/src/common/components/ProviderDialog/index.js new file mode 100644 index 00000000..908e023f --- /dev/null +++ b/client/src/common/components/ProviderDialog/index.js @@ -0,0 +1 @@ +export {ProviderDialog as default} from "./ProviderDialog"; \ No newline at end of file From 3ab63062a1649c54f541fd2aa988cd99577eca29 Mon Sep 17 00:00:00 2001 From: Mathias Wagner Date: Sun, 19 May 2024 20:26:30 +0200 Subject: [PATCH 35/39] Created the ProviderDialog styles.sass --- .../components/ProviderDialog/styles.sass | 95 +++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 client/src/common/components/ProviderDialog/styles.sass diff --git a/client/src/common/components/ProviderDialog/styles.sass b/client/src/common/components/ProviderDialog/styles.sass new file mode 100644 index 00000000..40032cf8 --- /dev/null +++ b/client/src/common/components/ProviderDialog/styles.sass @@ -0,0 +1,95 @@ +@import "@/common/styles/colors" + +.provider-dialog-content + display: flex + margin: 1rem 0.5rem + user-select: none + flex-direction: column + + .provider-header + display: flex + gap: 1rem + + .provider-item + display: flex + align-items: center + padding: 0.3rem 0.5rem + gap: 0.5rem + border-radius: 0.8rem + border: 2px solid $light-gray + color: $darker-white + cursor: pointer + + img + width: 2.5rem + height: 2.5rem + + h3 + margin: 0 + + &:hover + background-color: $darker-gray + + .provider-item-active + background-color: $light-gray + + &:hover + background-color: $light-gray + + .provider-content + display: flex + flex-direction: column + margin-top: 1rem + + + .provider-setting + display: flex + gap: 1rem + align-items: center + justify-content: space-between + + .provider-input + width: 20rem + box-sizing: border-box + margin-top: 0.5rem + margin-bottom: 0.5rem + font-size: 1.3rem + + h3 + color: $darker-white + + .cloudflare-provider-info + color: $subtext + text-align: center + +.provider-dialog-footer + display: flex + align-items: center + justify-content: space-between + + .provider-license-box + display: flex + align-items: center + gap: 0.5rem + + input + border: 2px solid $light-gray + + .cb-error + border-color: $red + + label + color: $subtext + max-width: 20rem + flex: 1 + + +@media screen and (max-width: 610px) + .provider-dialog-content + .provider-header + flex-direction: column + +@media screen and (max-width: 520px) + .provider-dialog-content + .provider-setting .provider-input + width: 60% \ No newline at end of file From 4297103b5a12ba716463bebb95cd37da39cd2861 Mon Sep 17 00:00:00 2001 From: Mathias Wagner Date: Sun, 19 May 2024 20:27:10 +0200 Subject: [PATCH 36/39] Implemented the new ProviderDialog into the DropdownComponent.jsx --- .../components/Dropdown/DropdownComponent.jsx | 21 +++++-------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/client/src/common/components/Dropdown/DropdownComponent.jsx b/client/src/common/components/Dropdown/DropdownComponent.jsx index b80968fe..93a59392 100644 --- a/client/src/common/components/Dropdown/DropdownComponent.jsx +++ b/client/src/common/components/Dropdown/DropdownComponent.jsx @@ -16,10 +16,9 @@ import { faPause, faPingPongPaddleBall, faPlay, - faServer, faWandMagicSparkles, faCheck, - faExclamationTriangle + faExclamationTriangle, faSliders } from "@fortawesome/free-solid-svg-icons"; import {ConfigContext} from "@/common/contexts/Config"; import {StatusContext} from "@/common/contexts/Status"; @@ -36,6 +35,7 @@ import {ToastNotificationContext} from "@/common/contexts/ToastNotification"; import {NodeContext} from "@/common/contexts/Node"; import {IntegrationDialog} from "@/common/components/IntegrationDialog"; import LanguageDialog from "@/common/components/LanguageDialog"; +import ProviderDialog from "@/common/components/ProviderDialog"; let icon; @@ -65,6 +65,7 @@ function DropdownComponent() { const [showViewDialog, setShowViewDialog] = useState(false); const [showIntegrationDialog, setShowIntegrationDialog] = useState(false); const [showLanguageDialog, setShowLanguageDialog] = useState(false); + const [showProviderDialog, setShowProviderDialog] = useState(false); const ref = useRef(); useEffect(() => { @@ -130,19 +131,6 @@ function DropdownComponent() { } else setDialog({title: t("update.recommendations_title"), description: t("info.recommendations_error"), buttonText: t("dialog.okay")}); } - const updateServer = () => patchDialog("serverId", async (value) => ({ - title: t("update.server_title"), - select: true, - selectOptions: await jsonRequest("/info/server"), - unsetButton: t("update.manually"), - onClear: updateServerManually, - value - })); - - const updateServerManually = () => patchDialog("serverId", (value) => ({ - title: t("update.manual_server_title"), placeholder: t("update.manual_server_id"), type: "number", value: value, - })); - const updatePassword = async () => { const passwordSet = currentNode !== 0 ? findNode(currentNode).password : localStorage.getItem("password") != null; @@ -239,7 +227,7 @@ function DropdownComponent() { {run: updateDownload, icon: faArrowDown, text: t("dropdown.download")}, {run: recommendedSettings, icon: faWandMagicSparkles, text: t("dropdown.recommendations")}, {hr: true, key: 1}, - {run: updateServer, icon: faServer, text: t("dropdown.server")}, + {run: () => setShowProviderDialog(true), icon: faSliders, text: t("dropdown.server")}, {run: updatePassword, icon: faKey, text: t("dropdown.password"), previewHidden: true}, {run: updateCron, icon: faClock, text: t("dropdown.cron")}, {run: exportDialog, icon: faFileExport, text: t("dropdown.export")}, @@ -258,6 +246,7 @@ function DropdownComponent() { {showViewDialog && setShowViewDialog(false)}/>} {showIntegrationDialog && setShowIntegrationDialog(false)}/>} {showLanguageDialog && setShowLanguageDialog(false)}/>} + {showProviderDialog && setShowProviderDialog(false)}/>}