支持彩色编译信息输出

This commit is contained in:
undefined committed 2020-06-18 13:14:39 +08:00
1 parent f293e1f59e
commit d040b153a1
18 files changed
+130 -59

No files matched your search

+21 -9
View File
@@ -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,
};
+6 -5
View File
@@ -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;
+6
View File
@@ -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`,
+3 -1
View File
@@ -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]();
+2 -1
View File
@@ -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();
}
}
+1 -1
View File
@@ -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 -1
View File
@@ -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
View File
@@ -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,
};
+1
View File
@@ -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'));
}
}
+9
View File
@@ -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
View File
@@ -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
View File
@@ -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,
-1
View File
@@ -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);
}
+3 -7
View File
@@ -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 = {
+4 -4
View File
@@ -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}` });
}
+2
View File
@@ -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",
+2 -2
View File
@@ -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 %}
+10
View File
@@ -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"