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:
9 files changed
+51
-25
No files matched your search
@@ -465,7 +465,7 @@ ${c.response.status} ${endTime - startTime}ms ${c.response.length}`);
|
|||||||
});
|
});
|
||||||
await new Promise((r) => {
|
await new Promise((r) => {
|
||||||
httpServer.listen(this.config.port, this.config.host || '127.0.0.1', () => {
|
httpServer.listen(this.config.port, this.config.host || '127.0.0.1', () => {
|
||||||
logger.success('Server listening at: %d', this.config.port);
|
logger.success('Server listening at: %c', `${this.config.host || '127.0.0.1'}:${this.config.port}`);
|
||||||
r(true);
|
r(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -685,6 +685,10 @@ ${c.response.status} ${endTime - startTime}ms ${c.response.length}`);
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// if (name === 'ContestScoreboard') {
|
||||||
|
// console.log('-------------', this.ctx, this.ctx.scoreboard);
|
||||||
|
// }
|
||||||
|
|
||||||
if (type === 'route') {
|
if (type === 'route') {
|
||||||
router.all(routeName, path, (ctx) => this.handleHttp(ctx as any, HandlerClass, Checker(permPrivChecker)));
|
router.all(routeName, path, (ctx) => this.handleHttp(ctx as any, HandlerClass, Checker(permPrivChecker)));
|
||||||
} else {
|
} else {
|
||||||
@@ -707,6 +711,7 @@ ${c.response.status} ${endTime - startTime}ms ${c.response.length}`);
|
|||||||
public withHandlerClass<T extends string>(
|
public withHandlerClass<T extends string>(
|
||||||
name: T, callback: (HandlerClass: T extends `${string}ConnectionHandler` ? typeof ConnectionHandler<C> : typeof Handler<C>) => any,
|
name: T, callback: (HandlerClass: T extends `${string}ConnectionHandler` ? typeof ConnectionHandler<C> : typeof Handler<C>) => any,
|
||||||
) {
|
) {
|
||||||
|
name = name.replace(/Handler$/, '') as any;
|
||||||
if (this.registry[name]) callback(this.registry[name]);
|
if (this.registry[name]) callback(this.registry[name]);
|
||||||
// FIXME: should pass type check
|
// FIXME: should pass type check
|
||||||
this.ctx.on(`handler/register/${name}`, callback as any);
|
this.ctx.on(`handler/register/${name}`, callback as any);
|
||||||
@@ -714,6 +719,10 @@ ${c.response.status} ${endTime - startTime}ms ${c.response.length}`);
|
|||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||||
public Route(name: string, path: string, RouteHandler: typeof Handler<C>, ...permPrivChecker) {
|
public Route(name: string, path: string, RouteHandler: typeof Handler<C>, ...permPrivChecker) {
|
||||||
|
// if (name === 'contest_scoreboard') {
|
||||||
|
// console.log('+++', this.ctx);
|
||||||
|
// console.log(this.ctx.scoreboard);
|
||||||
|
// }
|
||||||
return this.register('route', name, path, RouteHandler, ...permPrivChecker);
|
return this.register('route', name, path, RouteHandler, ...permPrivChecker);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,13 +6,19 @@ const { homedir } = require('os');
|
|||||||
const { default: hook } = require('@undefined-moe/require-resolve-hook');
|
const { default: hook } = require('@undefined-moe/require-resolve-hook');
|
||||||
const { bypass } = hook(/^(hydrooj|@hydrooj|cordis|lodash|js-yaml)($|\/)/, (id) => {
|
const { bypass } = hook(/^(hydrooj|@hydrooj|cordis|lodash|js-yaml)($|\/)/, (id) => {
|
||||||
if (id.startsWith('hydrooj/src')) {
|
if (id.startsWith('hydrooj/src')) {
|
||||||
console.log('module require via %s is deprecated.', id);
|
|
||||||
if (process.env.DEV) {
|
if (process.env.DEV) {
|
||||||
console.log(
|
const error = new Error(`module require via ${id} is deprecated.`);
|
||||||
new Error().stack.split('\n')
|
const filter = [
|
||||||
.filter((i) => !i.includes('node:internal') && i.startsWith(' '))
|
'node:diagnostics', 'node:internal',
|
||||||
.join('\n'),
|
'_resolveFilename', 'ignoreModuleNotFoundError',
|
||||||
);
|
'framework/register', '@hydrooj/register',
|
||||||
|
];
|
||||||
|
error.stack = error.stack.split('\n')
|
||||||
|
.filter((i) => !filter.some((f) => i.includes(f)))
|
||||||
|
.join('\n');
|
||||||
|
console.error(error);
|
||||||
|
} else {
|
||||||
|
console.warn('Module require via %s is deprecated.', id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (id.startsWith('hydrooj')) {
|
if (id.startsWith('hydrooj')) {
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ class I18nService extends Service {
|
|||||||
if (languages[0]?.startsWith('en')) {
|
if (languages[0]?.startsWith('en')) {
|
||||||
// For most use cases, source text equals to translated text in English.
|
// For most use cases, source text equals to translated text in English.
|
||||||
// So if it doesn't exist, we should use the original text instead of fallback.
|
// So if it doesn't exist, we should use the original text instead of fallback.
|
||||||
return this.get(str, languages[0]) || this.get(str, 'en') || this.toString();
|
return this.get(str, languages[0]) || this.get(str, 'en') || str.toString();
|
||||||
}
|
}
|
||||||
for (const language of languages.filter(Boolean)) {
|
for (const language of languages.filter(Boolean)) {
|
||||||
const curr = this.get(str, language) || this.get(str, language.split('_')[0])
|
const curr = this.get(str, language) || this.get(str, language.split('_')[0])
|
||||||
|
|||||||
@@ -388,7 +388,7 @@ const oi = buildContestRule({
|
|||||||
score: tsddict[pid]?.score,
|
score: tsddict[pid]?.score,
|
||||||
};
|
};
|
||||||
if (tsddict[pid]?.status === STATUS.STATUS_ACCEPTED) {
|
if (tsddict[pid]?.status === STATUS.STATUS_ACCEPTED) {
|
||||||
if (tsddict[pid].rid.getTimestamp().getTime() - (tsdoc.startAt.getTime() || tdoc.beginAt.getTime())) {
|
if (tsddict[pid].rid.getTimestamp().getTime() - (tsdoc.startAt || tdoc.beginAt).getTime() === meta?.first?.[pid]) {
|
||||||
node.style = 'background-color: rgb(217, 240, 199);';
|
node.style = 'background-color: rgb(217, 240, 199);';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -403,9 +403,9 @@ const oi = buildContestRule({
|
|||||||
const psdict = {};
|
const psdict = {};
|
||||||
const first = {};
|
const first = {};
|
||||||
for (const [, tsdoc] of rankedTsdocs) {
|
for (const [, tsdoc] of rankedTsdocs) {
|
||||||
for (const [pid, detail] of Object.entries(tsdoc.detail)) {
|
for (const [pid, detail] of Object.entries(tsdoc.detail || {})) {
|
||||||
if (detail.status !== STATUS.STATUS_ACCEPTED) continue;
|
if (detail.status !== STATUS.STATUS_ACCEPTED) continue;
|
||||||
const time = detail.rid.getTimestamp().getTime() - (tsdoc.startAt.getTime() || tdoc.beginAt.getTime());
|
const time = detail.rid.getTimestamp().getTime() - (tsdoc.startAt || tdoc.beginAt).getTime();
|
||||||
if (!first[pid] || first[pid] > time) first[pid] = time;
|
if (!first[pid] || first[pid] > time) first[pid] = time;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -222,15 +222,22 @@ export async function apply(ctx: Context) {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
server.wsHandlerMixin((s) => ({
|
server.wsHandlerMixin({
|
||||||
async onerror(err: HydroError) {
|
async onerror(err: HydroError) {
|
||||||
if (![NotFoundError, PrivilegeError, PermissionError].some((i) => err instanceof i) || this.user?._id !== 0) {
|
if (![NotFoundError, PrivilegeError, PermissionError].some((i) => err instanceof i) || this.user?._id !== 0) {
|
||||||
logger.error(`Path:${this.request.path}, User:${this.user?._id}(${this.user?.uname})`);
|
logger.error(`Path:${this.request.path}, User:${this.user?._id}(${this.user?.uname})`);
|
||||||
logger.error(err);
|
logger.error(err);
|
||||||
}
|
}
|
||||||
await s.onerror(err);
|
if (err instanceof UserFacingError) err.stack = this.request.path;
|
||||||
|
this.send({
|
||||||
|
error: {
|
||||||
|
name: err.name,
|
||||||
|
params: err.params || [],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
this.close(4000, err.toString());
|
||||||
},
|
},
|
||||||
}));
|
});
|
||||||
|
|
||||||
on('handler/create', async (h) => {
|
on('handler/create', async (h) => {
|
||||||
h.user = h.context.HydroContext.user as any;
|
h.user = h.context.HydroContext.user as any;
|
||||||
|
|||||||
@@ -274,6 +274,3 @@ export class TemplateService extends Service {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function apply(ctx: Context) {
|
|
||||||
}
|
|
||||||
@@ -155,7 +155,9 @@ class AccountService {
|
|||||||
this.syncing = false;
|
this.syncing = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
async stop() { } // eslint-disable-line @typescript-eslint/no-empty-function
|
async stop() {
|
||||||
|
return this.api?.stop?.();
|
||||||
|
}
|
||||||
|
|
||||||
async main() {
|
async main() {
|
||||||
const res = await this.login();
|
const res = await this.login();
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ export interface IBasicProvider {
|
|||||||
submitProblem(id: string, lang: string, code: string, info: any, next: NextFunction, end: NextFunction): Promise<string | void>;
|
submitProblem(id: string, lang: string, code: string, info: any, next: NextFunction, end: NextFunction): Promise<string | void>;
|
||||||
waitForSubmission(id: string, next: NextFunction, end: NextFunction): Promise<void>;
|
waitForSubmission(id: string, next: NextFunction, end: NextFunction): Promise<void>;
|
||||||
checkStatus?: (onCheckFunc: boolean) => Promise<void>;
|
checkStatus?: (onCheckFunc: boolean) => Promise<void>;
|
||||||
|
stop?: () => Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface BasicProvider {
|
export interface BasicProvider {
|
||||||
|
|||||||
+11
-7
@@ -30,7 +30,10 @@ describe('App', () => {
|
|||||||
}, { timeout: 30000 });
|
}, { timeout: 30000 });
|
||||||
|
|
||||||
const routes = ['/', '/api', '/p', '/contest', '/homework', '/user/1', '/training'];
|
const routes = ['/', '/api', '/p', '/contest', '/homework', '/user/1', '/training'];
|
||||||
routes.forEach((route) => it(`GET ${route}`, () => agent.get(route).expect(200)));
|
for (const route of routes) {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-loop-func
|
||||||
|
it(`GET ${route}`, () => agent.get(route).expect(200));
|
||||||
|
}
|
||||||
|
|
||||||
it('API user', async () => {
|
it('API user', async () => {
|
||||||
await agent.get('/api?{user(id:1){uname}}').expect({ data: { user: { uname: 'Hydro' } } });
|
await agent.get('/api?{user(id:1){uname}}').expect({ data: { user: { uname: 'Hydro' } } });
|
||||||
@@ -63,12 +66,13 @@ describe('App', () => {
|
|||||||
|
|
||||||
const results: Record<string, autocannon.Result> = {};
|
const results: Record<string, autocannon.Result> = {};
|
||||||
if (process.env.BENCHMARK) {
|
if (process.env.BENCHMARK) {
|
||||||
routes.forEach((route) => it(`Performance test ${route}`, { timeout: 60000 }, async () => {
|
for (const route of routes) {
|
||||||
await global.Hydro.model.system.set('limit.global', 99999);
|
it(`Performance test ${route}`, { timeout: 60000 }, async () => {
|
||||||
const result = await autocannon({ url: `http://localhost:8888${route}` });
|
const result = await autocannon({ url: `http://localhost:8888${route}` });
|
||||||
assert(result.errors === 0, `test ${route} returns errors`);
|
assert(result.errors === 0, `test ${route} returns errors`);
|
||||||
results[route] = result;
|
results[route] = result;
|
||||||
}));
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
after(() => {
|
after(() => {
|
||||||
|
|||||||
Reference in new issue
Block a user