Browse Source

Merge branch 'master' of github.com:syzoj/syzoj

master
Menci 6 years ago
parent
commit
b69827fbe7
  1. 12
      libs/judger.js
  2. 1
      libs/submissions_process.js
  3. 12
      models/problem.js
  4. 6
      modules/problem.js
  5. 29
      modules/socketio.js
  6. 2
      views/contest.ejs
  7. 4
      views/problem.ejs
  8. 8
      views/statistics.ejs
  9. 2
      views/submission.ejs

12
libs/judger.js

@ -66,7 +66,7 @@ async function connect() {
waitingForTask = true; waitingForTask = true;
winston.verbose(`Judge client ${socket.id} emitted waitForTask.`); winston.warn(`Judge client ${socket.id} emitted waitForTask.`);
// Poll the judge queue, timeout = 10s. // Poll the judge queue, timeout = 10s.
let obj; let obj;
@ -80,9 +80,11 @@ async function connect() {
return; return;
} }
winston.warn(`Judge task ${obj.data.content.taskId} poped from queue.`);
// Re-push to queue if got task but judge client already disconnected. // Re-push to queue if got task but judge client already disconnected.
if (socket.disconnected) { if (socket.disconnected) {
winston.warn(`Judge client ${socket.id} got task but disconnected re-pushing task to queue.`); winston.warn(`Judge client ${socket.id} got task but disconnected re-pushing task ${obj.data.content.taskId} to queue.`);
judgeQueue.push(obj.data, obj.priority); judgeQueue.push(obj.data, obj.priority);
return; return;
} }
@ -90,10 +92,10 @@ async function connect() {
// Send task to judge client, and wait for ack. // Send task to judge client, and wait for ack.
const task = obj.data; const task = obj.data;
pendingAckTaskObj = obj; pendingAckTaskObj = obj;
winston.verbose(`Sending task ${task.content.taskId} to judge client ${socket.id}.`); winston.warn(`Sending task ${task.content.taskId} to judge client ${socket.id}.`);
socket.emit('onTask', msgPack.encode(task), () => { socket.emit('onTask', msgPack.encode(task), () => {
// Acked. // Acked.
winston.verbose(`Judge client ${socket.id} acked task ${task.content.taskId}.`); winston.warn(`Judge client ${socket.id} acked task ${task.content.taskId}.`);
pendingAckTaskObj = null; pendingAckTaskObj = null;
waitingForTask = false; waitingForTask = false;
}); });
@ -232,6 +234,8 @@ module.exports.judge = async function (judge_state, problem, priority) {
content: content, content: content,
extraData: extraData extraData: extraData
}, priority); }, priority);
winston.warn(`Judge task ${content.taskId} enqueued.`);
} }
module.exports.getCachedJudgeState = taskId => judgeStateCache.get(taskId); module.exports.getCachedJudgeState = taskId => judgeStateCache.get(taskId);

1
libs/submissions_process.js

@ -66,6 +66,7 @@ const processOverallResult = (source, config) => {
score: st.score, score: st.score,
cases: st.cases.map(cs => ({ cases: st.cases.map(cs => ({
status: cs.status, status: cs.status,
errorMessage: cs.errorMessage,
result: cs.result && { result: cs.result && {
type: cs.result.type, type: cs.result.type,
time: config.showUsage ? cs.result.time : undefined, time: config.showUsage ? cs.result.time : undefined,

12
models/problem.js

@ -58,15 +58,15 @@ SELECT \
`id` \ `id` \
FROM `judge_state` `inner_table` \ FROM `judge_state` `inner_table` \
WHERE `problem_id` = `outer_table`.`problem_id` AND `user_id` = `outer_table`.`user_id` AND `status` = "Accepted" AND `type` = 0 \ WHERE `problem_id` = `outer_table`.`problem_id` AND `user_id` = `outer_table`.`user_id` AND `status` = "Accepted" AND `type` = 0 \
ORDER BY LENGTH(`code`) ASC \ ORDER BY `code_length` ASC \
LIMIT 1 \ LIMIT 1 \
) AS `id`, \ ) AS `id`, \
( \ ( \
SELECT \ SELECT \
LENGTH(`code`) \ `code_length` \
FROM `judge_state` `inner_table` \ FROM `judge_state` `inner_table` \
WHERE `problem_id` = `outer_table`.`problem_id` AND `user_id` = `outer_table`.`user_id` AND `status` = "Accepted" AND `type` = 0 \ WHERE `problem_id` = `outer_table`.`problem_id` AND `user_id` = `outer_table`.`user_id` AND `status` = "Accepted" AND `type` = 0 \
ORDER BY LENGTH(`code`) ASC \ ORDER BY `code_length` ASC \
LIMIT 1 \ LIMIT 1 \
) AS `code_length` \ ) AS `code_length` \
FROM `judge_state` `outer_table` \ FROM `judge_state` `outer_table` \
@ -83,15 +83,15 @@ SELECT \
`id` \ `id` \
FROM `judge_state` `inner_table` \ FROM `judge_state` `inner_table` \
WHERE `problem_id` = `outer_table`.`problem_id` AND `user_id` = `outer_table`.`user_id` AND `status` = "Accepted" AND `type` = 0 \ WHERE `problem_id` = `outer_table`.`problem_id` AND `user_id` = `outer_table`.`user_id` AND `status` = "Accepted" AND `type` = 0 \
ORDER BY LENGTH(`code`) DESC \ ORDER BY `code_length` DESC \
LIMIT 1 \ LIMIT 1 \
) AS `id`, \ ) AS `id`, \
( \ ( \
SELECT \ SELECT \
LENGTH(`code`) \ `code_length` \
FROM `judge_state` `inner_table` \ FROM `judge_state` `inner_table` \
WHERE `problem_id` = `outer_table`.`problem_id` AND `user_id` = `outer_table`.`user_id` AND `status` = "Accepted" AND `type` = 0 \ WHERE `problem_id` = `outer_table`.`problem_id` AND `user_id` = `outer_table`.`user_id` AND `status` = "Accepted" AND `type` = 0 \
ORDER BY LENGTH(`code`) DESC \ ORDER BY `code_length` DESC \
LIMIT 1 \ LIMIT 1 \
) AS `code_length` \ ) AS `code_length` \
FROM `judge_state` `outer_table` \ FROM `judge_state` `outer_table` \

6
modules/problem.js

@ -257,6 +257,7 @@ app.get('/problem/:id/export', async (req, res) => {
limit_and_hint: problem.limit_and_hint, limit_and_hint: problem.limit_and_hint,
time_limit: problem.time_limit, time_limit: problem.time_limit,
memory_limit: problem.memory_limit, memory_limit: problem.memory_limit,
have_additional_file: problem.additional_file_id != null,
file_io: problem.file_io, file_io: problem.file_io,
file_io_input_name: problem.file_io_input_name, file_io_input_name: problem.file_io_input_name,
file_io_output_name: problem.file_io_output_name, file_io_output_name: problem.file_io_output_name,
@ -465,6 +466,11 @@ app.post('/problem/:id/import', async (req, res) => {
let data = await download(req.body.url + (req.body.url.endsWith('/') ? 'testdata/download' : '/testdata/download')); let data = await download(req.body.url + (req.body.url.endsWith('/') ? 'testdata/download' : '/testdata/download'));
await fs.writeFileAsync(tmpFile.path, data); await fs.writeFileAsync(tmpFile.path, data);
await problem.updateTestdata(tmpFile.path, await res.locals.user.hasPrivilege('manage_problem')); await problem.updateTestdata(tmpFile.path, await res.locals.user.hasPrivilege('manage_problem'));
if (json.obj.have_additional_file) {
let additional_file = await download(req.body.url + (req.body.url.endsWith('/') ? 'download/additional_file' : '/download/additional_file'));
await fs.writeFileAsync(tmpFile.path, additional_file);
await problem.updateFile(tmpFile.path, 'additional_file', await res.locals.user.hasPrivilege('manage_problem'));
}
} catch (e) { } catch (e) {
syzoj.log(e); syzoj.log(e);
} }

29
modules/socketio.js

@ -14,6 +14,7 @@ const finishedJudgeList = {};
const compiledList = []; const compiledList = [];
const clientDetailProgressList = {}; const clientDetailProgressList = {};
const clientDisplayConfigList = {}; const clientDisplayConfigList = {};
const debug = false;
function processOverallResult(source, config) { function processOverallResult(source, config) {
if (source == null) if (source == null)
@ -75,25 +76,25 @@ function forAllClients(ns, taskId, exec) {
}); });
} }
else { else {
winston.warn(`Error while listing socketio clients in ${taskId}`, err); if (debug) winston.warn(`Error while listing socketio clients in ${taskId}`, err);
} }
}); });
} }
function initializeSocketIO(s) { function initializeSocketIO(s) {
ioInstance = socketio(s); ioInstance = socketio(s);
const initializeNamespace = (name, exec) => { const initializeNamespace = (name, exec) => {
winston.debug('initializing socketIO', name); if (debug) winston.debug('initializing socketIO', name);
const newNamespace = ioInstance.of('/' + name); const newNamespace = ioInstance.of('/' + name);
newNamespace.on('connection', (socket) => { newNamespace.on('connection', (socket) => {
socket.on('disconnect', () => { socket.on('disconnect', () => {
winston.info(`Client ${socket.id} disconnected.`); if (debug) winston.info(`Client ${socket.id} disconnected.`);
delete clientDisplayConfigList[socket.id]; delete clientDisplayConfigList[socket.id];
if (clientDetailProgressList[socket.id]) { if (clientDetailProgressList[socket.id]) {
delete clientDetailProgressList[socket.id]; delete clientDetailProgressList[socket.id];
} }
}); });
socket.on('join', (reqJwt, cb) => { socket.on('join', (reqJwt, cb) => {
winston.info(`Client ${socket.id} connected.`); if (debug) winston.info(`Client ${socket.id} connected.`);
let req; let req;
try { try {
req = jwt.verify(reqJwt, syzoj.config.session_secret); req = jwt.verify(reqJwt, syzoj.config.session_secret);
@ -102,12 +103,12 @@ function initializeSocketIO(s) {
} }
clientDisplayConfigList[socket.id] = req.displayConfig; clientDisplayConfigList[socket.id] = req.displayConfig;
const taskId = req.taskId; const taskId = req.taskId;
winston.verbose(`A client trying to join ${name} namespace for ${taskId}.`); if (debug) winston.verbose(`A client trying to join ${name} namespace for ${taskId}.`);
socket.join(taskId.toString()); socket.join(taskId.toString());
exec(req, socket).then(x => cb(x), err => cb({ ok: false, message: err.toString() })); exec(req, socket).then(x => cb(x), err => cb({ ok: false, message: err.toString() }));
} }
catch (err) { catch (err) {
winston.info('Error while joining.'); if (debug) winston.info('Error while joining.');
cb({ cb({
ok: false, ok: false,
message: err.toString() message: err.toString()
@ -121,7 +122,7 @@ function initializeSocketIO(s) {
detailProgressNamespace = initializeNamespace('detail', async (req, socket) => { detailProgressNamespace = initializeNamespace('detail', async (req, socket) => {
const taskId = req.taskId; const taskId = req.taskId;
if (finishedJudgeList[taskId]) { if (finishedJudgeList[taskId]) {
winston.debug(`Judge task #${taskId} has been finished, ${JSON.stringify(currentJudgeList[taskId])}`); if (debug) winston.debug(`Judge task #${taskId} has been finished, ${JSON.stringify(currentJudgeList[taskId])}`);
return { return {
ok: true, ok: true,
running: false, running: false,
@ -131,7 +132,7 @@ function initializeSocketIO(s) {
}; };
} }
else { else {
winston.debug(`Judge task #${taskId} has not been finished`); if (debug) winston.debug(`Judge task #${taskId} has not been finished`);
if (currentJudgeList[taskId]) { if (currentJudgeList[taskId]) {
clientDetailProgressList[socket.id] = { clientDetailProgressList[socket.id] = {
version: 0, version: 0,
@ -208,7 +209,7 @@ function initializeSocketIO(s) {
} }
exports.initializeSocketIO = initializeSocketIO; exports.initializeSocketIO = initializeSocketIO;
function createTask(taskId) { function createTask(taskId) {
winston.debug(`Judge task #${taskId} has started`); if (debug) winston.debug(`Judge task #${taskId} has started`);
currentJudgeList[taskId] = {}; currentJudgeList[taskId] = {};
finishedJudgeList[taskId] = null; finishedJudgeList[taskId] = null;
forAllClients(detailProgressNamespace, taskId, (clientId) => { forAllClients(detailProgressNamespace, taskId, (clientId) => {
@ -223,7 +224,7 @@ function createTask(taskId) {
} }
exports.createTask = createTask; exports.createTask = createTask;
function updateCompileStatus(taskId, result) { function updateCompileStatus(taskId, result) {
winston.debug(`Updating compilation status for #${taskId}`); if (debug) winston.debug(`Updating compilation status for #${taskId}`);
compiledList[taskId] = { result: result.status === interfaces.TaskStatus.Done ? 'Submitted' : 'Compile Error' }; compiledList[taskId] = { result: result.status === interfaces.TaskStatus.Done ? 'Submitted' : 'Compile Error' };
compileProgressNamespace.to(taskId.toString()).emit('finish', { compileProgressNamespace.to(taskId.toString()).emit('finish', {
taskId: taskId, taskId: taskId,
@ -232,7 +233,7 @@ function updateCompileStatus(taskId, result) {
} }
exports.updateCompileStatus = updateCompileStatus; exports.updateCompileStatus = updateCompileStatus;
function updateProgress(taskId, data) { function updateProgress(taskId, data) {
winston.verbose(`Updating progress for #${taskId}`); if (debug) winston.verbose(`Updating progress for #${taskId}`);
currentJudgeList[taskId] = data; currentJudgeList[taskId] = data;
const finalResult = judgeResult.convertResult(taskId, data); const finalResult = judgeResult.convertResult(taskId, data);
const roughResult = { const roughResult = {
@ -243,7 +244,7 @@ function updateProgress(taskId, data) {
}; };
forAllClients(detailProgressNamespace, taskId, (client) => { forAllClients(detailProgressNamespace, taskId, (client) => {
try { try {
winston.debug(`Pushing progress update to ${client}`); if (debug) winston.debug(`Pushing progress update to ${client}`);
if (clientDetailProgressList[client] && clientDisplayConfigList[client]) { if (clientDetailProgressList[client] && clientDisplayConfigList[client]) {
const original = clientDetailProgressList[client].content; const original = clientDetailProgressList[client].content;
const updated = processOverallResult(currentJudgeList[taskId], clientDisplayConfigList[client]); const updated = processOverallResult(currentJudgeList[taskId], clientDisplayConfigList[client]);
@ -283,7 +284,7 @@ function updateResult(taskId, data) {
}; };
finishedJudgeList[taskId] = roughResult; finishedJudgeList[taskId] = roughResult;
forAllClients(roughProgressNamespace, taskId, (client) => { forAllClients(roughProgressNamespace, taskId, (client) => {
winston.debug(`Pushing rough result to ${client}`); if (debug) winston.debug(`Pushing rough result to ${client}`);
roughProgressNamespace.sockets[client].emit('finish', { roughProgressNamespace.sockets[client].emit('finish', {
taskId: taskId, taskId: taskId,
result: processRoughResult(finishedJudgeList[taskId], clientDisplayConfigList[client]) result: processRoughResult(finishedJudgeList[taskId], clientDisplayConfigList[client])
@ -291,7 +292,7 @@ function updateResult(taskId, data) {
}); });
forAllClients(detailProgressNamespace, taskId, (client) => { forAllClients(detailProgressNamespace, taskId, (client) => {
if (clientDisplayConfigList[client]) { if (clientDisplayConfigList[client]) {
winston.debug(`Pushing detail result to ${client}`); if (debug) winston.debug(`Pushing detail result to ${client}`);
detailProgressNamespace.sockets[client].emit('finish', { detailProgressNamespace.sockets[client].emit('finish', {
taskId: taskId, taskId: taskId,
result: processOverallResult(currentJudgeList[taskId], clientDisplayConfigList[client]), result: processOverallResult(currentJudgeList[taskId], clientDisplayConfigList[client]),

2
views/contest.ejs

@ -75,8 +75,10 @@
<a href="<%= syzoj.utils.makeUrl(['contest', 'submission', problem.judge_id]) %>"> <a href="<%= syzoj.utils.makeUrl(['contest', 'submission', problem.judge_id]) %>">
<% if (typeof problem.status === 'string') { %> <% if (typeof problem.status === 'string') { %>
<span class="status <%= problem.status.toLowerCase().split(' ').join('_') %>"> <span class="status <%= problem.status.toLowerCase().split(' ').join('_') %>">
<b>
<i class="<%= icon[getStatusMeta(problem.status)] || 'remove' %> icon"></i> <i class="<%= icon[getStatusMeta(problem.status)] || 'remove' %> icon"></i>
<%= problem.feedback || problem.status %> <%= problem.feedback || problem.status %>
</b>
</span> </span>
<% } else if (typeof problem.status === 'object') { %> <% } else if (typeof problem.status === 'object') { %>
<% if (problem.status.accepted) { %> <% if (problem.status.accepted) { %>

4
views/problem.ejs

@ -41,8 +41,8 @@ div[class*=ace_br] {
<% if (problem.type === 'interaction') { %> <% if (problem.type === 'interaction') { %>
<span class="ui label">题目类型:交互</span> <span class="ui label">题目类型:交互</span>
<% } else if (problem.file_io) { %> <% } else if (problem.file_io) { %>
<span class="ui label">输入文件: <%= problem.file_io_input_name %></span> <span class="ui label">输入文件<%= problem.file_io_input_name %></span>
<span class="ui label">输出文件: <%= problem.file_io_output_name %></span> <span class="ui label">输出文件<%= problem.file_io_output_name %></span>
<% } else { %> <% } else { %>
<span class="ui label">标准输入输出</span> <span class="ui label">标准输入输出</span>
<% } %> <% } %>

8
views/statistics.ejs

@ -71,19 +71,21 @@ function getColorOfScore(score) {
<% for (let judge of statistics.judge_state) { %> <% for (let judge of statistics.judge_state) { %>
<% include util %> <% include util %>
<tr> <tr>
<td><a href="<%= syzoj.utils.makeUrl(['submission', judge.id]) %>">#<%= judge.id %></a></td> <td><a href="<%= syzoj.utils.makeUrl(['submission', judge.id]) %>"><b>#<%= judge.id %></b></a></td>
<td><a href="<%= syzoj.utils.makeUrl(['problem', judge.problem_id]) %>">#<%= judge.problem_id %>. <%= judge.problem.title %></a></td> <td><a href="<%= syzoj.utils.makeUrl(['problem', judge.problem_id]) %>"><b>#<%= judge.problem_id %>.</b> <%= judge.problem.title %></a></td>
<td><a href="<%= syzoj.utils.makeUrl(['submission', judge.id]) %>"> <td><a href="<%= syzoj.utils.makeUrl(['submission', judge.id]) %>">
<b>
<span class="status <%= getStatusMeta(judge.status).toLowerCase().split(' ').join('_') %>"> <span class="status <%= getStatusMeta(judge.status).toLowerCase().split(' ').join('_') %>">
<i class="<%= icon[getStatusMeta(judge.status)] || 'remove' %> icon"></i> <i class="<%= icon[getStatusMeta(judge.status)] || 'remove' %> icon"></i>
<%= judge.status %> <%= judge.status %>
</span> </span>
</b>
</a></td> </a></td>
<td><a href="<%= syzoj.utils.makeUrl(['submission', judge.id]) %>"><span class="score score_<%= parseInt(judge.score / 10) || 0 %>"><%= judge.score %></span></a></td> <td><a href="<%= syzoj.utils.makeUrl(['submission', judge.id]) %>"><span class="score score_<%= parseInt(judge.score / 10) || 0 %>"><%= judge.score %></span></a></td>
<% if (problem.type !== 'submit-answer') { %> <% if (problem.type !== 'submit-answer') { %>
<td><%= judge.total_time %> ms</td> <td><%= judge.total_time %> ms</td>
<td><%= parseInt(judge.max_memory) || 0 %> K</td> <td><%= parseInt(judge.max_memory) || 0 %> K</td>
<td><a href="<%= syzoj.utils.makeUrl(['submission', judge.id]) %>"><%= syzoj.languages[judge.language].show %></a> / <%= syzoj.utils.formatSize(judge.code.length) %></td> <td><a href="<%= syzoj.utils.makeUrl(['submission', judge.id]) %>"><b><%= syzoj.languages[judge.language].show %></b></a> / <%= syzoj.utils.formatSize(judge.code.length) %></td>
<% } else { %> <% } else { %>
<td><%= syzoj.utils.formatSize(judge.max_memory) %></td> <td><%= syzoj.utils.formatSize(judge.max_memory) %></td>
<% } %> <% } %>

2
views/submission.ejs

@ -85,7 +85,7 @@
<div class="content" :class="singleSubtask ? 'active' : ''"> <div class="content" :class="singleSubtask ? 'active' : ''">
<div class="accordion"> <div class="accordion">
<template v-for="curCase, $caseIndex in subtask.cases"> <template v-for="curCase, $caseIndex in subtask.cases">
<div class="title" :class="checkTestcaseOK(curCase) ? '' : 'unexpandable'"> <div class="title" :class="checkTestcaseOK(curCase) || curCase.errorMessage ? '' : 'unexpandable'">
<div class="ui grid"> <div class="ui grid">
<div class="three wide column"> <div class="three wide column">
<i class="dropdown icon"></i> <i class="dropdown icon"></i>

Loading…
Cancel
Save