core&ui: add setting provider

This commit is contained in:
undefined committed 2024-01-15 15:58:28 +08:00
1 parent 886fa6821d
commit 5d2ac74b04
10 files changed
+56 -28

No files matched your search

+6 -3
View File
@@ -1,6 +1,6 @@
import * as cordis from 'cordis';
import Schema from 'schemastery';
import { GeoIP, ModuleInterfaces } from './interface';
import type { DomainDoc, GeoIP, ModuleInterfaces } from './interface';
import { inject } from './lib/ui';
import { Loader } from './loader';
import { EventMap } from './service/bus';
@@ -33,14 +33,16 @@ export interface Context {
setImmediate: typeof setImmediate;
addScript: typeof addScript;
provideModule: typeof provideModule;
/** @deprecated use injectUI instead */
inject: typeof inject;
injectUI: typeof inject;
api: ApiMixin;
broadcast: Context['emit'];
geoip?: GeoIP;
}
export class Context extends cordis.Context {
static readonly session = Symbol('session');
domain?: DomainDoc;
}
export namespace Context {
@@ -64,13 +66,14 @@ const T = <F extends (...args: any[]) => any>(origFunc: F, disposeFunc?) =>
this.caller?.on('dispose', () => (disposeFunc ? disposeFunc(res) : res()));
};
export class ApiMixin extends Service {
static readonly methods = ['addScript', 'setInterval', 'setTimeout', 'setImmediate', 'provideModule', 'inject', 'broadcast'];
static readonly methods = ['addScript', 'setInterval', 'setTimeout', 'setImmediate', 'provideModule', 'inject', 'injectUI', 'broadcast'];
addScript = T(addScript);
setInterval = T(setInterval, clearInterval);
setTimeout = T(setTimeout, clearTimeout);
setImmediate = T(setImmediate, clearImmediate);
provideModule = T(provideModule);
inject = T(inject);
injectUI = T(inject);
broadcast = (event: keyof EventMap, ...payload) => this.ctx.emit('bus/broadcast', event, payload);
constructor(ctx) {
super(ctx, 'api', true);
+1 -1
View File
@@ -146,7 +146,7 @@ export class HomeHandler extends Handler {
}
async get({ domainId }) {
const homepageConfig = this.domain.homepage || system.get('hydrooj.homepage');
const homepageConfig = this.ctx.setting.get('hydrooj.homepage');
const info = yaml.load(homepageConfig) as any;
const contents = [];
for (const column of info) {
+5 -2
View File
@@ -170,13 +170,16 @@ export async function load() {
console.warn('DISCLAIMER:');
console.warn(' You are under development mode.');
console.warn(' The Hydro project is licensed under AGPL3,');
console.warn(' which means you have to open source your modifications,');
console.warn(' which means you have to open source all your modifications');
console.warn(' and keep all copyright notice');
console.warn(' unless you have got another license from the original author.');
console.warn('');
console.warn('声明:');
console.warn(' 你正在运行开发者模式。');
console.warn(' Hydro 项目基于 AGPL3 协议开源,');
console.warn(' 这意味着除非你获得了原作者的其他授权,你需要同样以 AGPL3 协议开源所有的修改。');
console.warn(' 这意味着除非你获得了原作者的其他授权,');
console.warn(' 你需要同样以 AGPL3 协议开源所有的修改,');
console.warn(' 并保留所有的版权声明。');
console.warn('\x1b[39m');
console.log('');
console.log('Hydro will start in 5s.');
+4
View File
@@ -315,6 +315,10 @@ export class SettingService extends Service {
constructor(ctx: Context) {
super(ctx, 'setting', true);
}
get(key: string) {
return (this.caller ? this.caller.domain?.config?.[key.replace(/\./g, '$')] : null) ?? global.Hydro.model.system.get(key);
}
}
export async function apply(ctx: Context) {
+23 -7
View File
@@ -23,6 +23,7 @@ import { Types } from '../lib/validator';
import { Logger } from '../logger';
import { PERM, PRIV } from '../model/builtin';
import * as opcount from '../model/opcount';
import * as OplogModel from '../model/oplog';
import * as system from '../model/system';
import { User } from '../model/user';
import { builtinConfig } from '../settings';
@@ -119,9 +120,9 @@ export class HandlerCommon {
url: (name: string, args?: any) => string;
translate: (key: string) => string;
session: Record<string, any>;
ctx: Context;
/** @deprecated */
domainId: string;
ctx: Context = global.app;
constructor(
public context: KoaContext, public readonly args: Record<string, any>,
@@ -134,6 +135,9 @@ export class HandlerCommon {
this.translate = context.translate.bind(context);
this.session = context.session;
this.domainId = args.domainId;
this.ctx = global.app.extend({
domain: this.domain,
});
}
async limitRate(op: string, periodSecs: number, maxOperations: number, withUserId = system.get('limit.by_user')) {
@@ -243,10 +247,11 @@ async function handle(ctx: KoaContext, HandlerClass, checker) {
args, request, response, user, domain, UiContext,
} = ctx.HydroContext;
Object.assign(args, ctx.params);
const init = Date.now();
const h = new HandlerClass(ctx, args, request, response, user, domain, UiContext);
ctx.handler = h;
const method = ctx.method.toLowerCase();
try {
const method = ctx.method.toLowerCase();
const operation = (method === 'post' && ctx.request.body?.operation)
? `_${ctx.request.body.operation}`.replace(/_([a-z])/gm, (s) => s[1].toUpperCase())
: '';
@@ -307,8 +312,16 @@ async function handle(ctx: KoaContext, HandlerClass, checker) {
await h.onerror(e);
} catch (err) {
h.response.code = 500;
h.response.type = 'text/plain';
h.response.body = `${err.message}\n${err.stack}`;
}
} finally {
const finish = Date.now();
if (finish - init > 5000) {
const id = await OplogModel.log(h, 'slow_request', { method, processtime: finish - init });
logger.warn(`Slow handler: ID=${id}, `, method, ctx.path, `${finish - init}ms`);
}
// TODO metrics: calc avg response time
}
}
@@ -532,12 +545,15 @@ export async function apply(pluginContext: Context) {
if (process.env.DEV) {
app.use(async (ctx: Koa.Context, next: Function) => {
const startTime = Date.now();
await next();
const endTime = Date.now();
if (ctx.nolog || ctx.response.headers.nolog) return;
ctx._remoteAddress = ctx.request.ip;
logger.debug(`${ctx.request.method} /${ctx.domainId || 'system'}${ctx.request.path} \
try {
await next();
} finally {
const endTime = Date.now();
if (!(ctx.nolog || ctx.response.headers.nolog)) {
logger.debug(`${ctx.request.method} /${ctx.domainId || 'system'}${ctx.request.path} \
${ctx.response.status} ${endTime - startTime}ms ${ctx.response.length}`);
}
}
});
}
const uploadDir = join(tmpdir(), 'hydro', 'upload', process.env.NODE_APP_INSTANCE || '0');