diff --git a/hydro/entry/cli.ts b/hydro/entry/cli.ts index 839a787ee..0534c8185 100644 --- a/hydro/entry/cli.ts +++ b/hydro/entry/cli.ts @@ -1,10 +1,9 @@ -/* eslint-disable no-eval */ /* eslint-disable no-await-in-loop */ /* eslint-disable import/no-dynamic-require */ import { argv } from 'yargs'; import { - lib, service, model, script, - builtinLib, builtinScript, builtinModel, + lib, service, model, + builtinLib, builtinModel, } from './common'; const COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg; @@ -45,10 +44,9 @@ async function cli() { return console.log(result); } -export async function load(call, args) { - let pending = args; +export async function load() { + const pending = global.addons; const fail = []; - const active = []; require('../lib/i18n'); require('../utils'); require('../error'); @@ -68,21 +66,6 @@ export async function load(call, args) { await service(pending, fail); for (const i of builtinModel) require(`../model/${i}`); await model(pending, fail); - for (const i in global.Hydro.service) { - if (global.Hydro.service[i].postInit) { - try { - await global.Hydro.service[i].postInit(); - } catch (e) { - console.error(e); - } - } - } - for (const i of builtinScript) require(`../script/${i}`); - await script(pending, fail, active); - for (const postInit of global.Hydro.postInit) { - await postInit(); - } - pending = []; + for (const postInit of global.Hydro.postInit) await postInit(); await cli(); - return { active, fail }; } diff --git a/hydro/entry/master.ts b/hydro/entry/master.ts index ade691147..eada6452d 100644 --- a/hydro/entry/master.ts +++ b/hydro/entry/master.ts @@ -1,8 +1,30 @@ /* eslint-disable no-await-in-loop */ /* eslint-disable import/no-dynamic-require */ +import os from 'os'; +import path from 'path'; +import fs from 'fs-extra'; +import { argv } from 'yargs'; import { builtinModel } from './common'; +import { Entry } from '../loader'; -export async function load(call) { +const tmpdir = path.resolve(os.tmpdir(), 'hydro'); +const lockfile = path.resolve(tmpdir, 'lock.json'); + +export async function load(call: Entry) { + if (fs.existsSync(lockfile) && !argv.ignorelock) { + const file = require(lockfile); + console.error(`Lockfile exists, pid=${file.pid}`); + process.exit(1); + } + const context = { + addons: global.addons, + pid: process.pid, + ppid: process.ppid, + }; + await fs.writeFile(lockfile, JSON.stringify(context)); + global.onDestory.push(() => { + fs.emptyDirSync(tmpdir); + }); require('../lib/i18n'); require('../utils'); require('../error'); diff --git a/hydro/entry/worker.ts b/hydro/entry/worker.ts index 1691d274a..be89faf8e 100644 --- a/hydro/entry/worker.ts +++ b/hydro/entry/worker.ts @@ -5,8 +5,8 @@ import { builtinLib, builtinScript, builtinHandler, builtinModel, } from './common'; -export async function load(call, args) { - let pending = args; +export async function load() { + let pending = global.addons; const fail = []; const active = []; require('../lib/i18n'); diff --git a/hydro/handler/problem.ts b/hydro/handler/problem.ts index 7b36113f6..b895fb09e 100644 --- a/hydro/handler/problem.ts +++ b/hydro/handler/problem.ts @@ -206,11 +206,25 @@ class ProblemDetailHandler extends ProblemHandler { if (!udoc.hasPerm(PERM.PERM_CREATE_PROBLEM)) { throw new PermissionError(PERM.PERM_CREATE_PROBLEM); } - pid = await problem.add( - destDomainId, this.pdoc.pid, this.pdoc.title, - this.pdoc.content, this.user._id, this.pdoc.tag, - this.pdoc.category, { domainId, pid }, hidden, - ); + if (!this.pdoc.data) { + // Copy Without Data + pid = await problem.add( + destDomainId, this.pdoc.pid, this.pdoc.title, + this.pdoc.content, this.user._id, this.pdoc.tag, + this.pdoc.category, null, hidden, + ); + } else if (this.pdoc.data instanceof ObjectID) { + // With data + pid = await problem.add( + destDomainId, this.pdoc.pid, this.pdoc.title, + this.pdoc.content, this.user._id, this.pdoc.tag, + this.pdoc.category, { domainId, pid }, hidden, + ); + } else { + // TODO better message + // Data should only be copied once. + throw new BadRequestError('Cannot copy this problem.'); + } this.response.redirect = this.url('problem_settings', { domainId: destDomainId, pid }); } } @@ -417,11 +431,24 @@ class ProblemDataDownloadHandler extends ProblemDetailHandler { if (this.pdoc.data instanceof ObjectID) { this.response.redirect = await file.url(this.pdoc.data, `${this.pdoc.title}.zip`); } else if (this.pdoc.data) { - // Redirect? - this.response.redirect = this.url('problem_data', { - domainId: this.pdoc.domainId, - pid: this.pdoc.pid, - }); + if (!this.pdoc.data.host) { + this.response.redirect = this.url('problem_data', { + domainId: this.pdoc.data.domainId, + pid: this.pdoc.data.pid, + }); + } else { + const [scheme, raw] = this.pdoc.data.host.split('//'); + const args = JSON.parse(Buffer.from(raw, 'base64').toString()); + if (scheme === 'hydro') { + const [secure, host, port, domainId, id] = args; + this.response.redirect = `http${secure ? 's' : ''}://${host}:${port}/d/${domainId}/p/${id}/data`; + } else if (scheme === 'syzoj') { + const [secure, host, port, id] = args; + this.response.redirect = `http${secure ? 's' : ''}://${host}:${port}/problem/${id}/testdata/download`; + } else { + throw new ProblemDataNotFoundError(pid); + } + } } else throw new ProblemDataNotFoundError(pid); } } diff --git a/hydro/loader.ts b/hydro/loader.ts index e145170f6..2c884cf0e 100644 --- a/hydro/loader.ts +++ b/hydro/loader.ts @@ -54,7 +54,12 @@ async function fork(args: string[] = []) { return cluster.fork(); } -async function entry(config: any) { +interface EntryConfig { + entry: string, + newProcess?: boolean, +} + +async function entry(config: EntryConfig) { if (config.entry) { if (config.newProcess) { const sargv = [`--entry=${config.entry}`]; @@ -74,6 +79,8 @@ async function entry(config: any) { return null; } +export type Entry = typeof entry; + async function stopWorker() { cluster.disconnect(); } @@ -201,7 +208,7 @@ export async function load() { console.log(global.addons); if (argv.entry) { console.log(`Worker ${process.pid} Starting as ${argv.entry}`); - await entry({ entry: argv.entry }); + await entry({ entry: argv.entry as string }); console.log(`Worker ${process.pid} Started as ${argv.entry}`); } else { if (argv.firstWorker) cluster.isFirstWorker = true; diff --git a/hydro/service/server.ts b/hydro/service/server.ts index cf6038cfc..8b4205d6f 100644 --- a/hydro/service/server.ts +++ b/hydro/service/server.ts @@ -767,6 +767,7 @@ export function Connection( sock.installHandlers(server); } +// TODO use postInit? export async function start() { const [disableLog, port] = await system.getMany(['server.log', 'server.port']); if (!disableLog) { diff --git a/locales/en.yaml b/locales/en.yaml index 00a2db3da..b2f42c414 100644 --- a/locales/en.yaml +++ b/locales/en.yaml @@ -54,6 +54,7 @@ perm_problem: Problems perm_record: Records perm_training: Trainings problem_create: Problem Create +problem_detail: Problem Detail problem_edit: Problem Edit problem_import: Import Problem problem_main: Problem Set diff --git a/locales/zh_CN.yaml b/locales/zh_CN.yaml index 9bb158bf4..0df07cb59 100644 --- a/locales/zh_CN.yaml +++ b/locales/zh_CN.yaml @@ -523,6 +523,7 @@ Problem Solution List: 题解列表 Problem Solution: 题解列表 Problem Tags Visibility: 题目标签可见性 problem_create: 创建题目 +problem_detail: 题目详情 problem_edit: 编辑题目 problem_import: 导入题目 problem_main: 题库 diff --git a/package.json b/package.json index 68aadfbde..ee96733a3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hydrooj", - "version": "2.9.12", + "version": "2.9.13", "main": "dist/loader.js", "bin": "bin/hydrooj.js", "repository": "https://github.com/hydro-dev/Hydro.git",