mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-20 01:38:19 +08:00
judge: 可调的性能设置
This commit is contained in:
1 parent
8c8dcb89eb
commit
2bf1a18890
21 files changed
+148
-185
No files matched your search
@@ -1,6 +1,5 @@
|
|||||||
'Error parsing memory: {0}': 无法解析内存:{0}
|
'Error parsing memory: {0}': 无法解析内存:{0}
|
||||||
'Error parsing time: {0}': 无法解析时间:{0}
|
'Error parsing time: {0}': 无法解析时间:{0}
|
||||||
Cannot connect to sandbox service.: 无法连接到沙箱服务。
|
|
||||||
Cannot find checker {0}.: 找不到比较器 {0}。
|
Cannot find checker {0}.: 找不到比较器 {0}。
|
||||||
Cannot find input file {0}.: 找不到输入文件 {0}。
|
Cannot find input file {0}.: 找不到输入文件 {0}。
|
||||||
Cannot find judge extra file {0}.: 找不到评测额外文件 {0}。
|
Cannot find judge extra file {0}.: 找不到评测额外文件 {0}。
|
||||||
@@ -14,6 +13,7 @@ Invalid judge_extra_files config.: 无效的 judge_extra_files 配置。
|
|||||||
Invalid user_extra_files config.: 无效的 user_extra_files 配置。
|
Invalid user_extra_files config.: 无效的 user_extra_files 配置。
|
||||||
Problem data not found.: 没有找到测试数据。
|
Problem data not found.: 没有找到测试数据。
|
||||||
Read {0}, expect {1}.: 读取到 {0},应为 {1}。
|
Read {0}, expect {1}.: 读取到 {0},应为 {1}。
|
||||||
|
Sandbox Error: 沙箱错误
|
||||||
Standard answer longer than user output.: 标准输出比选手输出长。
|
Standard answer longer than user output.: 标准输出比选手输出长。
|
||||||
Testdata configuration incorrect.: 题目配置错误。
|
Testdata configuration incorrect.: 题目配置错误。
|
||||||
Too many files.: 文件过多。
|
Too many files.: 文件过多。
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@hydrooj/hydrojudge",
|
"name": "@hydrooj/hydrojudge",
|
||||||
"bin": "bin/hydrojudge.js",
|
"bin": "bin/hydrojudge.js",
|
||||||
"version": "2.2.3",
|
"version": "2.3.0",
|
||||||
"main": "package.json",
|
"main": "package.json",
|
||||||
"author": "undefined <i@undefined.moe>",
|
"author": "undefined <i@undefined.moe>",
|
||||||
"repository": "https://github.com/hydro-dev/Hydro.git",
|
"repository": "https://github.com/hydro-dev/Hydro.git",
|
||||||
|
|||||||
@@ -1,10 +1,40 @@
|
|||||||
|
sandbox_host:
|
||||||
|
type: text
|
||||||
|
name: Sandbox Host
|
||||||
|
default: http://localhost:5050
|
||||||
|
tmp_dir:
|
||||||
|
type: text
|
||||||
|
name: Temp directory
|
||||||
|
default: $TEMP/hydro/judge.tmp
|
||||||
|
tmpfs_size:
|
||||||
|
type: text
|
||||||
|
name: Tmpfs size
|
||||||
|
default: 256m
|
||||||
|
testcases_max:
|
||||||
|
type: number
|
||||||
|
name: Max testcases per problem
|
||||||
|
default: 100
|
||||||
|
total_time_limit:
|
||||||
|
type: number
|
||||||
|
name: Total time limit per problem
|
||||||
|
default: 60
|
||||||
|
retry_delay_sec:
|
||||||
|
type: number
|
||||||
|
name: Retry delay sec
|
||||||
|
default: 15
|
||||||
|
cache_dir:
|
||||||
|
type: text
|
||||||
|
name: Testdata cache directory
|
||||||
|
default: $HOME/.cache/hydro/judge
|
||||||
|
parallelism:
|
||||||
|
type: number
|
||||||
|
name: Runner parallelism
|
||||||
|
default: 2
|
||||||
langs:
|
langs:
|
||||||
type: textarea
|
type: textarea
|
||||||
category: system
|
name: Language file settings
|
||||||
desc: Language file settings
|
|
||||||
name: langs
|
|
||||||
default: |
|
default: |
|
||||||
ccWithoutO2:
|
ccWithoutO2: # Do not remove this entry
|
||||||
type: compiler
|
type: compiler
|
||||||
compile: /usr/bin/g++ -Wall -o ${name} foo.cc
|
compile: /usr/bin/g++ -Wall -o ${name} foo.cc
|
||||||
code_file: foo.cc
|
code_file: foo.cc
|
||||||
|
|||||||
@@ -2,9 +2,9 @@ import fs from 'fs-extra';
|
|||||||
import path from 'path';
|
import path from 'path';
|
||||||
import yaml from 'js-yaml';
|
import yaml from 'js-yaml';
|
||||||
import { Dictionary, sum } from 'lodash';
|
import { Dictionary, sum } from 'lodash';
|
||||||
import { argv } from 'yargs';
|
|
||||||
import { FormatError, SystemError } from './error';
|
import { FormatError, SystemError } from './error';
|
||||||
import { parseTimeMS, parseMemoryMB, ensureFile } from './utils';
|
import { parseTimeMS, parseMemoryMB, ensureFile } from './utils';
|
||||||
|
import { getConfig } from './config';
|
||||||
|
|
||||||
interface Re0 {
|
interface Re0 {
|
||||||
reg: RegExp,
|
reg: RegExp,
|
||||||
@@ -285,12 +285,12 @@ function convertIniConfig(ini: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function isValidConfig(config) {
|
function isValidConfig(config) {
|
||||||
if (config.count > (argv.max_testcases_count as string || 100)) {
|
if (config.count > (getConfig('testcases_max') || 100)) {
|
||||||
throw new FormatError('Too many testcases. Cancelled.');
|
throw new FormatError('Too many testcases. Cancelled.');
|
||||||
}
|
}
|
||||||
const total_time = sum(config.subtasks.map((subtask) => subtask.time_limit_ms * subtask.cases.length));
|
const total_time = sum(config.subtasks.map((subtask) => subtask.time_limit_ms * subtask.cases.length));
|
||||||
if (total_time > (+argv.max_time_limit || 60) * 1000) {
|
if (total_time > (getConfig('total_time_limit') || 60) * 1000) {
|
||||||
throw new FormatError('Total time limit longer than {0}s. Cancelled.', [+argv.max_time_limit || 60]);
|
throw new FormatError('Total time limit longer than {0}s. Cancelled.', [+getConfig('total_time_limit') || 60]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,13 +4,12 @@ import { run, del } from './sandbox';
|
|||||||
import { CompileError, SystemError } from './error';
|
import { CompileError, SystemError } from './error';
|
||||||
import { compilerText } from './utils';
|
import { compilerText } from './utils';
|
||||||
import { Execute } from './interface';
|
import { Execute } from './interface';
|
||||||
|
import { getConfig } from './config';
|
||||||
|
|
||||||
export = async function compile(
|
export = async function compile(
|
||||||
lang: string, code: string, target: string, copyIn: any, next?: Function,
|
lang: string, code: string, target: string, copyIn: any, next?: Function,
|
||||||
): Promise<Execute> {
|
): Promise<Execute> {
|
||||||
const LANGS = global.Hydro
|
const LANGS = yaml.load(getConfig('langs'));
|
||||||
? yaml.load(global.Hydro.model.system.get('hydrojudge.langs'))
|
|
||||||
: require('./config').LANGS;
|
|
||||||
if (!LANGS[lang]) throw new SystemError('Unsupported language {0}.', [lang]);
|
if (!LANGS[lang]) throw new SystemError('Unsupported language {0}.', [lang]);
|
||||||
const info = LANGS[lang];
|
const info = LANGS[lang];
|
||||||
target = info.target || target;
|
target = info.target || target;
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
/* eslint-disable prefer-const */
|
/* eslint-disable prefer-const */
|
||||||
/* eslint-disable import/no-mutable-exports */
|
|
||||||
import { argv } from 'yargs';
|
import { argv } from 'yargs';
|
||||||
import os from 'os';
|
import os from 'os';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
@@ -7,17 +6,26 @@ import fs from 'fs-extra';
|
|||||||
import yaml from 'js-yaml';
|
import yaml from 'js-yaml';
|
||||||
import log from './log';
|
import log from './log';
|
||||||
|
|
||||||
export let CONFIG_FILE = path.resolve(os.homedir(), '.config', 'hydro', 'judge.yaml');
|
let CONFIG_FILE = path.resolve(os.homedir(), '.config', 'hydro', 'judge.yaml');
|
||||||
export let CACHE_DIR = path.resolve(os.homedir(), '.cache', 'hydro', 'judge');
|
|
||||||
export let FILES_DIR = path.resolve(os.homedir(), '.cache', 'hydro', 'files', 'judge');
|
|
||||||
export let RETRY_DELAY_SEC = 15;
|
|
||||||
export let TEMP_DIR = path.resolve(os.tmpdir(), 'hydro', 'judge');
|
|
||||||
export let EXECUTION_HOST = 'http://localhost:5050';
|
|
||||||
export let CONFIG = null;
|
|
||||||
export let LANGS = null;
|
|
||||||
|
|
||||||
let LANGS_FILE = path.resolve(os.homedir(), '.config', 'hydro', 'langs.yaml');
|
let LANGS_FILE = path.resolve(os.homedir(), '.config', 'hydro', 'langs.yaml');
|
||||||
|
|
||||||
|
let config = {
|
||||||
|
cache_dir: path.resolve(os.homedir(), '.cache', 'hydro', 'judge'),
|
||||||
|
tmp_dir: path.resolve(os.tmpdir(), 'hydro', 'judge'),
|
||||||
|
tmpfs_size: '256m',
|
||||||
|
retry_delay_sec: 15,
|
||||||
|
sandbox_host: 'http://localhost:5050',
|
||||||
|
testcases_max: 100,
|
||||||
|
total_time_limit: 60,
|
||||||
|
parallelism: 2,
|
||||||
|
config: null,
|
||||||
|
langs: null,
|
||||||
|
};
|
||||||
|
|
||||||
|
export function getConfig(key: string) {
|
||||||
|
return global.Hydro ? global.Hydro.model.system.get(`hydrojudge.${key}`) : config[key];
|
||||||
|
}
|
||||||
|
|
||||||
if (fs.existsSync(path.resolve(process.cwd(), '.env'))) {
|
if (fs.existsSync(path.resolve(process.cwd(), '.env'))) {
|
||||||
const env = {};
|
const env = {};
|
||||||
const f = fs.readFileSync('.env').toString();
|
const f = fs.readFileSync('.env').toString();
|
||||||
@@ -28,34 +36,30 @@ if (fs.existsSync(path.resolve(process.cwd(), '.env'))) {
|
|||||||
Object.assign(process.env, env);
|
Object.assign(process.env, env);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (process.env.CONFIG_FILE || argv.config) {
|
|
||||||
CONFIG_FILE = path.resolve(process.env.CONFIG_FILE || argv.config as string);
|
|
||||||
}
|
|
||||||
if (process.env.LANGS_FILE || argv.langs) {
|
|
||||||
LANGS_FILE = path.resolve(process.env.LANGS_FILE || argv.langs as string);
|
|
||||||
}
|
|
||||||
if (process.env.TEMP_DIR || argv.tmp) {
|
|
||||||
TEMP_DIR = path.resolve(process.env.TEMP_DIR || argv.tmp as string);
|
|
||||||
}
|
|
||||||
if (process.env.CACHE_DIR || argv.cache) {
|
|
||||||
CACHE_DIR = path.resolve(process.env.CACHE_DIR || argv.cache as string);
|
|
||||||
}
|
|
||||||
if (process.env.FILES_DIR || argv.files) {
|
|
||||||
FILES_DIR = path.resolve(process.env.FILES_DIR || argv.files as string);
|
|
||||||
}
|
|
||||||
if (process.env.EXECUTION_HOST || argv.execute) {
|
|
||||||
EXECUTION_HOST = path.resolve(process.env.EXECUTION_HOST || argv.execute as string);
|
|
||||||
}
|
|
||||||
if (!global.Hydro) {
|
if (!global.Hydro) {
|
||||||
if (fs.existsSync(LANGS_FILE)) LANGS = yaml.load(fs.readFileSync(LANGS_FILE).toString());
|
// standalone
|
||||||
|
if (process.env.CONFIG_FILE || argv.config) {
|
||||||
|
CONFIG_FILE = path.resolve(process.env.CONFIG_FILE || argv.config as string);
|
||||||
|
}
|
||||||
|
if (process.env.LANGS_FILE || argv.langs) {
|
||||||
|
LANGS_FILE = path.resolve(process.env.LANGS_FILE || argv.langs as string);
|
||||||
|
}
|
||||||
|
if (process.env.TEMP_DIR || argv.tmp) {
|
||||||
|
config.tmp_dir = path.resolve(process.env.TEMP_DIR || argv.tmp as string);
|
||||||
|
}
|
||||||
|
if (process.env.CACHE_DIR || argv.cache) {
|
||||||
|
config.cache_dir = path.resolve(process.env.CACHE_DIR || argv.cache as string);
|
||||||
|
}
|
||||||
|
if (process.env.EXECUTION_HOST || argv.sandbox) {
|
||||||
|
config.sandbox_host = path.resolve(process.env.EXECUTION_HOST || argv.execute as string);
|
||||||
|
}
|
||||||
|
const configFile = fs.readFileSync(CONFIG_FILE).toString();
|
||||||
|
config = { ...config, ...yaml.load(configFile) as any };
|
||||||
|
if (fs.existsSync(LANGS_FILE)) config.langs = yaml.load(fs.readFileSync(LANGS_FILE).toString());
|
||||||
else {
|
else {
|
||||||
log.error('Language file not found, using default.');
|
log.error('Language file not found, using default.');
|
||||||
const file = path.join(path.dirname(require.resolve('@hydrooj/hydrojudge')), 'setting.yaml');
|
const file = path.join(path.dirname(require.resolve('@hydrooj/hydrojudge')), 'setting.yaml');
|
||||||
const content = yaml.load(fs.readFileSync(file).toString()) as any;
|
const content = yaml.load(fs.readFileSync(file).toString()) as any;
|
||||||
LANGS = yaml.load(content.langs.default) as any;
|
config.langs = yaml.load(content.langs.default) as any;
|
||||||
}
|
|
||||||
if (!(fs.existsSync(LANGS_FILE) || global.Hydro)) {
|
|
||||||
fs.ensureDirSync(path.dirname(LANGS_FILE));
|
|
||||||
LANGS_FILE = path.join(__dirname, '..', 'examples', 'langs.yaml');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -12,10 +12,9 @@
|
|||||||
`-.__ 听取人生经验。 __.-'
|
`-.__ 听取人生经验。 __.-'
|
||||||
````- - -.......- - -''' ~
|
````- - -.......- - -''' ~
|
||||||
~ */
|
~ */
|
||||||
import fs from 'fs-extra';
|
|
||||||
import yaml from 'js-yaml';
|
|
||||||
import * as Session from './hosts/index';
|
import * as Session from './hosts/index';
|
||||||
import { sleep, Queue } from './utils';
|
import { sleep, Queue } from './utils';
|
||||||
|
import { getConfig } from './config';
|
||||||
import log from './log';
|
import log from './log';
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
@@ -30,8 +29,6 @@ if (!global.onDestory) global.onDestory = [];
|
|||||||
if (!global.hosts) global.hosts = [];
|
if (!global.hosts) global.hosts = [];
|
||||||
let SI = false;
|
let SI = false;
|
||||||
|
|
||||||
const { RETRY_DELAY_SEC, CONFIG_FILE, CONFIG } = require('./config');
|
|
||||||
|
|
||||||
const terminate = async () => {
|
const terminate = async () => {
|
||||||
log.info('正在保存数据');
|
log.info('正在保存数据');
|
||||||
try {
|
try {
|
||||||
@@ -52,42 +49,16 @@ process.on('unhandledRejection', (reason, p) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
async function daemon() {
|
async function daemon() {
|
||||||
let config;
|
const _hosts = getConfig('hosts');
|
||||||
try {
|
const retry_delay_sec = getConfig('retry_delay_sec');
|
||||||
if (CONFIG) config = CONFIG;
|
|
||||||
else {
|
|
||||||
config = (await fs.readFile(CONFIG_FILE)).toString();
|
|
||||||
config = yaml.load(config);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
log.error('配置文件无效或未找到。');
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
const hosts = {};
|
const hosts = {};
|
||||||
const queue = new Queue<any>();
|
const queue = new Queue<any>();
|
||||||
for (const i in config.hosts) {
|
for (const i in _hosts) {
|
||||||
config.hosts[i].host = i;
|
_hosts[i].host = i;
|
||||||
hosts[i] = new Session[config.hosts[i].type || 'vj4'](config.hosts[i]);
|
hosts[i] = new Session[_hosts[i].type || 'vj4'](_hosts[i]);
|
||||||
await hosts[i].init();
|
await hosts[i].init();
|
||||||
}
|
}
|
||||||
global.hosts = hosts;
|
global.hosts = hosts;
|
||||||
if (!CONFIG) {
|
|
||||||
global.onDestory.push(async () => {
|
|
||||||
const cfg = { hosts: {} };
|
|
||||||
for (const i in hosts) {
|
|
||||||
cfg.hosts[i] = {
|
|
||||||
host: i,
|
|
||||||
type: hosts[i].config.type || 'default',
|
|
||||||
uname: hosts[i].config.uname,
|
|
||||||
password: hosts[i].config.password,
|
|
||||||
server_url: hosts[i].config.server_url,
|
|
||||||
};
|
|
||||||
if (hosts[i].config.cookie) cfg.hosts[i].cookie = hosts[i].config.cookie;
|
|
||||||
if (hosts[i].config.detail) cfg.hosts[i].detail = hosts[i].config.detail;
|
|
||||||
}
|
|
||||||
await fs.writeFile(CONFIG_FILE, yaml.dump(cfg));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
while ('Orz twd2') {
|
while ('Orz twd2') {
|
||||||
try {
|
try {
|
||||||
for (const i in hosts) await hosts[i].consume(queue);
|
for (const i in hosts) await hosts[i].consume(queue);
|
||||||
@@ -97,11 +68,11 @@ async function daemon() {
|
|||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log.error(e, e.stack);
|
log.error(e, e.stack);
|
||||||
log.info(`在 ${RETRY_DELAY_SEC} 秒后重试`);
|
log.info(`在 ${retry_delay_sec} 秒后重试`);
|
||||||
await sleep(RETRY_DELAY_SEC * 1000);
|
await sleep(retry_delay_sec * 1000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!module.parent) daemon();
|
if (require.main === module) daemon();
|
||||||
export = daemon;
|
export = daemon;
|
||||||
@@ -1,15 +1,13 @@
|
|||||||
|
import { CompileErrorInfo } from './interface';
|
||||||
import { STATUS_TEXTS } from './status';
|
import { STATUS_TEXTS } from './status';
|
||||||
|
|
||||||
export class CompileError extends Error {
|
export class CompileError extends Error {
|
||||||
stdout: string;
|
stdout: string;
|
||||||
|
|
||||||
stderr: string;
|
stderr: string;
|
||||||
|
|
||||||
status: string;
|
status: string;
|
||||||
|
|
||||||
type: string;
|
type: string;
|
||||||
|
|
||||||
constructor(obj) {
|
constructor(obj: string | CompileErrorInfo) {
|
||||||
super('Compile Error');
|
super('Compile Error');
|
||||||
if (typeof obj === 'string') {
|
if (typeof obj === 'string') {
|
||||||
this.stdout = obj;
|
this.stdout = obj;
|
||||||
@@ -25,10 +23,9 @@ export class CompileError extends Error {
|
|||||||
|
|
||||||
export class FormatError extends Error {
|
export class FormatError extends Error {
|
||||||
type: string;
|
type: string;
|
||||||
|
|
||||||
params: any[];
|
params: any[];
|
||||||
|
|
||||||
constructor(message, params = []) {
|
constructor(message: string, params = []) {
|
||||||
super(message);
|
super(message);
|
||||||
this.type = 'FormatError';
|
this.type = 'FormatError';
|
||||||
this.params = params;
|
this.params = params;
|
||||||
@@ -37,10 +34,9 @@ export class FormatError extends Error {
|
|||||||
|
|
||||||
export class RuntimeError extends Error {
|
export class RuntimeError extends Error {
|
||||||
type: string;
|
type: string;
|
||||||
|
|
||||||
detail: any;
|
detail: any;
|
||||||
|
|
||||||
constructor(detail, message) {
|
constructor(detail: string, message: string) {
|
||||||
super(message);
|
super(message);
|
||||||
this.type = 'RuntimeError';
|
this.type = 'RuntimeError';
|
||||||
this.detail = detail;
|
this.detail = detail;
|
||||||
@@ -49,7 +45,6 @@ export class RuntimeError extends Error {
|
|||||||
|
|
||||||
export class SystemError extends Error {
|
export class SystemError extends Error {
|
||||||
type: string;
|
type: string;
|
||||||
|
|
||||||
params: any[];
|
params: any[];
|
||||||
|
|
||||||
constructor(message: string, params = []) {
|
constructor(message: string, params = []) {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import { ObjectID } from 'bson';
|
|||||||
import * as tmpfs from '../tmpfs';
|
import * as tmpfs from '../tmpfs';
|
||||||
import log from '../log';
|
import log from '../log';
|
||||||
import { compilerText, Queue } from '../utils';
|
import { compilerText, Queue } from '../utils';
|
||||||
import { CACHE_DIR, TEMP_DIR } from '../config';
|
import { getConfig } from '../config';
|
||||||
import { FormatError, CompileError, SystemError } from '../error';
|
import { FormatError, CompileError, SystemError } from '../error';
|
||||||
import { STATUS_COMPILE_ERROR, STATUS_SYSTEM_ERROR } from '../status';
|
import { STATUS_COMPILE_ERROR, STATUS_SYSTEM_ERROR } from '../status';
|
||||||
import readCases from '../cases';
|
import readCases from '../cases';
|
||||||
@@ -17,39 +17,22 @@ import judge from '../judge';
|
|||||||
|
|
||||||
class JudgeTask {
|
class JudgeTask {
|
||||||
stat: Record<string, Date>;
|
stat: Record<string, Date>;
|
||||||
|
|
||||||
session: any;
|
session: any;
|
||||||
|
|
||||||
host: string;
|
host: string;
|
||||||
|
|
||||||
request: any;
|
request: any;
|
||||||
|
|
||||||
ws: WebSocket;
|
ws: WebSocket;
|
||||||
|
|
||||||
tag: any;
|
tag: any;
|
||||||
|
|
||||||
type: any;
|
type: any;
|
||||||
|
|
||||||
domainId: string;
|
domainId: string;
|
||||||
|
|
||||||
pid: string;
|
pid: string;
|
||||||
|
|
||||||
rid: string;
|
rid: string;
|
||||||
|
|
||||||
lang: string;
|
lang: string;
|
||||||
|
|
||||||
code: string;
|
code: string;
|
||||||
|
|
||||||
tmpdir: string;
|
tmpdir: string;
|
||||||
|
|
||||||
clean: Function[];
|
clean: Function[];
|
||||||
|
|
||||||
folder: string;
|
folder: string;
|
||||||
|
|
||||||
config: any;
|
config: any;
|
||||||
|
|
||||||
nextId = 1;
|
nextId = 1;
|
||||||
|
|
||||||
nextWaiting = [];
|
nextWaiting = [];
|
||||||
|
|
||||||
constructor(session: Hydro, request, ws: WebSocket) {
|
constructor(session: Hydro, request, ws: WebSocket) {
|
||||||
@@ -73,7 +56,7 @@ class JudgeTask {
|
|||||||
this.lang = this.request.lang;
|
this.lang = this.request.lang;
|
||||||
this.code = this.request.code;
|
this.code = this.request.code;
|
||||||
this.config = this.request.config;
|
this.config = this.request.config;
|
||||||
this.tmpdir = path.resolve(TEMP_DIR, 'tmp', this.host, this.rid);
|
this.tmpdir = path.resolve(getConfig('tmp_dir'), this.host, this.rid);
|
||||||
this.clean = [];
|
this.clean = [];
|
||||||
fs.ensureDirSync(this.tmpdir);
|
fs.ensureDirSync(this.tmpdir);
|
||||||
tmpfs.mount(this.tmpdir, '512m');
|
tmpfs.mount(this.tmpdir, '512m');
|
||||||
@@ -206,7 +189,7 @@ export default class Hydro {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async cacheOpen(domainId: string, pid: string, files: any[], next?) {
|
async cacheOpen(domainId: string, pid: string, files: any[], next?) {
|
||||||
const domainDir = path.join(CACHE_DIR, this.config.host, domainId);
|
const domainDir = path.join(getConfig('cache_dir'), this.config.host, domainId);
|
||||||
const filePath = path.join(domainDir, pid); await fs.ensureDir(filePath);
|
const filePath = path.join(domainDir, pid); await fs.ensureDir(filePath);
|
||||||
if (!files.length) throw new SystemError('Problem data not found.');
|
if (!files.length) throw new SystemError('Problem data not found.');
|
||||||
let etags: Record<string, string>;
|
let etags: Record<string, string>;
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { noop } from 'lodash';
|
|||||||
import * as tmpfs from '../tmpfs';
|
import * as tmpfs from '../tmpfs';
|
||||||
import log from '../log';
|
import log from '../log';
|
||||||
import { compilerText, Queue } from '../utils';
|
import { compilerText, Queue } from '../utils';
|
||||||
import { CACHE_DIR, TEMP_DIR } from '../config';
|
import { getConfig } from '../config';
|
||||||
import { FormatError, CompileError, SystemError } from '../error';
|
import { FormatError, CompileError, SystemError } from '../error';
|
||||||
import { STATUS_COMPILE_ERROR, STATUS_SYSTEM_ERROR } from '../status';
|
import { STATUS_COMPILE_ERROR, STATUS_SYSTEM_ERROR } from '../status';
|
||||||
import readCases from '../cases';
|
import readCases from '../cases';
|
||||||
@@ -16,39 +16,22 @@ import judge from '../judge';
|
|||||||
|
|
||||||
class JudgeTask {
|
class JudgeTask {
|
||||||
stat: Record<string, Date>;
|
stat: Record<string, Date>;
|
||||||
|
|
||||||
session: any;
|
session: any;
|
||||||
|
|
||||||
host: string;
|
host: string;
|
||||||
|
|
||||||
request: any;
|
request: any;
|
||||||
|
|
||||||
ws: WebSocket;
|
ws: WebSocket;
|
||||||
|
|
||||||
tag: any;
|
tag: any;
|
||||||
|
|
||||||
type: any;
|
type: any;
|
||||||
|
|
||||||
domain_id: string;
|
domain_id: string;
|
||||||
|
|
||||||
pid: string;
|
pid: string;
|
||||||
|
|
||||||
rid: string;
|
rid: string;
|
||||||
|
|
||||||
lang: string;
|
lang: string;
|
||||||
|
|
||||||
code: string;
|
code: string;
|
||||||
|
|
||||||
tmpdir: string;
|
tmpdir: string;
|
||||||
|
|
||||||
clean: Function[];
|
clean: Function[];
|
||||||
|
|
||||||
folder: string;
|
folder: string;
|
||||||
|
|
||||||
config: any;
|
config: any;
|
||||||
|
|
||||||
nextId = 1;
|
nextId = 1;
|
||||||
|
|
||||||
nextWaiting = [];
|
nextWaiting = [];
|
||||||
|
|
||||||
constructor(session: VJ4, request, ws: WebSocket) {
|
constructor(session: VJ4, request, ws: WebSocket) {
|
||||||
@@ -71,7 +54,7 @@ class JudgeTask {
|
|||||||
this.rid = this.request.rid;
|
this.rid = this.request.rid;
|
||||||
this.lang = this.request.lang;
|
this.lang = this.request.lang;
|
||||||
this.code = this.request.code;
|
this.code = this.request.code;
|
||||||
this.tmpdir = path.resolve(TEMP_DIR, 'tmp', this.host, this.rid);
|
this.tmpdir = path.resolve(getConfig('tmp_dir'), 'tmp', this.host, this.rid);
|
||||||
this.clean = [];
|
this.clean = [];
|
||||||
fs.ensureDirSync(this.tmpdir);
|
fs.ensureDirSync(this.tmpdir);
|
||||||
tmpfs.mount(this.tmpdir, '512m');
|
tmpfs.mount(this.tmpdir, '512m');
|
||||||
@@ -180,9 +163,7 @@ class JudgeTask {
|
|||||||
|
|
||||||
export default class VJ4 {
|
export default class VJ4 {
|
||||||
config: any;
|
config: any;
|
||||||
|
|
||||||
axios: any;
|
axios: any;
|
||||||
|
|
||||||
ws: WebSocket;
|
ws: WebSocket;
|
||||||
|
|
||||||
constructor(config) {
|
constructor(config) {
|
||||||
@@ -241,7 +222,7 @@ export default class VJ4 {
|
|||||||
log.info(`Getting problem data: ${this.config.host}/${domainId}/${pid}`);
|
log.info(`Getting problem data: ${this.config.host}/${domainId}/${pid}`);
|
||||||
await this.ensureLogin();
|
await this.ensureLogin();
|
||||||
if (next) next({ judge_text: '正在同步测试数据,请稍后' });
|
if (next) next({ judge_text: '正在同步测试数据,请稍后' });
|
||||||
const tmpFilePath = path.resolve(CACHE_DIR, `download_${this.config.host}_${domainId}_${pid}`);
|
const tmpFilePath = path.resolve(getConfig('cache_dir'), `download_${this.config.host}_${domainId}_${pid}`);
|
||||||
try {
|
try {
|
||||||
const res = await this.axios.get(
|
const res = await this.axios.get(
|
||||||
`${this.config.server_url}d/${domainId}/p/${pid}/data`,
|
`${this.config.server_url}d/${domainId}/p/${pid}/data`,
|
||||||
@@ -274,7 +255,7 @@ export default class VJ4 {
|
|||||||
|
|
||||||
async recordPretestData(rid: string, savePath: string) {
|
async recordPretestData(rid: string, savePath: string) {
|
||||||
log.info(`Getting pretest data: ${this.config.host}/${rid}`);
|
log.info(`Getting pretest data: ${this.config.host}/${rid}`);
|
||||||
const tmpFilePath = path.resolve(CACHE_DIR, `download_${this.config.host}_${rid}`);
|
const tmpFilePath = path.resolve(getConfig('cache_dir'), `download_${this.config.host}_${rid}`);
|
||||||
await this.ensureLogin();
|
await this.ensureLogin();
|
||||||
const res = await this.axios.get(`records/${rid}/data`, { responseType: 'stream' });
|
const res = await this.axios.get(`records/${rid}/data`, { responseType: 'stream' });
|
||||||
const w = fs.createWriteStream(tmpFilePath);
|
const w = fs.createWriteStream(tmpFilePath);
|
||||||
@@ -393,7 +374,7 @@ export default class VJ4 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async cacheOpen(domainId: string, pid: string, next) {
|
async cacheOpen(domainId: string, pid: string, next) {
|
||||||
const domainDir = path.join(CACHE_DIR, this.config.host, domainId);
|
const domainDir = path.join(getConfig('cache_dir'), this.config.host, domainId);
|
||||||
const filePath = path.join(domainDir, pid);
|
const filePath = path.join(domainDir, pid);
|
||||||
const version = await this.problemDataVersion(domainId, pid);
|
const version = await this.problemDataVersion(domainId, pid);
|
||||||
if (fs.existsSync(filePath)) {
|
if (fs.existsSync(filePath)) {
|
||||||
|
|||||||
@@ -9,3 +9,8 @@ export interface Execute {
|
|||||||
copyIn: Record<string, SFile>,
|
copyIn: Record<string, SFile>,
|
||||||
time?: number,
|
time?: number,
|
||||||
}
|
}
|
||||||
|
export interface CompileErrorInfo {
|
||||||
|
stdout?: string,
|
||||||
|
stderr?: string,
|
||||||
|
status?: string
|
||||||
|
}
|
||||||
@@ -9,6 +9,7 @@ import { run } from '../sandbox';
|
|||||||
import compile from '../compile';
|
import compile from '../compile';
|
||||||
import signals from '../signals';
|
import signals from '../signals';
|
||||||
import { check, compileChecker } from '../check';
|
import { check, compileChecker } from '../check';
|
||||||
|
import { getConfig } from '../config';
|
||||||
|
|
||||||
const Score = {
|
const Score = {
|
||||||
sum: (a: number, b: number) => (a + b),
|
sum: (a: number, b: number) => (a + b),
|
||||||
@@ -158,7 +159,7 @@ export const judge = async (ctx) => {
|
|||||||
ctx.total_score = 0;
|
ctx.total_score = 0;
|
||||||
ctx.total_memory_usage_kb = 0;
|
ctx.total_memory_usage_kb = 0;
|
||||||
ctx.total_time_usage_ms = 0;
|
ctx.total_time_usage_ms = 0;
|
||||||
ctx.queue = new Queue({ concurrency: ctx.config.concurrency || 2 });
|
ctx.queue = new Queue({ concurrency: getConfig('parallelism') });
|
||||||
ctx.failed = {};
|
ctx.failed = {};
|
||||||
for (const sid in ctx.config.subtasks) tasks.push(judgeSubtask(ctx.config.subtasks[sid], sid)(ctx));
|
for (const sid in ctx.config.subtasks) tasks.push(judgeSubtask(ctx.config.subtasks[sid], sid)(ctx));
|
||||||
const scores = await Promise.all(tasks);
|
const scores = await Promise.all(tasks);
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { parseFilename } from '../utils';
|
|||||||
import { run } from '../sandbox';
|
import { run } from '../sandbox';
|
||||||
import compile from '../compile';
|
import compile from '../compile';
|
||||||
import signals from '../signals';
|
import signals from '../signals';
|
||||||
|
import { getConfig } from '../config';
|
||||||
|
|
||||||
const Score = {
|
const Score = {
|
||||||
sum: (a, b) => (a + b),
|
sum: (a, b) => (a + b),
|
||||||
@@ -39,7 +40,7 @@ function judgeCase(c) {
|
|||||||
status = STATUS.STATUS_RUNTIME_ERROR;
|
status = STATUS.STATUS_RUNTIME_ERROR;
|
||||||
if (code < 32) message = signals[code];
|
if (code < 32) message = signals[code];
|
||||||
else message = { message: 'Your program returned {0}.', params: [code] };
|
else message = { message: 'Your program returned {0}.', params: [code] };
|
||||||
} else [status, score, message] = resInteractor.files.stderr.split('\n');
|
} else[status, score, message] = resInteractor.files.stderr.split('\n');
|
||||||
ctxSubtask.score = Score[ctxSubtask.subtask.type](ctxSubtask.score, score);
|
ctxSubtask.score = Score[ctxSubtask.subtask.type](ctxSubtask.score, score);
|
||||||
ctxSubtask.status = Math.max(ctxSubtask.status, status);
|
ctxSubtask.status = Math.max(ctxSubtask.status, status);
|
||||||
ctx.total_time_usage_ms += time_usage_ms;
|
ctx.total_time_usage_ms += time_usage_ms;
|
||||||
@@ -104,7 +105,7 @@ export const judge = async (ctx) => {
|
|||||||
ctx.next({ status: STATUS.STATUS_JUDGING, progress: 0 });
|
ctx.next({ status: STATUS.STATUS_JUDGING, progress: 0 });
|
||||||
const tasks = [];
|
const tasks = [];
|
||||||
ctx.total_status = ctx.total_score = ctx.total_memory_usage_kb = ctx.total_time_usage_ms = 0;
|
ctx.total_status = ctx.total_score = ctx.total_memory_usage_kb = ctx.total_time_usage_ms = 0;
|
||||||
ctx.queue = new Queue({ concurrency: ctx.config.concurrency || 2 });
|
ctx.queue = new Queue({ concurrency: getConfig('parallelism') });
|
||||||
for (const sid in ctx.config.subtasks) {
|
for (const sid in ctx.config.subtasks) {
|
||||||
tasks.push(judgeSubtask(ctx.config.subtasks[sid])(ctx));
|
tasks.push(judgeSubtask(ctx.config.subtasks[sid])(ctx));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,30 +31,19 @@ const colors = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
const instances: Record<string, Logger> = {};
|
const instances: Record<string, Logger> = {};
|
||||||
|
|
||||||
type LogFunction = (format: any, ...param: any[]) => void
|
type LogFunction = (format: any, ...param: any[]) => void
|
||||||
|
|
||||||
type LogType = 'success' | 'error' | 'info' | 'warn' | 'debug'
|
type LogType = 'success' | 'error' | 'info' | 'warn' | 'debug'
|
||||||
|
|
||||||
export interface Logger extends Record<LogType, LogFunction> { }
|
export interface Logger extends Record<LogType, LogFunction> { }
|
||||||
|
|
||||||
export class Logger {
|
export class Logger {
|
||||||
static readonly SUCCESS = 1
|
static readonly SUCCESS = 1
|
||||||
|
|
||||||
static readonly ERROR = 1
|
static readonly ERROR = 1
|
||||||
|
|
||||||
static readonly INFO = 2
|
static readonly INFO = 2
|
||||||
|
|
||||||
static readonly WARN = 2
|
static readonly WARN = 2
|
||||||
|
|
||||||
static readonly DEBUG = 3
|
static readonly DEBUG = 3
|
||||||
|
|
||||||
static baseLevel = argv.debug ? 3 : 2
|
static baseLevel = argv.debug ? 3 : 2
|
||||||
|
|
||||||
static showDiff = false
|
static showDiff = false
|
||||||
|
|
||||||
static levels: Record<string, number> = {}
|
static levels: Record<string, number> = {}
|
||||||
|
|
||||||
static lastTime = 0
|
static lastTime = 0
|
||||||
|
|
||||||
static options: InspectOptions = {
|
static options: InspectOptions = {
|
||||||
@@ -73,9 +62,7 @@ export class Logger {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private code: number
|
private code: number
|
||||||
|
|
||||||
private displayName: string
|
private displayName: string
|
||||||
|
|
||||||
public stream: NodeJS.WritableStream = process.stderr
|
public stream: NodeJS.WritableStream = process.stderr
|
||||||
|
|
||||||
constructor(public name: string, private showDiff = false) {
|
constructor(public name: string, private showDiff = false) {
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ export async function runMultiple(execute) {
|
|||||||
body.cmd[1].files[1] = null;
|
body.cmd[1].files[1] = null;
|
||||||
res = await axios.post('/run', body);
|
res = await axios.post('/run', body);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw new SystemError('Cannot connect to sandbox service.');
|
throw new SystemError('Sandbox Error');
|
||||||
}
|
}
|
||||||
return res.data;
|
return res.data;
|
||||||
}
|
}
|
||||||
@@ -87,7 +87,7 @@ export async function run(execute, params?) {
|
|||||||
[result] = res.data;
|
[result] = res.data;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// FIXME request body larger than maxBodyLength limit
|
// FIXME request body larger than maxBodyLength limit
|
||||||
throw new SystemError('Cannot connect to sandbox service.', e.message);
|
throw new SystemError('Sandbox Error', e.message);
|
||||||
}
|
}
|
||||||
// FIXME: Signalled?
|
// FIXME: Signalled?
|
||||||
const ret: any = {
|
const ret: any = {
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import path from 'path';
|
|||||||
import { argv } from 'yargs';
|
import { argv } from 'yargs';
|
||||||
import { ObjectID } from 'bson';
|
import { ObjectID } from 'bson';
|
||||||
import fs from 'fs-extra';
|
import fs from 'fs-extra';
|
||||||
import { homedir, tmpdir } from 'os';
|
|
||||||
import { noop } from 'lodash';
|
import { noop } from 'lodash';
|
||||||
import { Logger } from 'hydrooj/dist/logger';
|
import { Logger } from 'hydrooj/dist/logger';
|
||||||
import * as monitor from 'hydrooj/dist/service/monitor';
|
import * as monitor from 'hydrooj/dist/service/monitor';
|
||||||
@@ -14,10 +13,19 @@ import { FormatError, CompileError, SystemError } from './error';
|
|||||||
import { STATUS_COMPILE_ERROR, STATUS_SYSTEM_ERROR } from './status';
|
import { STATUS_COMPILE_ERROR, STATUS_SYSTEM_ERROR } from './status';
|
||||||
import { compilerText } from './utils';
|
import { compilerText } from './utils';
|
||||||
import readYamlCases from './cases';
|
import readYamlCases from './cases';
|
||||||
|
import { getConfig } from './config';
|
||||||
|
|
||||||
declare module 'hydrooj/dist/interface' {
|
declare module 'hydrooj/dist/interface' {
|
||||||
interface SystemKeys {
|
interface SystemKeys {
|
||||||
'hydrojudge.langs': string,
|
'hydrojudge.langs': string,
|
||||||
|
'hydrojudge.cache_dir': string,
|
||||||
|
'hydrojudge.tmp_dir': string,
|
||||||
|
'hydrojudge.tmpfs_size': string,
|
||||||
|
'hydrojudge.retry_delay_sec': number,
|
||||||
|
'hydrojudge.sandbox_host': string,
|
||||||
|
'hydrojudge.testcases_max': number,
|
||||||
|
'hydrojudge.total_time_limit': number,
|
||||||
|
'hydrojudge.parallelism': number,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,7 +71,7 @@ async function postInit() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function cacheOpen(domainId: string, pid: string, files: any[]) {
|
async function cacheOpen(domainId: string, pid: string, files: any[]) {
|
||||||
const filePath = path.join(homedir(), '.cache', 'hydro', 'judge', domainId, pid);
|
const filePath = path.join(getConfig('cache_dir'), domainId, pid);
|
||||||
await fs.ensureDir(filePath);
|
await fs.ensureDir(filePath);
|
||||||
if (!files.length) throw new SystemError('Problem data not found.');
|
if (!files.length) throw new SystemError('Problem data not found.');
|
||||||
let etags: Record<string, string> = {};
|
let etags: Record<string, string> = {};
|
||||||
@@ -172,10 +180,10 @@ async function postInit() {
|
|||||||
this.config = this.request.config;
|
this.config = this.request.config;
|
||||||
this.next = getNext(this);
|
this.next = getNext(this);
|
||||||
this.end = getEnd(this.domainId, this.rid);
|
this.end = getEnd(this.domainId, this.rid);
|
||||||
this.tmpdir = path.resolve(tmpdir(), 'tmp', this.rid);
|
this.tmpdir = path.resolve(getConfig('tmp_dir'), this.rid);
|
||||||
this.clean = [];
|
this.clean = [];
|
||||||
fs.ensureDirSync(this.tmpdir);
|
fs.ensureDirSync(this.tmpdir);
|
||||||
tmpfs.mount(this.tmpdir, '512m');
|
tmpfs.mount(this.tmpdir, getConfig('tmpfs_size'));
|
||||||
logger.info(`Submission: ${this.rid}`, { pid: this.pid });
|
logger.info(`Submission: ${this.rid}`, { pid: this.pid });
|
||||||
if (this.config.input) await this.run();
|
if (this.config.input) await this.run();
|
||||||
else if (this.config.hack) await this.hack();
|
else if (this.config.hack) await this.hack();
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import path from 'path';
|
import path from 'path';
|
||||||
import fs from 'fs-extra';
|
import fs from 'fs-extra';
|
||||||
import systeminformation from 'systeminformation';
|
import systeminformation from 'systeminformation';
|
||||||
import { tmpdir } from 'os';
|
|
||||||
import { noop } from 'lodash';
|
import { noop } from 'lodash';
|
||||||
import { judge } from './judge/run';
|
import { judge } from './judge/run';
|
||||||
import * as tmpfs from './tmpfs';
|
import * as tmpfs from './tmpfs';
|
||||||
|
import { getConfig } from './config';
|
||||||
|
|
||||||
function size(s: number, base = 1) {
|
function size(s: number, base = 1) {
|
||||||
s *= base;
|
s *= base;
|
||||||
@@ -45,7 +45,7 @@ int main(){
|
|||||||
},
|
},
|
||||||
end: () => { },
|
end: () => { },
|
||||||
};
|
};
|
||||||
context.tmpdir = path.resolve(tmpdir(), 'hydro', 'tmp', 'sysinfo');
|
context.tmpdir = path.resolve(getConfig('tmp_dir'), 'sysinfo');
|
||||||
fs.ensureDirSync(context.tmpdir);
|
fs.ensureDirSync(context.tmpdir);
|
||||||
tmpfs.mount(context.tmpdir, '32m');
|
tmpfs.mount(context.tmpdir, '32m');
|
||||||
await judge(context).catch((e) => console.error(e));
|
await judge(context).catch((e) => console.error(e));
|
||||||
|
|||||||
@@ -30,9 +30,7 @@ export function parseMemoryMB(val: string | number) {
|
|||||||
|
|
||||||
export function sleep(timeout: number) {
|
export function sleep(timeout: number) {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
setTimeout(() => {
|
setTimeout(resolve, timeout);
|
||||||
resolve(null);
|
|
||||||
}, timeout);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,18 +40,11 @@ export function parseFilename(filePath: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class Queue<T> extends EventEmitter {
|
export class Queue<T> extends EventEmitter {
|
||||||
queue: T[];
|
queue: T[] = [];
|
||||||
|
waiting: any[] = [];
|
||||||
waiting: any[];
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
this.queue = [];
|
|
||||||
this.waiting = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
get(count = 1) {
|
get(count = 1) {
|
||||||
if (this.empty() || this.queue.length < count) {
|
if (this.queue.length < count) {
|
||||||
return new Promise<T[]>((resolve) => {
|
return new Promise<T[]>((resolve) => {
|
||||||
this.waiting.push({ count, resolve });
|
this.waiting.push({ count, resolve });
|
||||||
});
|
});
|
||||||
@@ -64,10 +55,6 @@ export class Queue<T> extends EventEmitter {
|
|||||||
return items as T[];
|
return items as T[];
|
||||||
}
|
}
|
||||||
|
|
||||||
empty() {
|
|
||||||
return this.queue.length === 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
push(value: T) {
|
push(value: T) {
|
||||||
this.queue.push(value);
|
this.queue.push(value);
|
||||||
if (this.waiting.length && this.waiting[0].count <= this.queue.length) {
|
if (this.waiting.length && this.waiting[0].count <= this.queue.length) {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "hydrooj",
|
"name": "hydrooj",
|
||||||
"version": "2.15.27",
|
"version": "2.15.28",
|
||||||
"bin": "bin/hydrooj.js",
|
"bin": "bin/hydrooj.js",
|
||||||
"main": "dist/loader.js",
|
"main": "dist/loader.js",
|
||||||
"typings": "dist/loader.d.ts",
|
"typings": "dist/loader.d.ts",
|
||||||
|
|||||||
@@ -100,9 +100,9 @@ export async function setting(pending: string[], fail: string[], modelSetting: t
|
|||||||
try {
|
try {
|
||||||
const cfg: any = yaml.load(fs.readFileSync(p).toString());
|
const cfg: any = yaml.load(fs.readFileSync(p).toString());
|
||||||
for (const key in cfg) {
|
for (const key in cfg) {
|
||||||
let val;
|
let val = cfg[key].default;
|
||||||
if (typeof cfg[key].default === 'string') {
|
if (typeof val === 'string') {
|
||||||
val = cfg[key].default
|
val = val
|
||||||
.replace(/\$TEMP/g, os.tmpdir())
|
.replace(/\$TEMP/g, os.tmpdir())
|
||||||
.replace(/\$HOME/g, os.homedir());
|
.replace(/\$HOME/g, os.homedir());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { Client, BucketItem, ItemBucketMetadata } from 'minio';
|
|||||||
import { createReadStream } from 'fs-extra';
|
import { createReadStream } from 'fs-extra';
|
||||||
import { Logger } from '../logger';
|
import { Logger } from '../logger';
|
||||||
import { streamToBuffer } from '../utils';
|
import { streamToBuffer } from '../utils';
|
||||||
|
import * as system from '../model/system';
|
||||||
|
|
||||||
const logger = new Logger('storage');
|
const logger = new Logger('storage');
|
||||||
|
|
||||||
@@ -96,10 +97,20 @@ class StorageService {
|
|||||||
assert(result.toString() === 'test');
|
assert(result.toString() === 'test');
|
||||||
await this.del('storage.test');
|
await this.del('storage.test');
|
||||||
logger.success('Storage connected.');
|
logger.success('Storage connected.');
|
||||||
|
this.error = null;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error('Storage init fail.');
|
logger.warn('Storage init fail. will retry later.');
|
||||||
logger.error(e);
|
|
||||||
this.error = e.toString();
|
this.error = e.toString();
|
||||||
|
setTimeout(async () => {
|
||||||
|
const [endPoint, accessKey, secretKey, bucket, region, endPointForUser, endPointForJudge] = system.getMany([
|
||||||
|
'file.endPoint', 'file.accessKey', 'file.secretKey', 'file.bucket', 'file.region',
|
||||||
|
'file.endPointForUser', 'file.endPointForJudge',
|
||||||
|
]);
|
||||||
|
const sopts = {
|
||||||
|
endPoint, accessKey, secretKey, bucket, region, endPointForUser, endPointForJudge,
|
||||||
|
};
|
||||||
|
await this.start(sopts);
|
||||||
|
}, 10000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user