This commit is contained in:
undefined committed 2024-06-27 16:20:08 +08:00
1 parent 6c0a1d06be
commit 738047dc63
4 files changed
+46 -99

No files matched your search

+31 -94
View File
@@ -1,102 +1,39 @@
/* eslint-disable no-await-in-loop */
import os from 'os'; import os from 'os';
import path from 'path'; import path from 'path';
import cac from 'cac';
import fs from 'fs-extra'; import fs from 'fs-extra';
import type { Context } from 'koa';
import { MongoClient, WriteConcern } from 'mongodb'; import { MongoClient, WriteConcern } from 'mongodb';
import mongoUri from 'mongodb-uri'; import mongoUri from 'mongodb-uri';
import { Context as PluginContext } from '../context'; import { readline } from '../ui';
const listenPort = cac().parse().options.port || 8888; export async function load() {
let resolve; console.error('Config file not found.');
if (!process.stdin.isTTY) {
async function get(ctx: Context) { console.error('Please fill in ~/.hydro/config.json with MongoDB connection string in the following format:');
ctx.body = `<!DOCTYPE html> console.error('{"url":"mongodb://localhost:27017/hydro"}');
<html data-page="setup" data-layout="immersive" class="layout--immersive page--setup nojs"> process.exit(1);
<head> }
<meta charset="UTF-8"> // eslint-disable-next-line no-constant-condition
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> while (true) {
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" /> console.error('Please type your MongoDB connection string below:');
<link rel="stylesheet" media="all" href="/default.theme.css"> console.error('Example: mongodb://localhost:27017/hydro');
<title>Setup</title> try {
</head> const uri = await readline();
<body> if (!uri) throw new Error('no url found');
<div class="slideout-panel" id="panel"> const url = mongoUri.parse(uri);
<div class="main"> const Database = await MongoClient.connect(uri, {
<div class="row"><div class="columns"> readPreference: 'nearest',
<div class="immersive--content immersive--center"> writeConcern: new WriteConcern('majority'),
<h1>Setup</h1> });
<form method="POST"> const db = Database.db(url.database);
<div class="row"><div class="columns"> const coll = db.collection<any>('system');
<label class="inverse material textbox"> await coll.updateOne({ _id: '_test' }, { $set: { value: 1 } }, { upsert: true });
MongoDB Connection URI await coll.deleteOne({ _id: '_test' });
<input name="url" type="text" value="mongodb://user:pass@127.0.0.1:27017/hydro" autofocus> fs.ensureDirSync(path.resolve(os.homedir(), '.hydro'));
</label> fs.writeFileSync(path.resolve(os.homedir(), '.hydro', 'config.json'), JSON.stringify({ url: uri }));
</div></div> break;
<div class="row"><div class="columns"> } catch (e) {
<div class="text-center"> console.error(e);
<input type="submit" value="Confirm" class="inverse expanded rounded primary button"> }
</div>
</div></div>
</form>
</div>
</div></div>
</div>
</div>
</body>
</html>`;
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<any>('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 = '<h1>Done! Hydro is now starting.</h1>';
resolve?.();
} catch (e) {
ctx.body = `Error connecting to database: ${e.message}\n${e.stack}`;
} }
} }
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);
};
});
}
+13 -3
View File
@@ -22,7 +22,6 @@ process.on('SIGTERM', terminate);
const shell = new Logger('shell'); const shell = new Logger('shell');
async function executeCommand(input: string) { async function executeCommand(input: string) {
input = input.trim();
// Clear the stack // Clear the stack
setImmediate(async () => { setImmediate(async () => {
if (input === 'exit' || input === 'quit' || input === 'shutdown') { 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.setEncoding('utf-8');
process.stdin.setRawMode?.(false); process.stdin.setRawMode?.(false);
process.stdin.on('data', (buf) => { process.stdin.on('data', (buf) => {
const input = buf.toString(); const input = buf.toString().trim();
executeCommand(input); 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<string>((resolve) => { useReadline(resolve); });
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@hydrooj/ui-default", "name": "@hydrooj/ui-default",
"version": "4.51.2", "version": "4.51.3",
"author": "undefined <i@undefined.moe>", "author": "undefined <i@undefined.moe>",
"license": "AGPL-3.0", "license": "AGPL-3.0",
"main": "index.ts", "main": "index.ts",
+1 -1
View File
@@ -12,7 +12,7 @@ browserUpdate({
}); });
// monaco-editor requires this polyfill // monaco-editor requires this polyfill
if (window.MediaQueryList) { if (window.MediaQueryList && !MediaQueryList.prototype.addEventListener) {
MediaQueryList.prototype.addEventListener = (k, listener) => { MediaQueryList.prototype.addEventListener = (k, listener) => {
MediaQueryList.prototype.addListener(listener); MediaQueryList.prototype.addListener(listener);
}; };