mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-20 09:46:28 +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
|
yarn build:production
|
||||||
- uses: actions/upload-artifact@v1
|
- uses: actions/upload-artifact@v1
|
||||||
with:
|
with:
|
||||||
name: hydro
|
name: development.js
|
||||||
path: .build
|
path: .build/development.js
|
||||||
|
- uses: actions/upload-artifact@v1
|
||||||
|
with:
|
||||||
|
name: module
|
||||||
|
path: .build/module
|
||||||
- uses: elgohr/Publish-Docker-Github-Action@master
|
- uses: elgohr/Publish-Docker-Github-Action@master
|
||||||
with:
|
with:
|
||||||
name: hydrooj/hydro:alpine
|
name: hydrooj/hydro:alpine
|
||||||
|
|||||||
@@ -269,7 +269,7 @@ class ProblemSolutionHandler extends ProblemDetailHandler {
|
|||||||
['problem_solution', null],
|
['problem_solution', null],
|
||||||
];
|
];
|
||||||
this.response.body = {
|
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 nodemailer = require('nodemailer');
|
||||||
const options = require('../options');
|
|
||||||
const { SendMailError } = require('../error');
|
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 = {
|
module.exports = {
|
||||||
/**
|
/**
|
||||||
* @param {string} to
|
* @param {string} to
|
||||||
@@ -27,9 +11,21 @@ module.exports = {
|
|||||||
async sendMail(to, subject, text, html) {
|
async sendMail(to, subject, text, html) {
|
||||||
let t;
|
let t;
|
||||||
try {
|
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) => {
|
t = await new Promise((resolve, reject) => {
|
||||||
transporter.sendMail({
|
transporter.sendMail({
|
||||||
from: options.VJ_SMTP_FROM,
|
from,
|
||||||
to,
|
to,
|
||||||
subject,
|
subject,
|
||||||
text,
|
text,
|
||||||
|
|||||||
+17
-37
@@ -1,3 +1,4 @@
|
|||||||
|
/* eslint-disable import/no-dynamic-require */
|
||||||
/* eslint-disable no-await-in-loop */
|
/* eslint-disable no-await-in-loop */
|
||||||
/* eslint-disable no-eval */
|
/* eslint-disable no-eval */
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
@@ -19,6 +20,7 @@ function ensureDir(dir) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const active = [];
|
const active = [];
|
||||||
|
const fail = [];
|
||||||
try {
|
try {
|
||||||
// Let webpack pack builtin module together.
|
// Let webpack pack builtin module together.
|
||||||
// eslint-disable-next-line import/no-unresolved
|
// eslint-disable-next-line import/no-unresolved
|
||||||
@@ -59,7 +61,7 @@ async function preload() {
|
|||||||
for (const i of active) {
|
for (const i of active) {
|
||||||
try {
|
try {
|
||||||
if (i.os) {
|
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) {
|
if (i.file) {
|
||||||
i.files = {};
|
i.files = {};
|
||||||
@@ -87,6 +89,7 @@ async function handler() {
|
|||||||
for (const i of active) {
|
for (const i of active) {
|
||||||
if (i.handler && !i.fail) {
|
if (i.handler && !i.fail) {
|
||||||
try {
|
try {
|
||||||
|
console.log(`Handler init: ${i.id}`);
|
||||||
console.time(`Handler init: ${i.id}`);
|
console.time(`Handler init: ${i.id}`);
|
||||||
const exports = {};
|
const exports = {};
|
||||||
// eslint-disable-next-line no-unused-vars
|
// eslint-disable-next-line no-unused-vars
|
||||||
@@ -136,6 +139,7 @@ async function model() {
|
|||||||
for (const i of active) {
|
for (const i of active) {
|
||||||
if (i.model && !i.fail) {
|
if (i.model && !i.fail) {
|
||||||
try {
|
try {
|
||||||
|
console.log(`Model init: ${i.id}`);
|
||||||
console.time(`Model init: ${i.id}`);
|
console.time(`Model init: ${i.id}`);
|
||||||
const exports = {};
|
const exports = {};
|
||||||
const module = { exports, file: i.files || {} };
|
const module = { exports, file: i.files || {} };
|
||||||
@@ -155,6 +159,7 @@ async function lib() {
|
|||||||
for (const i of active) {
|
for (const i of active) {
|
||||||
if (i.lib && !i.fail) {
|
if (i.lib && !i.fail) {
|
||||||
try {
|
try {
|
||||||
|
console.log(`Lib init: ${i.id}`);
|
||||||
console.time(`Lib init: ${i.id}`);
|
console.time(`Lib init: ${i.id}`);
|
||||||
const exports = {};
|
const exports = {};
|
||||||
// eslint-disable-next-line no-unused-vars
|
// eslint-disable-next-line no-unused-vars
|
||||||
@@ -184,44 +189,15 @@ async function service() {
|
|||||||
i.fail = true;
|
i.fail = true;
|
||||||
fail.push(i.id);
|
fail.push(i.id);
|
||||||
console.error(`Service Load Fail: ${i.id}`);
|
console.error(`Service Load Fail: ${i.id}`);
|
||||||
|
console.error(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function install() {
|
async function install() {
|
||||||
await Promise.all([lib(), locale(), template()]);
|
const setup = require('./service/setup');
|
||||||
require('./service/setup');
|
await setup.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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function load() {
|
async function load() {
|
||||||
@@ -243,11 +219,12 @@ async function load() {
|
|||||||
require('./utils');
|
require('./utils');
|
||||||
require('./error');
|
require('./error');
|
||||||
require('./permission');
|
require('./permission');
|
||||||
|
await Promise.all([locale(), template()]);
|
||||||
try {
|
try {
|
||||||
require('./options');
|
require('./options');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
await install();
|
await install();
|
||||||
return;
|
require('./options');
|
||||||
}
|
}
|
||||||
const bus = require('./service/bus');
|
const bus = require('./service/bus');
|
||||||
await new Promise((resolve) => {
|
await new Promise((resolve) => {
|
||||||
@@ -265,7 +242,7 @@ async function load() {
|
|||||||
'template', 'validator', 'nav',
|
'template', 'validator', 'nav',
|
||||||
];
|
];
|
||||||
for (const i of builtinLib) require(`./lib/${i}`);
|
for (const i of builtinLib) require(`./lib/${i}`);
|
||||||
await Promise.all([lib(), locale(), template()]);
|
await lib();
|
||||||
require('./service/gridfs');
|
require('./service/gridfs');
|
||||||
const server = require('./service/server');
|
const server = require('./service/server');
|
||||||
await server.prepare();
|
await server.prepare();
|
||||||
@@ -281,7 +258,10 @@ async function load() {
|
|||||||
}
|
}
|
||||||
const system = require('./model/system');
|
const system = require('./model/system');
|
||||||
const dbVer = await system.get('db.ver');
|
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 = [
|
const builtinHandler = [
|
||||||
'home', 'problem', 'record', 'judge', 'user',
|
'home', 'problem', 'record', 'judge', 'user',
|
||||||
'contest', 'training', 'discussion', 'manage', 'import',
|
'contest', 'training', 'discussion', 'manage', 'import',
|
||||||
@@ -300,4 +280,4 @@ async function load() {
|
|||||||
await server.start();
|
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
|
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,
|
add,
|
||||||
inc,
|
inc,
|
||||||
get,
|
get,
|
||||||
@@ -175,4 +181,5 @@ module.exports = {
|
|||||||
getMultiStatus,
|
getMultiStatus,
|
||||||
setTestdata,
|
setTestdata,
|
||||||
updateStatus,
|
updateStatus,
|
||||||
|
getData,
|
||||||
};
|
};
|
||||||
+2
-2
@@ -21,7 +21,7 @@ function del(_id) {
|
|||||||
|
|
||||||
async function getFirst(query) {
|
async function getFirst(query) {
|
||||||
const res = await coll.find(query).sort('_id', 1).limit(1).toArray();
|
const res = await coll.find(query).sort('_id', 1).limit(1).toArray();
|
||||||
if (res) {
|
if (res.length) {
|
||||||
await coll.deleteOne({ _id: res[0]._id });
|
await coll.deleteOne({ _id: res[0]._id });
|
||||||
return res[0];
|
return res[0];
|
||||||
}
|
}
|
||||||
@@ -35,6 +35,6 @@ async function consume(query, cb) {
|
|||||||
}, 100);
|
}, 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
global.Hydro.model.task = module.exports = {
|
||||||
add, get, del, count, getFirst, consume,
|
add, get, del, count, getFirst, consume,
|
||||||
};
|
};
|
||||||
+7
-46
@@ -1,59 +1,20 @@
|
|||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const os = require('os');
|
const os = require('os');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const { defaultsDeep } = require('lodash');
|
const { defaults } = require('lodash');
|
||||||
|
|
||||||
let options = {
|
let options = {
|
||||||
db: {
|
name: 'hydro',
|
||||||
name: 'hydro',
|
host: '127.0.0.1',
|
||||||
host: '127.0.0.1',
|
port: 27017,
|
||||||
port: 27017,
|
username: '',
|
||||||
username: '',
|
password: '',
|
||||||
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,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let f = path.resolve(process.cwd(), 'config.json');
|
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(os.homedir(), '.config', 'hydro', 'config.json');
|
||||||
if (!fs.existsSync(f)) f = path.resolve('/config/config.json');
|
if (!fs.existsSync(f)) f = path.resolve('/config/config.json');
|
||||||
const t = JSON.parse(fs.readFileSync(f));
|
const t = JSON.parse(fs.readFileSync(f));
|
||||||
options = defaultsDeep(t, options);
|
options = defaults(t, options);
|
||||||
|
|
||||||
module.exports = options;
|
module.exports = options;
|
||||||
+68
-32
@@ -1,46 +1,82 @@
|
|||||||
const { defaults } = require('lodash');
|
const { defaults } = require('lodash');
|
||||||
const db = require('../service/db');
|
const db = require('../service/db');
|
||||||
const builtin = require('../model/builtin');
|
const builtin = require('../model/builtin');
|
||||||
|
const system = require('../model/system');
|
||||||
const pwhash = require('../lib/pwhash');
|
const pwhash = require('../lib/pwhash');
|
||||||
const { udoc } = require('../interface');
|
const { udoc } = require('../interface');
|
||||||
|
|
||||||
const collUser = db.collection('user');
|
const collUser = db.collection('user');
|
||||||
const collRole = db.collection('role');
|
const collRole = db.collection('role');
|
||||||
const collSystem = db.collection('system');
|
|
||||||
|
|
||||||
async function run() {
|
async function run() {
|
||||||
const salt = pwhash.salt();
|
const def = {
|
||||||
await collUser.insertMany([
|
PROBLEM_PER_PAGE: 100,
|
||||||
defaults({
|
RECORD_PER_PAGE: 100,
|
||||||
_id: 0,
|
SOLUTION_PER_PAGE: 20,
|
||||||
uname: 'Hydro',
|
CONTEST_PER_PAGE: 20,
|
||||||
unameLower: 'hydro',
|
TRAINING_PER_PAGE: 10,
|
||||||
mail: 'hydro@hydro',
|
DISCUSSION_PER_PAGE: 50,
|
||||||
mailLower: 'hydro@hydro',
|
REPLY_PER_PAGE: 50,
|
||||||
role: 'guest',
|
CONTESTS_ON_MAIN: 5,
|
||||||
}, udoc),
|
TRAININGS_ON_MAIN: 5,
|
||||||
defaults({
|
DISCUSSIONS_ON_MAIN: 20,
|
||||||
_id: 1,
|
'smtp.host': '',
|
||||||
mail: 'guest@hydro',
|
'smtp.port': 465,
|
||||||
mailLower: 'guest@hydro',
|
'smtp.from': '',
|
||||||
uname: 'Guest',
|
'smtp.user': '',
|
||||||
unameLower: 'guest',
|
'smtp.pass': '',
|
||||||
role: 'guest',
|
'smtp.secure': false,
|
||||||
}, udoc),
|
'db.ver': 1,
|
||||||
defaults({
|
'listen.https': false,
|
||||||
_id: -1,
|
'listen.port': 8888,
|
||||||
mail: 'root@hydro',
|
'session.keys': ['Hydro'],
|
||||||
mailLower: 'root@hydro',
|
'session.secure': false,
|
||||||
uname: 'Root',
|
'session.saved_expire_seconds': 3600 * 24,
|
||||||
unameLower: 'root',
|
'session.unsaved_expire_seconds': 600,
|
||||||
hash: pwhash.hash('rootroot', salt),
|
changemail_token_expire_seconds: 3600 * 24,
|
||||||
salt,
|
registration_token_expire_seconds: 600,
|
||||||
gravatar: 'root@hydro',
|
};
|
||||||
role: 'root',
|
const tasks = [];
|
||||||
}, udoc),
|
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);
|
await collRole.insertMany(builtin.BUILTIN_ROLES);
|
||||||
console.log('Installed');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { run };
|
module.exports = { run };
|
||||||
+3
-3
@@ -3,15 +3,15 @@ const bus = require('./bus');
|
|||||||
const options = require('../options');
|
const options = require('../options');
|
||||||
|
|
||||||
let mongourl = 'mongodb://';
|
let mongourl = 'mongodb://';
|
||||||
if (options.db.username) mongourl += `${options.db.username}:${options.db.password}@`;
|
if (options.username) mongourl += `${options.username}:${options.password}@`;
|
||||||
mongourl += `${options.db.host}:${options.db.port}/${options.db.name}`;
|
mongourl += `${options.host}:${options.port}/${options.name}`;
|
||||||
/**
|
/**
|
||||||
* @type {import('mongodb').Db}
|
* @type {import('mongodb').Db}
|
||||||
*/
|
*/
|
||||||
let db = null;
|
let db = null;
|
||||||
Mongo.MongoClient.connect(mongourl, { useNewUrlParser: true, useUnifiedTopology: true })
|
Mongo.MongoClient.connect(mongourl, { useNewUrlParser: true, useUnifiedTopology: true })
|
||||||
.then((Database) => {
|
.then((Database) => {
|
||||||
db = Database.db(options.db.name);
|
db = Database.db(options.name);
|
||||||
db.Db = Database;
|
db.Db = Database;
|
||||||
bus.publish('system_database_connected', null);
|
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 };
|
const args = { ...ctx.params, ...ctx.query, ...ctx.request.body };
|
||||||
|
|
||||||
if (h.___prepare) await h.___prepare(args);
|
if (h.___prepare) await h.___prepare(args);
|
||||||
|
try {
|
||||||
for (const l of check) {
|
for (const l of check) {
|
||||||
if (args[l]) {
|
if (args[l]) {
|
||||||
args[l] = new ObjectID(args[l]);
|
args[l] = new ObjectID(args[l]);
|
||||||
if (!args[l]) throw new ValidationError(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);
|
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",
|
"name": "sandbox-linux",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"os": "Linux",
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
"description": "Sandbox service for linux"
|
"description": "Sandbox service for linux"
|
||||||
}
|
}
|
||||||
@@ -2,7 +2,7 @@ const os = require('os');
|
|||||||
const path = require('path');
|
const path = require('path');
|
||||||
const child = require('child_process');
|
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');
|
if (!p.stdout) throw new Error('Cannot start executorserver');
|
||||||
else {
|
else {
|
||||||
p.stdout.on('data', (data) => {
|
p.stdout.on('data', (data) => {
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "hydro",
|
"name": "hydro",
|
||||||
"version": "0.0.0",
|
"version": "1.0.0-preview",
|
||||||
"main": "hydro/development.js",
|
"main": "hydro/development.js",
|
||||||
"repository": "https://github.com/hydro-dev/Hydro.git",
|
"repository": "https://github.com/hydro-dev/Hydro.git",
|
||||||
"author": "masnn",
|
"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