mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-17 09:36:08 +08:00
1.0.0-preview
This commit is contained in:
1 parent
90b06d6aa7
commit
8cd84f29e8
18 files changed
+152
-401
No files matched your search
@@ -22,8 +22,12 @@ jobs:
|
||||
yarn build:production
|
||||
- uses: actions/upload-artifact@v1
|
||||
with:
|
||||
name: hydro
|
||||
path: .build
|
||||
name: development.js
|
||||
path: .build/development.js
|
||||
- uses: actions/upload-artifact@v1
|
||||
with:
|
||||
name: module
|
||||
path: .build/module
|
||||
- uses: elgohr/Publish-Docker-Github-Action@master
|
||||
with:
|
||||
name: hydrooj/hydro:alpine
|
||||
|
||||
@@ -269,7 +269,7 @@ class ProblemSolutionHandler extends ProblemDetailHandler {
|
||||
['problem_solution', null],
|
||||
];
|
||||
this.response.body = {
|
||||
path, psdocs, page, pcount, pscount, udict, pssdict,
|
||||
path, psdocs, page, pcount, pscount, udict, pssdict, pdoc: this.pdoc,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
+13
-17
@@ -1,22 +1,6 @@
|
||||
const nodemailer = require('nodemailer');
|
||||
const options = require('../options');
|
||||
const { SendMailError } = require('../error');
|
||||
|
||||
let transporter = null;
|
||||
try {
|
||||
transporter = nodemailer.createTransport({
|
||||
host: options.VJ_SMTP_HOST,
|
||||
port: options.VJ_DB_PORT,
|
||||
secure: options.VJ_SMTP_SECURE,
|
||||
auth: {
|
||||
user: options.VJ_SMTP_USER,
|
||||
pass: options.VJ_SMTP_PASSWORD,
|
||||
},
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
/**
|
||||
* @param {string} to
|
||||
@@ -27,9 +11,21 @@ module.exports = {
|
||||
async sendMail(to, subject, text, html) {
|
||||
let t;
|
||||
try {
|
||||
const system = require('../model/system');
|
||||
const [host, port, secure, user, pass, from] = await Promise.all([
|
||||
system.get('smtp.host'),
|
||||
system.get('smtp.port'),
|
||||
system.get('smtp.secure'),
|
||||
system.get('smtp.user'),
|
||||
system.get('smtp.pass'),
|
||||
system.get('smtp.from'),
|
||||
]);
|
||||
const transporter = nodemailer.createTransport({
|
||||
host, port, secure, auth: { user, pass },
|
||||
});
|
||||
t = await new Promise((resolve, reject) => {
|
||||
transporter.sendMail({
|
||||
from: options.VJ_SMTP_FROM,
|
||||
from,
|
||||
to,
|
||||
subject,
|
||||
text,
|
||||
|
||||
+17
-37
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable import/no-dynamic-require */
|
||||
/* eslint-disable no-await-in-loop */
|
||||
/* eslint-disable no-eval */
|
||||
const fs = require('fs');
|
||||
@@ -19,6 +20,7 @@ function ensureDir(dir) {
|
||||
}
|
||||
|
||||
const active = [];
|
||||
const fail = [];
|
||||
try {
|
||||
// Let webpack pack builtin module together.
|
||||
// eslint-disable-next-line import/no-unresolved
|
||||
@@ -59,7 +61,7 @@ async function preload() {
|
||||
for (const i of active) {
|
||||
try {
|
||||
if (i.os) {
|
||||
if (!i.os.includes(os.platform())) throw new Error('Unsupported OS');
|
||||
if (!i.os.includes(os.platform().toLowerCase())) throw new Error('Unsupported OS');
|
||||
}
|
||||
if (i.file) {
|
||||
i.files = {};
|
||||
@@ -87,6 +89,7 @@ async function handler() {
|
||||
for (const i of active) {
|
||||
if (i.handler && !i.fail) {
|
||||
try {
|
||||
console.log(`Handler init: ${i.id}`);
|
||||
console.time(`Handler init: ${i.id}`);
|
||||
const exports = {};
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
@@ -136,6 +139,7 @@ async function model() {
|
||||
for (const i of active) {
|
||||
if (i.model && !i.fail) {
|
||||
try {
|
||||
console.log(`Model init: ${i.id}`);
|
||||
console.time(`Model init: ${i.id}`);
|
||||
const exports = {};
|
||||
const module = { exports, file: i.files || {} };
|
||||
@@ -155,6 +159,7 @@ async function lib() {
|
||||
for (const i of active) {
|
||||
if (i.lib && !i.fail) {
|
||||
try {
|
||||
console.log(`Lib init: ${i.id}`);
|
||||
console.time(`Lib init: ${i.id}`);
|
||||
const exports = {};
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
@@ -184,44 +189,15 @@ async function service() {
|
||||
i.fail = true;
|
||||
fail.push(i.id);
|
||||
console.error(`Service Load Fail: ${i.id}`);
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function install() {
|
||||
await Promise.all([lib(), locale(), template()]);
|
||||
require('./service/setup');
|
||||
}
|
||||
|
||||
async function installDb() {
|
||||
const system = require('./model/system');
|
||||
const def = {
|
||||
PROBLEM_PER_PAGE: 100,
|
||||
RECORD_PER_PAGE: 100,
|
||||
SOLUTION_PER_PAGE: 20,
|
||||
CONTEST_PER_PAGE: 20,
|
||||
TRAINING_PER_PAGE: 10,
|
||||
DISCUSSION_PER_PAGE: 50,
|
||||
REPLY_PER_PAGE: 50,
|
||||
CONTESTS_ON_MAIN: 5,
|
||||
TRAININGS_ON_MAIN: 5,
|
||||
DISCUSSIONS_ON_MAIN: 20,
|
||||
'db.ver': 1,
|
||||
'listen.https': false,
|
||||
'listen.port': 8888,
|
||||
'session.keys': ['Hydro'],
|
||||
'session.secure': false,
|
||||
'session.saved_expire_seconds': 3600 * 24,
|
||||
'session.unsaved_expire_seconds': 600,
|
||||
changemail_token_expire_seconds: 3600 * 24,
|
||||
registration_token_expire_seconds: 600,
|
||||
};
|
||||
const tasks = [];
|
||||
for (const key in def) {
|
||||
tasks.push(system.set(key, def[key]));
|
||||
}
|
||||
await Promise.all(tasks);
|
||||
const setup = require('./service/setup');
|
||||
await setup.setup();
|
||||
}
|
||||
|
||||
async function load() {
|
||||
@@ -243,11 +219,12 @@ async function load() {
|
||||
require('./utils');
|
||||
require('./error');
|
||||
require('./permission');
|
||||
await Promise.all([locale(), template()]);
|
||||
try {
|
||||
require('./options');
|
||||
} catch (e) {
|
||||
await install();
|
||||
return;
|
||||
require('./options');
|
||||
}
|
||||
const bus = require('./service/bus');
|
||||
await new Promise((resolve) => {
|
||||
@@ -265,7 +242,7 @@ async function load() {
|
||||
'template', 'validator', 'nav',
|
||||
];
|
||||
for (const i of builtinLib) require(`./lib/${i}`);
|
||||
await Promise.all([lib(), locale(), template()]);
|
||||
await lib();
|
||||
require('./service/gridfs');
|
||||
const server = require('./service/server');
|
||||
await server.prepare();
|
||||
@@ -281,7 +258,10 @@ async function load() {
|
||||
}
|
||||
const system = require('./model/system');
|
||||
const dbVer = await system.get('db.ver');
|
||||
if (dbVer !== 1) await installDb();
|
||||
if (dbVer !== 1) {
|
||||
const ins = require('./script/install');
|
||||
await ins.run();
|
||||
}
|
||||
const builtinHandler = [
|
||||
'home', 'problem', 'record', 'judge', 'user',
|
||||
'contest', 'training', 'discussion', 'manage', 'import',
|
||||
@@ -300,4 +280,4 @@ async function load() {
|
||||
await server.start();
|
||||
}
|
||||
|
||||
module.exports = { load, active };
|
||||
module.exports = { load, active, fail };
|
||||
@@ -160,7 +160,13 @@ async function setTestdata(_id, readStream) {
|
||||
return await edit(_id, { data: f.id }); // eslint-disable-line no-return-await
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
async function getData(pid) {
|
||||
const pdoc = await get(pid);
|
||||
if (!pdoc.data) return null;
|
||||
return gridfs.openDownloadStream(pdoc.data);
|
||||
}
|
||||
|
||||
global.Hydro.model.problem = module.exports = {
|
||||
add,
|
||||
inc,
|
||||
get,
|
||||
@@ -175,4 +181,5 @@ module.exports = {
|
||||
getMultiStatus,
|
||||
setTestdata,
|
||||
updateStatus,
|
||||
getData,
|
||||
};
|
||||
+2
-2
@@ -21,7 +21,7 @@ function del(_id) {
|
||||
|
||||
async function getFirst(query) {
|
||||
const res = await coll.find(query).sort('_id', 1).limit(1).toArray();
|
||||
if (res) {
|
||||
if (res.length) {
|
||||
await coll.deleteOne({ _id: res[0]._id });
|
||||
return res[0];
|
||||
}
|
||||
@@ -35,6 +35,6 @@ async function consume(query, cb) {
|
||||
}, 100);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
global.Hydro.model.task = module.exports = {
|
||||
add, get, del, count, getFirst, consume,
|
||||
};
|
||||
+7
-46
@@ -1,59 +1,20 @@
|
||||
const fs = require('fs');
|
||||
const os = require('os');
|
||||
const path = require('path');
|
||||
const { defaultsDeep } = require('lodash');
|
||||
const { defaults } = require('lodash');
|
||||
|
||||
let options = {
|
||||
db: {
|
||||
name: 'hydro',
|
||||
host: '127.0.0.1',
|
||||
port: 27017,
|
||||
username: '',
|
||||
password: '',
|
||||
},
|
||||
template: {
|
||||
path: path.join(process.cwd(), 'templates'),
|
||||
},
|
||||
listen: {
|
||||
host: '127.0.0.1',
|
||||
port: 8888,
|
||||
domain: '',
|
||||
https: false,
|
||||
},
|
||||
smtp: {
|
||||
from: '',
|
||||
host: '',
|
||||
port: 465,
|
||||
user: '',
|
||||
pass: '',
|
||||
secure: false,
|
||||
},
|
||||
session: {
|
||||
keys: ['Hydro'],
|
||||
secure: false,
|
||||
domain: '127.0.0.1',
|
||||
saved_expire_seconds: 3600 * 24,
|
||||
unsaved_expire_seconds: 600,
|
||||
registration_token_expire_seconds: 600,
|
||||
},
|
||||
constants: {
|
||||
PROBLEM_PER_PAGE: 100,
|
||||
RECORD_PER_PAGE: 100,
|
||||
SOLUTION_PER_PAGE: 20,
|
||||
CONTEST_PER_PAGE: 20,
|
||||
TRAINING_PER_PAGE: 10,
|
||||
DISCUSSION_PER_PAGE: 50,
|
||||
REPLY_PER_PAGE: 50,
|
||||
CONTESTS_ON_MAIN: 5,
|
||||
TRAININGS_ON_MAIN: 5,
|
||||
DISCUSSIONS_ON_MAIN: 20,
|
||||
},
|
||||
name: 'hydro',
|
||||
host: '127.0.0.1',
|
||||
port: 27017,
|
||||
username: '',
|
||||
password: '',
|
||||
};
|
||||
|
||||
let f = path.resolve(process.cwd(), 'config.json');
|
||||
if (!fs.existsSync(f)) f = path.resolve(os.homedir(), '.config', 'hydro', 'config.json');
|
||||
if (!fs.existsSync(f)) f = path.resolve('/config/config.json');
|
||||
const t = JSON.parse(fs.readFileSync(f));
|
||||
options = defaultsDeep(t, options);
|
||||
options = defaults(t, options);
|
||||
|
||||
module.exports = options;
|
||||
+68
-32
@@ -1,46 +1,82 @@
|
||||
const { defaults } = require('lodash');
|
||||
const db = require('../service/db');
|
||||
const builtin = require('../model/builtin');
|
||||
const system = require('../model/system');
|
||||
const pwhash = require('../lib/pwhash');
|
||||
const { udoc } = require('../interface');
|
||||
|
||||
const collUser = db.collection('user');
|
||||
const collRole = db.collection('role');
|
||||
const collSystem = db.collection('system');
|
||||
|
||||
async function run() {
|
||||
const salt = pwhash.salt();
|
||||
await collUser.insertMany([
|
||||
defaults({
|
||||
_id: 0,
|
||||
uname: 'Hydro',
|
||||
unameLower: 'hydro',
|
||||
mail: 'hydro@hydro',
|
||||
mailLower: 'hydro@hydro',
|
||||
role: 'guest',
|
||||
}, udoc),
|
||||
defaults({
|
||||
_id: 1,
|
||||
mail: 'guest@hydro',
|
||||
mailLower: 'guest@hydro',
|
||||
uname: 'Guest',
|
||||
unameLower: 'guest',
|
||||
role: 'guest',
|
||||
}, udoc),
|
||||
defaults({
|
||||
_id: -1,
|
||||
mail: 'root@hydro',
|
||||
mailLower: 'root@hydro',
|
||||
uname: 'Root',
|
||||
unameLower: 'root',
|
||||
hash: pwhash.hash('rootroot', salt),
|
||||
salt,
|
||||
gravatar: 'root@hydro',
|
||||
role: 'root',
|
||||
}, udoc),
|
||||
]);
|
||||
const def = {
|
||||
PROBLEM_PER_PAGE: 100,
|
||||
RECORD_PER_PAGE: 100,
|
||||
SOLUTION_PER_PAGE: 20,
|
||||
CONTEST_PER_PAGE: 20,
|
||||
TRAINING_PER_PAGE: 10,
|
||||
DISCUSSION_PER_PAGE: 50,
|
||||
REPLY_PER_PAGE: 50,
|
||||
CONTESTS_ON_MAIN: 5,
|
||||
TRAININGS_ON_MAIN: 5,
|
||||
DISCUSSIONS_ON_MAIN: 20,
|
||||
'smtp.host': '',
|
||||
'smtp.port': 465,
|
||||
'smtp.from': '',
|
||||
'smtp.user': '',
|
||||
'smtp.pass': '',
|
||||
'smtp.secure': false,
|
||||
'db.ver': 1,
|
||||
'listen.https': false,
|
||||
'listen.port': 8888,
|
||||
'session.keys': ['Hydro'],
|
||||
'session.secure': false,
|
||||
'session.saved_expire_seconds': 3600 * 24,
|
||||
'session.unsaved_expire_seconds': 600,
|
||||
changemail_token_expire_seconds: 3600 * 24,
|
||||
registration_token_expire_seconds: 600,
|
||||
};
|
||||
const tasks = [];
|
||||
for (const key in def) {
|
||||
tasks.push(system.set(key, def[key]));
|
||||
}
|
||||
await Promise.all(tasks);
|
||||
try {
|
||||
const salt = pwhash.salt();
|
||||
await collUser.insertMany([
|
||||
defaults({
|
||||
_id: 0,
|
||||
uname: 'Hydro',
|
||||
unameLower: 'hydro',
|
||||
mail: 'hydro@hydro',
|
||||
mailLower: 'hydro@hydro',
|
||||
role: 'guest',
|
||||
}, udoc),
|
||||
defaults({
|
||||
_id: 1,
|
||||
mail: 'guest@hydro',
|
||||
mailLower: 'guest@hydro',
|
||||
uname: 'Guest',
|
||||
unameLower: 'guest',
|
||||
role: 'guest',
|
||||
}, udoc),
|
||||
defaults({
|
||||
_id: -1,
|
||||
mail: 'root@hydro',
|
||||
mailLower: 'root@hydro',
|
||||
uname: 'Root',
|
||||
unameLower: 'root',
|
||||
hash: pwhash.hash('rootroot', salt),
|
||||
salt,
|
||||
gravatar: 'root@hydro',
|
||||
role: 'root',
|
||||
}, udoc),
|
||||
]);
|
||||
} catch (e) {
|
||||
// Ignore user already exist error
|
||||
}
|
||||
await collRole.deleteMany({ _id: { $in: builtin.BUILTIN_ROLES.map((role) => role._id) } });
|
||||
await collRole.insertMany(builtin.BUILTIN_ROLES);
|
||||
console.log('Installed');
|
||||
}
|
||||
|
||||
module.exports = { run };
|
||||
+3
-3
@@ -3,15 +3,15 @@ const bus = require('./bus');
|
||||
const options = require('../options');
|
||||
|
||||
let mongourl = 'mongodb://';
|
||||
if (options.db.username) mongourl += `${options.db.username}:${options.db.password}@`;
|
||||
mongourl += `${options.db.host}:${options.db.port}/${options.db.name}`;
|
||||
if (options.username) mongourl += `${options.username}:${options.password}@`;
|
||||
mongourl += `${options.host}:${options.port}/${options.name}`;
|
||||
/**
|
||||
* @type {import('mongodb').Db}
|
||||
*/
|
||||
let db = null;
|
||||
Mongo.MongoClient.connect(mongourl, { useNewUrlParser: true, useUnifiedTopology: true })
|
||||
.then((Database) => {
|
||||
db = Database.db(options.db.name);
|
||||
db = Database.db(options.name);
|
||||
db.Db = Database;
|
||||
bus.publish('system_database_connected', null);
|
||||
});
|
||||
|
||||
+22
-19
@@ -249,27 +249,30 @@ function Route(route, RouteHandler) {
|
||||
const args = { ...ctx.params, ...ctx.query, ...ctx.request.body };
|
||||
|
||||
if (h.___prepare) await h.___prepare(args);
|
||||
|
||||
for (const l of check) {
|
||||
if (args[l]) {
|
||||
args[l] = new ObjectID(args[l]);
|
||||
if (!args[l]) throw new ValidationError(l);
|
||||
try {
|
||||
for (const l of check) {
|
||||
if (args[l]) {
|
||||
args[l] = new ObjectID(args[l]);
|
||||
if (!args[l]) throw new ValidationError(l);
|
||||
}
|
||||
}
|
||||
if (args.content) validator.checkContent(args.content);
|
||||
if (args.title) validator.checkContent(args.title);
|
||||
if (args.uid) args.uid = parseInt(validator.checkUid(args.uid));
|
||||
if (args.password) validator.checkPassword(args.password);
|
||||
if (args.mail) validator.checkEmail(args.mail);
|
||||
if (args.uname) validator.checkUname(args.uname);
|
||||
if (args.page) args.page = parseInt(args.page);
|
||||
if (args.duration) args.duration = parseFloat(args.duration);
|
||||
if (args.pids) args.pids = args.pids.split(',').map((i) => i.trim());
|
||||
if (args.role) validator.checkRole(args.role);
|
||||
if (args.roles) {
|
||||
for (const i of args.roles) validator.checkRole(i);
|
||||
}
|
||||
} catch (e) {
|
||||
if (e instanceof ValidationError) throw e;
|
||||
throw new ValidationError('Argument check failed');
|
||||
}
|
||||
if (args.content) validator.checkContent(args.content);
|
||||
if (args.title) validator.checkContent(args.title);
|
||||
if (args.uid) args.uid = parseInt(validator.checkUid(args.uid));
|
||||
if (args.password) validator.checkPassword(args.password);
|
||||
if (args.mail) validator.checkEmail(args.mail);
|
||||
if (args.uname) validator.checkUname(args.uname);
|
||||
if (args.page) args.page = parseInt(args.page);
|
||||
if (args.duration) args.duration = parseFloat(args.duration);
|
||||
if (args.pids) args.pids = args.pids.split(',').map((i) => i.trim());
|
||||
if (args.role) validator.checkRole(args.role);
|
||||
if (args.roles) {
|
||||
for (const i of args.roles) validator.checkRole(i);
|
||||
}
|
||||
|
||||
if (h.__prepare) await h.__prepare(args);
|
||||
if (h._prepare) await h._prepare(args);
|
||||
if (h.prepare) await h.prepare(args);
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
const Mongo = require('mongodb');
|
||||
const options = require('./options');
|
||||
|
||||
async function run() {
|
||||
let mongourl = 'mongodb://';
|
||||
if (options.db.username) mongourl += `${options.db.username}:${options.db.password}@`;
|
||||
mongourl += `${options.db.host}:${options.db.port}/${options.db.name}`;
|
||||
const Database = await Mongo.MongoClient.connect(mongourl, {
|
||||
useNewUrlParser: true, useUnifiedTopology: true,
|
||||
});
|
||||
const db = Database.db(options.db.name);
|
||||
await db.dropDatabase();
|
||||
console.log('Dropped');
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
run().catch((e) => {
|
||||
console.error(e);
|
||||
process.exit(1);
|
||||
});
|
||||
@@ -1,14 +0,0 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const child = require('child_process');
|
||||
const yaml = require('js-yaml');
|
||||
|
||||
exports.prebuild = async function prebuild() {
|
||||
if (!fs.existsSync(path.resolve(__dirname, 'HydroJudger'))) {
|
||||
const res = child.spawnSync('git clone https://github.com/hydro-dev/HydroJudger.git');
|
||||
if (res.error) throw res.error;
|
||||
}
|
||||
let lang = fs.readFileSync(path.resolve(__dirname, 'langs.yaml')).toString();
|
||||
lang = yaml.safeLoad(lang);
|
||||
fs.writeFileSync(path.resolve(__dirname, '__lang.json'), JSON.stringify(lang));
|
||||
};
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"name": "judger",
|
||||
"version": "1.0.0",
|
||||
"description": "HydroJudger"
|
||||
}
|
||||
@@ -1,167 +0,0 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const child = require('child_process');
|
||||
|
||||
async function postInit() {
|
||||
const config = require('./HydroJudger/judger/config');
|
||||
// eslint-disable-next-line import/no-unresolved
|
||||
config.LANGS = require('./__langs.json');
|
||||
const { mkdirp, rmdir, compilerText } = require('./HydroJudger/judger/utils');
|
||||
const log = require('./HydroJudger/judger/log');
|
||||
const tmpfs = require('./HydroJudger/judger/tmpfs');
|
||||
const { FormatError, CompileError, SystemError } = require('./HydroJudger/judger/error');
|
||||
const { STATUS_COMPILE_ERROR, STATUS_SYSTEM_ERROR } = require('./HydroJudger/judger/status');
|
||||
const readCases = require('./HydroJudger/judger/cases');
|
||||
const judger = require('./HydroJudger/judger/judger');
|
||||
|
||||
const fsp = fs.promises;
|
||||
const { problem, task } = global.Hydro.model;
|
||||
const { judge } = global.Hydro.handler;
|
||||
|
||||
async function problemData(pid, savePath) {
|
||||
const tmpFilePath = path.resolve(config.CACHE_DIR, `download_${pid}`);
|
||||
const res = await problem.getData(pid);
|
||||
const w = await fs.createWriteStream(tmpFilePath);
|
||||
res.data.pipe(w);
|
||||
await new Promise((resolve, reject) => {
|
||||
w.on('finish', resolve);
|
||||
w.on('error', reject);
|
||||
});
|
||||
mkdirp(path.dirname(savePath));
|
||||
await new Promise((resolve, reject) => {
|
||||
child.exec(`unzip ${tmpFilePath} -d ${savePath}`, (e) => {
|
||||
if (e) reject(e);
|
||||
else resolve();
|
||||
});
|
||||
});
|
||||
await fsp.unlink(tmpFilePath);
|
||||
await this.processData(savePath).catch();
|
||||
return savePath;
|
||||
}
|
||||
|
||||
async function cacheOpen(pid, version) {
|
||||
const filePath = path.join(config.CACHE_DIR, pid);
|
||||
if (fs.existsSync(filePath)) {
|
||||
let ver;
|
||||
try {
|
||||
ver = fs.readFileSync(path.join(filePath, 'version')).toString();
|
||||
} catch (e) { /* ignore */ }
|
||||
if (version === ver) return filePath;
|
||||
rmdir(filePath);
|
||||
}
|
||||
mkdirp(filePath);
|
||||
await problemData(pid, filePath);
|
||||
fs.writeFileSync(path.join(filePath, 'version'), version);
|
||||
return filePath;
|
||||
}
|
||||
|
||||
function getNext(that) {
|
||||
that.nextId = 1;
|
||||
that.nextWaiting = [];
|
||||
return (data, id) => {
|
||||
data.key = 'next';
|
||||
data.rid = that.rid;
|
||||
if (id) {
|
||||
if (id === that.nextId) {
|
||||
judge.next(data);
|
||||
that.nextId++;
|
||||
let t = true;
|
||||
while (t) {
|
||||
t = false;
|
||||
for (const i in that.nextWaiting) {
|
||||
if (that.nextId === that.nextWaiting[i].id) {
|
||||
judge.next(that.nextWaiting[i].data);
|
||||
that.nextId++;
|
||||
that.nextWaiting.splice(i, 1);
|
||||
t = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else that.nextWaiting.push({ data, id });
|
||||
} else judge.next(data);
|
||||
};
|
||||
}
|
||||
|
||||
function getEnd(rid) {
|
||||
return (data) => {
|
||||
data.key = 'end';
|
||||
data.rid = rid;
|
||||
log.log({
|
||||
status: data.status,
|
||||
score: data.score,
|
||||
time_ms: data.time_ms,
|
||||
memory_kb: data.memory_kb,
|
||||
});
|
||||
judge.end(data);
|
||||
};
|
||||
}
|
||||
|
||||
class JudgeTask {
|
||||
constructor(request) {
|
||||
this.stat = {};
|
||||
this.stat.receive = new Date();
|
||||
this.request = request;
|
||||
}
|
||||
|
||||
async handle() {
|
||||
try {
|
||||
this.stat.handle = new Date();
|
||||
this.event = this.request.event;
|
||||
this.pid = this.request.pid;
|
||||
this.rid = this.request.rid;
|
||||
this.lang = this.request.lang;
|
||||
this.code = this.request.code;
|
||||
this.data = this.request.data;
|
||||
this.next = getNext(this);
|
||||
this.end = getEnd(this.rid);
|
||||
this.tmpdir = path.resolve(config.TEMP_DIR, 'tmp', this.rid);
|
||||
this.clean = [];
|
||||
mkdirp(this.tmpdir);
|
||||
tmpfs.mount(this.tmpdir, '64m');
|
||||
log.submission(`${this.rid}`, { pid: this.pid });
|
||||
if (!this.event) await this.submission();
|
||||
else throw new SystemError(`Unsupported type: ${this.type}`);
|
||||
} catch (e) {
|
||||
if (e instanceof CompileError) {
|
||||
this.next({ compiler_text: compilerText(e.stdout, e.stderr) });
|
||||
this.end({
|
||||
status: STATUS_COMPILE_ERROR, score: 0, time_ms: 0, memory_kb: 0,
|
||||
});
|
||||
} else if (e instanceof FormatError) {
|
||||
this.next({ judge_text: `${e.message}\n${JSON.stringify(e.params)}` });
|
||||
this.end({
|
||||
status: STATUS_SYSTEM_ERROR, score: 0, time_ms: 0, memory_kb: 0,
|
||||
});
|
||||
} else {
|
||||
log.error(e);
|
||||
this.next({ judge_text: `${e.message}\n${e.stack}\n${JSON.stringify(e.params)}` });
|
||||
this.end({
|
||||
status: STATUS_SYSTEM_ERROR, score: 0, time_ms: 0, memory_kb: 0,
|
||||
});
|
||||
}
|
||||
}
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
for (const clean of this.clean) await clean().catch();
|
||||
tmpfs.umount(this.tmpdir);
|
||||
await rmdir(this.tmpdir);
|
||||
}
|
||||
|
||||
async submission() {
|
||||
this.stat.cache_start = new Date();
|
||||
this.folder = await cacheOpen(this.pid, this.data);
|
||||
this.stat.read_cases = new Date();
|
||||
this.config = await readCases(
|
||||
this.folder,
|
||||
{ detail: true },
|
||||
{ next: this.next },
|
||||
);
|
||||
this.stat.judge = new Date();
|
||||
await judger[this.config.type || 'default'].judge(this);
|
||||
}
|
||||
}
|
||||
task.consume({ type: 'judge' }, (t) => {
|
||||
(new JudgeTask(t)).handle();
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = { postInit };
|
||||
@@ -1,6 +1,8 @@
|
||||
{
|
||||
"name": "sandbox-linux",
|
||||
"version": "1.0.0",
|
||||
"os": "Linux",
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"description": "Sandbox service for linux"
|
||||
}
|
||||
@@ -2,7 +2,7 @@ const os = require('os');
|
||||
const path = require('path');
|
||||
const child = require('child_process');
|
||||
|
||||
const p = child.spawn(path.resolve(os.tmpdir(), 'hydro', 'sandbox-linux-amd64', 'executorserver', ['-silent']));
|
||||
const p = child.spawn(path.resolve(os.tmpdir(), 'hydro', 'sandbox-linux-amd64', 'executorserver'), ['-silent']);
|
||||
if (!p.stdout) throw new Error('Cannot start executorserver');
|
||||
else {
|
||||
p.stdout.on('data', (data) => {
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "hydro",
|
||||
"version": "0.0.0",
|
||||
"version": "1.0.0-preview",
|
||||
"main": "hydro/development.js",
|
||||
"repository": "https://github.com/hydro-dev/Hydro.git",
|
||||
"author": "masnn",
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html data-page="setup" data-layout="immersive" class="layout--immersive page--setup nojs">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<meta http-equiv="X-UA-Compatible" content="chrome=1"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
|
||||
<meta name="msapplication-TileColor" content="#579e9a">
|
||||
<meta name="theme-color" content="#56758f">
|
||||
<link rel="stylesheet" media="all" href="{{ static_url('vj4.css') }}">
|
||||
<title>{{ _('Setup') }}</title>
|
||||
<script>
|
||||
var _htmlNode = document.documentElement;
|
||||
_htmlNode.className = _htmlNode.className.replace(' nojs', ' hasjs');
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="slideout-panel" id="panel">
|
||||
<div class="main">
|
||||
<div class="row"><div class="columns">
|
||||
<div class="immersive--content immersive--center">
|
||||
<h1>{{ _('Setup') }}</h1>
|
||||
<div class="text-center">
|
||||
{{ _('Done. Please restart the program.') }}
|
||||
</div>
|
||||
</div>
|
||||
</div></div>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript" src="{{ static_url('vj4.js') }}"></script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in new issue
Block a user