From 1231fb2ce726d419b9ca3341bc7e08495c48ca99 Mon Sep 17 00:00:00 2001 From: undefined Date: Fri, 30 Oct 2020 21:27:53 +0800 Subject: [PATCH] =?UTF-8?q?judge:=20=E9=99=90=E5=88=B6=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E5=8C=85=E4=B8=AD=E6=96=87=E4=BB=B6=E6=95=B0=E9=87=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/hydrojudge/package.json | 3 ++- packages/hydrojudge/src/cases.ts | 11 +++++++---- packages/hydrojudge/src/hosts/vj4.ts | 22 ++++++++++++++-------- packages/hydrojudge/src/service.ts | 7 +++++-- packages/hydrojudge/src/utils.ts | 8 ++++---- 5 files changed, 32 insertions(+), 19 deletions(-) diff --git a/packages/hydrojudge/package.json b/packages/hydrojudge/package.json index b13932008..5926020e2 100644 --- a/packages/hydrojudge/package.json +++ b/packages/hydrojudge/package.json @@ -1,11 +1,12 @@ { "name": "@hydrooj/hydrojudge", "bin": "bin/hydrojudge.js", - "version": "2.1.13", + "version": "2.1.14", "main": "package.json", "author": "masnn", "repository": "https://github.com/hydro-dev/Hydro.git", "dependencies": { + "adm-zip": "^0.4.16", "axios": "^0.21.0", "bson": "^4.1.0", "fs-extra": "^9.0.1", diff --git a/packages/hydrojudge/src/cases.ts b/packages/hydrojudge/src/cases.ts index ce8a13ae3..3164f4aeb 100644 --- a/packages/hydrojudge/src/cases.ts +++ b/packages/hydrojudge/src/cases.ts @@ -243,7 +243,7 @@ export async function readYamlCases(folder: string, cfg: Dictionary = {}, a } else if (cfg.subtasks) { for (const subtask of cfg.subtasks) { const cases = []; - for (const c of subtask) { + for (const c of subtask.cases) { config.count++; cases.push({ input: checkFile(c.input, '找不到输入文件 '), @@ -269,14 +269,17 @@ export async function readYamlCases(folder: string, cfg: Dictionary = {}, a function convertIniConfig(ini: string) { const f = ini.split('\n'); const count = parseInt(f[0], 10); - const res = { cases: [] }; + const res = { subtasks: [] }; for (let i = 1; i <= count; i++) { const [input, output, time, score, memory] = f[i].split('|'); const cur = { - input: `input/${input}`, output: `output/${output}`, score: parseInt(score, 10), time: `${time}s`, memory: '128m', + cases: [{ input: `input/${input}`, output: `output/${output}` }], + score: parseInt(score, 10), + time: `${time}s`, + memory: '128m', }; if (!Number.isNaN(parseInt(memory, 10))) cur.memory = `${Math.floor(parseInt(memory, 10) / 1024)}m`; - res.cases.push(cur); + res.subtasks.push(cur); } return res; } diff --git a/packages/hydrojudge/src/hosts/vj4.ts b/packages/hydrojudge/src/hosts/vj4.ts index 3e18aaa79..1e9981230 100644 --- a/packages/hydrojudge/src/hosts/vj4.ts +++ b/packages/hydrojudge/src/hosts/vj4.ts @@ -1,12 +1,12 @@ /* eslint-disable no-await-in-loop */ import path from 'path'; -import child from 'child_process'; import axios from 'axios'; +import AdmZip from 'adm-zip'; import fs from 'fs-extra'; import WebSocket from 'ws'; import * as tmpfs from '../tmpfs'; import log from '../log'; -import { compilerText } from '../utils'; +import { compilerText, Queue } from '../utils'; import { CACHE_DIR, TEMP_DIR } from '../config'; import { FormatError, CompileError, SystemError } from '../error'; import { STATUS_COMPILE_ERROR, STATUS_SYSTEM_ERROR } from '../status'; @@ -240,15 +240,18 @@ export default class VJ4 { `${this.config.server_url}d/${domainId}/p/${pid}/data`, { responseType: 'stream' }, ); - const w = await fs.createWriteStream(tmpFilePath); + const w = fs.createWriteStream(tmpFilePath); res.data.pipe(w); await new Promise((resolve, reject) => { w.on('finish', resolve); w.on('error', reject); }); fs.ensureDirSync(path.dirname(savePath)); + const zip = new AdmZip(tmpFilePath); + const entries = zip.getEntries(); + if (entries.length > 1000) throw new FormatError('Too many files'); await new Promise((resolve, reject) => { - child.exec(`unzip ${tmpFilePath} -d ${savePath}`, (e) => { + zip.extractAllToAsync(savePath, true, (e) => { if (e) reject(e); else resolve(); }); @@ -262,20 +265,23 @@ export default class VJ4 { return savePath; } - async recordPretestData(rid, savePath) { + async recordPretestData(rid: string, savePath: string) { log.info(`Getting pretest data: ${this.config.host}/${rid}`); const tmpFilePath = path.resolve(CACHE_DIR, `download_${this.config.host}_${rid}`); await this.ensureLogin(); const res = await this.axios.get(`records/${rid}/data`, { responseType: 'stream' }); - const w = await fs.createWriteStream(tmpFilePath); + const w = fs.createWriteStream(tmpFilePath); res.data.pipe(w); await new Promise((resolve, reject) => { w.on('finish', resolve); w.on('error', reject); }); fs.ensureDirSync(path.dirname(savePath)); + const zip = new AdmZip(tmpFilePath); + const entries = zip.getEntries(); + if (entries.length > 1000) throw new FormatError('Too many files'); await new Promise((resolve, reject) => { - child.exec(`unzip ${tmpFilePath} -d ${savePath}`, (e) => { + zip.extractAllToAsync(savePath, true, (e) => { if (e) reject(e); else resolve(); }); @@ -285,7 +291,7 @@ export default class VJ4 { return savePath; } - async consume(queue) { + async consume(queue: Queue) { log.info('正在连接 %sjudge/consume-conn', this.config.server_url); const res = await this.axios.get('judge/consume-conn/info'); this.ws = new WebSocket(`${this.config.server_url.replace(/^http/i, 'ws')}judge/consume-conn/websocket?t=${res.data.entropy}`, { diff --git a/packages/hydrojudge/src/service.ts b/packages/hydrojudge/src/service.ts index c34ea19fd..6852a574e 100644 --- a/packages/hydrojudge/src/service.ts +++ b/packages/hydrojudge/src/service.ts @@ -2,10 +2,10 @@ /* eslint-disable no-await-in-loop */ import 'hydrooj'; import path from 'path'; -import child from 'child_process'; import { ObjectID } from 'bson'; import fs from 'fs-extra'; import { homedir, tmpdir } from 'os'; +import AdmZip from 'adm-zip'; declare module 'hydrooj/dist/interface' { interface SystemKeys { @@ -73,8 +73,11 @@ async function postInit() { w.on('error', reject); }); fs.ensureDirSync(path.dirname(savePath)); + const zip = new AdmZip(tmpFilePath); + const entries = zip.getEntries(); + if (entries.length > 1000) throw new FormatError('Too many files'); await new Promise((resolve, reject) => { - child.exec(`unzip ${tmpFilePath} -d ${savePath}`, (e) => { + zip.extractAllToAsync(savePath, true, (e) => { if (e) reject(e); else resolve(); }); diff --git a/packages/hydrojudge/src/utils.ts b/packages/hydrojudge/src/utils.ts index f18d5d397..ecec18ac0 100644 --- a/packages/hydrojudge/src/utils.ts +++ b/packages/hydrojudge/src/utils.ts @@ -13,19 +13,19 @@ const EMPTY_STR = /^[ \r\n\t]*$/i; export const cmd = parse; -export function parseTimeMS(str) { +export function parseTimeMS(str: string) { const match = TIME_RE.exec(str); if (!match) throw new FormatError(str, ['error parsing time']); return Math.floor(parseFloat(match[1]) * TIME_UNITS[match[2]]); } -export function parseMemoryMB(str) { +export function parseMemoryMB(str: string) { const match = MEMORY_RE.exec(str); if (!match) throw new FormatError(str, ['error parsing memory']); return Math.floor(parseFloat(match[1]) * MEMORY_UNITS[match[2]]); } -export function sleep(timeout) { +export function sleep(timeout: number) { return new Promise((resolve) => { setTimeout(() => { resolve(); @@ -84,7 +84,7 @@ export function compilerText(stdout: string, stderr: string) { return ret.join('\n'); } -export function copyInDir(dir) { +export function copyInDir(dir: string) { const files = {}; if (fs.existsSync(dir)) { fs.readdirSync(dir).forEach((f1) => {