Skip to content

Commit 9200306

Browse files
committed
impl middlewares and extends
1 parent 9caff19 commit 9200306

File tree

23 files changed

+360
-396
lines changed

23 files changed

+360
-396
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { MiddlewareFunc } from '../../../../src/index.js';
2+
3+
export const hello: MiddlewareFunc = async (ctx, next) => {
4+
ctx.body = 'Hello World!';
5+
console.log(ctx.app.type, ctx.app.server, ctx.app.ctxStorage.getStore()?.performanceStarttime);
6+
console.log(ctx.performanceStarttime);
7+
const res = await ctx.curl('https://eggjs.org');
8+
console.log(res.status);
9+
await next();
10+
};

package.json

+5-8
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,10 @@
2121
"dependencies": {
2222
"@eggjs/cluster": "beta",
2323
"@eggjs/cookies": "^3.0.0",
24-
"@eggjs/core": "^6.1.0",
24+
"@eggjs/core": "^6.2.3",
2525
"@eggjs/schedule": "^5.0.1",
2626
"@eggjs/utils": "^4.0.2",
2727
"@eggjs/watcher": "^4.0.0",
28-
"@types/accepts": "^1.3.5",
29-
"accepts": "^1.3.8",
30-
"cache-content-type": "^2.0.0",
3128
"circular-json-for-egg": "^1.0.0",
3229
"cluster-client": "^3.7.0",
3330
"delegates": "^1.0.0",
@@ -44,13 +41,13 @@
4441
"egg-static": "^2.2.0",
4542
"egg-view": "^2.1.3",
4643
"extend2": "^4.0.0",
47-
"graceful": "^1.1.0",
44+
"graceful": "^2.0.0",
45+
"humanize-ms": "^2.0.0",
4846
"is-type-of": "^2.1.0",
4947
"koa-bodyparser": "^4.4.1",
50-
"koa-is-json": "^1.0.0",
5148
"koa-override": "^4.0.0",
52-
"ms": "^2.1.3",
5349
"onelogger": "^1.0.0",
50+
"performance-ms": "^1.1.0",
5451
"sendmessage": "^3.0.1",
5552
"urllib": "^4.0.0",
5653
"utility": "^2.1.0",
@@ -112,7 +109,7 @@
112109
"license": "MIT",
113110
"egg": {
114111
"framework": true,
115-
"baseDir": {
112+
"exports": {
116113
"import": "./dist/esm",
117114
"require": "./dist/commonjs"
118115
}

src/app/extend/context.ts

+114-101
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,75 @@
1-
import { performance } from 'node:perf_hooks';
21
import delegate from 'delegates';
32
import { assign } from 'utility';
4-
import { utils } from '@eggjs/core';
3+
import { now, diff } from 'performance-ms';
4+
import {
5+
utils, Context as EggCoreContext, Router,
6+
type ContextDelegation as EggCoreContextDelegation,
7+
} from '@eggjs/core';
8+
import type { Cookies as ContextCookies } from '@eggjs/cookies';
9+
import type { Application } from '../../lib/application.js';
10+
import type { ContextHttpClient } from '../../lib/core/context_httpclient.js';
11+
import type { BaseContextClass } from '../../lib//core/base_context_class.js';
12+
import Request from './request.js';
13+
import Response from './response.js';
14+
import { EggLogger } from 'egg-logger';
515

6-
const HELPER = Symbol('Context#helper');
7-
const LOCALS = Symbol('Context#locals');
8-
const LOCALS_LIST = Symbol('Context#localsList');
9-
const COOKIES = Symbol('Context#cookies');
10-
const CONTEXT_LOGGERS = Symbol('Context#logger');
11-
const CONTEXT_HTTPCLIENT = Symbol('Context#httpclient');
12-
const CONTEXT_ROUTER = Symbol('Context#router');
16+
const HELPER = Symbol('ctx helper');
17+
const LOCALS = Symbol('ctx locals');
18+
const LOCALS_LIST = Symbol('ctx localsList');
19+
const COOKIES = Symbol('ctx cookies');
20+
const CONTEXT_HTTPCLIENT = Symbol('ctx httpclient');
21+
const CONTEXT_ROUTER = Symbol('ctx router');
22+
23+
interface Cookies extends ContextCookies {
24+
request: any;
25+
response: any;
26+
}
27+
28+
export default class Context extends EggCoreContext {
29+
declare app: Application;
30+
declare request: Request;
31+
declare service: BaseContextClass;
32+
33+
/**
34+
* Request start time
35+
* @member {Number} Context#starttime
36+
*/
37+
starttime: number;
38+
/**
39+
* Request start timer using `performance.now()`
40+
* @member {Number} Context#performanceStarttime
41+
*/
42+
performanceStarttime: number;
1343

14-
const Context = {
1544
/**
1645
* Get the current visitor's cookies.
1746
*/
1847
get cookies() {
19-
if (!this[COOKIES]) {
20-
this[COOKIES] = new this.app.ContextCookies(this, this.app.keys, this.app.config.cookies);
48+
let cookies = this[COOKIES];
49+
if (!cookies) {
50+
this[COOKIES] = cookies = new this.app.ContextCookies(this, this.app.keys, this.app.config.cookies);
2151
}
22-
return this[COOKIES];
23-
},
52+
return cookies as Cookies;
53+
}
2454

2555
/**
2656
* Get a wrapper httpclient instance contain ctx in the hold request process
2757
*
2858
* @return {ContextHttpClient} the wrapper httpclient instance
2959
*/
30-
get httpclient() {
60+
get httpclient(): ContextHttpClient {
3161
if (!this[CONTEXT_HTTPCLIENT]) {
32-
this[CONTEXT_HTTPCLIENT] = new this.app.ContextHttpClient(this);
62+
this[CONTEXT_HTTPCLIENT] = new this.app.ContextHttpClient(this as any);
3363
}
34-
return this[CONTEXT_HTTPCLIENT];
35-
},
64+
return this[CONTEXT_HTTPCLIENT] as ContextHttpClient;
65+
}
66+
67+
/**
68+
* Alias to {@link Context#httpclient}
69+
*/
70+
get httpClient(): ContextHttpClient {
71+
return this.httpclient;
72+
}
3673

3774
/**
3875
* Shortcut for httpclient.curl
@@ -42,9 +79,9 @@ const Context = {
4279
* @param {Object} [options] - options for request.
4380
* @return {Object} see {@link ContextHttpClient#curl}
4481
*/
45-
curl(url: string, options?: object) {
46-
return this.httpclient.curl(url, options);
47-
},
82+
async curl(url: string, options?: object): ReturnType<ContextHttpClient['curl']> {
83+
return await this.httpclient.curl(url, options);
84+
}
4885

4986
/**
5087
* Alias to {@link Application#router}
@@ -56,20 +93,17 @@ const Context = {
5693
* this.router.pathFor('post', { id: 12 });
5794
* ```
5895
*/
59-
get router() {
60-
if (!this[CONTEXT_ROUTER]) {
61-
this[CONTEXT_ROUTER] = this.app.router;
62-
}
63-
return this[CONTEXT_ROUTER];
64-
},
96+
get router(): Router {
97+
return this.app.router;
98+
}
6599

66100
/**
67101
* Set router to Context, only use on EggRouter
68-
* @param {EggRouter} val router instance
102+
* @param {Router} val router instance
69103
*/
70-
set router(val) {
104+
set router(val: Router) {
71105
this[CONTEXT_ROUTER] = val;
72-
},
106+
}
73107

74108
/**
75109
* Get helper instance from {@link Application#Helper}
@@ -79,64 +113,45 @@ const Context = {
79113
*/
80114
get helper() {
81115
if (!this[HELPER]) {
82-
this[HELPER] = new this.app.Helper(this);
116+
this[HELPER] = new this.app.Helper(this as any);
83117
}
84118
return this[HELPER];
85-
},
119+
}
86120

87121
/**
88122
* Wrap app.loggers with context information,
89123
* if a custom logger is defined by naming aLogger, then you can `ctx.getLogger('aLogger')`
90124
*
91125
* @param {String} name - logger name
92-
* @return {Logger} logger
93126
*/
94-
getLogger(name: string) {
95-
if (this.app.config.logger.enableFastContextLogger) {
96-
return this.app.getLogger(name);
97-
}
98-
let cache = this[CONTEXT_LOGGERS];
99-
if (!cache) {
100-
cache = this[CONTEXT_LOGGERS] = {};
101-
}
102-
103-
// read from cache
104-
if (cache[name]) return cache[name];
105-
106-
// get no exist logger
107-
const appLogger = this.app.getLogger(name);
108-
if (!appLogger) return null;
109-
110-
// write to cache
111-
cache[name] = new this.app.ContextLogger(this, appLogger);
112-
return cache[name];
113-
},
127+
getLogger(name: string): EggLogger {
128+
return this.app.getLogger(name);
129+
}
114130

115131
/**
116-
* Logger for Application, wrapping app.coreLogger with context infomation
132+
* Logger for Application
117133
*
118-
* @member {ContextLogger} Context#logger
134+
* @member {Logger} Context#logger
119135
* @since 1.0.0
120136
* @example
121137
* ```js
122138
* this.logger.info('some request data: %j', this.request.body);
123139
* this.logger.warn('WARNING!!!!');
124140
* ```
125141
*/
126-
get logger() {
142+
get logger(): EggLogger {
127143
return this.getLogger('logger');
128-
},
144+
}
129145

130146
/**
131-
* Logger for frameworks and plugins,
132-
* wrapping app.coreLogger with context infomation
147+
* Logger for frameworks and plugins
133148
*
134-
* @member {ContextLogger} Context#coreLogger
149+
* @member {Logger} Context#coreLogger
135150
* @since 1.0.0
136151
*/
137-
get coreLogger() {
152+
get coreLogger(): EggLogger {
138153
return this.getLogger('coreLogger');
139-
},
154+
}
140155

141156
/**
142157
* locals is an object for view, you can use `app.locals` and `ctx.locals` to set variables,
@@ -169,19 +184,18 @@ const Context = {
169184
if (!this[LOCALS]) {
170185
this[LOCALS] = assign({}, this.app.locals);
171186
}
172-
if (this[LOCALS_LIST] && this[LOCALS_LIST].length) {
187+
if (Array.isArray(this[LOCALS_LIST]) && this[LOCALS_LIST].length > 0) {
173188
assign(this[LOCALS], this[LOCALS_LIST]);
174189
this[LOCALS_LIST] = null;
175190
}
176-
return this[LOCALS];
177-
},
191+
return this[LOCALS] as Record<string, any>;
192+
}
178193

179194
set locals(val) {
180-
if (!this[LOCALS_LIST]) {
181-
this[LOCALS_LIST] = [];
182-
}
183-
this[LOCALS_LIST].push(val);
184-
},
195+
const localsList = this[LOCALS_LIST] as Record<string, any>[] ?? [];
196+
localsList.push(val);
197+
this[LOCALS_LIST] = localsList;
198+
}
185199

186200
/**
187201
* alias to {@link Context#locals}, compatible with koa that use this variable
@@ -190,11 +204,11 @@ const Context = {
190204
*/
191205
get state() {
192206
return this.locals;
193-
},
207+
}
194208

195209
set state(val) {
196210
this.locals = val;
197-
},
211+
}
198212

199213
/**
200214
* Run async function in the background
@@ -208,43 +222,40 @@ const Context = {
208222
* });
209223
* ```
210224
*/
211-
runInBackground(scope: (ctx: any) => Promise<void>) {
225+
runInBackground(scope: (ctx: ContextDelegation) => Promise<void>, taskName?: string): void {
212226
// try to use custom function name first
213-
/* istanbul ignore next */
214-
const taskName = Reflect.get(scope, '_name') || scope.name || utils.getCalleeFromStack(true);
215-
this._runInBackground(scope, taskName);
216-
},
227+
if (!taskName) {
228+
taskName = Reflect.get(scope, '_name') || scope.name || utils.getCalleeFromStack(true);
229+
}
230+
// use setImmediate to ensure all sync logic will run async
231+
setImmediate(() => {
232+
this._runInBackground(scope, taskName!);
233+
});
234+
}
217235

218236
// let plugins or frameworks to reuse _runInBackground in some cases.
219237
// e.g.: https://github.com/eggjs/egg-mock/pull/78
220-
_runInBackground(scope: (ctx: any) => Promise<void>, taskName: string) {
221-
// eslint-disable-next-line @typescript-eslint/no-this-alias
222-
const ctx = this;
223-
const start = performance.now();
224-
// use setImmediate to ensure all sync logic will run async
225-
return new Promise(resolve => setImmediate(resolve))
226-
.then(() => scope(ctx))
227-
.then(() => {
228-
ctx.coreLogger.info('[egg:background] task:%s success (%dms)',
229-
taskName, Math.floor((performance.now() - start) * 1000) / 1000);
230-
})
231-
.catch(err => {
232-
// background task process log
233-
ctx.coreLogger.info('[egg:background] task:%s fail (%dms)',
234-
taskName, Math.floor((performance.now() - start) * 1000) / 1000);
238+
async _runInBackground(scope: (ctx: ContextDelegation) => Promise<void>, taskName: string) {
239+
const startTime = now();
240+
try {
241+
await scope(this as any);
242+
this.coreLogger.info('[egg:background] task:%s success (%dms)', taskName, diff(startTime));
243+
} catch (err: any) {
244+
// background task process log
245+
this.coreLogger.info('[egg:background] task:%s fail (%dms)', taskName, diff(startTime));
235246

236-
// emit error when promise catch, and set err.runInBackground flag
237-
err.runInBackground = true;
238-
ctx.app.emit('error', err, ctx);
239-
});
240-
},
241-
} as any;
247+
// emit error when promise catch, and set err.runInBackground flag
248+
err.runInBackground = true;
249+
this.app.emit('error', err, this);
250+
}
251+
}
252+
}
242253

243254
/**
244255
* Context delegation.
245256
*/
246257

247-
delegate(Context, 'request')
258+
delegate(Context.prototype, 'request')
248259
/**
249260
* @member {Boolean} Context#acceptJSON
250261
* @see Request#acceptJSON
@@ -270,12 +281,14 @@ delegate(Context, 'request')
270281
*/
271282
.access('ip');
272283

273-
delegate(Context, 'response')
284+
delegate(Context.prototype, 'response')
274285
/**
275286
* @member {Number} Context#realStatus
276287
* @see Response#realStatus
277288
* @since 1.0.0
278289
*/
279290
.access('realStatus');
280291

281-
export default Context;
292+
export type ContextDelegation = EggCoreContextDelegation & Context
293+
& Pick<Request, 'acceptJSON' | 'queries' | 'accept' | 'ip'>
294+
& Pick<Response, 'realStatus'>;

0 commit comments

Comments
 (0)