typespeed 2.5.0 → 2.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +2 -0
- package/README.en.md +169 -0
- package/README.md +123 -37
- package/dist/default/rabbitmq.class.js +18 -1
- package/dist/default/redis.class.js +14 -1
- package/dist/default/socket-io.class.js +53 -4
- package/dist/typespeed.d.ts +7 -7
- package/package.json +7 -2
- package/.github/workflows/test.yml +0 -50
- package/app/nodemon.json +0 -5
- package/app/package.json +0 -17
- package/app/src/aop-test.class.ts +0 -29
- package/app/src/config-development.json +0 -26
- package/app/src/config-production.json +0 -15
- package/app/src/config.json +0 -50
- package/app/src/custom-log.class.ts +0 -33
- package/app/src/entities/mutil-users.class.ts +0 -5
- package/app/src/entities/user-dto.class.ts +0 -3
- package/app/src/first-page.class.ts +0 -46
- package/app/src/jwt-authentication.class.ts +0 -30
- package/app/src/main.ts +0 -24
- package/app/src/second-page.class.ts +0 -43
- package/app/src/test-bind.class.ts +0 -41
- package/app/src/test-database.class.ts +0 -81
- package/app/src/test-log.class.ts +0 -11
- package/app/src/test-mq.class.ts +0 -21
- package/app/src/test-orm.class.ts +0 -63
- package/app/src/test-redis.class.ts +0 -45
- package/app/src/test-request.class.ts +0 -37
- package/app/src/test-socket.class.ts +0 -56
- package/app/src/user-model.class.ts +0 -50
- package/app/src/views/index.html +0 -1
- package/app/src/views/socket.html +0 -23
- package/app/src/views/upload.html +0 -14
- package/app/static/favicon.ico +0 -0
- package/app/static/k.jpg +0 -0
- package/app/tsconfig.json +0 -20
- package/introduction/decorator/example-import.class.ts +0 -6
- package/introduction/decorator/main-app.ts +0 -6
- package/introduction/decorator/main-decorator.ts +0 -108
- package/introduction/decorator/main-import.ts +0 -1
- package/introduction/decorator/main-reflect.ts +0 -25
- package/introduction/decorator-next/dist/main.js +0 -116
- package/introduction/decorator-next/package.json +0 -14
- package/introduction/decorator-next/src/main.ts +0 -64
- package/introduction/decorator-next/tsconfig.json +0 -17
- package/introduction/decorator-next//346/225/231/347/250/213.md +0 -384
- package/introduction/tsconfig.json +0 -23
- package/introduction/web-services/db-init.ts +0 -39
- package/introduction/web-services/db-singleton.ts +0 -59
- package/introduction/web-services/http-if.ts +0 -10
- package/introduction/web-services/http-init.ts +0 -6
- package/introduction/web-services/http-router.ts +0 -28
- package/src/bind.decorator.ts +0 -50
- package/src/core.decorator.ts +0 -184
- package/src/database.decorator.ts +0 -446
- package/src/decorator-utils.ts +0 -53
- package/src/default/default-authentication.class.ts +0 -10
- package/src/default/express-server.class.ts +0 -150
- package/src/default/log-default.class.ts +0 -9
- package/src/default/node-cache.class.ts +0 -40
- package/src/default/pages/404.html +0 -226
- package/src/default/pages/500.html +0 -713
- package/src/default/rabbitmq.class.ts +0 -61
- package/src/default/read-write-db.class.ts +0 -53
- package/src/default/redis.class.ts +0 -79
- package/src/default/socket-io.class.ts +0 -81
- package/src/factory/authentication-factory.class.ts +0 -9
- package/src/factory/cache-factory.class.ts +0 -7
- package/src/factory/data-source-factory.class.ts +0 -4
- package/src/factory/log-factory.class.ts +0 -8
- package/src/factory/server-factory.class.ts +0 -6
- package/src/route.decorator.ts +0 -334
- package/src/scaffold/command.ts +0 -40
- package/src/scaffold/templates/front-page.class.ts.tpl +0 -12
- package/src/scaffold/templates/main.ts.tpl +0 -13
- package/src/scaffold/templates/nodemon.json.tpl +0 -7
- package/src/scaffold/templates/package.json.tpl +0 -16
- package/src/scaffold/templates/tsconfig.json.tpl +0 -17
- package/src/typespeed.d.ts +0 -403
- package/src/typespeed.ts +0 -139
- package/test/bind.test.ts +0 -28
- package/test/database.test.ts +0 -76
- package/test/decorator-utils.test.ts +0 -42
- package/test/first-page.test.ts +0 -42
- package/test/hooks.ts +0 -13
- package/test/mq.test.ts +0 -17
- package/test/orm.test.ts +0 -66
- package/test/redis.test.ts +0 -48
- package/test/request.test.ts +0 -51
- package/test/second-page.test.ts +0 -50
- package/test/socket.test.ts +0 -60
- package/test-env/docker-compose.test.yml +0 -31
- package/test-env/mysql-init/init.sql +0 -8
- package/test-env//346/234/254/345/234/260Docker/346/265/213/350/257/225/346/226/271/346/241/210.md +0 -69
- package/tsconfig.json +0 -25
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import { bean, getComponent } from "../core.decorator";
|
|
2
|
-
import { config } from "../typespeed";
|
|
3
|
-
import { connect } from "amqplib";
|
|
4
|
-
let rabbitConnection = null;
|
|
5
|
-
|
|
6
|
-
class RabbitMQ {
|
|
7
|
-
|
|
8
|
-
@bean
|
|
9
|
-
public getRabbitMQ(): RabbitMQ {
|
|
10
|
-
if (!config("rabbitmq")) {
|
|
11
|
-
return null;
|
|
12
|
-
}
|
|
13
|
-
return new RabbitMQ();
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
public async publishMessageToExchange(exchange: string, routingKey: string, message: string): Promise<void> {
|
|
17
|
-
const channel = await getChannel();
|
|
18
|
-
await channel.assertExchange(exchange);
|
|
19
|
-
channel.publish(exchange, routingKey, Buffer.from(message));
|
|
20
|
-
await channel.close();
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
public async sendMessageToQueue(queue: string, message: string): Promise<void> {
|
|
24
|
-
const channel = await getChannel();
|
|
25
|
-
await channel.accertQueue(queue);
|
|
26
|
-
channel.sendToQueue(queue, Buffer.from(message));
|
|
27
|
-
await channel.close();
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
public async publish(exchange: string, routingKey: string, message: string): Promise<void> {
|
|
31
|
-
await this.publishMessageToExchange(exchange, routingKey, message);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
public async send(queue: string, message: string): Promise<void> {
|
|
35
|
-
await this.sendMessageToQueue(queue, message);
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
async function getChannel() {
|
|
40
|
-
if (rabbitConnection === null) {
|
|
41
|
-
rabbitConnection = await connect(config("rabbitmq"));
|
|
42
|
-
process.once('SIGINT', async () => {
|
|
43
|
-
await rabbitConnection.close();
|
|
44
|
-
});
|
|
45
|
-
}
|
|
46
|
-
const channel = await rabbitConnection.createChannel();
|
|
47
|
-
return channel;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
function rabbitListener(queue: string) {
|
|
51
|
-
return (target: any, propertyKey: string) => {
|
|
52
|
-
(async function () {
|
|
53
|
-
const channel = await getChannel();
|
|
54
|
-
await channel.assertQueue(queue);
|
|
55
|
-
const targetBean = getComponent(target.constructor);
|
|
56
|
-
await channel.consume(queue, targetBean[propertyKey], { noAck: true });
|
|
57
|
-
}());
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
export { RabbitMQ, rabbitListener };
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import { createConnection, createPool } from "mysql2";
|
|
2
|
-
import DataSourceFactory from "../factory/data-source-factory.class";
|
|
3
|
-
import { bean } from "../core.decorator";
|
|
4
|
-
import { config } from "../typespeed";
|
|
5
|
-
export default class ReadWriteDb extends DataSourceFactory {
|
|
6
|
-
private readonly readSession;
|
|
7
|
-
private readonly writeSession;
|
|
8
|
-
|
|
9
|
-
@bean
|
|
10
|
-
public getDataSource(): DataSourceFactory {
|
|
11
|
-
if (!config("mysql")) {
|
|
12
|
-
return null;
|
|
13
|
-
}
|
|
14
|
-
return new ReadWriteDb();
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
constructor() {
|
|
18
|
-
super();
|
|
19
|
-
const dbConfig = config("mysql");
|
|
20
|
-
if (dbConfig["master"] && dbConfig["slave"]) {
|
|
21
|
-
this.writeSession = this.getConnectionByConfig(dbConfig["master"]);
|
|
22
|
-
if (Array.isArray(dbConfig["slave"])) {
|
|
23
|
-
this.readSession = dbConfig["slave"].map(config => this.getConnectionByConfig(config));
|
|
24
|
-
} else {
|
|
25
|
-
this.readSession = [this.getConnectionByConfig(dbConfig["slave"])];
|
|
26
|
-
}
|
|
27
|
-
} else {
|
|
28
|
-
this.writeSession = this.getConnectionByConfig(dbConfig);
|
|
29
|
-
this.readSession = [this.writeSession];
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
private getConnectionByConfig(config: object) {
|
|
34
|
-
if (config["PoolOptions"] !== undefined) {
|
|
35
|
-
// we need pool
|
|
36
|
-
if (Object.keys(config["PoolOptions"]).length !== 0) {
|
|
37
|
-
config = Object.assign(config, config["PoolOptions"]);
|
|
38
|
-
}
|
|
39
|
-
return createPool(config).promise();
|
|
40
|
-
} else {
|
|
41
|
-
// only connection
|
|
42
|
-
return createConnection(config).promise();
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
public readConnection() {
|
|
47
|
-
return this.readSession[Math.floor(Math.random() * this.readSession.length)];
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
public writeConnection() {
|
|
51
|
-
return this.writeSession;
|
|
52
|
-
}
|
|
53
|
-
}
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
import { bean, getComponent } from "../core.decorator";
|
|
2
|
-
import { default as IoRedis, RedisKey} from "ioredis";
|
|
3
|
-
import { config } from "../typespeed";
|
|
4
|
-
const redisSubscribers = {};
|
|
5
|
-
|
|
6
|
-
class Redis extends IoRedis {
|
|
7
|
-
private static pubObj: Redis = null;
|
|
8
|
-
private static subObj: Redis = null;
|
|
9
|
-
|
|
10
|
-
@bean
|
|
11
|
-
public getRedis(): Redis {
|
|
12
|
-
return Redis.getInstanceOfRedis("pub");
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
public async zrevranking(key: RedisKey, start: number | string, stop: number | string): Promise<Map<string, number>> {
|
|
16
|
-
const list = await this.zrevrange(key, start, stop, "WITHSCORES");
|
|
17
|
-
const map = new Map<string, number>();
|
|
18
|
-
for (let i = 0; i < list.length; i = i + 2) {
|
|
19
|
-
map.set(list[i], Number(list[i + 1]));
|
|
20
|
-
}
|
|
21
|
-
return map;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
public async zranking(key: RedisKey, start: number | string, stop: number | string): Promise<Map<string, number>> {
|
|
25
|
-
const list = await this.zrange(key, start, stop, "WITHSCORES");
|
|
26
|
-
const map = new Map<string, number>();
|
|
27
|
-
for (let i = 0; i < list.length; i = i + 2) {
|
|
28
|
-
map.set(list[i], Number(list[i + 1]));
|
|
29
|
-
}
|
|
30
|
-
return map;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
static getInstanceOfRedis(mode: "sub" | "pub") {
|
|
34
|
-
if (!config("redis")) {
|
|
35
|
-
return null;
|
|
36
|
-
}
|
|
37
|
-
if (mode === "pub") {
|
|
38
|
-
this.pubObj = this.pubObj || new Redis(config("redis"));
|
|
39
|
-
return this.pubObj;
|
|
40
|
-
} else {
|
|
41
|
-
this.subObj = this.subObj || new Redis(config("redis"));
|
|
42
|
-
return this.subObj;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
static async close() {
|
|
47
|
-
if(this.subObj != null) { await this.subObj.quit(); }
|
|
48
|
-
if(this.pubObj != null) { await this.pubObj.quit(); }
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
function redisSubscriber(channel: string) {
|
|
53
|
-
if (!config("redis")) return function(){
|
|
54
|
-
throw new Error("redis not configured");
|
|
55
|
-
};
|
|
56
|
-
Redis.getInstanceOfRedis("sub").subscribe(channel, function (err, count) {
|
|
57
|
-
if (err) {
|
|
58
|
-
console.error(err);
|
|
59
|
-
}
|
|
60
|
-
});
|
|
61
|
-
return function (target: any, propertyKey: string) {
|
|
62
|
-
redisSubscribers[channel] = {
|
|
63
|
-
target: target,
|
|
64
|
-
propertyKey: propertyKey
|
|
65
|
-
};
|
|
66
|
-
};
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
if (config("redis")) {
|
|
70
|
-
Redis.getInstanceOfRedis("sub").on("message", async function (channel, message) {
|
|
71
|
-
await getComponent(redisSubscribers[channel].target.constructor)[redisSubscribers[channel].propertyKey](message);
|
|
72
|
-
});
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
process.once('SIGINT', () => {
|
|
76
|
-
Redis.close();
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
export { Redis, redisSubscriber };
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
import { Server as IoServer } from "socket.io";
|
|
2
|
-
import { createServer } from "http";
|
|
3
|
-
import { getComponent } from "../core.decorator";
|
|
4
|
-
|
|
5
|
-
let io: IoServer = null;
|
|
6
|
-
const listeners = { "event": [], "disconnect": null, "error": null, "connected": null };
|
|
7
|
-
|
|
8
|
-
class SocketIo {
|
|
9
|
-
|
|
10
|
-
public static setIoServer(app, ioSocketConfig) {
|
|
11
|
-
const httpServer = createServer(app);
|
|
12
|
-
io = new IoServer(httpServer, ioSocketConfig);
|
|
13
|
-
io.use(async (socket, next) => {
|
|
14
|
-
if (listeners["connected"] !== null) {
|
|
15
|
-
await getComponent(listeners["connected"].target.constructor)[listeners["connected"].propertyKey](socket, async (err) => {
|
|
16
|
-
if (listeners["error"] !== null && err) {
|
|
17
|
-
await getComponent(listeners["error"].target.constructor)[listeners["error"].propertyKey](socket, err);
|
|
18
|
-
}
|
|
19
|
-
});
|
|
20
|
-
}
|
|
21
|
-
next();
|
|
22
|
-
});
|
|
23
|
-
io.on("connection", async (socket) => {
|
|
24
|
-
if (listeners["disconnect"] !== null) {
|
|
25
|
-
socket.on("disconnect", async (reason) => {
|
|
26
|
-
await getComponent(listeners["disconnect"].target.constructor)[listeners["disconnect"].propertyKey](socket, reason);
|
|
27
|
-
});
|
|
28
|
-
}
|
|
29
|
-
socket.use(async ([event, ...args], next) => {
|
|
30
|
-
try {
|
|
31
|
-
for (let listener of listeners["event"]) {
|
|
32
|
-
if (listener[1] === event) {
|
|
33
|
-
await getComponent(listener[0].target.constructor)[listener[0].propertyKey](socket, ...args);
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
} catch (err) {
|
|
37
|
-
next(err);
|
|
38
|
-
}
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
if (listeners["error"] !== null) {
|
|
42
|
-
socket.on("error", async (err) => {
|
|
43
|
-
await getComponent(listeners["error"].target.constructor)[listeners["error"].propertyKey](socket, err);
|
|
44
|
-
});
|
|
45
|
-
}
|
|
46
|
-
});
|
|
47
|
-
return httpServer;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
public static onEvent(event: string) {
|
|
51
|
-
return (target: any, propertyKey: string) => {
|
|
52
|
-
listeners["event"].push([{
|
|
53
|
-
target: target,
|
|
54
|
-
propertyKey: propertyKey
|
|
55
|
-
}, event]);
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
public static onError(target: any, propertyKey: string) {
|
|
60
|
-
listeners["error"] = {
|
|
61
|
-
target: target,
|
|
62
|
-
propertyKey: propertyKey
|
|
63
|
-
};
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
public static onDisconnect(target: any, propertyKey: string) {
|
|
67
|
-
listeners["disconnect"] = {
|
|
68
|
-
target: target,
|
|
69
|
-
propertyKey: propertyKey
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
public static onConnected(target: any, propertyKey: string) {
|
|
74
|
-
listeners["connected"] = {
|
|
75
|
-
target: target,
|
|
76
|
-
propertyKey: propertyKey
|
|
77
|
-
};
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
export { SocketIo, io }
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import * as express from 'express';
|
|
2
|
-
export default abstract class AuthenticationFactory {
|
|
3
|
-
public preHandle(req: express.Request, res: express.Response, next: express.NextFunction): void{
|
|
4
|
-
next();
|
|
5
|
-
}
|
|
6
|
-
public afterCompletion(req: express.Request, res: express.Response, next: express.NextFunction): void{
|
|
7
|
-
next();
|
|
8
|
-
}
|
|
9
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
export default abstract class CacheFactory {
|
|
2
|
-
public abstract get(key: string): any;
|
|
3
|
-
public abstract set(key: string, value: any, expire?: number): void;
|
|
4
|
-
public abstract del(key: string): void;
|
|
5
|
-
public abstract has(key: string): boolean;
|
|
6
|
-
public abstract flush(): void;
|
|
7
|
-
}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
export default abstract class LogFactory {
|
|
2
|
-
public log(message?: any, ...optionalParams: any[]) : void {
|
|
3
|
-
console.log(message, ...optionalParams);
|
|
4
|
-
}
|
|
5
|
-
public error(message?: any, ...optionalParams: any[]) : void {
|
|
6
|
-
console.error(message, ...optionalParams);
|
|
7
|
-
}
|
|
8
|
-
}
|
package/src/route.decorator.ts
DELETED
|
@@ -1,334 +0,0 @@
|
|
|
1
|
-
import * as express from "express";
|
|
2
|
-
import * as multiparty from "multiparty";
|
|
3
|
-
import { expressjwt } from "express-jwt";
|
|
4
|
-
import { getComponent } from "./core.decorator";
|
|
5
|
-
import { isStd, getStdArgs } from "./decorator-utils";
|
|
6
|
-
import { getBindMapping } from "./bind.decorator";
|
|
7
|
-
|
|
8
|
-
const routerMapper = {
|
|
9
|
-
"get": {},
|
|
10
|
-
"post": {},
|
|
11
|
-
"all": {}
|
|
12
|
-
};
|
|
13
|
-
const routerParams = {};
|
|
14
|
-
const routerParamsTotal = {};
|
|
15
|
-
const routerMiddleware = {};
|
|
16
|
-
function setRouter(app: express.Application) {
|
|
17
|
-
["get", "post", "all"].forEach(method => {
|
|
18
|
-
for (let key in routerMapper[method]) {
|
|
19
|
-
const rounterFunction = routerMapper[method][key];
|
|
20
|
-
if (routerMiddleware[rounterFunction["name"]]) {
|
|
21
|
-
const args: Array<any> = [key, ...routerMiddleware[rounterFunction["name"]], rounterFunction["invoker"]];
|
|
22
|
-
app[method].apply(app, args);
|
|
23
|
-
} else {
|
|
24
|
-
app[method](key, rounterFunction["invoker"]);
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
});
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
function mapperFunction(method: string, value: string) {
|
|
31
|
-
return (...args: any[]): any => {
|
|
32
|
-
if (isStd(args)) {
|
|
33
|
-
const [methodFn, ctx] = getStdArgs(args);
|
|
34
|
-
ctx.addInitializer(function (this: any) {
|
|
35
|
-
const className = this.constructor.name;
|
|
36
|
-
const propertyKey = String(ctx.name);
|
|
37
|
-
applyRouteBind(className, propertyKey, methodFn);
|
|
38
|
-
routerMapper[method][value] = {
|
|
39
|
-
"path": value,
|
|
40
|
-
"name": [className, propertyKey].toString(),
|
|
41
|
-
"target": this.constructor,
|
|
42
|
-
"propertyKey": propertyKey,
|
|
43
|
-
"invoker": async (req, res, next) => {
|
|
44
|
-
const routerBean = getComponent(this.constructor);
|
|
45
|
-
try {
|
|
46
|
-
let paramTotal = routerBean[propertyKey].length;
|
|
47
|
-
if (routerParamsTotal[[className, propertyKey].toString()]) {
|
|
48
|
-
paramTotal = Math.max(paramTotal, routerParamsTotal[[className, propertyKey].toString()]);
|
|
49
|
-
}
|
|
50
|
-
const callArgs = [req, res, next];
|
|
51
|
-
if (paramTotal > 0) {
|
|
52
|
-
for (let i = 0; i < paramTotal; i++) {
|
|
53
|
-
if (routerParams[[className, propertyKey, i].toString()]) {
|
|
54
|
-
callArgs[i] = routerParams[[className, propertyKey, i].toString()](req, res, next);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
const testResult = await routerBean[propertyKey].apply(routerBean, callArgs);
|
|
59
|
-
if (typeof testResult === "object") {
|
|
60
|
-
res.json(testResult);
|
|
61
|
-
} else if (typeof testResult !== "undefined") {
|
|
62
|
-
res.send(testResult);
|
|
63
|
-
}
|
|
64
|
-
return testResult;
|
|
65
|
-
} catch (err) {
|
|
66
|
-
next(err);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
};
|
|
70
|
-
});
|
|
71
|
-
return;
|
|
72
|
-
}
|
|
73
|
-
const target = args[0];
|
|
74
|
-
const propertyKey = args[1] as string;
|
|
75
|
-
applyRouteBind(target.constructor.name, propertyKey, target[propertyKey]);
|
|
76
|
-
routerMapper[method][value] = {
|
|
77
|
-
"path": value,
|
|
78
|
-
"name": [target.constructor.name, propertyKey].toString(),
|
|
79
|
-
"target": target.constructor,
|
|
80
|
-
"propertyKey": propertyKey,
|
|
81
|
-
"invoker": async (req, res, next) => {
|
|
82
|
-
const routerBean = getComponent(target.constructor);
|
|
83
|
-
try {
|
|
84
|
-
let paramTotal = routerBean[propertyKey].length;
|
|
85
|
-
if(routerParamsTotal[[target.constructor.name, propertyKey].toString()]){
|
|
86
|
-
paramTotal = Math.max(paramTotal, routerParamsTotal[[target.constructor.name, propertyKey].toString()]);
|
|
87
|
-
}
|
|
88
|
-
const args = [req, res, next];
|
|
89
|
-
if(paramTotal > 0) {
|
|
90
|
-
for(let i = 0; i < paramTotal; i++) {
|
|
91
|
-
if(routerParams[[target.constructor.name, propertyKey, i].toString()]){
|
|
92
|
-
args[i] = routerParams[[target.constructor.name, propertyKey, i].toString()](req, res, next);
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
const testResult = await routerBean[propertyKey].apply(routerBean, args);
|
|
97
|
-
if (typeof testResult === "object") {
|
|
98
|
-
res.json(testResult);
|
|
99
|
-
} else if (typeof testResult !== "undefined") {
|
|
100
|
-
res.send(testResult);
|
|
101
|
-
}
|
|
102
|
-
return testResult;
|
|
103
|
-
} catch (err) {
|
|
104
|
-
next(err)
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
function upload(...args: any[]): any {
|
|
112
|
-
if (isStd(args)) {
|
|
113
|
-
const [, ctx] = getStdArgs(args);
|
|
114
|
-
ctx.addInitializer(function (this: any) {
|
|
115
|
-
const key = [this.constructor.name, String(ctx.name)].toString();
|
|
116
|
-
if (routerMiddleware[key]) {
|
|
117
|
-
routerMiddleware[key].push(uploadMiddleware);
|
|
118
|
-
} else {
|
|
119
|
-
routerMiddleware[key] = [uploadMiddleware];
|
|
120
|
-
}
|
|
121
|
-
});
|
|
122
|
-
return;
|
|
123
|
-
}
|
|
124
|
-
const target = args[0];
|
|
125
|
-
const propertyKey = args[1] as string;
|
|
126
|
-
const key = [target.constructor.name, propertyKey].toString();
|
|
127
|
-
if (routerMiddleware[key]) {
|
|
128
|
-
routerMiddleware[key].push(uploadMiddleware);
|
|
129
|
-
} else {
|
|
130
|
-
routerMiddleware[key] = [uploadMiddleware];
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
function uploadMiddleware(req, res, next) {
|
|
135
|
-
const form = new multiparty.Form();
|
|
136
|
-
form.parse(req, (err, fields, files) => {
|
|
137
|
-
req.files = files || undefined;
|
|
138
|
-
next();
|
|
139
|
-
});
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
function jwt(jwtConfig) {
|
|
143
|
-
return (...args: any[]): any => {
|
|
144
|
-
if (isStd(args)) {
|
|
145
|
-
const [, ctx] = getStdArgs(args);
|
|
146
|
-
ctx.addInitializer(function (this: any) {
|
|
147
|
-
const key = [this.constructor.name, String(ctx.name)].toString();
|
|
148
|
-
if (routerMiddleware[key]) {
|
|
149
|
-
routerMiddleware[key].push(expressjwt(jwtConfig));
|
|
150
|
-
} else {
|
|
151
|
-
routerMiddleware[key] = [expressjwt(jwtConfig)];
|
|
152
|
-
}
|
|
153
|
-
});
|
|
154
|
-
return;
|
|
155
|
-
}
|
|
156
|
-
const target = args[0];
|
|
157
|
-
const propertyKey = args[1] as string;
|
|
158
|
-
const key = [target.constructor.name, propertyKey].toString();
|
|
159
|
-
if (routerMiddleware[key]) {
|
|
160
|
-
routerMiddleware[key].push(expressjwt(jwtConfig));
|
|
161
|
-
} else {
|
|
162
|
-
routerMiddleware[key] = [expressjwt(jwtConfig)];
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
function before(constructorFunction, methodName: string) {
|
|
168
|
-
const targetBean = getComponent(constructorFunction);
|
|
169
|
-
return function (...args: any[]) {
|
|
170
|
-
if (isStd(args)) {
|
|
171
|
-
const [, ctx] = getStdArgs(args);
|
|
172
|
-
const hookKey = String(ctx.name);
|
|
173
|
-
ctx.addInitializer(function (this: any) {
|
|
174
|
-
const currentMethod = this[methodName];
|
|
175
|
-
if (currentMethod && currentMethod.length > 0) {
|
|
176
|
-
routerParamsTotal[[constructorFunction.name, methodName].toString()] = currentMethod.length;
|
|
177
|
-
}
|
|
178
|
-
Object.assign(this, {
|
|
179
|
-
[methodName]: function (...innerArgs: any[]) {
|
|
180
|
-
this[hookKey](...innerArgs);
|
|
181
|
-
return currentMethod.apply(this, innerArgs);
|
|
182
|
-
}
|
|
183
|
-
})
|
|
184
|
-
});
|
|
185
|
-
return;
|
|
186
|
-
}
|
|
187
|
-
const target = args[0];
|
|
188
|
-
const propertyKey = args[1] as string;
|
|
189
|
-
const currentMethod = targetBean[methodName];
|
|
190
|
-
if(currentMethod.length > 0){
|
|
191
|
-
routerParamsTotal[[constructorFunction.name, methodName].toString()] = currentMethod.length;
|
|
192
|
-
}
|
|
193
|
-
Object.assign(targetBean, {
|
|
194
|
-
[methodName]: function (...innerArgs) {
|
|
195
|
-
target[propertyKey](...innerArgs);
|
|
196
|
-
return currentMethod.apply(targetBean, innerArgs);
|
|
197
|
-
}
|
|
198
|
-
})
|
|
199
|
-
};
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
function after(constructorFunction, methodName: string) {
|
|
203
|
-
const targetBean = getComponent(constructorFunction);
|
|
204
|
-
return function (...args: any[]) {
|
|
205
|
-
if (isStd(args)) {
|
|
206
|
-
const [, ctx] = getStdArgs(args);
|
|
207
|
-
const hookKey = String(ctx.name);
|
|
208
|
-
ctx.addInitializer(function (this: any) {
|
|
209
|
-
const currentMethod = this[methodName];
|
|
210
|
-
if (currentMethod && currentMethod.length > 0) {
|
|
211
|
-
routerParamsTotal[[constructorFunction.name, methodName].toString()] = currentMethod.length;
|
|
212
|
-
}
|
|
213
|
-
Object.assign(this, {
|
|
214
|
-
[methodName]: function (...innerArgs: any[]) {
|
|
215
|
-
const result = currentMethod.apply(this, innerArgs);
|
|
216
|
-
const afterResult = this[hookKey](result);
|
|
217
|
-
return afterResult ?? result;
|
|
218
|
-
}
|
|
219
|
-
})
|
|
220
|
-
});
|
|
221
|
-
return;
|
|
222
|
-
}
|
|
223
|
-
const target = args[0];
|
|
224
|
-
const propertyKey = args[1] as string;
|
|
225
|
-
const currentMethod = targetBean[methodName];
|
|
226
|
-
if(currentMethod.length > 0){
|
|
227
|
-
routerParamsTotal[[constructorFunction.name, methodName].toString()] = currentMethod.length;
|
|
228
|
-
}
|
|
229
|
-
Object.assign(targetBean, {
|
|
230
|
-
[methodName]: function (...innerArgs) {
|
|
231
|
-
const result = currentMethod.apply(targetBean, innerArgs);
|
|
232
|
-
const afterResult = target[propertyKey](result);
|
|
233
|
-
return afterResult ?? result;
|
|
234
|
-
}
|
|
235
|
-
})
|
|
236
|
-
};
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
function req(target: any, propertyKey: string, parameterIndex: number) {
|
|
240
|
-
const key = [target.constructor.name, propertyKey, parameterIndex].toString();
|
|
241
|
-
routerParams[key] = (req, res, next) => req;
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
function res(target: any, propertyKey: string, parameterIndex: number) {
|
|
245
|
-
const key = [target.constructor.name, propertyKey, parameterIndex].toString();
|
|
246
|
-
routerParams[key] = (req, res, next) => res;
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
function next(target: any, propertyKey: string, parameterIndex: number) {
|
|
250
|
-
const key = [target.constructor.name, propertyKey, parameterIndex].toString();
|
|
251
|
-
routerParams[key] = (req, res, next) => next;
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
function reqBody(target: any, propertyKey: string, parameterIndex: number) {
|
|
255
|
-
const key = [target.constructor.name, propertyKey, parameterIndex].toString();
|
|
256
|
-
routerParams[key] = (req, res, next) => req.body;
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
function reqParam(target: any, propertyKey: string, parameterIndex: number) {
|
|
260
|
-
const key = [target.constructor.name, propertyKey, parameterIndex].toString();
|
|
261
|
-
const paramName = getParamInFunction(target[propertyKey], parameterIndex);
|
|
262
|
-
routerParams[key] = (req, res, next) => req.params[paramName];
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
function getParamInFunction(fn: Function, index: number) {
|
|
266
|
-
const code = fn.toString().replace(/((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg, '').replace(/=>.*$/mg, '').replace(/=[^,]+/mg, '');
|
|
267
|
-
const result = code.slice(code.indexOf('(') + 1, code.indexOf(')')).match(/([^\s,]+)/g);
|
|
268
|
-
return result[index] || null;
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
/** 解析函数参数名列表(供 route @bind 做「参数名 → 索引」映射) */
|
|
272
|
-
function getParamNames(fn: Function): string[] {
|
|
273
|
-
const code = fn.toString().replace(/((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg, '').replace(/=>.*$/mg, '').replace(/=[^,)]+/g, '');
|
|
274
|
-
const paramsStr = code.slice(code.indexOf('(') + 1, code.indexOf(')'));
|
|
275
|
-
if (!paramsStr.trim()) return [];
|
|
276
|
-
return paramsStr.split(',').map(p => {
|
|
277
|
-
const matched = p.trim().match(/([A-Za-z_$][\w$]*)/);
|
|
278
|
-
return matched ? matched[1] : p.trim();
|
|
279
|
-
}).filter(Boolean);
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
/** 把 route @bind 的「来源字符串」转成参数解析器 */
|
|
283
|
-
function getRouteSourceResolver(source: string, paramName: string) {
|
|
284
|
-
switch (source) {
|
|
285
|
-
case "req": return (req, res, next) => req;
|
|
286
|
-
case "res": return (req, res, next) => res;
|
|
287
|
-
case "next": return (req, res, next) => next;
|
|
288
|
-
case "reqBody": return (req, res, next) => req.body;
|
|
289
|
-
case "reqParam": return (req, res, next) => req.params[paramName];
|
|
290
|
-
case "reqQuery": return (req, res, next) => req.query[paramName];
|
|
291
|
-
case "reqForm": return (req, res, next) => req.body[paramName];
|
|
292
|
-
default: return null;
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
/** 读取 @bind 声明,把「参数名 → 来源」转成 routerParams 的「索引 → 解析器」 */
|
|
297
|
-
function applyRouteBind(className: string, propertyKey: string, method: Function) {
|
|
298
|
-
const bindMapping = getBindMapping(className, propertyKey);
|
|
299
|
-
if (!bindMapping) return;
|
|
300
|
-
const paramNames = getParamNames(method);
|
|
301
|
-
const nameToIndex: Record<string, number> = {};
|
|
302
|
-
paramNames.forEach((paramName, index) => {
|
|
303
|
-
if (paramName && nameToIndex[paramName] === undefined) nameToIndex[paramName] = index;
|
|
304
|
-
});
|
|
305
|
-
for (const bindName in bindMapping) {
|
|
306
|
-
const source = bindMapping[bindName];
|
|
307
|
-
if (typeof source !== "string") continue; // 跳过 database 的数值映射
|
|
308
|
-
const index = nameToIndex[bindName];
|
|
309
|
-
if (index === undefined) continue;
|
|
310
|
-
const resolver = getRouteSourceResolver(source, bindName);
|
|
311
|
-
if (resolver) {
|
|
312
|
-
routerParams[[className, propertyKey, index].toString()] = resolver;
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
function reqQuery(target: any, propertyKey: string, parameterIndex: number) {
|
|
318
|
-
const key = [target.constructor.name, propertyKey, parameterIndex].toString();
|
|
319
|
-
const paramName = getParamInFunction(target[propertyKey], parameterIndex);
|
|
320
|
-
routerParams[key] = (req, res, next) => req.query[paramName];
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
function reqForm(paramName: string) {
|
|
324
|
-
return (target: any, propertyKey: string, parameterIndex: number) => {
|
|
325
|
-
const key = [target.constructor.name, propertyKey, parameterIndex].toString();
|
|
326
|
-
routerParams[key] = (req, res, next) => req.body[paramName];
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
const getMapping = (value: string) => mapperFunction("get", value);
|
|
331
|
-
const postMapping = (value: string) => mapperFunction("post", value);
|
|
332
|
-
const requestMapping = (value: string) => mapperFunction("all", value);
|
|
333
|
-
|
|
334
|
-
export { next, reqBody, reqQuery, reqForm, reqParam, req, req as request, res, res as response, before, after, getMapping, postMapping, requestMapping, setRouter, upload, jwt };
|