Skip to content

Commit

Permalink
impl middlewares and extends
Browse files Browse the repository at this point in the history
  • Loading branch information
fengmk2 committed Dec 19, 2024
1 parent 9caff19 commit 9200306
Show file tree
Hide file tree
Showing 23 changed files with 360 additions and 396 deletions.
10 changes: 10 additions & 0 deletions example/helloworld-typescript/app/middleware/hello.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { MiddlewareFunc } from '../../../../src/index.js';

export const hello: MiddlewareFunc = async (ctx, next) => {
ctx.body = 'Hello World!';
console.log(ctx.app.type, ctx.app.server, ctx.app.ctxStorage.getStore()?.performanceStarttime);
console.log(ctx.performanceStarttime);
const res = await ctx.curl('https://eggjs.org');
console.log(res.status);
await next();
};
13 changes: 5 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,10 @@
"dependencies": {
"@eggjs/cluster": "beta",
"@eggjs/cookies": "^3.0.0",
"@eggjs/core": "^6.1.0",
"@eggjs/core": "^6.2.3",
"@eggjs/schedule": "^5.0.1",
"@eggjs/utils": "^4.0.2",
"@eggjs/watcher": "^4.0.0",
"@types/accepts": "^1.3.5",
"accepts": "^1.3.8",
"cache-content-type": "^2.0.0",
"circular-json-for-egg": "^1.0.0",
"cluster-client": "^3.7.0",
"delegates": "^1.0.0",
Expand All @@ -44,13 +41,13 @@
"egg-static": "^2.2.0",
"egg-view": "^2.1.3",
"extend2": "^4.0.0",
"graceful": "^1.1.0",
"graceful": "^2.0.0",
"humanize-ms": "^2.0.0",
"is-type-of": "^2.1.0",
"koa-bodyparser": "^4.4.1",
"koa-is-json": "^1.0.0",
"koa-override": "^4.0.0",
"ms": "^2.1.3",
"onelogger": "^1.0.0",
"performance-ms": "^1.1.0",
"sendmessage": "^3.0.1",
"urllib": "^4.0.0",
"utility": "^2.1.0",
Expand Down Expand Up @@ -112,7 +109,7 @@
"license": "MIT",
"egg": {
"framework": true,
"baseDir": {
"exports": {
"import": "./dist/esm",
"require": "./dist/commonjs"
}
Expand Down
215 changes: 114 additions & 101 deletions src/app/extend/context.ts
Original file line number Diff line number Diff line change
@@ -1,38 +1,75 @@
import { performance } from 'node:perf_hooks';
import delegate from 'delegates';
import { assign } from 'utility';
import { utils } from '@eggjs/core';
import { now, diff } from 'performance-ms';
import {
utils, Context as EggCoreContext, Router,
type ContextDelegation as EggCoreContextDelegation,
} from '@eggjs/core';
import type { Cookies as ContextCookies } from '@eggjs/cookies';
import type { Application } from '../../lib/application.js';
import type { ContextHttpClient } from '../../lib/core/context_httpclient.js';
import type { BaseContextClass } from '../../lib//core/base_context_class.js';
import Request from './request.js';
import Response from './response.js';
import { EggLogger } from 'egg-logger';

const HELPER = Symbol('Context#helper');
const LOCALS = Symbol('Context#locals');
const LOCALS_LIST = Symbol('Context#localsList');
const COOKIES = Symbol('Context#cookies');
const CONTEXT_LOGGERS = Symbol('Context#logger');
const CONTEXT_HTTPCLIENT = Symbol('Context#httpclient');
const CONTEXT_ROUTER = Symbol('Context#router');
const HELPER = Symbol('ctx helper');
const LOCALS = Symbol('ctx locals');
const LOCALS_LIST = Symbol('ctx localsList');
const COOKIES = Symbol('ctx cookies');
const CONTEXT_HTTPCLIENT = Symbol('ctx httpclient');
const CONTEXT_ROUTER = Symbol('ctx router');

interface Cookies extends ContextCookies {
request: any;
response: any;
}

export default class Context extends EggCoreContext {
declare app: Application;
declare request: Request;
declare service: BaseContextClass;

/**
* Request start time
* @member {Number} Context#starttime
*/
starttime: number;
/**
* Request start timer using `performance.now()`
* @member {Number} Context#performanceStarttime
*/
performanceStarttime: number;

Check warning on line 42 in src/app/extend/context.ts

View check run for this annotation

Codecov / codecov/patch

src/app/extend/context.ts#L29-L42

Added lines #L29 - L42 were not covered by tests

const Context = {
/**
* Get the current visitor's cookies.
*/
get cookies() {
if (!this[COOKIES]) {
this[COOKIES] = new this.app.ContextCookies(this, this.app.keys, this.app.config.cookies);
let cookies = this[COOKIES];
if (!cookies) {
this[COOKIES] = cookies = new this.app.ContextCookies(this, this.app.keys, this.app.config.cookies);

Check warning on line 50 in src/app/extend/context.ts

View check run for this annotation

Codecov / codecov/patch

src/app/extend/context.ts#L48-L50

Added lines #L48 - L50 were not covered by tests
}
return this[COOKIES];
},
return cookies as Cookies;
}

Check warning on line 53 in src/app/extend/context.ts

View check run for this annotation

Codecov / codecov/patch

src/app/extend/context.ts#L52-L53

Added lines #L52 - L53 were not covered by tests

/**
* Get a wrapper httpclient instance contain ctx in the hold request process
*
* @return {ContextHttpClient} the wrapper httpclient instance
*/
get httpclient() {
get httpclient(): ContextHttpClient {

Check warning on line 60 in src/app/extend/context.ts

View check run for this annotation

Codecov / codecov/patch

src/app/extend/context.ts#L60

Added line #L60 was not covered by tests
if (!this[CONTEXT_HTTPCLIENT]) {
this[CONTEXT_HTTPCLIENT] = new this.app.ContextHttpClient(this);
this[CONTEXT_HTTPCLIENT] = new this.app.ContextHttpClient(this as any);

Check warning on line 62 in src/app/extend/context.ts

View check run for this annotation

Codecov / codecov/patch

src/app/extend/context.ts#L62

Added line #L62 was not covered by tests
}
return this[CONTEXT_HTTPCLIENT];
},
return this[CONTEXT_HTTPCLIENT] as ContextHttpClient;
}

/**
* Alias to {@link Context#httpclient}
*/
get httpClient(): ContextHttpClient {
return this.httpclient;
}

Check warning on line 72 in src/app/extend/context.ts

View check run for this annotation

Codecov / codecov/patch

src/app/extend/context.ts#L64-L72

Added lines #L64 - L72 were not covered by tests

/**
* Shortcut for httpclient.curl
Expand All @@ -42,9 +79,9 @@ const Context = {
* @param {Object} [options] - options for request.
* @return {Object} see {@link ContextHttpClient#curl}
*/
curl(url: string, options?: object) {
return this.httpclient.curl(url, options);
},
async curl(url: string, options?: object): ReturnType<ContextHttpClient['curl']> {
return await this.httpclient.curl(url, options);
}

Check warning on line 84 in src/app/extend/context.ts

View check run for this annotation

Codecov / codecov/patch

src/app/extend/context.ts#L82-L84

Added lines #L82 - L84 were not covered by tests

/**
* Alias to {@link Application#router}
Expand All @@ -56,20 +93,17 @@ const Context = {
* this.router.pathFor('post', { id: 12 });
* ```
*/
get router() {
if (!this[CONTEXT_ROUTER]) {
this[CONTEXT_ROUTER] = this.app.router;
}
return this[CONTEXT_ROUTER];
},
get router(): Router {
return this.app.router;
}

Check warning on line 98 in src/app/extend/context.ts

View check run for this annotation

Codecov / codecov/patch

src/app/extend/context.ts#L96-L98

Added lines #L96 - L98 were not covered by tests

/**
* Set router to Context, only use on EggRouter
* @param {EggRouter} val router instance
* @param {Router} val router instance

Check warning on line 102 in src/app/extend/context.ts

View check run for this annotation

Codecov / codecov/patch

src/app/extend/context.ts#L102

Added line #L102 was not covered by tests
*/
set router(val) {
set router(val: Router) {

Check warning on line 104 in src/app/extend/context.ts

View check run for this annotation

Codecov / codecov/patch

src/app/extend/context.ts#L104

Added line #L104 was not covered by tests
this[CONTEXT_ROUTER] = val;
},
}

Check warning on line 106 in src/app/extend/context.ts

View check run for this annotation

Codecov / codecov/patch

src/app/extend/context.ts#L106

Added line #L106 was not covered by tests

/**
* Get helper instance from {@link Application#Helper}
Expand All @@ -79,64 +113,45 @@ const Context = {
*/
get helper() {
if (!this[HELPER]) {
this[HELPER] = new this.app.Helper(this);
this[HELPER] = new this.app.Helper(this as any);

Check warning on line 116 in src/app/extend/context.ts

View check run for this annotation

Codecov / codecov/patch

src/app/extend/context.ts#L116

Added line #L116 was not covered by tests
}
return this[HELPER];
},
}

Check warning on line 119 in src/app/extend/context.ts

View check run for this annotation

Codecov / codecov/patch

src/app/extend/context.ts#L119

Added line #L119 was not covered by tests

/**
* Wrap app.loggers with context information,

Check warning on line 122 in src/app/extend/context.ts

View check run for this annotation

Codecov / codecov/patch

src/app/extend/context.ts#L122

Added line #L122 was not covered by tests
* if a custom logger is defined by naming aLogger, then you can `ctx.getLogger('aLogger')`
*
* @param {String} name - logger name
* @return {Logger} logger
*/
getLogger(name: string) {
if (this.app.config.logger.enableFastContextLogger) {
return this.app.getLogger(name);
}
let cache = this[CONTEXT_LOGGERS];
if (!cache) {
cache = this[CONTEXT_LOGGERS] = {};
}

// read from cache
if (cache[name]) return cache[name];

// get no exist logger
const appLogger = this.app.getLogger(name);
if (!appLogger) return null;

// write to cache
cache[name] = new this.app.ContextLogger(this, appLogger);
return cache[name];
},
getLogger(name: string): EggLogger {
return this.app.getLogger(name);
}

Check warning on line 129 in src/app/extend/context.ts

View check run for this annotation

Codecov / codecov/patch

src/app/extend/context.ts#L127-L129

Added lines #L127 - L129 were not covered by tests

/**
* Logger for Application, wrapping app.coreLogger with context infomation
* Logger for Application

Check warning on line 132 in src/app/extend/context.ts

View check run for this annotation

Codecov / codecov/patch

src/app/extend/context.ts#L132

Added line #L132 was not covered by tests
*
* @member {ContextLogger} Context#logger
* @member {Logger} Context#logger

Check warning on line 134 in src/app/extend/context.ts

View check run for this annotation

Codecov / codecov/patch

src/app/extend/context.ts#L134

Added line #L134 was not covered by tests
* @since 1.0.0
* @example
* ```js
* this.logger.info('some request data: %j', this.request.body);
* this.logger.warn('WARNING!!!!');
* ```
*/
get logger() {
get logger(): EggLogger {

Check warning on line 142 in src/app/extend/context.ts

View check run for this annotation

Codecov / codecov/patch

src/app/extend/context.ts#L142

Added line #L142 was not covered by tests
return this.getLogger('logger');
},
}

Check warning on line 144 in src/app/extend/context.ts

View check run for this annotation

Codecov / codecov/patch

src/app/extend/context.ts#L144

Added line #L144 was not covered by tests

/**
* Logger for frameworks and plugins,
* wrapping app.coreLogger with context infomation
* Logger for frameworks and plugins

Check warning on line 147 in src/app/extend/context.ts

View check run for this annotation

Codecov / codecov/patch

src/app/extend/context.ts#L147

Added line #L147 was not covered by tests
*
* @member {ContextLogger} Context#coreLogger
* @member {Logger} Context#coreLogger

Check warning on line 149 in src/app/extend/context.ts

View check run for this annotation

Codecov / codecov/patch

src/app/extend/context.ts#L149

Added line #L149 was not covered by tests
* @since 1.0.0
*/
get coreLogger() {
get coreLogger(): EggLogger {

Check warning on line 152 in src/app/extend/context.ts

View check run for this annotation

Codecov / codecov/patch

src/app/extend/context.ts#L152

Added line #L152 was not covered by tests
return this.getLogger('coreLogger');
},
}

Check warning on line 154 in src/app/extend/context.ts

View check run for this annotation

Codecov / codecov/patch

src/app/extend/context.ts#L154

Added line #L154 was not covered by tests

/**
* locals is an object for view, you can use `app.locals` and `ctx.locals` to set variables,
Expand Down Expand Up @@ -169,19 +184,18 @@ const Context = {
if (!this[LOCALS]) {
this[LOCALS] = assign({}, this.app.locals);
}
if (this[LOCALS_LIST] && this[LOCALS_LIST].length) {
if (Array.isArray(this[LOCALS_LIST]) && this[LOCALS_LIST].length > 0) {

Check warning on line 187 in src/app/extend/context.ts

View check run for this annotation

Codecov / codecov/patch

src/app/extend/context.ts#L187

Added line #L187 was not covered by tests
assign(this[LOCALS], this[LOCALS_LIST]);
this[LOCALS_LIST] = null;
}
return this[LOCALS];
},
return this[LOCALS] as Record<string, any>;
}

Check warning on line 192 in src/app/extend/context.ts

View check run for this annotation

Codecov / codecov/patch

src/app/extend/context.ts#L191-L192

Added lines #L191 - L192 were not covered by tests

set locals(val) {
if (!this[LOCALS_LIST]) {
this[LOCALS_LIST] = [];
}
this[LOCALS_LIST].push(val);
},
const localsList = this[LOCALS_LIST] as Record<string, any>[] ?? [];
localsList.push(val);
this[LOCALS_LIST] = localsList;
}

Check warning on line 198 in src/app/extend/context.ts

View check run for this annotation

Codecov / codecov/patch

src/app/extend/context.ts#L195-L198

Added lines #L195 - L198 were not covered by tests

/**
* alias to {@link Context#locals}, compatible with koa that use this variable
Expand All @@ -190,11 +204,11 @@ const Context = {
*/
get state() {
return this.locals;
},
}

Check warning on line 207 in src/app/extend/context.ts

View check run for this annotation

Codecov / codecov/patch

src/app/extend/context.ts#L207

Added line #L207 was not covered by tests

set state(val) {
this.locals = val;
},
}

Check warning on line 211 in src/app/extend/context.ts

View check run for this annotation

Codecov / codecov/patch

src/app/extend/context.ts#L211

Added line #L211 was not covered by tests

/**
* Run async function in the background
Expand All @@ -208,43 +222,40 @@ const Context = {
* });
* ```
*/
runInBackground(scope: (ctx: any) => Promise<void>) {
runInBackground(scope: (ctx: ContextDelegation) => Promise<void>, taskName?: string): void {

Check warning on line 225 in src/app/extend/context.ts

View check run for this annotation

Codecov / codecov/patch

src/app/extend/context.ts#L225

Added line #L225 was not covered by tests
// try to use custom function name first
/* istanbul ignore next */
const taskName = Reflect.get(scope, '_name') || scope.name || utils.getCalleeFromStack(true);
this._runInBackground(scope, taskName);
},
if (!taskName) {
taskName = Reflect.get(scope, '_name') || scope.name || utils.getCalleeFromStack(true);
}
// use setImmediate to ensure all sync logic will run async
setImmediate(() => {
this._runInBackground(scope, taskName!);
});
}

Check warning on line 234 in src/app/extend/context.ts

View check run for this annotation

Codecov / codecov/patch

src/app/extend/context.ts#L227-L234

Added lines #L227 - L234 were not covered by tests

// let plugins or frameworks to reuse _runInBackground in some cases.
// e.g.: /~https://github.com/eggjs/egg-mock/pull/78
_runInBackground(scope: (ctx: any) => Promise<void>, taskName: string) {
// eslint-disable-next-line @typescript-eslint/no-this-alias
const ctx = this;
const start = performance.now();
// use setImmediate to ensure all sync logic will run async
return new Promise(resolve => setImmediate(resolve))
.then(() => scope(ctx))
.then(() => {
ctx.coreLogger.info('[egg:background] task:%s success (%dms)',
taskName, Math.floor((performance.now() - start) * 1000) / 1000);
})
.catch(err => {
// background task process log
ctx.coreLogger.info('[egg:background] task:%s fail (%dms)',
taskName, Math.floor((performance.now() - start) * 1000) / 1000);
async _runInBackground(scope: (ctx: ContextDelegation) => Promise<void>, taskName: string) {
const startTime = now();
try {
await scope(this as any);
this.coreLogger.info('[egg:background] task:%s success (%dms)', taskName, diff(startTime));
} catch (err: any) {
// background task process log
this.coreLogger.info('[egg:background] task:%s fail (%dms)', taskName, diff(startTime));

Check warning on line 245 in src/app/extend/context.ts

View check run for this annotation

Codecov / codecov/patch

src/app/extend/context.ts#L238-L245

Added lines #L238 - L245 were not covered by tests

// emit error when promise catch, and set err.runInBackground flag
err.runInBackground = true;
ctx.app.emit('error', err, ctx);
});
},
} as any;
// emit error when promise catch, and set err.runInBackground flag
err.runInBackground = true;
this.app.emit('error', err, this);
}
}
}

Check warning on line 252 in src/app/extend/context.ts

View check run for this annotation

Codecov / codecov/patch

src/app/extend/context.ts#L247-L252

Added lines #L247 - L252 were not covered by tests

/**
* Context delegation.
*/

delegate(Context, 'request')
delegate(Context.prototype, 'request')
/**
* @member {Boolean} Context#acceptJSON
* @see Request#acceptJSON
Expand All @@ -270,12 +281,14 @@ delegate(Context, 'request')
*/
.access('ip');

delegate(Context, 'response')
delegate(Context.prototype, 'response')
/**
* @member {Number} Context#realStatus
* @see Response#realStatus
* @since 1.0.0
*/
.access('realStatus');

export default Context;
export type ContextDelegation = EggCoreContextDelegation & Context
& Pick<Request, 'acceptJSON' | 'queries' | 'accept' | 'ip'>
& Pick<Response, 'realStatus'>;
Loading

0 comments on commit 9200306

Please sign in to comment.