mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-17 09:36:08 +08:00
支持彩色编译信息输出
This commit is contained in:
1 parent
f293e1f59e
commit
d040b153a1
18 files changed
+130
-59
No files matched your search
+21
-9
@@ -2,12 +2,13 @@
|
||||
/* eslint-disable no-eval */
|
||||
const os = require('os');
|
||||
const fs = require('fs');
|
||||
const yaml = require('js-yaml');
|
||||
|
||||
const builtinLib = [
|
||||
'axios', 'download', 'i18n', 'mail', 'markdown',
|
||||
'md5', 'misc', 'paginate', 'hash.hydro', 'rank',
|
||||
'template', 'validator', 'nav', 'sysinfo', 'testdata.convert.ini',
|
||||
'readConfig', 'logger',
|
||||
'readConfig', 'logger', 'useragent',
|
||||
];
|
||||
|
||||
const builtinModel = [
|
||||
@@ -60,17 +61,28 @@ async function locale(pending, fail) {
|
||||
}
|
||||
}
|
||||
|
||||
async function config(pending, fail, system) {
|
||||
async function setting(pending, fail, modelSetting, modelSystem) {
|
||||
const map = {
|
||||
system: modelSetting.SystemSetting,
|
||||
account: modelSetting.AccountSetting,
|
||||
preference: modelSetting.PreferenceSetting,
|
||||
};
|
||||
for (const i of pending) {
|
||||
const p = `${os.tmpdir()}/hydro/tmp/${i}/config.js`;
|
||||
const p = `${os.tmpdir()}/hydro/tmp/${i}/setting.yaml`;
|
||||
if (fs.existsSync(p) && !fail.includes(i)) {
|
||||
try {
|
||||
global.Hydro.config[i] = eval('require')(p);
|
||||
for (const key in global.Hydro.config[i]) {
|
||||
if (global.Hydro.config[i][key].default) {
|
||||
const current = await system.get(`${i}.${key}`);
|
||||
if (!current) await system.set(`${i}.${key}`, global.Hydro.config[i][key].default);
|
||||
const cfg = yaml.safeLoad(fs.readFileSync(p).toString());
|
||||
for (const key in cfg) {
|
||||
if (cfg[key].default && modelSystem) {
|
||||
const current = await modelSystem.get(`${i}.${key}`);
|
||||
if (!current) await modelSystem.set(`${i}.${key}`, cfg[key].default);
|
||||
}
|
||||
map[cfg[key].category || 'system'](
|
||||
modelSetting.Setting(
|
||||
i, `${i}.${key}`, cfg[key].range, cfg[key].default,
|
||||
cfg[key].type || 'text', cfg[key].name || key, cfg[key].desc || '',
|
||||
),
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(`Config Load Fail: ${i}`);
|
||||
@@ -177,5 +189,5 @@ module.exports = {
|
||||
script,
|
||||
service,
|
||||
template,
|
||||
config,
|
||||
setting,
|
||||
};
|
||||
@@ -4,7 +4,7 @@ const os = require('os');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const {
|
||||
lib, service, model, config,
|
||||
lib, service, model, setting,
|
||||
builtinLib, builtinHandler, builtinModel,
|
||||
} = require('./common');
|
||||
|
||||
@@ -61,13 +61,14 @@ async function load(call) {
|
||||
await global.Hydro.model[m].ensureIndexes();
|
||||
}
|
||||
}
|
||||
const system = require('../model/system');
|
||||
const dbVer = await system.get('db.ver');
|
||||
const modelSystem = require('../model/system');
|
||||
const modelSetting = require('../model/setting');
|
||||
const dbVer = await modelSystem.get('db.ver');
|
||||
if (dbVer !== 1) {
|
||||
const ins = require('../script/install');
|
||||
await ins.run({ username: 'Root', password: 'rootroot' });
|
||||
}
|
||||
await config(pending, fail);
|
||||
await setting(pending, fail, modelSetting, modelSystem);
|
||||
for (const i in global.Hydro.service) {
|
||||
if (global.Hydro.service[i].postInit) {
|
||||
try {
|
||||
@@ -78,7 +79,7 @@ async function load(call) {
|
||||
}
|
||||
}
|
||||
pending = [];
|
||||
return { fail, active };
|
||||
return await modelSystem.get('server.worker');
|
||||
}
|
||||
|
||||
module.exports = load;
|
||||
@@ -56,6 +56,12 @@ async function load() {
|
||||
JSON.stringify(m.locale),
|
||||
);
|
||||
}
|
||||
if (m.setting) {
|
||||
fs.writeFileSync(
|
||||
`${os.tmpdir()}/hydro/tmp/${id}/setting.yaml`,
|
||||
m.setting,
|
||||
);
|
||||
}
|
||||
if (m.template) {
|
||||
fs.writeFileSync(
|
||||
`${os.tmpdir()}/hydro/tmp/${id}/template.json`,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* eslint-disable no-await-in-loop */
|
||||
/* eslint-disable import/no-dynamic-require */
|
||||
const {
|
||||
locale, template, lib, service, model, handler, script,
|
||||
locale, template, lib, service, model, handler, script, setting,
|
||||
builtinLib, builtinScript, builtinHandler, builtinModel,
|
||||
} = require('./common');
|
||||
|
||||
@@ -34,6 +34,8 @@ async function load() {
|
||||
for (const i of builtinModel) require(`../model/${i}`);
|
||||
for (const i of builtinHandler) require(`../handler/${i}`);
|
||||
await model(pending, fail);
|
||||
const modelSetting = require('../model/setting');
|
||||
await setting(pending, fail, modelSetting);
|
||||
await handler(pending, fail);
|
||||
for (const i in global.Hydro.handler) {
|
||||
await global.Hydro.handler[i]();
|
||||
|
||||
@@ -33,7 +33,8 @@ class SystemDashboardHandler extends SystemHandler {
|
||||
}
|
||||
|
||||
async postRestart() {
|
||||
process.send({ event: 'restart' });
|
||||
const count = await system.get('server.worker');
|
||||
process.send({ event: 'restart', count });
|
||||
this.back();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,7 +183,7 @@ class ProblemSubmitHandler extends ProblemDetailHandler {
|
||||
user.incDomain(domainId, this.user._id, 'nSubmit'),
|
||||
]);
|
||||
this.response.body = { rid };
|
||||
this.response.redirect = `/r/${rid}`;
|
||||
this.response.redirect = this.url('record_detail', { rid });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
const crypto = require('crypto');
|
||||
|
||||
function hash(password, salt) {
|
||||
return crypto.pbkdf2Sync(password, salt, 100000, 64, 'sha256').toString('hex');
|
||||
return crypto.pbkdf2Sync(password, salt, 100000, 64, 'sha256').toString('hex').substr(0, 64);
|
||||
}
|
||||
|
||||
global.Hydro.lib['hash.hydro'] = module.exports = hash;
|
||||
+9
-1
@@ -1,5 +1,13 @@
|
||||
const ansiup = require('ansi_up');
|
||||
const md5 = require('./md5');
|
||||
|
||||
// eslint-disable-next-line new-cap
|
||||
const AU = new ansiup.default();
|
||||
|
||||
function ansiToHtml(str) {
|
||||
return AU.ansi_to_html(str);
|
||||
}
|
||||
|
||||
function gravatar(email, s = 32) {
|
||||
return `//gravatar.loli.net/avatar/${md5((email || '').toString().trim().toLowerCase())}?d=mm&s=${s}`;
|
||||
}
|
||||
@@ -64,5 +72,5 @@ function formatSeconds(seconds = 0) {
|
||||
}
|
||||
|
||||
global.Hydro.lib.misc = module.exports = {
|
||||
gravatar, datetimeSpan, paginate, size, formatSeconds,
|
||||
gravatar, datetimeSpan, paginate, size, formatSeconds, ansiToHtml,
|
||||
};
|
||||
@@ -23,6 +23,7 @@ class Nunjucks extends nunjucks.Environment {
|
||||
if (safe) return markdown.safe.render(self);
|
||||
return markdown.unsafe.render(self);
|
||||
});
|
||||
this.addFilter('ansi', (self) => misc.ansiToHtml(self));
|
||||
this.addFilter('base64_encode', (s) => Buffer.from(s).toString('base64'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
const browser = require('detect-browser');
|
||||
|
||||
function get(str) {
|
||||
const ua = browser.parseUserAgent(str);
|
||||
console.log(ua);
|
||||
return ua;
|
||||
}
|
||||
|
||||
global.Hydro.lib.useragent = module.exports = get;
|
||||
+12
-11
@@ -2,7 +2,6 @@
|
||||
/* eslint-disable no-await-in-loop */
|
||||
/* eslint-disable no-eval */
|
||||
const cluster = require('cluster');
|
||||
const numCPUs = require('os').cpus().length;
|
||||
|
||||
async function terminate() {
|
||||
for (const task of global.onDestory) {
|
||||
@@ -16,16 +15,17 @@ async function entry(config) {
|
||||
if (config.entry) {
|
||||
// TODO newProcess
|
||||
const loader = require(`./entry/${config.entry}`);
|
||||
await loader(entry);
|
||||
return await loader(entry);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
async function stopWorker() {
|
||||
cluster.disconnect();
|
||||
}
|
||||
|
||||
async function startWorker() {
|
||||
for (let i = 0; i < numCPUs; i++) {
|
||||
async function startWorker(cnt) {
|
||||
for (let i = 0; i < cnt; i++) {
|
||||
cluster.fork();
|
||||
}
|
||||
}
|
||||
@@ -46,7 +46,7 @@ async function messageHandler(worker, msg) {
|
||||
console.log('Restarting');
|
||||
await stopWorker();
|
||||
console.log('Worker stopped');
|
||||
await startWorker();
|
||||
await startWorker(msg.count);
|
||||
} else if (msg.event && msg.event === 'run') {
|
||||
await executeCommand(msg.command);
|
||||
}
|
||||
@@ -74,6 +74,7 @@ async function load() {
|
||||
process.on('unhandledRejection', (e) => console.error(e));
|
||||
process.on('SIGINT', terminate);
|
||||
process.on('message', messageHandler);
|
||||
cluster.on('message', messageHandler);
|
||||
if (cluster.isMaster) {
|
||||
console.log(`Master ${process.pid} Starting`);
|
||||
process.stdin.setEncoding('utf8');
|
||||
@@ -84,20 +85,20 @@ async function load() {
|
||||
executeCommand(input);
|
||||
}
|
||||
});
|
||||
await entry({ entry: 'master' });
|
||||
const cnt = await entry({ entry: 'master' });
|
||||
cluster.on('exit', (worker, code, signal) => {
|
||||
console.log(`Worker ${worker.process.pid} exit: ${code} ${signal}`);
|
||||
console.log(`Worker ${worker.process.pid} ${worker.id} exit: ${code} ${signal}`);
|
||||
});
|
||||
cluster.on('disconnect', (worker) => {
|
||||
console.log(`Worker ${worker.process.pid} disconnected`);
|
||||
console.log(`Worker ${worker.process.pid} ${worker.id} disconnected`);
|
||||
});
|
||||
cluster.on('listening', (worker, address) => {
|
||||
console.log(`Worker ${worker.process.pid} listening at `, address);
|
||||
console.log(`Worker ${worker.process.pid} ${worker.id} listening at `, address);
|
||||
});
|
||||
cluster.on('online', (worker) => {
|
||||
console.log(`Worker ${worker.process.pid} is online`);
|
||||
console.log(`Worker ${worker.process.pid} ${worker.id} is online`);
|
||||
});
|
||||
await startWorker();
|
||||
await startWorker(cnt);
|
||||
} else {
|
||||
console.log(`Worker ${process.pid} Starting`);
|
||||
await entry({ entry: 'worker' });
|
||||
|
||||
+38
-15
@@ -10,6 +10,13 @@ for (const country of countries) {
|
||||
}
|
||||
const timezones = Array.from(tzs).sort().map((tz) => [tz, tz]);
|
||||
|
||||
const PREFERENCE_SETTINGS = [];
|
||||
const ACCOUNT_SETTINGS = [];
|
||||
const SYSTEM_SETTINGS = [];
|
||||
const SETTINGS = [];
|
||||
const SETTINGS_BY_KEY = {};
|
||||
const SYSTEM_SETTINGS_BY_KEY = {};
|
||||
|
||||
const Setting = (
|
||||
family, key, range = null,
|
||||
value = null, ui = 'text', name = '',
|
||||
@@ -18,7 +25,28 @@ const Setting = (
|
||||
family, key, range, value, ui, name, desc,
|
||||
});
|
||||
|
||||
const PREFERENCE_SETTINGS = [
|
||||
const PreferenceSetting = (...settings) => {
|
||||
for (const setting of settings) {
|
||||
PREFERENCE_SETTINGS.push(setting);
|
||||
SETTINGS.push(setting);
|
||||
SETTINGS_BY_KEY[setting.key] = setting;
|
||||
}
|
||||
};
|
||||
const AccountSetting = (...settings) => {
|
||||
for (const setting of settings) {
|
||||
ACCOUNT_SETTINGS.push(setting);
|
||||
SETTINGS.push(setting);
|
||||
SETTINGS_BY_KEY[setting.key] = setting;
|
||||
}
|
||||
};
|
||||
const SystemSetting = (...settings) => {
|
||||
for (const setting of settings) {
|
||||
SYSTEM_SETTINGS.push(setting);
|
||||
SYSTEM_SETTINGS_BY_KEY[setting.key] = setting;
|
||||
}
|
||||
};
|
||||
|
||||
PreferenceSetting(
|
||||
Setting('setting_display', 'viewLang', builtin.VIEW_LANGS.map((i) => [i.code, i.name]),
|
||||
options.default_locale, 'select', 'UI Language'),
|
||||
Setting('setting_display', 'timezone', timezones,
|
||||
@@ -28,9 +56,9 @@ const PREFERENCE_SETTINGS = [
|
||||
Setting('setting_usage', 'codeTemplate', null,
|
||||
null, 'textarea', 'Default Code Template',
|
||||
'If left blank, the built-in template of the corresponding language will be used.'),
|
||||
];
|
||||
);
|
||||
|
||||
const ACCOUNT_SETTINGS = [
|
||||
AccountSetting(
|
||||
Setting('setting_info', 'gravatar', null,
|
||||
null, 'text', 'Gravatar Email',
|
||||
'We use <a href="https://en.gravatar.com/" target="_blank">Gravatar</a> to present your avatar icon.'),
|
||||
@@ -43,14 +71,9 @@ const ACCOUNT_SETTINGS = [
|
||||
Setting('setting_customize', 'backgroundImage', null,
|
||||
'/components/background/profile/backgrounds/1.jpg', 'text', 'Profile Background Image',
|
||||
'Choose the background image in your profile page.'),
|
||||
];
|
||||
);
|
||||
|
||||
const SETTINGS = [...PREFERENCE_SETTINGS, ...ACCOUNT_SETTINGS];
|
||||
const SETTINGS_BY_KEY = {};
|
||||
|
||||
for (const setting of SETTINGS) SETTINGS_BY_KEY[setting.key] = setting;
|
||||
|
||||
const SYSTEM_SETTINGS = [
|
||||
SystemSetting(
|
||||
Setting('setting_basic', 'user.register', null, false, 'checkbox', 'Allow register'),
|
||||
Setting('setting_basic', 'user.create_domain', null, true, 'checkbox', 'Allow domain creation'),
|
||||
Setting('setting_smtp', 'smtp.user', null, null, 'text', 'SMTP Username'),
|
||||
@@ -59,6 +82,7 @@ const SYSTEM_SETTINGS = [
|
||||
Setting('setting_smtp', 'smtp.port', null, 465, 'number', 'SMTP Server Port'),
|
||||
Setting('setting_smtp', 'smtp.from', null, null, 'text', 'Mail From'),
|
||||
Setting('setting_smtp', 'smtp.secure', null, false, 'checkbox', 'SSL'),
|
||||
Setting('setting_server', 'server.worker', null, 1, 'number', 'Server Workers Number'),
|
||||
Setting('setting_server', 'server.hostname', null, null, 'text', 'Server Hostname'),
|
||||
Setting('setting_server', 'server.host', null, null, 'text', 'Server Host'),
|
||||
Setting('setting_server', 'server.url', null, null, 'text', 'Server BaseURL'),
|
||||
@@ -70,14 +94,13 @@ const SYSTEM_SETTINGS = [
|
||||
Setting('setting_constant', 'SOLUTION_PER_PAGE', null, 20, 'number', 'Solutions per Page'),
|
||||
Setting('setting_constant', 'TRAINING_PER_PAGE', null, 10, 'number', 'Training per Page'),
|
||||
Setting('setting_constant', 'REPLY_PER_PAGE', null, 50, 'number', 'Reply per Page'),
|
||||
];
|
||||
|
||||
const SYSTEM_SETTINGS_BY_KEY = {};
|
||||
|
||||
for (const setting of SYSTEM_SETTINGS) SYSTEM_SETTINGS_BY_KEY[setting.key] = setting;
|
||||
);
|
||||
|
||||
global.Hydro.model.setting = module.exports = {
|
||||
Setting,
|
||||
PreferenceSetting,
|
||||
AccountSetting,
|
||||
SystemSetting,
|
||||
PREFERENCE_SETTINGS,
|
||||
ACCOUNT_SETTINGS,
|
||||
SETTINGS,
|
||||
|
||||
@@ -42,7 +42,6 @@ class USER {
|
||||
checkPassword(password) {
|
||||
const h = global.Hydro.lib[`hash.${this.hashType || 'hydro'}`];
|
||||
if (!h) throw new Error('Unknown hash method');
|
||||
console.log(h(password, this.salt(), this), this.hash());
|
||||
if (!(h(password, this.salt(), this) === this.hash())) {
|
||||
throw new LoginError(this.uname);
|
||||
}
|
||||
|
||||
@@ -487,13 +487,9 @@ async function start() {
|
||||
app.use(morgan(':method :url :status :res[content-length] - :response-time ms'));
|
||||
app.use(router.routes()).use(router.allowedMethods());
|
||||
Route('notfound_handler', '*', Handler);
|
||||
if (cluster.worker.id === 1) {
|
||||
const port = await system.get('server.port');
|
||||
server.listen(port);
|
||||
console.log('Server listening at: %s', port);
|
||||
} else {
|
||||
server.listen();
|
||||
}
|
||||
const port = await system.get('server.port');
|
||||
server.listen(port);
|
||||
console.log('Server listening at: %s', port);
|
||||
}
|
||||
|
||||
global.Hydro.service.server = module.exports = {
|
||||
|
||||
@@ -268,10 +268,10 @@ async function domainUser(src, report) {
|
||||
for (const key in doc) {
|
||||
if (typeof mapper[key] === 'string') {
|
||||
d[mapper[key]] = doc[key];
|
||||
} else if (typeof mapper[key] === 'object') {
|
||||
d[mapper[key].field] = mapper[key].processer(doc[key]);
|
||||
} else if (mapper[key] === null) {
|
||||
// Ignore this key
|
||||
} else if (typeof mapper[key] === 'object') {
|
||||
d[mapper[key].field] = mapper[key].processer(doc[key]);
|
||||
} else {
|
||||
await report({ message: `Unknown key ${key} in collection domain.user` });
|
||||
}
|
||||
@@ -348,10 +348,10 @@ async function task(name, src, report) {
|
||||
for (const key in doc) {
|
||||
if (typeof mapper[key] === 'string') {
|
||||
d[mapper[key]] = doc[key];
|
||||
} else if (typeof mapper[key] === 'object') {
|
||||
d[mapper[key].field] = mapper[key].processer(doc[key]);
|
||||
} else if (mapper[key] === null) {
|
||||
// Ignore this key
|
||||
} else if (typeof mapper[key] === 'object') {
|
||||
d[mapper[key].field] = mapper[key].processer(doc[key]);
|
||||
} else {
|
||||
await report({ message: `Unknown key ${key} in collection ${name}` });
|
||||
}
|
||||
|
||||
@@ -7,8 +7,10 @@
|
||||
"license": "GPL-3.0-only",
|
||||
"dependencies": {
|
||||
"adm-zip": "^0.4.14",
|
||||
"ansi_up": "^4.0.4",
|
||||
"axios": "^0.19.0",
|
||||
"bson": "^4.0.2",
|
||||
"detect-browser": "^5.1.1",
|
||||
"js-yaml": "^3.13.1",
|
||||
"koa": "^2.11.0",
|
||||
"koa-body": "^4.1.1",
|
||||
|
||||
@@ -9,12 +9,12 @@
|
||||
</div>
|
||||
{% if rdoc.compilerTexts.length %}
|
||||
<div class="section__body">
|
||||
<pre class="compiler-text">{{ rdoc.compilerTexts|join('\n') }}</pre>
|
||||
<pre class="compiler-text">{{ rdoc.compilerTexts|join('\n')|ansi|safe }}</pre>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if rdoc.judgeTexts.length %}
|
||||
<div class="section__body">
|
||||
<pre class="judge-text">{{ rdoc.judgeTexts|join('\n') }}</pre>
|
||||
<pre class="judge-text">{{ rdoc.judgeTexts|join('\n')|ansi|safe }}</pre>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if rdoc.testCases.length %}
|
||||
|
||||
@@ -316,6 +316,11 @@ ansi-styles@^4.1.0:
|
||||
"@types/color-name" "^1.1.1"
|
||||
color-convert "^2.0.1"
|
||||
|
||||
ansi_up@^4.0.4:
|
||||
version "4.0.4"
|
||||
resolved "https://registry.yarnpkg.com/ansi_up/-/ansi_up-4.0.4.tgz#5b8c35f0b02e4476f3f18cf89c3bf48d15d054f6"
|
||||
integrity sha512-vRxC8q6QY918MbehO869biJW4tiunJdjOhi5fpY6NLOliBQlZhOkKgABJKJqH+JZfb/WfjvjN1chLWI6tODerw==
|
||||
|
||||
any-promise@^1.0.0, any-promise@^1.1.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f"
|
||||
@@ -1142,6 +1147,11 @@ destroy@^1.0.4:
|
||||
resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80"
|
||||
integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=
|
||||
|
||||
detect-browser@^5.1.1:
|
||||
version "5.1.1"
|
||||
resolved "https://registry.yarnpkg.com/detect-browser/-/detect-browser-5.1.1.tgz#a800db91d3fd60d0861669f5984f1be9ffbe009c"
|
||||
integrity sha512-5n2aWI57qC3kZaK4j2zYsG6L1LrxgLptGCNhMQgdKhVn6cSdcq43pp6xHPfTHG3TYM6myF4tIPWiZtfdVDgb9w==
|
||||
|
||||
diffie-hellman@^5.0.0:
|
||||
version "5.0.3"
|
||||
resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875"
|
||||
|
||||
Reference in new issue
Block a user