1 | import * as KoaRouter from 'koa-router';
|
2 | import * as fs from 'fs';
|
3 | import logger from './logger';
|
4 | import { BaseContext } from 'koa';
|
5 | import { Burn, KV } from './core';
|
6 |
|
7 |
|
8 | const HASLOADED = Symbol('hasloaded')
|
9 |
|
10 | interface FileModule {
|
11 | module: any,
|
12 | filename: string
|
13 | }
|
14 |
|
15 | interface StringSub {
|
16 | source: string,
|
17 | isFound: boolean
|
18 | }
|
19 |
|
20 | export class Loader {
|
21 | private controller: KV = {};
|
22 | private koaRouter: any = new KoaRouter;
|
23 | private app: Burn;
|
24 |
|
25 | constructor(app: Burn) {
|
26 | this.app = app;
|
27 | }
|
28 |
|
29 | private appDir() {
|
30 | const subString = removeString(__dirname, 'node_modules');
|
31 | if (subString.isFound) {
|
32 | return subString.source;
|
33 | }
|
34 | return subString.source.substr(0, subString.source.length - 4);
|
35 | }
|
36 |
|
37 | private fileLoader(url: string): Array<FileModule> {
|
38 | const merge = this.appDir() + url;
|
39 |
|
40 | return fs.readdirSync(merge).map((name) => {
|
41 | return {
|
42 | module: require(merge + '/' + name),
|
43 | filename: name
|
44 | };
|
45 | });
|
46 | }
|
47 | private convertController(ctler: object, funcNames: Array<string>) {
|
48 | const tmp: { [key: string]: any } = {};
|
49 | funcNames.forEach((name) => {
|
50 | if (name !== 'constructor') {
|
51 | tmp[name] = {
|
52 | class: ctler,
|
53 | funcName: name
|
54 | };
|
55 | }
|
56 | })
|
57 | return tmp;
|
58 | }
|
59 |
|
60 | loadController() {
|
61 | const controllers = this.fileLoader('app/controller');
|
62 | controllers.forEach((mod) => {
|
63 | const names = Object.getOwnPropertyNames(mod.module.prototype);
|
64 | Object.defineProperty(this.controller, mod.module.name.toLowerCase(), {
|
65 | value: this.convertController(mod.module, names)
|
66 | })
|
67 | })
|
68 | }
|
69 |
|
70 | loadRouter() {
|
71 | const routerUrl = this.appDir() + 'app/router.js';
|
72 | const routing = require(routerUrl)({
|
73 | controller: this.controller
|
74 | });
|
75 |
|
76 | Object.keys(routing).forEach((key) => {
|
77 | const [method, url] = key.split(' ');
|
78 | const d = routing[key];
|
79 | this.koaRouter[method](url, async (ctx: BaseContext) => {
|
80 | const instance = new d.class(ctx, this.app);
|
81 | await instance[d.funcName]();
|
82 | })
|
83 | });
|
84 | this.app.use(this.koaRouter.routes());
|
85 | }
|
86 |
|
87 | loadToContext(target: Array<FileModule>, app: Burn, property: string) {
|
88 | Object.defineProperty(app.context, property, {
|
89 | get() {
|
90 | if (!(<any>this)[HASLOADED]) {
|
91 | (<any>this)[HASLOADED] = {};
|
92 | }
|
93 | const loaded = (<any>this)[HASLOADED];
|
94 | if (!loaded[property]) {
|
95 | loaded[property] = {};
|
96 | target.forEach((mod) => {
|
97 | const key = mod.filename.split('.')[0]
|
98 | loaded[property][key] = new mod.module(this, app);
|
99 | })
|
100 | return loaded.service
|
101 | }
|
102 | return loaded.service;
|
103 | }
|
104 | })
|
105 | }
|
106 |
|
107 |
|
108 | loadService() {
|
109 | const service = this.fileLoader('app/service');
|
110 | this.loadToContext(service, this.app, 'service');
|
111 | }
|
112 |
|
113 | loadMiddleware() {
|
114 | try {
|
115 | const middleware = this.fileLoader('app/middleware');
|
116 | const registedMid = this.app.config['middleware'];
|
117 |
|
118 | if (!registedMid) return;
|
119 | registedMid.forEach((name: string) => {
|
120 | logger.blue(name);
|
121 | for (const index in middleware) {
|
122 | const mod = middleware[index];
|
123 | const fname = mod.filename.split('.')[0];
|
124 | if (name === fname) {
|
125 | this.app.use(mod.module());
|
126 | }
|
127 | }
|
128 | })
|
129 | } catch (e) { }
|
130 | }
|
131 |
|
132 | loadConfig() {
|
133 | const configDef = this.appDir() + 'app/config/config.default.js';
|
134 | const configEnv = this.appDir()
|
135 | + (process.env.NODE_ENV === 'production' ? 'app/config/config.pro.js' : 'app/config/config.dev.js');
|
136 | const conf = require(configEnv);
|
137 | const confDef = require(configDef);
|
138 | const merge = Object.assign({}, conf, confDef);
|
139 | Object.defineProperty(this.app, 'config', {
|
140 | get: () => {
|
141 | return merge
|
142 | }
|
143 | })
|
144 | }
|
145 |
|
146 | load() {
|
147 | this.loadController();
|
148 | this.loadService();
|
149 | this.loadConfig();
|
150 | this.loadMiddleware();
|
151 | this.loadRouter();
|
152 | }
|
153 | }
|
154 |
|
155 | function removeString(source: string, str: string): StringSub {
|
156 | const index = source.indexOf(str);
|
157 | if (index > 0) {
|
158 | return {
|
159 | source: source.substr(0, index),
|
160 | isFound: true
|
161 | };
|
162 | }
|
163 | return {
|
164 | source: source,
|
165 | isFound: false
|
166 | };
|
167 | } |
\ | No newline at end of file |