diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 65a9d11..7aa9927 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,4 +1,4 @@ -lockfileVersion: '6.0' +lockfileVersion: '6.1' settings: autoInstallPeers: true @@ -23,8 +23,8 @@ importers: specifier: ^6.10.2 version: 6.10.2 '@tomphttp/bare-client': - specifier: ^2.2.0-alpha - version: 2.2.0-alpha + specifier: file:../bare-client-custom + version: file:bare-client-custom '@tomphttp/bare-server-node': specifier: ^2.0.1 version: 2.0.1 @@ -94,10 +94,14 @@ importers: version: 5.1.6 Ultraviolet: + dependencies: + bare-client-custom: + specifier: workspace:2.2.0-alpha + version: link:../bare-client-custom devDependencies: '@tomphttp/bare-client': - specifier: ^2.2.0-alpha - version: 2.2.0-alpha + specifier: file:../bare-client-custom/ + version: file:bare-client-custom css-tree: specifier: ^2.3.1 version: 2.3.1 @@ -197,7 +201,7 @@ importers: corium: dependencies: '@rollup/browser': - specifier: ^3.17.2 + specifier: ^3.28.0 version: 3.28.0 '@swc/helpers': specifier: ^0.4.14 @@ -379,6 +383,9 @@ importers: '@inquirer/select': specifier: ^1.2.7 version: 1.2.7 + '@types/follow-redirects': + specifier: ^1.14.1 + version: 1.14.1 boxen: specifier: ^7.1.1 version: 7.1.1 @@ -400,6 +407,9 @@ importers: firebase: specifier: ^10.1.0 version: 10.1.0(react-native@0.72.3) + follow-redirects: + specifier: ^1.15.2 + version: 1.15.2 inquirer: specifier: ^9.2.10 version: 9.2.10 @@ -4409,9 +4419,6 @@ packages: resolution: {integrity: sha512-WyIVnSAqzfrLejmOhh/l/LtDOeK+SHnBGi/z+QyliVP1T1JxoNE5eecwxlV+osM9J6FTAYVGNHr8/5bubaIj6Q==} dev: false - /@tomphttp/bare-client@2.2.0-alpha: - resolution: {integrity: sha512-xhcflOpwr92tkpp8SoDhB3nK3LHMBIjx+vgow37XobQew2k0/mXSxmaU7BsDFpOIa1CcLCEsR8gWn0v7Cy9+7Q==} - /@tomphttp/bare-server-node@2.0.1: resolution: {integrity: sha512-L42TC/AldYRFBRZSxhkI0FC5TL8EC/NAsepNC/cWYTTiHQJ7mGg/vdTqNz8ShTYHr6LTHYkuD3/81nhX55SYtA==} engines: {node: '>=18.0.0'} @@ -4534,6 +4541,12 @@ packages: '@types/qs': 6.9.7 '@types/serve-static': 1.15.2 + /@types/follow-redirects@1.14.1: + resolution: {integrity: sha512-THBEFwqsLuU/K62B5JRwab9NW97cFmL4Iy34NTMX0bMycQVzq2q7PKOkhfivIwxdpa/J72RppgC42vCHfwKJ0Q==} + dependencies: + '@types/node': 20.4.10 + dev: false + /@types/glob@8.1.0: resolution: {integrity: sha512-IO+MJPVhoqz+28h1qLAcBEH2+xHMK6MTyHJc7MTnnYb6wsoLR29POVGJ7LycmVXIqyy/4/2ShP5sUwTXuOwb/w==} requiresBuild: true @@ -4702,7 +4715,6 @@ packages: /@types/uuid@9.0.2: resolution: {integrity: sha512-kNnC1GFBLuhImSnV7w4njQkUiJi0ZXUycu1rUaouPqiKlXkh77JKgdRnTAp1x5eBwcIwbtI+3otwzuIDEuDoxQ==} - dev: false /@types/webrtc@0.0.36: resolution: {integrity: sha512-tYFarc92EluXU7XyRmWbkQXSbZIOHTdDOudFPal9u/TNTQuouWpIHV/2o9bNAdqvTJFjLJh/zflCOLWbL30tEQ==} @@ -7764,6 +7776,16 @@ packages: engines: {node: '>=0.4.0'} dev: false + /follow-redirects@1.15.2: + resolution: {integrity: sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + dev: false + /for-each@0.3.3: resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} dependencies: @@ -12827,7 +12849,6 @@ packages: /uuid@9.0.0: resolution: {integrity: sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==} hasBin: true - dev: false /v8-compile-cache-lib@3.0.1: resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} @@ -13314,14 +13335,15 @@ packages: file:bare-client-custom: resolution: {directory: bare-client-custom, type: directory} name: bare-client-custom + version: 2.2.0-alpha dependencies: '@types/uuid': 9.0.2 uuid: 9.0.0 - dev: false file:corium: resolution: {directory: corium, type: directory} name: corium + version: 1.0.0-alpha.2 dependencies: '@rollup/browser': 3.28.0 '@swc/helpers': 0.4.14 diff --git a/server/package.json b/server/package.json index c4885e0..2911657 100644 --- a/server/package.json +++ b/server/package.json @@ -16,6 +16,7 @@ "@esbuild-plugins/node-resolve": "^0.2.2", "@inquirer/prompts": "^3.0.2", "@inquirer/select": "^1.2.7", + "@types/follow-redirects": "^1.14.1", "boxen": "^7.1.1", "chalk": "^5.3.0", "dotenv": "^16.3.1", @@ -23,6 +24,7 @@ "express": "^4.18.2", "express-ws": "^5.0.2", "firebase": "^10.1.0", + "follow-redirects": "^1.15.2", "inquirer": "^9.2.10", "ipaddr.js": "^2.1.0", "isomorphic-ws": "^5.0.0", diff --git a/server/src/autoupdater.ts b/server/src/autoupdater.ts new file mode 100644 index 0000000..0952494 --- /dev/null +++ b/server/src/autoupdater.ts @@ -0,0 +1,24 @@ +import { datadir } from "./lib"; +import { spawn } from "child_process"; +import fs from "fs"; +import { https } from 'follow-redirects'; +let dir = datadir(); +let platform = `${process.platform}-${process.arch}` +let appname = `adrift-server-${platform}`; +if (process.platform == "win32") { + appname += ".exe"; +} +https.get( + "https://github.com/MercuryWorkshop/adrift/releases/latest/download/adrift-server-${}", resp => { + let file = fs.createWriteStream(`${dir}/${appname}`); + resp.pipe(file); + + + file.on("finish", () => { + fs.chmodSync(`${dir}/${appname}`, "755"); + setTimeout(() => { + // this timeout shouldn't be needed, but it is + spawn(`${dir}/${appname}`, [], { stdio: "inherit" }); + }, 2000); + }); + }) \ No newline at end of file diff --git a/server/src/lib.ts b/server/src/lib.ts new file mode 100644 index 0000000..df2ab4b --- /dev/null +++ b/server/src/lib.ts @@ -0,0 +1,8 @@ +import fs from "fs"; + +export function datadir(): string { + let base = (process.env.APPDATA || (process.platform == 'darwin' ? process.env.HOME + '/Library/Preferences' : process.env.HOME + "/.config")) + "/adrift-server" + if (!fs.existsSync(base)) + fs.mkdirSync(base); + return base; +} \ No newline at end of file diff --git a/server/src/main.ts b/server/src/main.ts index 89dae95..3627bc1 100644 --- a/server/src/main.ts +++ b/server/src/main.ts @@ -17,134 +17,139 @@ import TrackerList from "tracker-list"; import fs from "fs"; import { exit } from "process"; +import { datadir } from "./lib"; async function config() { - if ( - !(await confirm({ - message: - "No config.json found. Would you like to go through first-time setup?", - })) - ) - exit(1); - console.log( - boxen( - `${chalk.yellow("")} ${chalk.blue( - "Adrift Server Setup" - )} ${chalk.yellow("")}`, - { padding: 1 } + let dir = datadir(); + + if ( + !(await confirm({ + message: + "No config.json found. Would you like to go through first-time setup?", + })) ) - ); - const tracker = (await select({ - message: "Select a central tracker", - choices: Object.keys(TrackerList).map((name) => ({ name, value: name })), - })) as keyof typeof TrackerList; - const type = await select({ - message: "Select a central tracker", - choices: [ - { - value: "swarm", - name: "Join global swarm", - description: - "Allow requests from any Adrift user to connect to your server", - }, - { - value: "account", - name: "Link to a personal account", - description: - "Connect to your account, no one but you will be able to connect to the server", - }, - ], - }); + exit(1); + console.log( + boxen( + `${chalk.yellow("")} ${chalk.blue( + "Adrift Server Setup" + )} ${chalk.yellow("")}`, + { padding: 1 } + ) + ); + const tracker = (await select({ + message: "Select a central tracker", + choices: Object.keys(TrackerList).map((name) => ({ name, value: name })), + })) as keyof typeof TrackerList; + const type = await select({ + message: "Select a central tracker", + choices: [ + { + value: "swarm", + name: "Join global swarm", + description: + "Allow requests from any Adrift user to connect to your server", + }, + { + value: "account", + name: "Link to a personal account", + description: + "Connect to your account, no one but you will be able to connect to the server", + }, + ], + }); - let credentials: any = {}; - if (type == "account") { - initializeApp(TrackerList[tracker].firebase); - await login(credentials); - } + let credentials: any = {}; + if (type == "account") { + initializeApp(TrackerList[tracker].firebase); + await login(credentials); + } - let conf = { - tracker, - type, - credentials, - }; - console.log(chalk.bold("Writing choices to config.json...")); + let conf = { + tracker, + type, + credentials, + }; + console.log(chalk.bold(`Writing choices to ${dir}/config.json...`)); - fs.writeFile("config.json", JSON.stringify(conf), () => {}); - return conf; + fs.writeFile(`${dir}/config.json`, JSON.stringify(conf), () => { }); + return conf; } async function login(credentials: any) { - for (;;) { - credentials.email = await input({ - message: "Enter your account's email address", - }); - credentials.password = await password({ - message: "Enter your account's password", - }); + for (; ;) { + credentials.email = await input({ + message: "Enter your account's email address", + }); + credentials.password = await password({ + message: "Enter your account's password", + }); - let auth = getAuth(); - try { - let creds = await signInWithEmailAndPassword( - auth, - credentials.email, - credentials.password - ); - return creds; - } catch (err) { - console.error(chalk.red(`Error signing in: ${err.code}`)); + let auth = getAuth(); + try { + let creds = await signInWithEmailAndPassword( + auth, + credentials.email, + credentials.password + ); + return creds; + } catch (err) { + console.error(chalk.red(`Error signing in: ${err.code}`)); + } } - } } (async () => { - let conf; - try { - conf = JSON.parse(fs.readFileSync("config.json").toString()); - } catch { - conf = await config(); - } - let tracker = TrackerList[conf.tracker as keyof typeof TrackerList]; + let dir = datadir(); - console.log(chalk.blue("Starting server!")); - if (conf.type == "swarm") { - let connect = () => { - let trackerws = new WebSocket(tracker.tracker + "/join"); - trackerws.onclose = () => { - console.log(`Disconnected from tracker. Retrying...`); - setTimeout(() => { - connect(); - }, 10000); - }; - trackerws.onopen = () => { - console.log(`Connected to tracker ${tracker.tracker}`); - }; - connectTracker(trackerws); - }; - connect(); - } else { - initializeApp(tracker.firebase); + let conf; + try { + conf = JSON.parse(fs.readFileSync(`${dir}/config.json`).toString()); + } catch { + conf = await config(); + } + let tracker = TrackerList[conf.tracker as keyof typeof TrackerList]; - let creds = await signInWithEmailAndPassword( - getAuth(), - conf.credentials.email, - conf.credentials.password - ); + console.log(chalk.blue("Starting server!")); + if (conf.type == "swarm") { + let connect = () => { + let trackerws = new WebSocket(tracker.tracker + "/join"); + trackerws.onclose = () => { + console.log(`Disconnected from tracker. Retrying...`); + setTimeout(() => { + connect(); + }, 10000); + }; + trackerws.onopen = () => { + console.log(`Connected to tracker ${tracker.tracker}`); + }; + connectTracker(trackerws); + }; + connect(); + } else { + initializeApp(tracker.firebase); - const db = getDatabase(); - let peer = ref(db, `/peers/${creds.user.uid}`); + let creds = await signInWithEmailAndPassword( + getAuth(), + conf.credentials.email, + conf.credentials.password + ); - set(peer, ""); + const db = getDatabase(); + let peer = ref(db, `/peers/${creds.user.uid}`); - onValue(peer, (snapshot) => { - const str = snapshot.val(); + set(peer, ""); - if (str) { - let data = JSON.parse(str); - if (data && data.offer && data.localCandidates) { - answerRtc(data, (answer) => { - console.log("answering"); - set(peer, JSON.stringify(answer)); - }); - } - } - }); - } + onValue(peer, (snapshot) => { + const str = snapshot.val(); + + if (str) { + let data = JSON.parse(str); + if (data && data.offer && data.localCandidates) { + answerRtc(data, (answer) => { + console.log("answering"); + set(peer, JSON.stringify(answer)); + }); + } + } + }); + } })();