feat(remote_judger): init

This commit is contained in:
Baoshuo Ren 2023-01-19 21:26:59 +08:00
parent 1689c34aa3
commit 3a2e3ce1db
Signed by: baoshuo
GPG Key ID: 00CB9680AB29F51A
16 changed files with 2766 additions and 16 deletions

View File

@ -3,7 +3,12 @@ root = true
[*]
indent_style = tab
indent_size = 4
end_of_line = lf
[*.y{,a}ml]
indent_style = space
indent_size = 2
[remote_judger/**.{js,ts}]
indent_style = space
indent_size = 2

View File

@ -42,6 +42,20 @@ services:
- SOCKET_PORT=2333
- SOCKET_PASSWORD=_judger_socket_password_
uoj-remote-judger:
build:
context: ./remote_judger/
dockerfile: Dockerfile
args:
- USE_MIRROR=1
container_name: uoj-remote-judger
restart: always
volumes:
- ./uoj_data/judger/log:/opt/uoj_judger/log
environment:
- UOJ_PROTOCOL=http
- UOJ_HOST=uoj-web
uoj-web:
build:
context: ./

3
remote_judger/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
dist/
node_modules/
*-error.log

14
remote_judger/.prettierrc Normal file
View File

@ -0,0 +1,14 @@
{
"arrowParens": "avoid",
"bracketSpacing": true,
"endOfLine": "lf",
"jsxSingleQuote": false,
"printWidth": 80,
"proseWrap": "preserve",
"quoteProps": "as-needed",
"semi": true,
"singleQuote": true,
"tabWidth": 2,
"useTabs": false,
"organizeImportsSkipDestructiveCodeActions": true
}

12
remote_judger/Dockerfile Normal file
View File

@ -0,0 +1,12 @@
FROM node:18
WORKDIR /opt/s2oj_remote_judger
COPY package*.json ./
RUN npm ci --only=production
COPY . .
RUN npm run build
CMD [ "node", "dist/entrypoint.js" ]

2545
remote_judger/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,32 @@
{
"name": "s2oj-remote-judger",
"version": "0.0.0",
"description": "Remote judger of S2OJ.",
"scripts": {
"build": "tsc -p .",
"start": "node dist/entrypoint.js"
},
"type": "module",
"repository": "https://github.com/renbaoshuo/S2OJ",
"author": "Baoshuo <i@baoshuo.ren>",
"license": "AGPL-3.0",
"private": true,
"dependencies": {
"jsdom": "^21.0.0",
"math-sum": "^2.0.0",
"reggol": "^1.3.4",
"superagent": "^8.0.6",
"superagent-prefix": "^0.0.2",
"superagent-proxy": "^3.0.0",
"xml-js": "^1.6.11"
},
"devDependencies": {
"@types/js-yaml": "^4.0.5",
"@types/jsdom": "^20.0.1",
"@types/node": "^18.11.18",
"@types/superagent": "^4.1.16",
"@types/superagent-proxy": "^3.0.0",
"js-yaml": "^4.1.0",
"typescript": "^4.9.4"
}
}

View File

@ -0,0 +1,62 @@
import fs from 'fs';
import superagent from 'superagent';
import proxy from 'superagent-proxy';
import prefix from 'superagent-prefix';
import Logger from '@/utils/logger';
import sleep from '@/utils/sleep';
import * as TIME from '@/utils/time';
proxy(superagent);
const logger = new Logger('daemon');
interface UOJConfig {
server_url: string;
judger_name: string;
password: string;
}
interface UOJSubmission {
id: number;
problem_id: number;
problem_mtime: number;
content: any;
status: string;
}
export default async function daemon(config: UOJConfig) {
const agent = superagent
.agent()
.use(prefix(`${this.config.server_url}/judge`))
.type('application/x-www-form-urlencoded')
.serialize(data =>
new URLSearchParams({
judger_name: config.judger_name,
password: config.password,
...data,
}).toString()
);
while (true) {
try {
const { body, error } = await agent.post('/submit');
if (error) {
logger.error(error.message);
await sleep(TIME.second);
} else if (body === 'Nothing to judge') {
await sleep(2 * TIME.second);
} else {
const data: UOJSubmission = JSON.parse(body);
logger.info('Start judging', data.id);
// TODO: judge
}
} catch (err) {
logger.error(err);
await sleep(TIME.second);
}
}
}

View File

@ -0,0 +1,15 @@
import daemon from './daemon';
const {
UOJ_PROTOCOL = 'http',
UOJ_HOST = 'uoj-web',
UOJ_JUDGER_NAME = 'remote_judger',
UOJ_JUDGER_PASSWORD = '',
} = process.env;
const UOJ_BASEURL = `${UOJ_PROTOCOL}://${UOJ_HOST}`;
daemon({
server_url: UOJ_BASEURL,
judger_name: UOJ_JUDGER_NAME,
password: UOJ_JUDGER_PASSWORD,
});

View File

@ -0,0 +1,7 @@
declare module 'superagent' {
interface Request {
proxy(url: string): this;
}
}
export default {};

View File

@ -0,0 +1,11 @@
import Logger from 'reggol';
Logger.levels.base = process.env.DEV ? 3 : 2;
Logger.targets[0].showTime = 'dd hh:mm:ss';
Logger.targets[0].label = {
align: 'right',
width: 9,
margin: 1,
};
export default Logger;

View File

@ -0,0 +1,5 @@
export default function sleep(timeout: number) {
return new Promise(resolve => {
setTimeout(() => resolve(true), timeout);
});
}

View File

@ -0,0 +1,5 @@
export const second = 1000;
export const minute = second * 60;
export const hour = minute * 60;
export const day = hour * 24;
export const week = day * 7;

View File

@ -0,0 +1,23 @@
{
"compilerOptions": {
"target": "esnext",
"lib": ["esnext"],
"allowJs": true,
"skipLibCheck": true,
// "strict": true,
"forceConsistentCasingInFileNames": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"incremental": true,
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
},
"outDir": "./dist"
},
"include": ["**/*.ts"],
"exclude": ["node_modules"]
}

View File

@ -64,21 +64,21 @@ class UOJLang {
return [];
}
$is_avail = [];
$dep_list = [
['C++98', 'C++03', 'C++11', 'C++', 'C++17', 'C++20'],
['Java8', 'Java11', 'Java17']
];
// $dep_list = [
// ['C++98', 'C++03', 'C++11', 'C++', 'C++17', 'C++20'],
// ['Java8', 'Java11', 'Java17']
// ];
foreach ($list as $lang) {
$lang = static::getUpgradedLangCode($lang);
foreach ($dep_list as $dep) {
$ok = false;
foreach ($dep as $d) {
if ($ok || $d == $lang) {
$is_avail[$d] = true;
$ok = true;
}
}
}
// foreach ($dep_list as $dep) {
// $ok = false;
// foreach ($dep as $d) {
// if ($ok || $d == $lang) {
// $is_avail[$d] = true;
// $ok = true;
// }
// }
// }
$is_avail[$lang] = true;
}

View File

@ -86,9 +86,6 @@ Route::group(
Route::any('/super_manage(?:/{tab})?', '/super_manage.php');
Route::any('/download/problem/{id}/data.zip', '/download.php?type=problem');
Route::any('/download/problem/{id}/attachment.zip', '/download.php?type=attachment');
Route::any('/check-notice', '/check_notice.php');
Route::any('/click-zan', '/click_zan.php');