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