mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-20 01:38:19 +08:00
bug fixes
This commit is contained in:
11 files changed
+45
-19
No files matched your search
@@ -670,7 +670,6 @@ ${c.response.status} ${endTime - startTime}ms ${c.response.length}`);
|
|||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// error during initialization (prepare, hooks)
|
// error during initialization (prepare, hooks)
|
||||||
logger.error(e);
|
|
||||||
await clean(e);
|
await clean(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-3
@@ -195,6 +195,7 @@ const Caddyfile = `\
|
|||||||
# 仅需将 :80 改为你的域名(如 hydro.ac)后使用 caddy reload 重载配置即可自动签发 ssl 证书。
|
# 仅需将 :80 改为你的域名(如 hydro.ac)后使用 caddy reload 重载配置即可自动签发 ssl 证书。
|
||||||
# 填写完整域名,注意区分有无 www (www.hydro.ac 和 hydro.ac 不同,请检查 DNS 设置)
|
# 填写完整域名,注意区分有无 www (www.hydro.ac 和 hydro.ac 不同,请检查 DNS 设置)
|
||||||
# 请注意在防火墙/安全组中放行端口,且部分运营商会拦截未经备案的域名。
|
# 请注意在防火墙/安全组中放行端口,且部分运营商会拦截未经备案的域名。
|
||||||
|
# 其他需求清参照 https://caddyserver.com/docs/ 说明进行设置。
|
||||||
# For more information, refer to caddy v2 documentation.
|
# For more information, refer to caddy v2 documentation.
|
||||||
:80 {
|
:80 {
|
||||||
encode zstd gzip
|
encode zstd gzip
|
||||||
@@ -242,6 +243,7 @@ hosts:
|
|||||||
uname: judge
|
uname: judge
|
||||||
password: examplepassword
|
password: examplepassword
|
||||||
detail: true
|
detail: true
|
||||||
|
concurrency: 2
|
||||||
tmpfs_size: 512m
|
tmpfs_size: 512m
|
||||||
stdio_size: 256m
|
stdio_size: 256m
|
||||||
memoryMax: ${Math.min(1024, os.totalmem() / 4)}m
|
memoryMax: ${Math.min(1024, os.totalmem() / 4)}m
|
||||||
@@ -253,7 +255,7 @@ parallelism: ${Math.max(1, Math.floor(cpus().length / 4))}
|
|||||||
singleTaskParallelism: 2
|
singleTaskParallelism: 2
|
||||||
rate: 1.00
|
rate: 1.00
|
||||||
rerun: 2
|
rerun: 2
|
||||||
secret: ${String.random(32)}
|
secret: ${crypto.randomBytes(32).toString('hex')}
|
||||||
env: |
|
env: |
|
||||||
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
|
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
|
||||||
HOME=/w
|
HOME=/w
|
||||||
@@ -409,8 +411,8 @@ ${nixConfBase}`);
|
|||||||
const docker = !exec('docker -v').code;
|
const docker = !exec('docker -v').code;
|
||||||
if (!docker) return;
|
if (!docker) return;
|
||||||
const containers = exec('docker ps -a --format json').output?.split('\n')
|
const containers = exec('docker ps -a --format json').output?.split('\n')
|
||||||
.map((i) => i.trim()).filter((i) => i).map((i) => JSON.parse(i));
|
.map((i) => i.trim()).filter((i) => i).map((i) => JSON.parse(i)) || [];
|
||||||
const uoj = containers?.find((i) => i.Image.toLowerCase() === 'universaloj/uoj-system' && i.State === 'running');
|
const uoj = containers.find((i) => i.Image.toLowerCase() === 'universaloj/uoj-system' && i.State === 'running');
|
||||||
if (uoj) {
|
if (uoj) {
|
||||||
log.info('migrate.uojFound');
|
log.info('migrate.uojFound');
|
||||||
const res = await rl.question('>');
|
const res = await rl.question('>');
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ const session: Session = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export async function* apply(ctx: HydroContext) {
|
export async function apply(ctx: HydroContext) {
|
||||||
ctx.inject(['check'], (c) => {
|
ctx.inject(['check'], (c) => {
|
||||||
c.check.addChecker('Judge', async (_ctx, log, warn, error) => {
|
c.check.addChecker('Judge', async (_ctx, log, warn, error) => {
|
||||||
await versionCheck(warn, error);
|
await versionCheck(warn, error);
|
||||||
@@ -75,9 +75,7 @@ export async function* apply(ctx: HydroContext) {
|
|||||||
}
|
}
|
||||||
await (new JudgeTask(session, JSON.parse(JSON.stringify(Object.assign(rdoc, t))))).handle().catch(logger.error);
|
await (new JudgeTask(session, JSON.parse(JSON.stringify(Object.assign(rdoc, t))))).handle().catch(logger.error);
|
||||||
};
|
};
|
||||||
const parallelism = Math.max(getConfig('parallelism'), 2);
|
const parallelism = getConfig('parallelism');
|
||||||
const taskConsumer = TaskModel.consume({ type: 'judge' }, handle, true, parallelism);
|
|
||||||
yield () => taskConsumer.destroy();
|
|
||||||
async function collectInfo() {
|
async function collectInfo() {
|
||||||
const coll = db.collection('status');
|
const coll = db.collection('status');
|
||||||
const compilers = await compilerVersions(langs);
|
const compilers = await compilerVersions(langs);
|
||||||
@@ -93,11 +91,20 @@ export async function* apply(ctx: HydroContext) {
|
|||||||
{ upsert: true },
|
{ upsert: true },
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
yield ctx.on('system/setting', () => {
|
ctx.effect(() => {
|
||||||
taskConsumer.setConcurrency(Math.max(getConfig('parallelism'), 2));
|
const taskConsumer = TaskModel.consume({ type: 'judge' }, handle, true, parallelism);
|
||||||
collectInfo();
|
const dispose = ctx.on('system/setting', () => {
|
||||||
|
taskConsumer.setConcurrency(getConfig('parallelism'));
|
||||||
|
collectInfo();
|
||||||
|
});
|
||||||
|
return () => {
|
||||||
|
taskConsumer.destroy();
|
||||||
|
dispose();
|
||||||
|
};
|
||||||
|
});
|
||||||
|
ctx.effect(() => {
|
||||||
|
const generateConsumer = TaskModel.consume({ type: 'generate' }, handle);
|
||||||
|
return () => generateConsumer.destroy();
|
||||||
});
|
});
|
||||||
collectInfo();
|
collectInfo();
|
||||||
const generateConsumer = TaskModel.consume({ type: 'generate' }, handle);
|
|
||||||
yield () => generateConsumer.destroy();
|
|
||||||
}
|
}
|
||||||
@@ -2,7 +2,6 @@
|
|||||||
/* eslint-disable no-await-in-loop */
|
/* eslint-disable no-await-in-loop */
|
||||||
import '../lib/index';
|
import '../lib/index';
|
||||||
|
|
||||||
import os from 'os';
|
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import fs from 'fs-extra';
|
import fs from 'fs-extra';
|
||||||
import yaml from 'js-yaml';
|
import yaml from 'js-yaml';
|
||||||
|
|||||||
@@ -181,7 +181,6 @@ export class HomeHandler extends Handler {
|
|||||||
class HomeSecurityHandler extends Handler {
|
class HomeSecurityHandler extends Handler {
|
||||||
@requireSudo
|
@requireSudo
|
||||||
async get() {
|
async get() {
|
||||||
const geoip = this.ctx.get('geoip');
|
|
||||||
// TODO(iceboy): pagination? or limit session count for uid?
|
// TODO(iceboy): pagination? or limit session count for uid?
|
||||||
const sessions = await token.getSessionListByUid(this.user._id);
|
const sessions = await token.getSessionListByUid(this.user._id);
|
||||||
for (const session of sessions) {
|
for (const session of sessions) {
|
||||||
@@ -189,7 +188,7 @@ class HomeSecurityHandler extends Handler {
|
|||||||
session._id = md5(session._id);
|
session._id = md5(session._id);
|
||||||
const ua = session.updateUa || session.createUa;
|
const ua = session.updateUa || session.createUa;
|
||||||
if (ua) session.updateUaInfo = UAParser(ua);
|
if (ua) session.updateUaInfo = UAParser(ua);
|
||||||
session.updateGeoip = geoip?.lookup?.(
|
session.updateGeoip = this.ctx.geoip?.lookup?.(
|
||||||
session.updateIp || session.createIp,
|
session.updateIp || session.createIp,
|
||||||
this.translate('geoip_locale'),
|
this.translate('geoip_locale'),
|
||||||
);
|
);
|
||||||
@@ -202,7 +201,7 @@ class HomeSecurityHandler extends Handler {
|
|||||||
'credentialID', 'name', 'credentialType', 'credentialDeviceType',
|
'credentialID', 'name', 'credentialType', 'credentialDeviceType',
|
||||||
'authenticatorAttachment', 'regat', 'fmt',
|
'authenticatorAttachment', 'regat', 'fmt',
|
||||||
])),
|
])),
|
||||||
geoipProvider: geoip?.provider,
|
geoipProvider: this.ctx.geoip?.provider,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -610,6 +609,7 @@ class HomeMessagesConnectionHandler extends ConnectionHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const inject = { geoip: { required: false } };
|
||||||
export function apply(ctx: Context) {
|
export function apply(ctx: Context) {
|
||||||
ctx.Route('homepage', '/', HomeHandler);
|
ctx.Route('homepage', '/', HomeHandler);
|
||||||
ctx.Route('home_security', '/home/security', HomeSecurityHandler, PRIV.PRIV_USER_PROFILE);
|
ctx.Route('home_security', '/home/security', HomeSecurityHandler, PRIV.PRIV_USER_PROFILE);
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ declare module '../service/bus' {
|
|||||||
class I18nService extends Service {
|
class I18nService extends Service {
|
||||||
constructor(ctx: Context) {
|
constructor(ctx: Context) {
|
||||||
super(ctx, 'i18n');
|
super(ctx, 'i18n');
|
||||||
|
this.translate = this.translate.bind(this);
|
||||||
this.load('ja', { __flag: '🇯🇵', __id: 'ja', __langname: '日本語' });
|
this.load('ja', { __flag: '🇯🇵', __id: 'ja', __langname: '日本語' });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -304,6 +304,7 @@ export default async function (env: { watch?: boolean, production?: boolean, mea
|
|||||||
}),
|
}),
|
||||||
new webpack.NormalModuleReplacementPlugin(/\/(vscode-)?nls\.js/, require.resolve('../../components/monaco/nls')),
|
new webpack.NormalModuleReplacementPlugin(/\/(vscode-)?nls\.js/, require.resolve('../../components/monaco/nls')),
|
||||||
new webpack.NormalModuleReplacementPlugin(/^prettier[$/]/, root('../../modules/nop.ts')),
|
new webpack.NormalModuleReplacementPlugin(/^prettier[$/]/, root('../../modules/nop.ts')),
|
||||||
|
new webpack.NormalModuleReplacementPlugin(/^highlightjs[$/]/, root('../../modules/nop.ts')),
|
||||||
new webpack.NormalModuleReplacementPlugin(/core-js\/stable/, root('__core-js.js')),
|
new webpack.NormalModuleReplacementPlugin(/core-js\/stable/, root('__core-js.js')),
|
||||||
new MonacoWebpackPlugin({
|
new MonacoWebpackPlugin({
|
||||||
filename: '[name].[hash:6].worker.js',
|
filename: '[name].[hash:6].worker.js',
|
||||||
|
|||||||
@@ -1,3 +1,10 @@
|
|||||||
.decoration-hide
|
.decoration-hide
|
||||||
color: grey !important
|
color: grey !important
|
||||||
background-color: grey !important
|
background-color: grey !important
|
||||||
|
|
||||||
|
.md-editor-preview code
|
||||||
|
background-color: unset !important
|
||||||
|
color: unset !important
|
||||||
|
|
||||||
|
.md-editor-scrn pre.syntax-hl code
|
||||||
|
padding-left: unset !important
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
import $ from 'jquery';
|
import $ from 'jquery';
|
||||||
|
import { debounce } from 'lodash';
|
||||||
import { nanoid } from 'nanoid';
|
import { nanoid } from 'nanoid';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ReactDOM from 'react-dom/client';
|
import ReactDOM from 'react-dom/client';
|
||||||
@@ -156,8 +157,12 @@ export default class Editor extends DOMAttachedObject {
|
|||||||
const { onChange } = this.options;
|
const { onChange } = this.options;
|
||||||
const { MdEditor } = await import('./mdeditor');
|
const { MdEditor } = await import('./mdeditor');
|
||||||
|
|
||||||
|
const debouncedTrigger = debounce(() => {
|
||||||
|
$(document.querySelector('.md-editor-preview')).trigger('vjContentNew');
|
||||||
|
}, 500, { trailing: true });
|
||||||
const renderCallback = (ref) => {
|
const renderCallback = (ref) => {
|
||||||
this.markdownEditor = ref;
|
this.markdownEditor = ref;
|
||||||
|
setTimeout(debouncedTrigger, 200);
|
||||||
};
|
};
|
||||||
|
|
||||||
function EditorComponent() {
|
function EditorComponent() {
|
||||||
@@ -169,10 +174,12 @@ export default class Editor extends DOMAttachedObject {
|
|||||||
codeTheme='github'
|
codeTheme='github'
|
||||||
codeStyleReverse={false}
|
codeStyleReverse={false}
|
||||||
ref={renderCallback}
|
ref={renderCallback}
|
||||||
modelValue={val}
|
value={val}
|
||||||
theme={getTheme()}
|
theme={getTheme()}
|
||||||
noMermaid
|
noMermaid
|
||||||
noPrettier
|
noPrettier
|
||||||
|
noKatex
|
||||||
|
noHighlight
|
||||||
autoDetectCode
|
autoDetectCode
|
||||||
toolbarsExclude={[
|
toolbarsExclude={[
|
||||||
// 'bold',
|
// 'bold',
|
||||||
@@ -214,6 +221,7 @@ export default class Editor extends DOMAttachedObject {
|
|||||||
$dom.val(v);
|
$dom.val(v);
|
||||||
$dom.text(v);
|
$dom.text(v);
|
||||||
onChange?.(v);
|
onChange?.(v);
|
||||||
|
setTimeout(debouncedTrigger, 100);
|
||||||
}}
|
}}
|
||||||
onUploadImg={async (files, callback) => {
|
onUploadImg={async (files, callback) => {
|
||||||
let ext: string;
|
let ext: string;
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import MergeCells from 'markdown-it-merge-cells';
|
|||||||
import TOC from 'markdown-it-table-of-contents';
|
import TOC from 'markdown-it-table-of-contents';
|
||||||
import { config, MdEditor } from 'md-editor-rt';
|
import { config, MdEditor } from 'md-editor-rt';
|
||||||
import Imsize from '../../backendlib/markdown-it-imsize';
|
import Imsize from '../../backendlib/markdown-it-imsize';
|
||||||
|
import katex from '../../backendlib/markdown-it-katex';
|
||||||
import { Media } from '../../backendlib/markdown-it-media';
|
import { Media } from '../../backendlib/markdown-it-media';
|
||||||
import { xssProtector } from '../../backendlib/markdown-it-xss';
|
import { xssProtector } from '../../backendlib/markdown-it-xss';
|
||||||
|
|
||||||
@@ -28,6 +29,7 @@ config({
|
|||||||
mdit.use(TOC);
|
mdit.use(TOC);
|
||||||
mdit.use(MergeCells);
|
mdit.use(MergeCells);
|
||||||
mdit.use(xssProtector);
|
mdit.use(xssProtector);
|
||||||
|
mdit.use(katex);
|
||||||
if (isProblemPage) {
|
if (isProblemPage) {
|
||||||
mdit.core.ruler.before('normalize', 'xss', (state) => {
|
mdit.core.ruler.before('normalize', 'xss', (state) => {
|
||||||
state.src = state.src.replace(/file:\/\//g, pagename === 'problem_create' ? `/file/${UserContext._id}/` : './file/');
|
state.src = state.src.replace(/file:\/\//g, pagename === 'problem_create' ? `/file/${UserContext._id}/` : './file/');
|
||||||
|
|||||||
@@ -45,7 +45,7 @@
|
|||||||
label:'Difficulty',
|
label:'Difficulty',
|
||||||
help_text:'From 1-10',
|
help_text:'From 1-10',
|
||||||
name:'difficulty',
|
name:'difficulty',
|
||||||
value:pdoc['difficulty']
|
value:pdoc['difficulty'] or ''
|
||||||
}) }}
|
}) }}
|
||||||
</div>
|
</div>
|
||||||
<div class="section__tab-container nojs--hide">
|
<div class="section__tab-container nojs--hide">
|
||||||
|
|||||||
Reference in new issue
Block a user