diff --git a/packages/hydrooj/src/entry/setup.ts b/packages/hydrooj/src/entry/setup.ts index 2814c29f1..9f6e20fea 100644 --- a/packages/hydrooj/src/entry/setup.ts +++ b/packages/hydrooj/src/entry/setup.ts @@ -1,102 +1,39 @@ +/* eslint-disable no-await-in-loop */ import os from 'os'; import path from 'path'; -import cac from 'cac'; import fs from 'fs-extra'; -import type { Context } from 'koa'; import { MongoClient, WriteConcern } from 'mongodb'; import mongoUri from 'mongodb-uri'; -import { Context as PluginContext } from '../context'; +import { readline } from '../ui'; -const listenPort = cac().parse().options.port || 8888; -let resolve; - -async function get(ctx: Context) { - ctx.body = ` - - - - - - - Setup - - -
-
-
-
-

Setup

-
-
- -
-
-
- -
-
-
-
-
-
-
- - `; - ctx.response.type = 'text/html'; -} - -async function post(ctx: Context) { - try { - if (!ctx.request.body?.url) throw new Error('no url found'); - const url = mongoUri.parse(ctx.request.body.url); - const Database = await MongoClient.connect(ctx.request.body.url, { - readPreference: 'nearest', - writeConcern: new WriteConcern('majority'), - }); - const db = Database.db(url.database); - const coll = db.collection('system'); - await Promise.all([ - coll.updateOne( - { _id: 'server.url' }, - { $set: { value: ctx.request.href } }, - { upsert: true }, - ), - coll.updateOne( - { _id: 'server.port' }, - { $set: { value: parseInt(listenPort as string, 10) } }, - { upsert: true }, - ), - ]); - fs.ensureDirSync(path.resolve(os.homedir(), '.hydro')); - fs.writeFileSync(path.resolve(os.homedir(), '.hydro', 'config.json'), JSON.stringify({ url: ctx.request.body.url })); - ctx.body = '

Done! Hydro is now starting.

'; - resolve?.(); - } catch (e) { - ctx.body = `Error connecting to database: ${e.message}\n${e.stack}`; +export async function load() { + console.error('Config file not found.'); + if (!process.stdin.isTTY) { + console.error('Please fill in ~/.hydro/config.json with MongoDB connection string in the following format:'); + console.error('{"url":"mongodb://localhost:27017/hydro"}'); + process.exit(1); + } + // eslint-disable-next-line no-constant-condition + while (true) { + console.error('Please type your MongoDB connection string below:'); + console.error('Example: mongodb://localhost:27017/hydro'); + try { + const uri = await readline(); + if (!uri) throw new Error('no url found'); + const url = mongoUri.parse(uri); + const Database = await MongoClient.connect(uri, { + readPreference: 'nearest', + writeConcern: new WriteConcern('majority'), + }); + const db = Database.db(url.database); + const coll = db.collection('system'); + await coll.updateOne({ _id: '_test' }, { $set: { value: 1 } }, { upsert: true }); + await coll.deleteOne({ _id: '_test' }); + fs.ensureDirSync(path.resolve(os.homedir(), '.hydro')); + fs.writeFileSync(path.resolve(os.homedir(), '.hydro', 'config.json'), JSON.stringify({ url: uri })); + break; + } catch (e) { + console.error(e); + } } } - -export function load(ctx: PluginContext) { - let dispose; - ctx.plugin(require('@hydrooj/framework'), { - keys: [Math.random()], - proxy: false, - upload: false, - port: listenPort, - }); - ctx.inject(['server'], ({ server }) => { - dispose = server.addServerLayer('setup', (c) => { - if (c.request.method.toLowerCase() === 'post') return post(c); - return get(c); - }); - }); - return new Promise((r) => { - resolve = () => { - dispose?.(); - r(null); - }; - }); -} diff --git a/packages/hydrooj/src/ui.ts b/packages/hydrooj/src/ui.ts index 9372c9002..57747aca6 100644 --- a/packages/hydrooj/src/ui.ts +++ b/packages/hydrooj/src/ui.ts @@ -22,7 +22,6 @@ process.on('SIGTERM', terminate); const shell = new Logger('shell'); async function executeCommand(input: string) { - input = input.trim(); // Clear the stack setImmediate(async () => { if (input === 'exit' || input === 'quit' || input === 'shutdown') { @@ -39,9 +38,20 @@ async function executeCommand(input: string) { }); } +let readlineCallback; + process.stdin.setEncoding('utf-8'); process.stdin.setRawMode?.(false); process.stdin.on('data', (buf) => { - const input = buf.toString(); - executeCommand(input); + const input = buf.toString().trim(); + if (readlineCallback) { + readlineCallback(input); + readlineCallback = null; + } else executeCommand(input); }); + +export const useReadline = (callback: (string) => any) => { + if (readlineCallback) throw new Error('Already waiting for input.'); + readlineCallback = callback; +}; +export const readline = () => new Promise((resolve) => { useReadline(resolve); }); diff --git a/packages/ui-default/package.json b/packages/ui-default/package.json index 8826417b6..900f51081 100644 --- a/packages/ui-default/package.json +++ b/packages/ui-default/package.json @@ -1,6 +1,6 @@ { "name": "@hydrooj/ui-default", - "version": "4.51.2", + "version": "4.51.3", "author": "undefined ", "license": "AGPL-3.0", "main": "index.ts", diff --git a/packages/ui-default/polyfill.ts b/packages/ui-default/polyfill.ts index 30b4179fa..d635f0a1c 100644 --- a/packages/ui-default/polyfill.ts +++ b/packages/ui-default/polyfill.ts @@ -12,7 +12,7 @@ browserUpdate({ }); // monaco-editor requires this polyfill -if (window.MediaQueryList) { +if (window.MediaQueryList && !MediaQueryList.prototype.addEventListener) { MediaQueryList.prototype.addEventListener = (k, listener) => { MediaQueryList.prototype.addListener(listener); };