autoupdater, use ~/.config or windows equivalent for config

This commit is contained in:
CoolElectronics 2023-08-18 18:22:05 -04:00
parent ba77d77036
commit def0854064
No known key found for this signature in database
GPG key ID: F63593D168636C50
5 changed files with 185 additions and 124 deletions

46
pnpm-lock.yaml generated
View file

@ -1,4 +1,4 @@
lockfileVersion: '6.0' lockfileVersion: '6.1'
settings: settings:
autoInstallPeers: true autoInstallPeers: true
@ -23,8 +23,8 @@ importers:
specifier: ^6.10.2 specifier: ^6.10.2
version: 6.10.2 version: 6.10.2
'@tomphttp/bare-client': '@tomphttp/bare-client':
specifier: ^2.2.0-alpha specifier: file:../bare-client-custom
version: 2.2.0-alpha version: file:bare-client-custom
'@tomphttp/bare-server-node': '@tomphttp/bare-server-node':
specifier: ^2.0.1 specifier: ^2.0.1
version: 2.0.1 version: 2.0.1
@ -94,10 +94,14 @@ importers:
version: 5.1.6 version: 5.1.6
Ultraviolet: Ultraviolet:
dependencies:
bare-client-custom:
specifier: workspace:2.2.0-alpha
version: link:../bare-client-custom
devDependencies: devDependencies:
'@tomphttp/bare-client': '@tomphttp/bare-client':
specifier: ^2.2.0-alpha specifier: file:../bare-client-custom/
version: 2.2.0-alpha version: file:bare-client-custom
css-tree: css-tree:
specifier: ^2.3.1 specifier: ^2.3.1
version: 2.3.1 version: 2.3.1
@ -197,7 +201,7 @@ importers:
corium: corium:
dependencies: dependencies:
'@rollup/browser': '@rollup/browser':
specifier: ^3.17.2 specifier: ^3.28.0
version: 3.28.0 version: 3.28.0
'@swc/helpers': '@swc/helpers':
specifier: ^0.4.14 specifier: ^0.4.14
@ -379,6 +383,9 @@ importers:
'@inquirer/select': '@inquirer/select':
specifier: ^1.2.7 specifier: ^1.2.7
version: 1.2.7 version: 1.2.7
'@types/follow-redirects':
specifier: ^1.14.1
version: 1.14.1
boxen: boxen:
specifier: ^7.1.1 specifier: ^7.1.1
version: 7.1.1 version: 7.1.1
@ -400,6 +407,9 @@ importers:
firebase: firebase:
specifier: ^10.1.0 specifier: ^10.1.0
version: 10.1.0(react-native@0.72.3) version: 10.1.0(react-native@0.72.3)
follow-redirects:
specifier: ^1.15.2
version: 1.15.2
inquirer: inquirer:
specifier: ^9.2.10 specifier: ^9.2.10
version: 9.2.10 version: 9.2.10
@ -4409,9 +4419,6 @@ packages:
resolution: {integrity: sha512-WyIVnSAqzfrLejmOhh/l/LtDOeK+SHnBGi/z+QyliVP1T1JxoNE5eecwxlV+osM9J6FTAYVGNHr8/5bubaIj6Q==} resolution: {integrity: sha512-WyIVnSAqzfrLejmOhh/l/LtDOeK+SHnBGi/z+QyliVP1T1JxoNE5eecwxlV+osM9J6FTAYVGNHr8/5bubaIj6Q==}
dev: false dev: false
/@tomphttp/bare-client@2.2.0-alpha:
resolution: {integrity: sha512-xhcflOpwr92tkpp8SoDhB3nK3LHMBIjx+vgow37XobQew2k0/mXSxmaU7BsDFpOIa1CcLCEsR8gWn0v7Cy9+7Q==}
/@tomphttp/bare-server-node@2.0.1: /@tomphttp/bare-server-node@2.0.1:
resolution: {integrity: sha512-L42TC/AldYRFBRZSxhkI0FC5TL8EC/NAsepNC/cWYTTiHQJ7mGg/vdTqNz8ShTYHr6LTHYkuD3/81nhX55SYtA==} resolution: {integrity: sha512-L42TC/AldYRFBRZSxhkI0FC5TL8EC/NAsepNC/cWYTTiHQJ7mGg/vdTqNz8ShTYHr6LTHYkuD3/81nhX55SYtA==}
engines: {node: '>=18.0.0'} engines: {node: '>=18.0.0'}
@ -4534,6 +4541,12 @@ packages:
'@types/qs': 6.9.7 '@types/qs': 6.9.7
'@types/serve-static': 1.15.2 '@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: /@types/glob@8.1.0:
resolution: {integrity: sha512-IO+MJPVhoqz+28h1qLAcBEH2+xHMK6MTyHJc7MTnnYb6wsoLR29POVGJ7LycmVXIqyy/4/2ShP5sUwTXuOwb/w==} resolution: {integrity: sha512-IO+MJPVhoqz+28h1qLAcBEH2+xHMK6MTyHJc7MTnnYb6wsoLR29POVGJ7LycmVXIqyy/4/2ShP5sUwTXuOwb/w==}
requiresBuild: true requiresBuild: true
@ -4702,7 +4715,6 @@ packages:
/@types/uuid@9.0.2: /@types/uuid@9.0.2:
resolution: {integrity: sha512-kNnC1GFBLuhImSnV7w4njQkUiJi0ZXUycu1rUaouPqiKlXkh77JKgdRnTAp1x5eBwcIwbtI+3otwzuIDEuDoxQ==} resolution: {integrity: sha512-kNnC1GFBLuhImSnV7w4njQkUiJi0ZXUycu1rUaouPqiKlXkh77JKgdRnTAp1x5eBwcIwbtI+3otwzuIDEuDoxQ==}
dev: false
/@types/webrtc@0.0.36: /@types/webrtc@0.0.36:
resolution: {integrity: sha512-tYFarc92EluXU7XyRmWbkQXSbZIOHTdDOudFPal9u/TNTQuouWpIHV/2o9bNAdqvTJFjLJh/zflCOLWbL30tEQ==} resolution: {integrity: sha512-tYFarc92EluXU7XyRmWbkQXSbZIOHTdDOudFPal9u/TNTQuouWpIHV/2o9bNAdqvTJFjLJh/zflCOLWbL30tEQ==}
@ -7764,6 +7776,16 @@ packages:
engines: {node: '>=0.4.0'} engines: {node: '>=0.4.0'}
dev: false 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: /for-each@0.3.3:
resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==}
dependencies: dependencies:
@ -12827,7 +12849,6 @@ packages:
/uuid@9.0.0: /uuid@9.0.0:
resolution: {integrity: sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==} resolution: {integrity: sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==}
hasBin: true hasBin: true
dev: false
/v8-compile-cache-lib@3.0.1: /v8-compile-cache-lib@3.0.1:
resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==}
@ -13314,14 +13335,15 @@ packages:
file:bare-client-custom: file:bare-client-custom:
resolution: {directory: bare-client-custom, type: directory} resolution: {directory: bare-client-custom, type: directory}
name: bare-client-custom name: bare-client-custom
version: 2.2.0-alpha
dependencies: dependencies:
'@types/uuid': 9.0.2 '@types/uuid': 9.0.2
uuid: 9.0.0 uuid: 9.0.0
dev: false
file:corium: file:corium:
resolution: {directory: corium, type: directory} resolution: {directory: corium, type: directory}
name: corium name: corium
version: 1.0.0-alpha.2
dependencies: dependencies:
'@rollup/browser': 3.28.0 '@rollup/browser': 3.28.0
'@swc/helpers': 0.4.14 '@swc/helpers': 0.4.14

View file

@ -16,6 +16,7 @@
"@esbuild-plugins/node-resolve": "^0.2.2", "@esbuild-plugins/node-resolve": "^0.2.2",
"@inquirer/prompts": "^3.0.2", "@inquirer/prompts": "^3.0.2",
"@inquirer/select": "^1.2.7", "@inquirer/select": "^1.2.7",
"@types/follow-redirects": "^1.14.1",
"boxen": "^7.1.1", "boxen": "^7.1.1",
"chalk": "^5.3.0", "chalk": "^5.3.0",
"dotenv": "^16.3.1", "dotenv": "^16.3.1",
@ -23,6 +24,7 @@
"express": "^4.18.2", "express": "^4.18.2",
"express-ws": "^5.0.2", "express-ws": "^5.0.2",
"firebase": "^10.1.0", "firebase": "^10.1.0",
"follow-redirects": "^1.15.2",
"inquirer": "^9.2.10", "inquirer": "^9.2.10",
"ipaddr.js": "^2.1.0", "ipaddr.js": "^2.1.0",
"isomorphic-ws": "^5.0.0", "isomorphic-ws": "^5.0.0",

24
server/src/autoupdater.ts Normal file
View file

@ -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);
});
})

8
server/src/lib.ts Normal file
View file

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

View file

@ -17,134 +17,139 @@ import TrackerList from "tracker-list";
import fs from "fs"; import fs from "fs";
import { exit } from "process"; import { exit } from "process";
import { datadir } from "./lib";
async function config() { async function config() {
if ( let dir = datadir();
!(await confirm({
message: if (
"No config.json found. Would you like to go through first-time setup?", !(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 }
) )
); exit(1);
const tracker = (await select({ console.log(
message: "Select a central tracker", boxen(
choices: Object.keys(TrackerList).map((name) => ({ name, value: name })), `${chalk.yellow("")} ${chalk.blue(
})) as keyof typeof TrackerList; "Adrift Server Setup"
const type = await select({ )} ${chalk.yellow("")}`,
message: "Select a central tracker", { padding: 1 }
choices: [ )
{ );
value: "swarm", const tracker = (await select({
name: "Join global swarm", message: "Select a central tracker",
description: choices: Object.keys(TrackerList).map((name) => ({ name, value: name })),
"Allow requests from any Adrift user to connect to your server", })) as keyof typeof TrackerList;
}, const type = await select({
{ message: "Select a central tracker",
value: "account", choices: [
name: "Link to a personal account", {
description: value: "swarm",
"Connect to your account, no one but you will be able to connect to the server", 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 = {}; let credentials: any = {};
if (type == "account") { if (type == "account") {
initializeApp(TrackerList[tracker].firebase); initializeApp(TrackerList[tracker].firebase);
await login(credentials); await login(credentials);
} }
let conf = { let conf = {
tracker, tracker,
type, type,
credentials, credentials,
}; };
console.log(chalk.bold("Writing choices to config.json...")); console.log(chalk.bold(`Writing choices to ${dir}/config.json...`));
fs.writeFile("config.json", JSON.stringify(conf), () => {}); fs.writeFile(`${dir}/config.json`, JSON.stringify(conf), () => { });
return conf; return conf;
} }
async function login(credentials: any) { async function login(credentials: any) {
for (;;) { for (; ;) {
credentials.email = await input({ credentials.email = await input({
message: "Enter your account's email address", message: "Enter your account's email address",
}); });
credentials.password = await password({ credentials.password = await password({
message: "Enter your account's password", message: "Enter your account's password",
}); });
let auth = getAuth(); let auth = getAuth();
try { try {
let creds = await signInWithEmailAndPassword( let creds = await signInWithEmailAndPassword(
auth, auth,
credentials.email, credentials.email,
credentials.password credentials.password
); );
return creds; return creds;
} catch (err) { } catch (err) {
console.error(chalk.red(`Error signing in: ${err.code}`)); console.error(chalk.red(`Error signing in: ${err.code}`));
}
} }
}
} }
(async () => { (async () => {
let conf; let dir = datadir();
try {
conf = JSON.parse(fs.readFileSync("config.json").toString());
} catch {
conf = await config();
}
let tracker = TrackerList[conf.tracker as keyof typeof TrackerList];
console.log(chalk.blue("Starting server!")); let conf;
if (conf.type == "swarm") { try {
let connect = () => { conf = JSON.parse(fs.readFileSync(`${dir}/config.json`).toString());
let trackerws = new WebSocket(tracker.tracker + "/join"); } catch {
trackerws.onclose = () => { conf = await config();
console.log(`Disconnected from tracker. Retrying...`); }
setTimeout(() => { let tracker = TrackerList[conf.tracker as keyof typeof TrackerList];
connect();
}, 10000);
};
trackerws.onopen = () => {
console.log(`Connected to tracker ${tracker.tracker}`);
};
connectTracker(trackerws);
};
connect();
} else {
initializeApp(tracker.firebase);
let creds = await signInWithEmailAndPassword( console.log(chalk.blue("Starting server!"));
getAuth(), if (conf.type == "swarm") {
conf.credentials.email, let connect = () => {
conf.credentials.password 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 creds = await signInWithEmailAndPassword(
let peer = ref(db, `/peers/${creds.user.uid}`); getAuth(),
conf.credentials.email,
conf.credentials.password
);
set(peer, ""); const db = getDatabase();
let peer = ref(db, `/peers/${creds.user.uid}`);
onValue(peer, (snapshot) => { set(peer, "");
const str = snapshot.val();
if (str) { onValue(peer, (snapshot) => {
let data = JSON.parse(str); const str = snapshot.val();
if (data && data.offer && data.localCandidates) {
answerRtc(data, (answer) => { if (str) {
console.log("answering"); let data = JSON.parse(str);
set(peer, JSON.stringify(answer)); if (data && data.offer && data.localCandidates) {
}); answerRtc(data, (answer) => {
} console.log("answering");
} set(peer, JSON.stringify(answer));
}); });
} }
}
});
}
})(); })();