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 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 = `<!DOCTYPE html>
<html data-page="setup" data-layout="immersive" class="layout--immersive page--setup nojs">
<head>
<meta charset="UTF-8">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
<link rel="stylesheet" media="all" href="/default.theme.css">
<title>Setup</title>
</head>
<body>
<div class="slideout-panel" id="panel">
<div class="main">
<div class="row"><div class="columns">
<div class="immersive--content immersive--center">
<h1>Setup</h1>
<form method="POST">
<div class="row"><div class="columns">
<label class="inverse material textbox">
MongoDB Connection URI
<input name="url" type="text" value="mongodb://user:pass@127.0.0.1:27017/hydro" autofocus>
</label>
</div></div>
<div class="row"><div class="columns">
<div class="text-center">
<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 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<any>('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);
};
});
}
+13 -3
View File
@@ -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<string>((resolve) => { useReadline(resolve); });
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@hydrooj/ui-default",
"version": "4.51.2",
"version": "4.51.3",
"author": "undefined <i@undefined.moe>",
"license": "AGPL-3.0",
"main": "index.ts",
+1 -1
View File
@@ -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);
};