refactor(remote_judger): waitForSubmission

This commit is contained in:
Baoshuo Ren 2023-02-06 11:24:45 +08:00
parent 00fea4675f
commit 4c0167ee6e
Signed by: baoshuo
GPG Key ID: 00CB9680AB29F51A
7 changed files with 447 additions and 417 deletions

View File

@ -20,10 +20,10 @@ export interface IBasicProvider {
end: NextFunction end: NextFunction
): Promise<string | void>; ): Promise<string | void>;
waitForSubmission( waitForSubmission(
problem_id: string,
id: string, id: string,
next: NextFunction, next: NextFunction,
end: NextFunction end: NextFunction,
problem_id?: string
): Promise<void>; ): Promise<void>;
} }

View File

@ -8,7 +8,7 @@ import Logger from '../utils/logger';
proxy(superagent); proxy(superagent);
const logger = new Logger('remote/atcoder'); const logger = new Logger('remote/atcoder');
const langs_map = { const LANGS_MAP = {
C: { C: {
name: 'C (GCC 9.2.1)', name: 'C (GCC 9.2.1)',
id: 4001, id: 4001,
@ -182,7 +182,7 @@ export default class AtcoderProvider implements IBasicProvider {
next, next,
end end
) { ) {
const programType = langs_map[lang] || langs_map['C++']; const programType = LANGS_MAP[lang] || LANGS_MAP['C++'];
const comment = programType.comment; const comment = programType.comment;
if (comment) { if (comment) {
@ -244,90 +244,96 @@ export default class AtcoderProvider implements IBasicProvider {
.getAttribute('data-id'); .getAttribute('data-id');
} }
async waitForSubmission(problem_id: string, id: string, next, end) { async waitForSubmission(id: string, next, end, problem_id: string) {
let i = 0; let count = 0;
let fail = 0;
const [contestId] = parseProblemId(problem_id); const [contestId] = parseProblemId(problem_id);
const status_url = `/contests/${contestId}/submissions/me/status/json?reload=true&sids[]=${id}`; const status_url = `/contests/${contestId}/submissions/me/status/json?reload=true&sids[]=${id}`;
while (true) { while (count < 180 && fail < 10) {
if (++i > 180) { count++;
return await end({
id,
error: true,
status: 'Judgment Failed',
message: 'Failed to fetch submission details.',
});
}
await sleep(1000); await sleep(1000);
const { body, error, header } = await this.get(status_url).retry(3);
if (header['set-cookie']) { try {
this.cookie = header['set-cookie']; const { body, header } = await this.get(status_url).retry(3);
}
if (error) continue; if (header['set-cookie']) {
this.cookie = header['set-cookie'];
}
const result = body.Result[id]; const result = body.Result[id];
const { const {
window: { document }, window: { document },
} = new JSDOM(`<table>${result.Html}</table>`); } = new JSDOM(`<table>${result.Html}</table>`);
const elements = document.querySelectorAll('td'); const elements = document.querySelectorAll('td');
const statusTd = elements[0]; const statusTd = elements[0];
const statusElem = statusTd.querySelector('span'); const statusElem = statusTd.querySelector('span');
if ( if (
statusElem.title === 'Waiting for Judging' || statusElem.title === 'Waiting for Judging' ||
statusElem.title === 'Waiting for Re-judging' || statusElem.title === 'Waiting for Re-judging' ||
['WJ', 'WR'].includes(statusElem.innerHTML.trim()) ['WJ', 'WR'].includes(statusElem.innerHTML.trim())
) { ) {
await next({ test_id: 0 }); await next({ test_id: 0 });
continue; continue;
} }
if ( if (
statusElem.title === 'Judging' || statusElem.title === 'Judging' ||
(statusTd.colSpan == 3 && statusTd.className.includes('waiting-judge')) (statusTd.colSpan == 3 &&
) { statusTd.className.includes('waiting-judge'))
await next({ test_id: /(\d+)/.exec(statusElem.innerHTML)[1] || 0 }); ) {
await next({ test_id: /(\d+)/.exec(statusElem.innerHTML)[1] || 0 });
continue; continue;
} }
if (statusElem.title === 'Compilation Error') {
return await end({
id,
error: true,
status: 'Compile Error',
message: '',
});
}
if (statusElem.title === 'Internal Error') {
return await end({
error: true,
status: 'Judgment Failed',
message: 'AtCoder Internal Error.',
});
}
const time = parseInt(elements[1].innerHTML.trim());
const memory = parseInt(elements[2].innerHTML.trim());
if (statusElem.title === 'Compilation Error') {
return await end({ return await end({
id, id,
error: true, status: statusElem.title || 'None',
status: 'Compile Error', score:
message: '', statusElem.title === 'Accepted' ||
statusElem.innerHTML.trim() === 'AC'
? 100
: 0,
time,
memory,
}); });
} catch (e) {
logger.error(e);
fail++;
} }
if (statusElem.title === 'Internal Error') {
return await end({
error: true,
status: 'Judgment Failed',
message: 'AtCoder Internal Error.',
});
}
const time = parseInt(elements[1].innerHTML.trim());
const memory = parseInt(elements[2].innerHTML.trim());
return await end({
id,
status: statusElem.title || 'None',
score:
statusElem.title === 'Accepted' ||
statusElem.innerHTML.trim() === 'AC'
? 100
: 0,
time,
memory,
});
} }
return await end({
id,
error: true,
status: 'Judgment Failed',
message: 'Failed to fetch submission details.',
});
} }
} }

View File

@ -344,104 +344,113 @@ export default class CodeforcesProvider implements IBasicProvider {
.getAttribute('data-submission-id'); .getAttribute('data-submission-id');
} }
async waitForSubmission(problem_id: string, id: string, next, end) { async waitForSubmission(id: string, next, end) {
let i = 0; let count = 0;
let fail = 0;
while (true) {
if (++i > 180) {
return await end({
id,
error: true,
status: 'Judgment Failed',
message: 'Failed to fetch submission details.',
});
}
while (count < 180 && fail < 10) {
count++;
await sleep(1000); await sleep(1000);
const { body, error } = await this.post('/data/submitSource')
.send({ try {
csrf_token: this.csrf, const { body } = await this.post('/data/submitSource')
submissionId: id, .send({
}) csrf_token: this.csrf,
.retry(3); submissionId: id,
if (error) continue; })
if (body.compilationError === 'true') { .retry(3);
if (body.compilationError === 'true') {
return await end({
id,
error: true,
status: 'Compile Error',
message: crlf(body['checkerStdoutAndStderr#1'], LF),
});
}
const time = mathSum(
Object.keys(body)
.filter(k => k.startsWith('timeConsumed#'))
.map(k => +body[k])
);
const memory =
Math.max(
...Object.keys(body)
.filter(k => k.startsWith('memoryConsumed#'))
.map(k => +body[k])
) / 1024;
await next({ test_id: body.testCount });
if (body.waiting === 'true') continue;
const testCount = +body.testCount;
const status =
VERDICT[
Object.keys(VERDICT).find(k => normalize(body.verdict).includes(k))
];
let tests: string[] = [];
for (let i = 1; i <= testCount; i++) {
let test_info = '';
let info_text =
VERDICT[
Object.keys(VERDICT).find(k =>
normalize(body[`verdict#${i}`]).includes(k)
)
];
test_info += `<test num="${i}" info="${info_text}" time="${
body[`timeConsumed#${i}`]
}" memory="${+body[`memoryConsumed#${i}`] / 1024}">`;
const parse = (id: string) => crlf(body[id], LF);
test_info += `<in>${parse(`input#${i}`)}</in>\n`;
test_info += `<out>${parse(`output#${i}`)}</out>\n`;
test_info += `<ans>${parse(`answer#${i}`)}</ans>\n`;
test_info += `<res>${parse(`checkerStdoutAndStderr#${i}`)}</res>\n`;
test_info += '</test>';
tests.push(test_info);
}
const remote_handle = stripHtml(body.partyName).result;
const details =
'<div>' +
'<div class="border-bottom p-3">' +
`<p><b>Contest:</b> ${stripHtml(body.contestName).result}</p>` +
`<p><b>Problem:</b> ${stripHtml(body.problemName).result}</p>` +
`<p><b>Remote submission:</b> <a href="https://codeforces.com${body.href}" target="_blank">${id}</a></p>` +
`<p><b>Remote account:</b> <a href="https://codeforces.com/profile/${remote_handle}" target="_blank">${remote_handle}</a></p>` +
`<p class="mb-0"><b>Verdict:</b> ${
stripHtml(body.verdict).result
}</p>` +
'</div>' +
`<tests>${tests.join('\n')}</tests>` +
'</div>';
return await end({ return await end({
id, id,
error: true, status,
status: 'Compile Error', score: status === 'Accepted' ? 100 : 0,
message: crlf(body['checkerStdoutAndStderr#1'], LF), time,
memory,
details,
}); });
} catch (e) {
logger.error(e);
fail++;
} }
const time = mathSum(
Object.keys(body)
.filter(k => k.startsWith('timeConsumed#'))
.map(k => +body[k])
);
const memory =
Math.max(
...Object.keys(body)
.filter(k => k.startsWith('memoryConsumed#'))
.map(k => +body[k])
) / 1024;
await next({ test_id: body.testCount });
if (body.waiting === 'true') continue;
const testCount = +body.testCount;
const status =
VERDICT[
Object.keys(VERDICT).find(k => normalize(body.verdict).includes(k))
];
let tests: string[] = [];
for (let i = 1; i <= testCount; i++) {
let test_info = '';
let info_text =
VERDICT[
Object.keys(VERDICT).find(k =>
normalize(body[`verdict#${i}`]).includes(k)
)
];
test_info += `<test num="${i}" info="${info_text}" time="${
body[`timeConsumed#${i}`]
}" memory="${+body[`memoryConsumed#${i}`] / 1024}">`;
const parse = (id: string) => crlf(body[id], LF);
test_info += `<in>${parse(`input#${i}`)}</in>\n`;
test_info += `<out>${parse(`output#${i}`)}</out>\n`;
test_info += `<ans>${parse(`answer#${i}`)}</ans>\n`;
test_info += `<res>${parse(`checkerStdoutAndStderr#${i}`)}</res>\n`;
test_info += '</test>';
tests.push(test_info);
}
const remote_handle = stripHtml(body.partyName).result;
const details =
'<div>' +
'<div class="border-bottom p-3">' +
`<p><b>Contest:</b> ${stripHtml(body.contestName).result}</p>` +
`<p><b>Problem:</b> ${stripHtml(body.problemName).result}</p>` +
`<p><b>Remote submission:</b> <a href="https://codeforces.com${body.href}" target="_blank">${id}</a></p>` +
`<p><b>Remote account:</b> <a href="https://codeforces.com/profile/${remote_handle}" target="_blank">${remote_handle}</a></p>` +
`<p class="mb-0"><b>Verdict:</b> ${
stripHtml(body.verdict).result
}</p>` +
'</div>' +
`<tests>${tests.join('\n')}</tests>` +
'</div>';
return await end({
id,
status,
score: status === 'Accepted' ? 100 : 0,
time,
memory,
details,
});
} }
return await end({
id,
error: true,
status: 'Judgment Failed',
message: 'Failed to fetch submission details.',
});
} }
} }

View File

@ -285,7 +285,7 @@ export default class LibreojProvider implements IBasicProvider {
return user_id === submission_user_id; return user_id === submission_user_id;
} }
async waitForSubmission(problem_id: string, id: string, next, end) { async waitForSubmission(id: string, next, end, problem_id: string) {
if (!(await this.ensureLogin())) { if (!(await this.ensureLogin())) {
await end({ await end({
error: true, error: true,
@ -296,226 +296,234 @@ export default class LibreojProvider implements IBasicProvider {
return null; return null;
} }
let i = 0; let count = 0;
let fail = 0;
while (true) {
if (++i > 180) {
return await end({
id,
error: true,
status: 'Judgment Failed',
message: 'Failed to fetch submission details.',
});
}
while (count < 180 && fail < 10) {
count++;
await sleep(1000); await sleep(1000);
const { body, error } = await this.post('/submission/getSubmissionDetail')
.send({ submissionId: String(id), locale: 'zh_CN' })
.retry(3);
if (error) continue; try {
const { body } = await this.post('/submission/getSubmissionDetail')
.send({ submissionId: String(id), locale: 'zh_CN' })
.retry(3);
if (body.meta.problem.displayId != problem_id) { if (body.meta.problem.displayId != problem_id) {
return await end({ return await end({
id, id,
error: true, error: true,
status: 'Judgment Failed', status: 'Judgment Failed',
message: 'Submission does not match current problem.', message: 'Submission does not match current problem.',
}); });
}
if (!body.progress) {
await next({ status: 'Waiting for Remote Judge' });
continue;
}
await next({
status: `${body.progress.progressType}`,
});
if (body.progress.progressType !== 'Finished') {
continue;
}
const status =
VERDICT[
Object.keys(VERDICT).find(k =>
normalize(body.meta.status).includes(k)
)
];
if (status === 'Compile Error') {
await end({
error: true,
id,
status: 'Compile Error',
message: stripVTControlCharacters(body.progress.compile.message),
});
}
if (status === 'Judgment Failed') {
await end({
error: true,
id,
status: 'Judgment Failed',
message: 'Error occurred on remote online judge.',
});
}
const parse = (str: string) => crlf(str, LF);
const getSubtaskStatusDisplayText = (testcases: any): string => {
let result: string = null;
for (const testcase of testcases) {
if (!testcase.testcaseHash) {
result = 'Skipped';
break;
} else if (
body.progress.testcaseResult[testcase.testcaseHash].status !==
'Accepted'
) {
result = body.progress.testcaseResult[testcase.testcaseHash].status;
break;
}
} }
result ||= 'Accepted'; if (!body.progress) {
result = await next({ status: 'Waiting for Remote Judge' });
VERDICT[
Object.keys(VERDICT).find(k => normalize(result).includes(k))
];
return result; continue;
}; }
const getTestcaseBlock = (id: string, index: number): string => { await next({
const testcase = body.progress.testcaseResult[id]; status: `${body.progress.progressType}`,
});
if (!testcase) return ''; if (body.progress.progressType !== 'Finished') {
continue;
}
const status = const status =
VERDICT[ VERDICT[
Object.keys(VERDICT).find(k => Object.keys(VERDICT).find(k =>
normalize(testcase.status).includes(k) normalize(body.meta.status).includes(k)
) )
]; ];
let test_info = '';
test_info += `<test num="${ if (status === 'Compile Error') {
index + 1 await end({
}" info="${status}" time="${Math.round(testcase.time || 0)}" memory="${ error: true,
testcase.memory id,
}">`; status: 'Compile Error',
message: stripVTControlCharacters(body.progress.compile.message),
if (testcase.input) { });
if (typeof testcase.input === 'string') {
test_info += `<in>${parse(testcase.input)}</in>\n`;
} else {
test_info += `<in>${parse(testcase.input.data)}\n\n(${
testcase.input.omittedLength
} bytes omitted)</in>\n`;
}
} }
if (testcase.userOutput) { if (status === 'Judgment Failed') {
if (typeof testcase.userOutput === 'string') { await end({
test_info += `<out>${parse(testcase.userOutput)}</out>\n`; error: true,
} else { id,
test_info += `<out>${parse(testcase.userOutput.data)}\n\n(${ status: 'Judgment Failed',
testcase.userOutput.omittedLength message: 'Error occurred on remote online judge.',
} bytes omitted)</out>\n`; });
}
} }
if (testcase.output) { const parse = (str: string) => crlf(str, LF);
if (typeof testcase.output === 'string') {
test_info += `<ans>${parse(testcase.output)}</ans>\n`; const getSubtaskStatusDisplayText = (testcases: any): string => {
} else { let result: string = null;
test_info += `<ans>${parse(testcase.output.data)}\n\n(${
testcase.output.omittedLength for (const testcase of testcases) {
} bytes omitted)</ans>\n`; if (!testcase.testcaseHash) {
result = 'Skipped';
break;
} else if (
body.progress.testcaseResult[testcase.testcaseHash].status !==
'Accepted'
) {
result =
body.progress.testcaseResult[testcase.testcaseHash].status;
break;
}
} }
result ||= 'Accepted';
result =
VERDICT[
Object.keys(VERDICT).find(k => normalize(result).includes(k))
];
return result;
};
const getTestcaseBlock = (id: string, index: number): string => {
const testcase = body.progress.testcaseResult[id];
if (!testcase) return '';
const status =
VERDICT[
Object.keys(VERDICT).find(k =>
normalize(testcase.status).includes(k)
)
];
let test_info = '';
test_info += `<test num="${
index + 1
}" info="${status}" time="${Math.round(
testcase.time || 0
)}" memory="${testcase.memory}">`;
if (testcase.input) {
if (typeof testcase.input === 'string') {
test_info += `<in>${parse(testcase.input)}</in>\n`;
} else {
test_info += `<in>${parse(testcase.input.data)}\n\n(${
testcase.input.omittedLength
} bytes omitted)</in>\n`;
}
}
if (testcase.userOutput) {
if (typeof testcase.userOutput === 'string') {
test_info += `<out>${parse(testcase.userOutput)}</out>\n`;
} else {
test_info += `<out>${parse(testcase.userOutput.data)}\n\n(${
testcase.userOutput.omittedLength
} bytes omitted)</out>\n`;
}
}
if (testcase.output) {
if (typeof testcase.output === 'string') {
test_info += `<ans>${parse(testcase.output)}</ans>\n`;
} else {
test_info += `<ans>${parse(testcase.output.data)}\n\n(${
testcase.output.omittedLength
} bytes omitted)</ans>\n`;
}
}
if (testcase.checkerMessage) {
if (typeof testcase.checkerMessage === 'string') {
test_info += `<res>${parse(testcase.checkerMessage)}</res>\n`;
} else {
test_info += `<res>${parse(testcase.checkerMessage.data)}\n\n(${
testcase.checkerMessage.omittedLength
} bytes omitted)</res>\n`;
}
}
test_info += '</test>';
return test_info;
};
let details = '';
details +=
'<div class="border-bottom p-3">' +
`<p><b>Problem:</b> #${body.meta.problem.displayId}. ${body.meta.problemTitle}</p>` +
`<p><b>Remote submission:</b> <a href="https://loj.ac/s/${id}" target="_blank">${id}</a></p>` +
`<p><b>Remote submit time:</b> ${new Date(
body.meta.submitTime
).toLocaleString('zh-CN')}</p>` +
`<p><b>Remote account:</b> <a href="https://loj.ac/user/${body.meta.submitter.id}" target="_blank">${body.meta.submitter.username}</a></p>` +
`<p class="mb-0"><b>Verdict:</b> ${status}</p>` +
'</div>';
// Samples
if (body.progress.samples) {
details += `<subtask title="Samples" info="${getSubtaskStatusDisplayText(
body.progress.samples
)}" num="0">${body.progress.samples
.map((item, index) =>
item.testcaseHash
? getTestcaseBlock(item.testcaseHash, index)
: `<test num="${index + 1}" info="Skipped"></test>`
)
.join('\n')}</subtask>`;
} }
if (testcase.checkerMessage) { // Tests
if (typeof testcase.checkerMessage === 'string') { if (body.progress.subtasks.length === 1) {
test_info += `<res>${parse(testcase.checkerMessage)}</res>\n`; details += `<tests>${body.progress.subtasks[0].testcases
} else { .map((item, index) =>
test_info += `<res>${parse(testcase.checkerMessage.data)}\n\n(${ item.testcaseHash
testcase.checkerMessage.omittedLength ? getTestcaseBlock(item.testcaseHash, index)
} bytes omitted)</res>\n`; : `<test num="${index + 1}" info="Skipped"></test>`
} )
.join('\n')}</tests>`;
} else {
details += `<tests>${body.progress.subtasks
.map(
(subtask, index) =>
`<subtask num="${
index + 1
}" info="${getSubtaskStatusDisplayText(
subtask.testcases
)}">${subtask.testcases
.map((item, index) =>
item.testcaseHash
? getTestcaseBlock(item.testcaseHash, index)
: `<test num="${index + 1}" info="Skipped"></test>`
)
.join('\n')}</subtask>`
)
.join('\n')}</tests>`;
} }
test_info += '</test>'; return await end({
id,
status: body.meta.status,
score: body.meta.score,
time: body.meta.timeUsed,
memory: body.meta.memoryUsed,
details: `<div>${details}</div>`,
});
} catch (e) {
logger.error(e);
return test_info; fail++;
};
let details = '';
details +=
'<div class="border-bottom p-3">' +
`<p><b>Problem:</b> #${body.meta.problem.displayId}. ${body.meta.problemTitle}</p>` +
`<p><b>Remote submission:</b> <a href="https://loj.ac/s/${id}" target="_blank">${id}</a></p>` +
`<p><b>Remote submit time:</b> ${new Date(
body.meta.submitTime
).toLocaleString('zh-CN')}</p>` +
`<p><b>Remote account:</b> <a href="https://loj.ac/user/${body.meta.submitter.id}" target="_blank">${body.meta.submitter.username}</a></p>` +
`<p class="mb-0"><b>Verdict:</b> ${status}</p>` +
'</div>';
// Samples
if (body.progress.samples) {
details += `<subtask title="Samples" info="${getSubtaskStatusDisplayText(
body.progress.samples
)}" num="0">${body.progress.samples
.map((item, index) =>
item.testcaseHash
? getTestcaseBlock(item.testcaseHash, index)
: `<test num="${index + 1}" info="Skipped"></test>`
)
.join('\n')}</subtask>`;
} }
// Tests
if (body.progress.subtasks.length === 1) {
details += `<tests>${body.progress.subtasks[0].testcases
.map((item, index) =>
item.testcaseHash
? getTestcaseBlock(item.testcaseHash, index)
: `<test num="${index + 1}" info="Skipped"></test>`
)
.join('\n')}</tests>`;
} else {
details += `<tests>${body.progress.subtasks
.map(
(subtask, index) =>
`<subtask num="${index + 1}" info="${getSubtaskStatusDisplayText(
subtask.testcases
)}">${subtask.testcases
.map((item, index) =>
item.testcaseHash
? getTestcaseBlock(item.testcaseHash, index)
: `<test num="${index + 1}" info="Skipped"></test>`
)
.join('\n')}</subtask>`
)
.join('\n')}</tests>`;
}
return await end({
id,
status: body.meta.status,
score: body.meta.score,
time: body.meta.timeUsed,
memory: body.meta.memoryUsed,
details: `<div>${details}</div>`,
});
} }
return await end({
id,
error: true,
status: 'Judgment Failed',
message: 'Failed to fetch submission details.',
});
} }
} }

View File

@ -250,11 +250,11 @@ export default class LuoguProvider implements IBasicProvider {
return result.body.rid; return result.body.rid;
} }
async waitForSubmission(problem_id: string, id: string, next, end) { async waitForSubmission(id: string, next, end) {
let fail = 0; let fail = 0;
let count = 0; let count = 0;
while (count < 180 && fail < 5) { while (count < 180 && fail < 10) {
await sleep(1000); await sleep(1000);
count++; count++;

View File

@ -9,7 +9,7 @@ import sleep from '../utils/sleep';
proxy(superagent); proxy(superagent);
const logger = new Logger('remote/uoj'); const logger = new Logger('remote/uoj');
const langs_map = { const LANGS_MAP = {
C: { C: {
name: 'C', name: 'C',
id: 'C', id: 'C',
@ -175,7 +175,7 @@ export default class UOJProvider implements IBasicProvider {
next, next,
end end
) { ) {
const programType = langs_map[lang] || langs_map['C++']; const programType = LANGS_MAP[lang] || LANGS_MAP['C++'];
const comment = programType.comment; const comment = programType.comment;
if (comment) { if (comment) {
@ -206,65 +206,72 @@ export default class UOJProvider implements IBasicProvider {
.innerHTML.split('#')[1]; .innerHTML.split('#')[1];
} }
async waitForSubmission(problem_id: string, id: string, next, end) { async waitForSubmission(id: string, next, end) {
let i = 0; let count = 0;
let fail = 0;
while (true) {
if (++i > 180) {
return await end({
id,
error: true,
status: 'Judgment Failed',
message: 'Failed to fetch submission details.',
});
}
while (count < 180 && fail < 10) {
count++;
await sleep(1000); await sleep(1000);
const { text } = await this.get(`/submission/${id}`);
const { try {
window: { document }, const { text } = await this.get(`/submission/${id}`);
} = new JSDOM(text); const {
const find = (content: string) => window: { document },
Array.from( } = new JSDOM(text);
document.querySelectorAll('.panel-heading>.panel-title') const find = (content: string) =>
).find(n => n.innerHTML === content).parentElement.parentElement Array.from(
.children[1]; document.querySelectorAll('.panel-heading>.panel-title')
if (text.includes('Compile Error')) { ).find(n => n.innerHTML === content).parentElement.parentElement
.children[1];
if (text.includes('Compile Error')) {
return await end({
error: true,
id,
status: 'Compile Error',
message: find('详细').children[0].innerHTML,
});
}
await next({});
const summary = document.querySelector('tbody>tr');
if (!summary) continue;
const time = parseTimeMS(summary.children[4].innerHTML);
const memory = parseMemoryMB(summary.children[5].innerHTML) * 1024;
let panel = document.getElementById(
'details_details_accordion_collapse_subtask_1'
);
if (!panel) {
panel = document.getElementById('details_details_accordion');
if (!panel) continue;
}
if (document.querySelector('tbody').innerHTML.includes('Judging'))
continue;
const score = +summary.children[3]?.children[0]?.innerHTML || 0;
const status = score === 100 ? 'Accepted' : 'Unaccepted';
return await end({ return await end({
error: true,
id, id,
status: 'Compile Error', status,
message: find('详细').children[0].innerHTML, score,
time,
memory,
}); });
} catch (e) {
logger.error(e);
fail++;
} }
await next({});
const summary = document.querySelector('tbody>tr');
if (!summary) continue;
const time = parseTimeMS(summary.children[4].innerHTML);
const memory = parseMemoryMB(summary.children[5].innerHTML) * 1024;
let panel = document.getElementById(
'details_details_accordion_collapse_subtask_1'
);
if (!panel) {
panel = document.getElementById('details_details_accordion');
if (!panel) continue;
}
if (document.querySelector('tbody').innerHTML.includes('Judging'))
continue;
const score = +summary.children[3]?.children[0]?.innerHTML || 0;
const status = score === 100 ? 'Accepted' : 'Unaccepted';
return await end({
id,
status,
score,
time,
memory,
});
} }
return await end({
id,
error: true,
status: 'Judgment Failed',
message: 'Failed to fetch submission details.',
});
} }
} }

View File

@ -35,7 +35,7 @@ class AccountService {
if (!rid) return; if (!rid) return;
await this.api.waitForSubmission(problem_id, rid, next, end); await this.api.waitForSubmission(rid, next, end, problem_id);
} catch (e) { } catch (e) {
logger.error(e); logger.error(e);
@ -178,7 +178,7 @@ class VJudge {
if (!rid) return; if (!rid) return;
await provider.waitForSubmission(problem_id, rid, next, end); await provider.waitForSubmission(rid, next, end, problem_id);
} catch (e) { } catch (e) {
logger.error(e); logger.error(e);
@ -204,10 +204,10 @@ class VJudge {
if (await provider.ensureIsOwnSubmission(config.remote_submission_id)) { if (await provider.ensureIsOwnSubmission(config.remote_submission_id)) {
await provider.waitForSubmission( await provider.waitForSubmission(
problem_id,
config.remote_submission_id, config.remote_submission_id,
next, next,
end end,
problem_id
); );
} else { } else {
return await end({ return await end({