mirror of
https://github.com/renbaoshuo/S2OJ.git
synced 2024-09-08 02:25:17 +00:00
feat(remote_judger): init
This commit is contained in:
parent
1689c34aa3
commit
3a2e3ce1db
@ -3,7 +3,12 @@ root = true
|
|||||||
[*]
|
[*]
|
||||||
indent_style = tab
|
indent_style = tab
|
||||||
indent_size = 4
|
indent_size = 4
|
||||||
|
end_of_line = lf
|
||||||
|
|
||||||
[*.y{,a}ml]
|
[*.y{,a}ml]
|
||||||
indent_style = space
|
indent_style = space
|
||||||
indent_size = 2
|
indent_size = 2
|
||||||
|
|
||||||
|
[remote_judger/**.{js,ts}]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
@ -42,6 +42,20 @@ services:
|
|||||||
- SOCKET_PORT=2333
|
- SOCKET_PORT=2333
|
||||||
- SOCKET_PASSWORD=_judger_socket_password_
|
- 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:
|
uoj-web:
|
||||||
build:
|
build:
|
||||||
context: ./
|
context: ./
|
||||||
|
3
remote_judger/.gitignore
vendored
Normal file
3
remote_judger/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
dist/
|
||||||
|
node_modules/
|
||||||
|
*-error.log
|
14
remote_judger/.prettierrc
Normal file
14
remote_judger/.prettierrc
Normal 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
12
remote_judger/Dockerfile
Normal 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
2545
remote_judger/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
32
remote_judger/package.json
Normal file
32
remote_judger/package.json
Normal 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"
|
||||||
|
}
|
||||||
|
}
|
62
remote_judger/src/daemon.ts
Normal file
62
remote_judger/src/daemon.ts
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
15
remote_judger/src/entrypoint.ts
Normal file
15
remote_judger/src/entrypoint.ts
Normal 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,
|
||||||
|
});
|
7
remote_judger/src/proxy.ts
Normal file
7
remote_judger/src/proxy.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
declare module 'superagent' {
|
||||||
|
interface Request {
|
||||||
|
proxy(url: string): this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {};
|
11
remote_judger/src/utils/logger.ts
Normal file
11
remote_judger/src/utils/logger.ts
Normal 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;
|
5
remote_judger/src/utils/sleep.ts
Normal file
5
remote_judger/src/utils/sleep.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
export default function sleep(timeout: number) {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
setTimeout(() => resolve(true), timeout);
|
||||||
|
});
|
||||||
|
}
|
5
remote_judger/src/utils/time.ts
Normal file
5
remote_judger/src/utils/time.ts
Normal 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;
|
23
remote_judger/tsconfig.json
Normal file
23
remote_judger/tsconfig.json
Normal 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"]
|
||||||
|
}
|
@ -64,21 +64,21 @@ class UOJLang {
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
$is_avail = [];
|
$is_avail = [];
|
||||||
$dep_list = [
|
// $dep_list = [
|
||||||
['C++98', 'C++03', 'C++11', 'C++', 'C++17', 'C++20'],
|
// ['C++98', 'C++03', 'C++11', 'C++', 'C++17', 'C++20'],
|
||||||
['Java8', 'Java11', 'Java17']
|
// ['Java8', 'Java11', 'Java17']
|
||||||
];
|
// ];
|
||||||
foreach ($list as $lang) {
|
foreach ($list as $lang) {
|
||||||
$lang = static::getUpgradedLangCode($lang);
|
$lang = static::getUpgradedLangCode($lang);
|
||||||
foreach ($dep_list as $dep) {
|
// foreach ($dep_list as $dep) {
|
||||||
$ok = false;
|
// $ok = false;
|
||||||
foreach ($dep as $d) {
|
// foreach ($dep as $d) {
|
||||||
if ($ok || $d == $lang) {
|
// if ($ok || $d == $lang) {
|
||||||
$is_avail[$d] = true;
|
// $is_avail[$d] = true;
|
||||||
$ok = true;
|
// $ok = true;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
$is_avail[$lang] = true;
|
$is_avail[$lang] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,9 +86,6 @@ Route::group(
|
|||||||
|
|
||||||
Route::any('/super_manage(?:/{tab})?', '/super_manage.php');
|
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('/check-notice', '/check_notice.php');
|
||||||
Route::any('/click-zan', '/click_zan.php');
|
Route::any('/click-zan', '/click_zan.php');
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user