diff --git a/seeder/package-lock.json b/seeder/package-lock.json index 001514aae3..b50ab9bd8d 100644 --- a/seeder/package-lock.json +++ b/seeder/package-lock.json @@ -13,7 +13,8 @@ "@electron-toolkit/utils": "^3.0.0", "cors": "^2.8.5", "electron-updater": "^6.1.7", - "express": "^4.19.2" + "express": "^4.19.2", + "local-devices": "^4.0.0" }, "devDependencies": { "@coreproject-moe/icons": "^0.0.13", @@ -2928,7 +2929,6 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", - "dev": true, "license": "MIT" }, "node_modules/anymatch": { @@ -3824,6 +3824,11 @@ "node": ">=8" } }, + "node_modules/cidr-regex": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/cidr-regex/-/cidr-regex-1.0.7.tgz", + "integrity": "sha512-4sQNVjJw/I3kHyb9FGSJ/dBT18BP7pf5zongGsEYExNvtTss24hgJxZr0JK1eWlumX/ij4yiR/vYlndRynnkDQ==" + }, "node_modules/cli-truncate": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz", @@ -5874,6 +5879,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-ip-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/get-ip-range/-/get-ip-range-2.1.1.tgz", + "integrity": "sha512-n401kTpf57VhbW2UvInXxhw1DgTJSsZf24gpNhJrFU8Cv+Jk/sQ+qukP2x0EF4MUEjDWlDLeIhIY/f80IV0kqg==", + "dependencies": { + "cidr-regex": "^1.0.7", + "ip": "^1.1.5", + "ip-address": "^6.1.0" + } + }, "node_modules/get-stream": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", @@ -6351,6 +6366,33 @@ "dev": true, "license": "MIT" }, + "node_modules/ip": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.9.tgz", + "integrity": "sha512-cyRxvOEpNHNtchU3Ln9KC/auJgup87llfQpQ+t5ghoC/UhL16SWzbueiCsdTnWmqAWl7LadfuwhlqmtOaqMHdQ==" + }, + "node_modules/ip-address": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-6.4.0.tgz", + "integrity": "sha512-c5uxc2WUTuRBVHT/6r4m7HIr/DfV0bF6DvLH3iZGSK8wp8iMwwZSgIq2do0asFf8q9ECug0SE+6+1ACMe4sorA==", + "dependencies": { + "jsbn": "1.1.0", + "lodash.find": "4.6.0", + "lodash.max": "4.0.1", + "lodash.merge": "4.6.2", + "lodash.padstart": "4.6.1", + "lodash.repeat": "4.1.0", + "sprintf-js": "1.1.2" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/ip-address/node_modules/sprintf-js": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz", + "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==" + }, "node_modules/ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", @@ -6608,6 +6650,11 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/jsbn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", + "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==" + }, "node_modules/jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", @@ -6780,6 +6827,19 @@ "dev": true, "license": "MIT" }, + "node_modules/local-devices": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/local-devices/-/local-devices-4.0.0.tgz", + "integrity": "sha512-65EPltZW7bPRTmIiL9yuQcu0Om6dYl4dzRgiIYxl/cUO62FBW09ZpIVtpffXU8vryfGXEXxt68oWK/Kru12FEA==", + "dependencies": { + "get-ip-range": "^2.1.0", + "ip": "^1.1.5", + "mz": "^2.7.0" + }, + "engines": { + "node": ">=10.17" + } + }, "node_modules/locate-character": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz", @@ -6834,6 +6894,11 @@ "integrity": "sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw==", "license": "MIT" }, + "node_modules/lodash.find": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.find/-/lodash.find-4.6.0.tgz", + "integrity": "sha512-yaRZoAV3Xq28F1iafWN1+a0rflOej93l1DQUejs3SZ41h2O9UJBoS9aueGjPDgAl4B6tPC0NuuchLKaDQQ3Isg==" + }, "node_modules/lodash.flatten": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", @@ -6856,13 +6921,27 @@ "license": "MIT", "peer": true }, + "node_modules/lodash.max": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.max/-/lodash.max-4.0.1.tgz", + "integrity": "sha512-iykTDTb7PK33HSQmKy34zv+hh4WEu7WonJPXQcgODzUbbtradtNs8RsD/GI7XV++60KaKR1xhW56N4ISqHesfQ==" + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true, "license": "MIT" }, + "node_modules/lodash.padstart": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/lodash.padstart/-/lodash.padstart-4.6.1.tgz", + "integrity": "sha512-sW73O6S8+Tg66eY56DBk85aQzzUJDtpoXFBgELMd5P/SotAguo+1kYO6RuYgXxA4HJH3LFTFPASX6ET6bjfriw==" + }, + "node_modules/lodash.repeat": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/lodash.repeat/-/lodash.repeat-4.1.0.tgz", + "integrity": "sha512-eWsgQW89IewS95ZOcr15HHCX6FVDxq3f2PNUIng3fyzsPev9imFQxIYdFZ6crl8L56UR6ZlGDLcEb3RZsCSSqw==" + }, "node_modules/lodash.union": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz", @@ -7117,7 +7196,6 @@ "version": "2.7.0", "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", - "dev": true, "license": "MIT", "dependencies": { "any-promise": "^1.0.0", @@ -9010,7 +9088,6 @@ "version": "3.3.1", "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", - "dev": true, "license": "MIT", "dependencies": { "any-promise": "^1.0.0" @@ -9020,7 +9097,6 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", - "dev": true, "license": "MIT", "dependencies": { "thenify": ">= 3.1.0 < 4" diff --git a/seeder/package.json b/seeder/package.json index a3400b0cd0..e178f5fc2c 100644 --- a/seeder/package.json +++ b/seeder/package.json @@ -23,7 +23,8 @@ "@electron-toolkit/utils": "^3.0.0", "cors": "^2.8.5", "electron-updater": "^6.1.7", - "express": "^4.19.2" + "express": "^4.19.2", + "local-devices": "^4.0.0" }, "devDependencies": { "@coreproject-moe/icons": "^0.0.13", diff --git a/seeder/src/main/backend/index.ts b/seeder/src/main/backend/index.ts index 10054fb333..0cb1451b9a 100644 --- a/seeder/src/main/backend/index.ts +++ b/seeder/src/main/backend/index.ts @@ -10,4 +10,8 @@ app.get("/", (_, res) => { res.send("Hello World!"); }); +app.get("/shiinobi-healthcheck", (_, res) => { + res.send("We are friends"); +}); + export { app }; diff --git a/seeder/src/main/utils/port.ts b/seeder/src/main/utils/port.ts index f6aa734a7a..e7275badc3 100644 --- a/seeder/src/main/utils/port.ts +++ b/seeder/src/main/utils/port.ts @@ -1,11 +1,40 @@ import net, { AddressInfo } from "node:net"; +import find from "local-devices"; + +// Range : 49152 – 65535 +const PORT_START = 49152, + PORT_END = 65535; export function get_free_port() { - return new Promise((resolve) => { + return new Promise((resolve, reject) => { const server = net.createServer(); - server.listen(0, () => { - const port = (server.address() as AddressInfo)?.port; // Default to 0 if address is not AddressInfo + let port = Math.floor(Math.random() * (PORT_START - PORT_END + 1)) + PORT_START; + + // Try to listen on a random port within the range + server.listen(port, () => { + port = (server.address() as AddressInfo)?.port; server.close(() => resolve(port)); }); + + // Handle errors (e.g., port already in use) + server.on("error", () => { + // Retry with another port if the current one is unavailable + get_free_port().then(resolve).catch(reject); + }); }); } +export async function get_all_devices_running_shiinobi() { + let friends = new Array(); + const devices = await find(); + + for (const device of devices) { + for (let i = PORT_START; i < PORT_END; i++) { + const URL = `https://${device.ip}/shiinobi-healthcheck`; + const res = await fetch(URL); + const text = await res.text(); + if (text === "We are friends") { + friends.push(device.ip); + } + } + } +}