refactor(remote_judger): clean up daemon code
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
Baoshuo Ren 2023-02-02 15:37:26 +08:00
parent 0cc84f84c0
commit 16cd5bb162
Signed by: baoshuo
GPG Key ID: 00CB9680AB29F51A
2 changed files with 52 additions and 66 deletions

View File

@ -4,7 +4,6 @@ import proxy from 'superagent-proxy';
import Logger from './utils/logger'; import Logger from './utils/logger';
import sleep from './utils/sleep'; import sleep from './utils/sleep';
import * as TIME from './utils/time'; import * as TIME from './utils/time';
import htmlspecialchars from './utils/htmlspecialchars';
import { apply } from './vjudge'; import { apply } from './vjudge';
import path from 'path'; import path from 'path';
import child from 'child_process'; import child from 'child_process';
@ -56,9 +55,9 @@ export default async function daemon(config: UOJConfig) {
if (error) { if (error) {
logger.error('/submit', error.message); logger.error('/submit', error.message);
await sleep(3 * TIME.second); await sleep(2 * TIME.second);
} else if (text.startsWith('Nothing to judge')) { } else if (text.startsWith('Nothing to judge')) {
await sleep(3 * TIME.second); await sleep(TIME.second);
} else { } else {
const data: UOJSubmission = JSON.parse(text); const data: UOJSubmission = JSON.parse(text);
const { id, content, judge_time } = data; const { id, content, judge_time } = data;
@ -85,7 +84,35 @@ export default async function daemon(config: UOJConfig) {
fs.ensureDirSync(tmpdir); fs.ensureDirSync(tmpdir);
const reportError = async (error: string, details: string) => { let code = '';
try {
// Download source code
logger.debug('Downloading source code.', id);
const zipFilePath = path.resolve(tmpdir, 'all.zip');
const res = request(`/download${content.file_name}`);
const stream = fs.createWriteStream(zipFilePath);
res.pipe(stream);
await new Promise((resolve, reject) => {
stream.on('finish', resolve);
stream.on('error', reject);
});
// Extract source code
logger.debug('Extracting source code.', id);
const extractedPath = path.resolve(tmpdir, 'all');
await new Promise((resolve, reject) => {
child.exec(`unzip ${zipFilePath} -d ${extractedPath}`, e => {
if (e) reject(e);
else resolve(true);
});
});
// Read source code
logger.debug('Reading source code.', id);
const sourceCodePath = path.resolve(extractedPath, 'answer.code');
code = fs.readFileSync(sourceCodePath, 'utf-8');
} catch (e) {
await request('/submit', { await request('/submit', {
submit: true, submit: true,
fetch_new: false, fetch_new: false,
@ -93,67 +120,17 @@ export default async function daemon(config: UOJConfig) {
result: JSON.stringify({ result: JSON.stringify({
status: 'Judged', status: 'Judged',
score: 0, score: 0,
error, error: 'Judgment Failed',
details: `<error>${htmlspecialchars(details)}</error>`, details: `<error>Failed to download and extract source code.</error>`,
}), }),
judge_time, judge_time,
}); });
};
// Download source code logger.error(
logger.debug('Downloading source code.', id); 'Failed to download and extract source code.',
const zipFilePath = path.resolve(tmpdir, 'all.zip'); id,
const res = request(`/download${content.file_name}`); e.message
const stream = fs.createWriteStream(zipFilePath);
res.pipe(stream);
try {
await new Promise((resolve, reject) => {
stream.on('finish', resolve);
stream.on('error', reject);
});
} catch (e) {
await reportError(
'Judgment Failed',
`Failed to download source code.`
); );
logger.error('Failed to download source code.', id, e.message);
fs.removeSync(tmpdir);
continue;
}
// Unzip source code
logger.debug('Unzipping source code.', id);
const extractedPath = path.resolve(tmpdir, 'all');
try {
await new Promise((resolve, reject) => {
child.exec(`unzip ${zipFilePath} -d ${extractedPath}`, e => {
if (e) reject(e);
else resolve(true);
});
});
} catch (e) {
await reportError('Judgment Failed', `Failed to unzip source code.`);
logger.error('Failed to unzip source code.', id, e.message);
fs.removeSync(tmpdir);
continue;
}
// Read source code
logger.debug('Reading source code.', id);
const sourceCodePath = path.resolve(extractedPath, 'answer.code');
let code = '';
try {
code = fs.readFileSync(sourceCodePath, 'utf-8');
} catch (e) {
await reportError('Judgment Failed', `Failed to read source code.`);
logger.error('Failed to read source code.', id, e.message);
fs.removeSync(tmpdir); fs.removeSync(tmpdir);
@ -172,10 +149,19 @@ export default async function daemon(config: UOJConfig) {
judge_time judge_time
); );
} catch (err) { } catch (err) {
await reportError( await request('/submit', {
'Judgment Failed', submit: true,
'No details, please contact admin!' fetch_new: false,
); id,
result: JSON.stringify({
status: 'Judged',
score: 0,
error: 'Judgment Failed',
details: `<error>No details.</error>`,
}),
judge_time,
});
logger.error('Judgment Failed.', id, err.message); logger.error('Judgment Failed.', id, err.message);
fs.removeSync(tmpdir); fs.removeSync(tmpdir);
@ -188,7 +174,7 @@ export default async function daemon(config: UOJConfig) {
} catch (err) { } catch (err) {
logger.error(err.message); logger.error(err.message);
await sleep(3 * TIME.second); await sleep(2 * TIME.second);
} }
} }
} }

View File

@ -145,7 +145,7 @@ class VJudge {
) { ) {
if (!this.providers[type]) throw new Error(`no provider ${type}`); if (!this.providers[type]) throw new Error(`no provider ${type}`);
this.providers[type].judge(id, problem_id, language, code, judge_time); await this.providers[type].judge(id, problem_id, language, code, judge_time);
} }
} }