Browse Source

调整并增加新功能

HonorLee 1 year ago
parent
commit
7e38de7f3a

+ 14 - 0
README.md

@@ -26,6 +26,20 @@ tsc
 ```
 npm start
 ```
+
+### 5.Recommand run a develop server with hotfix feature by nodemon
+```
+npm i -g nodemon
+```
+Then
+```
+npm run dev
+```
+or
+```
+nodemon --watch source/ -e ts,tsx,js --exec 'tsc && node dist/main.js'
+```
+
 There are some examples in ```dist/app``` folder, you can edit by yourself for test.
 ## Features
 ```

+ 9 - 4
nginx.conf.example

@@ -1,11 +1,16 @@
 server {
         listen 8080;
-        server_name {YourServername.com};
-        root /{Your SugarNode path}/dist;
-        location ~.*\.(jpg|png|gif|txt)$ {
+        server_name honorlee.natappvip.cc;
+        root {Your SugarNode [dist] path};
+        #root /Volumes/HonorLee/Develop/work/Fan/WebServer;
+        location ~.*\.(jpg|png|gif|txt|html)$ {
                 try_files $uri @proxy;
         }
-        location /asset/ {
+        location /example {
+                add_header Cache-Control no-store;
+                try_files $uri $uri @proxy;
+        }
+        location /asset {
                 add_header Cache-Control no-store;
                 try_files $uri $uri @proxy;
         }

+ 12 - 1
package.json

@@ -9,6 +9,7 @@
     "build-example": "tsc -p tsconfigExample.json",
     "clean": "tsc --build --clean",
     "watch": "tsc --watch",
+    "dev": "nodemon --watch source/ -e ts,tsx,js --exec \"tsc && node dist/main.js\"",
     "start": "node dist/main.js"
   },
   "keywords": [
@@ -22,27 +23,37 @@
   "license": "MIT",
   "devDependencies": {
     "@types/formidable": "^2.0.5",
+    "@types/md5": "^2.3.2",
     "@types/memcached": "^2.2.7",
     "@types/mongodb": "^4.0.7",
     "@types/mysql": "^2.15.21",
     "@types/node": "^18.0.0",
     "@types/redis": "^4.0.11",
+    "@types/request": "^2.48.8",
+    "@types/sha1": "^1.1.3",
     "@typescript-eslint/eslint-plugin": "^5.29.0",
     "@typescript-eslint/parser": "^5.29.0",
     "eslint": "^8.18.0",
     "typescript": "^4.7.4"
   },
   "dependencies": {
+    "@types/crypto-js": "^4.1.1",
+    "aliyun-api-gateway": "^1.1.6",
     "colors": "^1.4.0",
+    "crypto-js": "^4.1.1",
+    "dotenv": "^16.0.2",
     "ejs": "^3.1.8",
     "formidable": "^2.0.1",
     "fs-extra": "^10.1.0",
     "klaw-sync": "^6.0.0",
+    "md5": "^2.3.0",
     "memcached": "^2.2.2",
     "mongodb": "^4.7.0",
     "mysql": "^2.18.1",
     "redis": "^4.1.0",
     "request": "^2.88.2",
-    "tracer": "^1.1.6"
+    "sha1": "^1.1.1",
+    "tracer": "^1.1.6",
+    "xml2js": "^0.4.23"
   }
 }

+ 34 - 3
source/@types/global.d.ts

@@ -1,5 +1,6 @@
-import { RedisClientType } from "@redis/client";
 import { IncomingMessage, ServerResponse } from "http";
+import request from "request";
+import Session from "../system/module/mvc/lib/session";
 
 /**
  * Global variable
@@ -9,6 +10,8 @@ declare global{
     let SYSTEM:any;
     //全局FS对象
     let FILE:any;
+    //全局Request
+    let REQUEST:request;
     //全局Moment
     let Moment:Moment;
     //Logger
@@ -23,7 +26,7 @@ declare global{
     declare interface DBOption{
         host:string,
         port:number,
-        username?:string,
+        user?:string,
         password?:string,
         database?:string,
         prefix?:string
@@ -45,12 +48,21 @@ declare global{
         req:IncomingMessage|undefined,
         res:ServerResponse|undefined,
         path:string|null,
+        method:string,
         COOKIE:any,
         GET:any,
         POST:any,
-        UPLOAD:any
+        UPLOAD:any,
+        SESSION:any
     }
     declare class CONTROLLER{
+        REFERER:string;
+        COOKIE:any;
+        GET:any;
+        POST:any;
+        UPLOAD:any;
+        SESSION:Session;
+        DATA:AnyKeyString;
         end(data:any,status?:number,mime?:string):void;
         endRedirect(location:string,permanently:boolean);
         endJSON(somthing:any);
@@ -59,6 +71,25 @@ declare global{
         setCookie(key:string,value:any,expire?:number|'forever',path?:string);
         renewCookie(key:string,expire:number|'forever',path?:string);
     }
+    declare class MysqlUtil{
+        /**
+         * K-V数据转为Sql语句结构
+        **/
+        public static objToKVString(obj:any,joinStr?:string,keyPrefix?:string);
+        /** 
+         * 自动处理数据模型与数据,返回处理后符合模型的数据对象,包含数据安全性处理
+         * @param module    数据模型
+         * @param data      待处理数据
+         * @param filter    自动过滤非模型字段数据(可选,默认不过滤)
+         * @prarm reverse   反向处理,由写入处理变为取出处理,并自动根据模型字段类型进行可视化处理(可选,默认写入状态)
+        **/
+        public static analyzeFields(module:any,data:any,filter?:boolean,reverse?:boolean)
+        public static escape(value:any);
+        public static createPageLimit(page?:number,perPage?:number,orderField?:string);
+        public static createOrderBy(order_filed?:string,order_desc?:boolean);
+    }
+    declare interface MysqlResult{err:any|null,data:any|Array|null|undefined}
+    declare interface AnyKeyString{[key:string]:any}
 }
 
 export = {}

+ 2 - 1
source/config.ts

@@ -3,7 +3,8 @@
  * @Version 1.0 (2019-09-17)
  * @License MIT
  */
- const CONFIG = {
+export = {}
+const CONFIG = {
     //入口文件,默认App目录
     entrance:'main.js',
     //扩展模块

+ 6 - 2
source/main.ts

@@ -25,7 +25,6 @@ if(SYSTEM.CONFIG.entrance){
             LOGGER.error(`Wrong entrance file: ${SYSTEM.CONFIG.entrance}`);
             LOGGER.error(`Entrance Error: ${err}`);
         }else{
-            await import(`${SYSTEM.PATH.App}/${SYSTEM.CONFIG.entrance}`);
             for(const module of SYSTEM.CONFIG.module){
                 if(!module.enable) continue;
                 const moduleName = module.name.toLowerCase();
@@ -40,8 +39,13 @@ if(SYSTEM.CONFIG.entrance){
                     if(e.stack) LOGGER.error(e.stack);
                 }
             }
+            await import(`${SYSTEM.PATH.App}/${SYSTEM.CONFIG.entrance}`);
         }
     })
 }else{
     LOGGER.error('Empty entrance option,please check Config.js');
-}
+}
+
+process.on('uncaughtException',(err)=>{
+    LOGGER.error(err.stack as string);
+})

+ 1 - 0
source/system/core.ts

@@ -12,6 +12,7 @@ SYSTEM.PATH = {
     Library     : SYSTEM.ROOTPATH + '/lib',
     Helper      : SYSTEM.ROOTPATH + '/lib/helper',
     Temp        : SYSTEM.ROOTPATH + '/temp',
+    Session     : SYSTEM.ROOTPATH + '/temp/session',
     Log         : SYSTEM.ROOTPATH + '/log'
 }
 

+ 112 - 33
source/system/lib/extra/mysqldb.ts

@@ -45,45 +45,17 @@ export class MysqlDB{
             });
         })
     }
-    objToKVString(obj:any,joinStr?:string,keyPrefix?:string){
-        const strArr:Array<string> = [];
-
-        Object.keys(obj).forEach(key =>{
-            let v = obj[key];
-            if(key=='extraStr'){
-                if(Array.isArray(v)){
-                    strArr.push(v.join(joinStr));
-                }else{
-                    strArr.push(v);
-                }
-            }else{
-                if(typeof(v)=='string'){
-                    if(v[0]=='='){
-                        v = v.substring(1,-1);
-                    }else{
-                        v = `"${v}"`;
-                    }
-                }
-                keyPrefix = keyPrefix?keyPrefix:'';
-                const sqlkey = `${keyPrefix}\`${key}\``;
-                strArr.push(`${sqlkey}=${v}`);
-                
-            }
-        })
-        if(joinStr) return strArr.join(joinStr);
-        return strArr.join(",");
-    }
     async update(tablename:string,updateObj:any,whereObj:any){
         if(!tablename || !updateObj) return;
         let whereRule="";
-        const updateRule = this.objToKVString(updateObj);
+        const updateRule = MysqlUtil.objToKVString(updateObj);
         if(whereObj){
-            whereRule = ` where ${this.objToKVString(whereObj,' and ')}`;
+            whereRule = ` where ${MysqlUtil.objToKVString(whereObj,' and ')}`;
         }
         const sqlStr = `update ${tablename} set ${updateRule} ${whereRule}`;
         return await this.querySync(sqlStr);
     }
-    async select(tablename:string,queryField?:Array<string>,whereObj?:any){
+    async select(tablename:string,queryField?:Array<string>|null,whereObj?:any){
         if(!tablename){
             const err = new Error("Missing table name")
             if(err.stack) LOGGER.error(err.stack);
@@ -91,7 +63,7 @@ export class MysqlDB{
         }
         let queryStr = "*",whereStr = "";
         if(queryField) queryStr = queryField.join(",");
-        if(whereObj) whereStr = ` where ${this.objToKVString(whereObj,' and ')}`;
+        if(whereObj) whereStr = ` where ${MysqlUtil.objToKVString(whereObj,' and ')}`;
 
         const sql = `select ${queryStr} from ${tablename} ${whereStr}`;
         return await this.querySync(sql);
@@ -109,7 +81,7 @@ export class MysqlDB{
         }
         let sql = `insert into ${tablename} `;
         if(insertData.constructor == Object){
-            sql += `set ${this.objToKVString(insertData)}`;
+            sql += `set ${MysqlUtil.objToKVString(insertData)}`;
         }else if(insertData.constructor == Array && insertData.length>0 && insertData[0].constructor == Object){
             const fields = Object.keys(insertData[0]);
             const values = [];
@@ -139,6 +111,113 @@ export class MysqlDB{
         return await this.querySync(sql);
     }
 }
+export class MysqlUtil{
+    /**
+     * K-V数据转为Sql语句结构
+    **/
+    public static objToKVString(obj:any,joinStr?:string,keyPrefix?:string){
+        const strArr:Array<string> = [];
+
+        const keys = Object.keys(obj);
+        let _extraSql = '',_extraLink = '';
+        keyPrefix = keyPrefix?`${keyPrefix}.`:'';
+        if(keys.length>0){
+            keys.forEach(key =>{
+                let v = obj[key];
+                if(key=='_extra'){
+                    if(Array.isArray(v)){
+                        _extraSql = v.join(joinStr);
+                    }else if(v.constructor == Object){
+                        if(v.sql){
+                            _extraSql = v.sql;
+                            _extraLink = v.link||'and';
+                        }
+                    }else{
+                        _extraSql = v;
+                    }
+                }else{
+                    if(typeof(v)=='string'){
+                        if(v[0]=='='){
+                            v = v.substring(1,-1);
+                        }else{
+                            if(!(v.substr(0,1)=="'" && v.substr(-1,1)=="'") && !(v.substr(0,1)=='"' && v.substr(-1,1)=='"')){
+                                v = `"${v}"`;
+                            }else{
+                                v = v;
+                            }
+                        }
+                    }
+                    keyPrefix = keyPrefix?`${keyPrefix}`:'';
+                    const sqlkey = `${keyPrefix}\`${key}\``;
+                    strArr.push(`${sqlkey}=${v}`);
+                    
+                }
+            })
+            const sql = `${strArr.join(joinStr||',')} ${_extraLink} ${_extraSql}`;
+            return sql;
+        }else{
+            return '';
+        }
+    }
+    /** 
+     * 自动处理数据模型与数据,返回处理后符合模型的数据对象,包含数据安全性处理
+     * @param module    数据模型
+     * @param data      待处理数据
+     * @param filter    自动过滤非模型字段数据(可选,默认不过滤)
+     * @prarm reverse   反向处理,由写入处理变为取出处理,并自动根据模型字段类型进行可视化处理(可选,默认写入状态)
+    **/
+    public static analyzeFields(module:any,data:any,filter?:boolean,reverse?:boolean){
+        const outData:AnyKeyString = {};
+        Object.keys(data).forEach(key=>{
+            if(module[key]!=undefined && data[key]!=null){
+                let value = data[key];
+                switch(module[key].type){
+                    case String:
+                        value = String(value);
+                        if(!reverse) value = Mysql.escape(value)
+                        break;
+                    case Number:
+                        value = Number(value)||0;
+                        break;
+                    case 'Date_Timestamp':
+                    case 'DateTime_Timestamp':
+                    case 'Time_Timestamp':
+                        value = Number(value)||0;
+                        if(value>0 && reverse){
+                            if(module[key].type=='Date_Timestamp') value = Moment.unix(value).format('YYYY-MM-DD');
+                            if(module[key].type=='DateTime_Timestamp') value = Moment.unix(value).format('YYYY-MM-DD HH:mm:ss');
+                            if(module[key].type=='Time_Timestamp') value = Moment.unix(value).format('HH:mm:ss');
+                        }
+                        break;
+                }
+                if(module[key].reverseKey && reverse) key = module[key].reverseKey;
+                outData[key] = value;
+            }else{
+                if(!filter) outData[key] = data[key];
+            }
+        })
+        return outData;
+    }
+    public static escape(value:any){
+        return Mysql.escape(value);
+    }
+    public static createPageLimit(page?:number,page_size?:number,orderField?:string){
+        page = page||0;
+        page_size = page_size||10;
+        let sql = ``;
+        if(orderField) sql += `ORDER BY \`${orderField}\` `;
+        sql += `LIMIT ${page*page_size},${page_size}`;
+        return sql;
+    }
+    public static createOrderBy(order_filed?:string,order_desc?:boolean){
+        let orderStr = '';
+        if(order_filed){
+            orderStr = `order by \`${order_filed}\``;
+            if(order_desc) orderStr += ' desc';
+        }
+        return orderStr;
+    }
+}
 
 
 //连接池

+ 117 - 121
source/system/lib/helper/database.ts

@@ -1,9 +1,11 @@
-import {MysqlDB}  from '../extra/mysqldb';
+import {MysqlDB,MysqlUtil}  from '../extra/mysqldb';
 // const RedisBridge   = require(Core.Path.ExtraLib + '/redisdb.js');
 import MongoDB    from 'mongodb';
 import MemcacheDB from 'memcached';
 import * as RedisDB    from 'redis';
 
+(global as any).MysqlUtil = MysqlUtil;
+
 //默认配置
 const DatabaseOption:any = {
     mysql    : '{"host":"localhost","port":3306,"user":"root","password":"","database":"","prefix":"","connectionLimit":10}',
@@ -19,23 +21,19 @@ class Database {
      * @param  {String} GlobalName      自动全局命名
      * @param  {Function} callback      回调函数
      */
-    public static create(DatabaseType:string,option:DBOption,GlobalName?:string,callback?:(err:Error|null,conn?:any)=>void){
+    public static async create(DatabaseType:string,option:DBOption,GlobalName?:string){
         DatabaseType = DatabaseType.toLowerCase();
         switch(DatabaseType){
             case 'mysql':
-                Creater._createMysqlConnection(option,GlobalName,callback);
-                break;
+                return await Creater._createMysqlConnection(option,GlobalName);
             case 'mongodb':
-                Creater._createMongoConnection(option,GlobalName,callback);
-                break;
+                return await Creater._createMongoConnection(option,GlobalName);
             case 'memcache':
-                Creater._createMemcacheConnection(option,GlobalName,callback);
-                break;
+                return await Creater._createMemcacheConnection(option,GlobalName);
             case 'redis':
-                Creater._createRedisConnection(option,GlobalName,callback);
-                break;
+                return await Creater._createRedisConnection(option,GlobalName);
             default:
-                if(callback) callback(new Error('Wrong database type!'));
+                return {err:new Error('Wrong database type!')};
         }
     }
 
@@ -50,133 +48,131 @@ class Database {
     }
 }
 
-
-
 //连接控制器
 class Creater{
-    static _createMysqlConnection (option:DBOption,GlobalName?:string,callback?:(err:Error|null,conn?:any)=>void){
-        const _MysqlDB = new MysqlDB(option);
-        // if(!callback || typeof(callback)!='function') callback = ()=>{return}
-        //连接测试
-        _MysqlDB.query('SELECT VERSION() as version',(err,result,fields?:any)=>{
-            if(err){
-                LOGGER.error('Mysql Connect error,please recheck your config');
-                if(err.stack) LOGGER.error(err.stack);
-                if(callback) callback(err,null);
-                return;
-            }else{
-                LOGGER.info('Mysql Connect success');
-                LOGGER.info(`Mysql Version: ${result[0]['version']} | User: ${option.username} | Database: ${option.database} | GlobalName: ${GlobalName}`);
-                if(GlobalName){
-                    if((global as any)[GlobalName]){
-                        LOGGER.error(`Create global name fail with "${GlobalName}"`);
-                        if(callback) callback(new Error('Duplicate global name'),null);
-                        return;
-                    }else{
-                        (global as any)[GlobalName] = _MysqlDB;
+    static _createMysqlConnection (option:DBOption,GlobalName?:string){
+        return new Promise((resolve,reject)=>{
+            const _MysqlDB = new MysqlDB(option);
+            // if(!callback || typeof(callback)!='function') callback = ()=>{return}
+            //连接测试
+            _MysqlDB.query('SELECT VERSION() as version',(err,result,fields?:any)=>{
+                if(err){
+                    LOGGER.error('Mysql Connect error,please recheck your config');
+                    if(err.stack) LOGGER.error(err.stack);
+                    return resolve({err})
+                }else{
+                    LOGGER.info('Mysql Connect success');
+                    LOGGER.info(`Mysql Version: ${result[0]['version']} | User: ${option.user} | Database: ${option.database} | GlobalName: ${GlobalName}`);
+                    if(GlobalName){
+                        if((global as any)[GlobalName]){
+                            LOGGER.error(`Create global name fail with "${GlobalName}"`);
+                            return resolve({err:new Error('Duplicate global name')})
+                        }else{
+                            (global as any)[GlobalName] = _MysqlDB;
+                        }
                     }
+                    resolve({err:null,client:_MysqlDB})
                 }
-                if(callback) callback(null,_MysqlDB);
-            }
-        });
+            });
+        })
+        
     }
-    static _createMongoConnection(option:DBOption,GlobalName?:string,callback?:(err:Error|null,conn?:any)=>void){
-        const verify = option.username?option.username+':'+option.password+'@':'';
-        const mongoConnect = 'mongodb://' + verify + option.host+':'+option.port+'/'+option.database;
-        // if(!callback) callback = ()=>{return}
-        MongoDB.MongoClient.connect(mongoConnect,(err?:Error,db?:any)=>{
-            if(err) {
-                LOGGER.error('MongoDB connect error!');
-                if(err.stack) LOGGER.error(err.stack);
-                if(callback) callback(err,null);
-                return;
-            }else{
-                LOGGER.info(`Mongodb Connect success | GlobalName: ${GlobalName}`);
-                const _mongoClient = {
-                    db:db,
-                    c:(collection:any)=>{
-                        return db.collection(option.prefix+collection);
+    static _createMongoConnection(option:DBOption,GlobalName?:string){
+        return new Promise((resolve,rejects)=>{
+            const verify = option.user?option.user+':'+option.password+'@':'';
+            const mongoConnect = 'mongodb://' + verify + option.host+':'+option.port+'/'+option.database;
+            // if(!callback) callback = ()=>{return}
+            MongoDB.MongoClient.connect(mongoConnect,(err?:Error,db?:any)=>{
+                if(err) {
+                    LOGGER.error('MongoDB connect error!');
+                    if(err.stack) LOGGER.error(err.stack);
+                    return resolve({err})
+                }else{
+                    LOGGER.info(`Mongodb Connect success | GlobalName: ${GlobalName}`);
+                    const _mongoClient = {
+                        db:db,
+                        c:(collection:any)=>{
+                            return db.collection(option.prefix+collection);
+                        }
+                    };
+                    if(GlobalName){
+                        if((global as any)[GlobalName]){
+                            LOGGER.error(`Create global name fail with "${GlobalName}"`);
+                            return resolve({err:new Error('Duplicate global name')})
+                        }
+                        (global as any)[GlobalName] = _mongoClient;
                     }
-                };
-                if(GlobalName){
-                    if((global as any)[GlobalName]){
-                        LOGGER.error(`Create global name fail with "${GlobalName}"`);
-                        if(callback) callback(new Error('Duplicate global name'),null);
-                        return;
+
+                    resolve({err:null,client:_mongoClient})
+                }
+            });
+        })
+        
+    }
+    static _createMemcacheConnection(option:DBOption,GlobalName?:string){
+        return new Promise(async (resolve,reject)=>{
+            const _Memcache  = new MemcacheDB(option.host+':'+option.port);
+            _Memcache.version(function(err,data){
+                if(err){
+                    LOGGER.error('Memcache Connect error,please recheck your config');
+                    LOGGER.error(err);
+                    resolve({err});
+                }else{
+                    LOGGER.info('Memcache Connect success');
+                    LOGGER.info(`Memcache Version: ${data[0]['version']} | GlobalName: ${GlobalName}`);
+                    if(GlobalName){
+                        if((global as any)[GlobalName]){
+                            LOGGER.error(`Create global name fail with "${GlobalName}"`);
+                            resolve({err:new Error('Duplicate global name')});
+                            return;
+                        }else{
+                            (global as any)[GlobalName] = _Memcache;
+                        }
                     }
-                    (global as any)[GlobalName] = _mongoClient;
+                    resolve({err:null,client:_Memcache});
                 }
-                if(callback) callback(null,_mongoClient);
-            }
+            });
         });
     }
-    static _createMemcacheConnection(option:DBOption,GlobalName?:string,callback?:(err:Error|null,conn?:any)=>void){
-        const _Memcache  = new MemcacheDB(option.host+':'+option.port);
-        _Memcache.version(function(err,data){
-            if(err){
-                LOGGER.error('Memcache Connect error,please recheck your config');
-                LOGGER.error(err);
-                if(callback) callback(err,null);
-                return;
-            }else{
-                LOGGER.info('Memcache Connect success');
-                LOGGER.info(`Memcache Version: ${data[0]['version']} | GlobalName: ${GlobalName}`);
+    static async _createRedisConnection(option:DBOption,GlobalName?:string){
+        return new Promise(async (resolve,reject)=>{
+            let _redisConnStr = `${option.host}:${option.port}`;
+            _redisConnStr = `redis://${option.user||''}:${option.password||''}@${_redisConnStr}`;
+            const _redisClient = RedisDB.createClient({url:_redisConnStr,socket:{keepAlive:30000}});
+            _redisClient.on('error',(err:Error)=>{
+                if(err instanceof RedisDB.SocketClosedUnexpectedlyError){
+                    LOGGER.error(`Redis [${option.host}:${option.port}] connect has been refused,please recheck your config,and make sure redis server is running!`);
+                    resolve({err:err});
+                }
+            })
+            _redisClient.on('ready',async ()=>{
+                LOGGER.info(`Redis Connect [${option.user||''}@${option.host}:${option.port}] success [${GlobalName||'UNKNOW'}]`);
+                const infoStr = <string>await _redisClient.info();
+                const infoLine = infoStr.split('\n');
+                const info:any = {};
+                for(const line of infoLine){
+                    const lineArr = line.split(':');
+                    if(lineArr.length>1) info[lineArr[0]] = lineArr[1];
+                }
+                if(info.redis_version) LOGGER.info(`GlobalName: ${GlobalName||'UNKNOW'} | Server Version: ${info.redis_version}`);
+                // _redisClient.stream.setKeepAlive(true,30 * 1000);
+    
                 if(GlobalName){
                     if((global as any)[GlobalName]){
                         LOGGER.error(`Create global name fail with "${GlobalName}"`);
-                        if(callback) callback(new Error('Duplicate global name'),null);
-                        return;
+                        return resolve({err:new Error('Duplicate global name')});
                     }else{
-                        (global as any)[GlobalName] = _Memcache;
+                        (global as any)[GlobalName] = _redisClient;
                     }
                 }
-                if(callback) callback(null,_Memcache);
-            }
-        });
-    }
-    static async _createRedisConnection(option:DBOption,GlobalName?:string,callback?:(err:Error|null,conn?:any)=>void){
-        let _redisConnStr = `${option.host}:${option.port}`;
-        if(option.username){
-            if(option.password){
-                _redisConnStr = `${option.username}:${option.password}@${_redisConnStr}`;
-            }else{
-                _redisConnStr = `${option.username}@${_redisConnStr}`;
-            }
-        }
-        _redisConnStr = `redis://${_redisConnStr}`;
-        const _redisClient = RedisDB.createClient({url:_redisConnStr,socket:{keepAlive:30000}});
-        _redisClient.on('error',(err:Error)=>{
-            if(err instanceof RedisDB.SocketClosedUnexpectedlyError){
-                LOGGER.error(`Redis [${option.host}:${option.port}] connect has been refused,please recheck your config,and make sure redis server is running!`);
-            }
+                resolve({err:null,client:_redisClient});
+            });
+            _redisClient.on('reconnecting',function(e:any){
+                LOGGER.warn('Redis lost connect,reconnecting!');
+            });
+            await _redisClient.connect();
         })
-        _redisClient.on('ready',async ()=>{
-            LOGGER.info('Redis Connect success');
-            const infoStr = <string>await _redisClient.info();
-            const infoLine = infoStr.split('\n');
-            const info:any = {};
-            for(const line of infoLine){
-                const lineArr = line.split(':');
-                if(lineArr.length>1) info[lineArr[0]] = lineArr[1];
-            }
-            if(info.redis_version) LOGGER.info(`GlobalName: ${GlobalName} | Redis Version: ${info.redis_version}`);
-            // _redisClient.stream.setKeepAlive(true,30 * 1000);
-
-            if(GlobalName){
-                if((global as any)[GlobalName]){
-                    LOGGER.error(`Create global name fail with "${GlobalName}"`);
-                    if(callback) callback(new Error('Duplicate global name'),null);
-                    return;
-                }else{
-                    (global as any)[GlobalName] = _redisClient;
-                }
-            }
-            if(callback) callback(null,_redisClient);
-        });
-        _redisClient.on('reconnecting',function(e:any){
-            LOGGER.warn('Redis lost connect,reconnecting!');
-        });
-        await _redisClient.connect();
+        
             
         //     {port:option.port,host:option.host,socket_keepalive:true,socket_initialdelay:30000,retry_strategy: function (retryData) {
         //     if (retryData.error && retryData.error.code === 'ECONNREFUSED') {

+ 172 - 0
source/system/lib/helper/wechat/errcodes.ts

@@ -0,0 +1,172 @@
+/**
+ * @Author  HonorLee (dev@honorlee.me)
+ * @Version 1.0 (2018-05-05)
+ * @License MIT
+ */
+export default {
+    '-1':"系统繁忙,此时请开发者稍候再试",
+    0:"请求成功",
+    10003:"redirect_uri域名与后台配置不一致",
+    10004:"此公众号被封禁",
+    10005:"此公众号并没有这些scope的权限",
+    10006:"必须关注此测试号",
+    10009:"操作太频繁了,请稍后重试",
+    10010:"scope不能为空",
+    10011:"redirect_uri不能为空",
+    10012:"appid不能为空",
+    10013:"state不能为空",
+    10015:"公众号未授权第三方平台,请检查授权状态",
+    10016:"不支持微信开放平台的Appid,请使用公众号Appid",
+    40001:"获取 access_token 时 AppSecret 错误,或者 access_token 无效。请开发者认真比对 AppSecret 的正确性,或查看是否正在为恰当的公众号调用接口",
+    40002:"不合法的凭证类型",
+    40003:"不合法的 OpenID ,请开发者确认 OpenID (该用户)是否已关注公众号,或是否是其他公众号的 OpenID",
+    40004:"不合法的媒体文件类型",
+    40005:"不合法的文件类型",
+    40006:"不合法的文件大小",
+    40007:"不合法的媒体文件 id",
+    40008:"不合法的消息类型",
+    40009:"不合法的图片文件大小",
+    40010:"不合法的语音文件大小",
+    40011:"不合法的视频文件大小",
+    40012:"不合法的缩略图文件大小",
+    40013:"不合法的 AppID ,请开发者检查 AppID 的正确性,避免异常字符,注意大小写",
+    40014:"不合法的 access_token ,请开发者认真比对 access_token 的有效性(如是否过期),或查看是否正在为恰当的公众号调用接口",
+    40015:"不合法的菜单类型",
+    40016:"不合法的按钮个数",
+    40017:"不合法的按钮个数",
+    40018:"不合法的按钮名字长度",
+    40019:"不合法的按钮 KEY 长度",
+    40020:"不合法的按钮 URL 长度",
+    40021:"不合法的菜单版本号",
+    40022:"不合法的子菜单级数",
+    40023:"不合法的子菜单按钮个数",
+    40024:"不合法的子菜单按钮类型",
+    40025:"不合法的子菜单按钮名字长度",
+    40026:"不合法的子菜单按钮 KEY 长度",
+    40027:"不合法的子菜单按钮 URL 长度",
+    40028:"不合法的自定义菜单使用用户",
+    40029:"不合法的 oauth_code",
+    40030:"不合法的 refresh_token",
+    40031:"不合法的 openid 列表",
+    40032:"不合法的 openid 列表长度",
+    40033:"不合法的请求字符,不能包含 \\uxxxx 格式的字符",
+    40035:"不合法的参数",
+    40038:"不合法的请求格式",
+    40039:"不合法的 URL 长度",
+    40050:"不合法的分组 id",
+    40051:"分组名字不合法",
+    40060:"删除单篇图文时,指定的 article_idx 不合法",
+    40117:"分组名字不合法",
+    40118:"media_id 大小不合法",
+    40119:"button 类型错误",
+    40120:"button 类型错误",
+    40121:"不合法的 media_id 类型",
+    40132:"微信号不合法",
+    40137:"不支持的图片格式",
+    40155:"请勿添加其他公众号的主页链接",
+    41001:"缺少 access_token 参数",
+    41002:"缺少 appid 参数",
+    41003:"缺少 refresh_token 参数",
+    41004:"缺少 secret 参数",
+    41005:"缺少多媒体文件数据",
+    41006:"缺少 media_id 参数",
+    41007:"缺少子菜单数据",
+    41008:"缺少 oauth code",
+    41009:"缺少 openid",
+    42001:"access_token 超时,请检查 access_token 的有效期,请参考基础支持 - 获取 access_token 中,对 access_token 的详细机制说明",
+    42002:"refresh_token 超时",
+    42003:"oauth_code 超时",
+    42007:"用户修改微信密码, accesstoken 和 refreshtoken 失效,需要重新授权",
+    43001:"需要 GET 请求",
+    43002:"需要 POST 请求",
+    43003:"需要 HTTPS 请求",
+    43004:"需要接收者关注",
+    43005:"需要好友关系",
+    43019:"需要将接收者从黑名单中移除",
+    44001:"多媒体文件为空",
+    44002:"POST 的数据包为空",
+    44003:"图文消息内容为空",
+    44004:"文本消息内容为空",
+    45001:"多媒体文件大小超过限制",
+    45002:"消息内容超过限制",
+    45003:"标题字段超过限制",
+    45004:"描述字段超过限制",
+    45005:"链接字段超过限制",
+    45006:"图片链接字段超过限制",
+    45007:"语音播放时间超过限制",
+    45008:"图文消息超过限制",
+    45009:"接口调用超过限制",
+    45010:"创建菜单个数超过限制",
+    45011:"API 调用太频繁,请稍候再试",
+    45015:"回复时间超过限制",
+    45016:"系统分组,不允许修改",
+    45017:"分组名字过长",
+    45018:"分组数量超过上限",
+    45047:"客服接口下行条数超过上限",
+    46001:"不存在媒体数据",
+    46002:"不存在的菜单版本",
+    46003:"不存在的菜单数据",
+    46004:"不存在的用户",
+    47001:"解析 JSON/XML 内容错误",
+    48001:"api 功能未授权,请确认公众号已获得该接口,可以在公众平台官网 - 开发者中心页中查看接口权限",
+    48002:"粉丝拒收消息(粉丝在公众号选项中,关闭了 “ 接收消息 ” )",
+    48004:"api 接口被封禁,请登录 mp.weixin.qq.com 查看详情",
+    48005:"api 禁止删除被自动回复和自定义菜单引用的素材",
+    48006:"api 禁止清零调用次数,因为清零次数达到上限",
+    48008:"没有该类型消息的发送权限",
+    50001:"用户未授权该 api",
+    50002:"用户受限,可能是违规后接口被封禁",
+    50005:"用户未关注公众号",
+    61451:"参数错误 (invalid parameter)",
+    61452:"无效客服账号 (invalid kf_account)",
+    61453:"客服帐号已存在 (kf_account exsited)",
+    61454:"客服帐号名长度超过限制 ( 仅允许 10 个英文字符,不包括 @ 及 @ 后的公众号的微信号 )(invalid kf_acount length)",
+    61455:"客服帐号名包含非法字符 ( 仅允许英文 + 数字 )(illegal character in kf_account)",
+    61456:"客服帐号个数超过限制 (10 个客服账号 )(kf_account count exceeded)",
+    61457:"无效头像文件类型 (invalid file type)",
+    61450:"系统错误 (system error)",
+    61500:"日期格式错误",
+    65301:"不存在此 menuid 对应的个性化菜单",
+    65302:"没有相应的用户",
+    65303:"没有默认菜单,不能创建个性化菜单",
+    65304:"MatchRule 信息为空",
+    65305:"个性化菜单数量受限",
+    65306:"不支持个性化菜单的帐号",
+    65307:"个性化菜单信息为空",
+    65308:"包含没有响应类型的 button",
+    65309:"个性化菜单开关处于关闭状态",
+    65310:"填写了省份或城市信息,国家信息不能为空",
+    65311:"填写了城市信息,省份信息不能为空",
+    65312:"不合法的国家信息",
+    65313:"不合法的省份信息",
+    65314:"不合法的城市信息",
+    65316:"该公众号的菜单设置了过多的域名外跳(最多跳转到 3 个域名的链接)",
+    65317:"不合法的 URL",
+    9001001:"POST 数据参数不合法",
+    9001002:"远端服务不可用",
+    9001003:"Ticket 不合法",
+    9001004:"获取摇周边用户信息失败",
+    9001005:"获取商户信息失败",
+    9001006:"获取 OpenID 失败",
+    9001007:"上传文件缺失",
+    9001008:"上传素材的文件类型不合法",
+    9001009:"上传素材的文件尺寸不合法",
+    9001010:"上传失败",
+    9001020:"帐号不合法",
+    9001021:"已有设备激活率低于 50% ,不能新增设备",
+    9001022:"设备申请数不合法,必须为大于 0 的数字",
+    9001023:"已存在审核中的设备 ID 申请",
+    9001024:"一次查询设备 ID 数量不能超过 50",
+    9001025:"设备 ID 不合法",
+    9001026:"页面 ID 不合法",
+    9001027:"页面参数不合法",
+    9001028:"一次删除页面 ID 数量不能超过 10",
+    9001029:"页面已应用在设备中,请先解除应用关系再删除",
+    9001030:"一次查询页面 ID 数量不能超过 50",
+    9001031:"时间区间不合法",
+    9001032:"保存设备与页面的绑定关系参数错误",
+    9001033:"门店 ID 不合法",
+    9001034:"设备备注信息过长",
+    9001035:"设备申请参数不合法",
+    9001036:"查询起始值 begin 不合法"
+}

+ 256 - 0
source/system/lib/helper/wechat/sdk/sdk_mch_redis.ts

@@ -0,0 +1,256 @@
+import { RedisClientType } from '@redis/client';
+import Crypto, { CipherKey } from 'crypto';
+// eslint-disable-next-line @typescript-eslint/no-var-requires
+const XML2JS = require(`xml2js`);
+// eslint-disable-next-line @typescript-eslint/no-var-requires
+// const random = require('string-random')
+const randomStr = (length?:number,nonum?:boolean)=>{
+    let arr = '1234567890abcdefghijklmnopqrstuvwxyz';
+    if(nonum) arr = 'abcdefghijklmnopqrstuvwxyz';
+    let str = '';
+    length = length?length:3;
+    for(let i = 0;i<length;i++){
+        str += arr.substr(Math.floor(Math.random()*26),1);
+    }
+    return str;
+}
+
+const WechatMchDomain  = `https://api.mch.weixin.qq.com`;
+
+class WechatMchSDK{
+    private _redisClient;
+    private _mchId;
+    private _appId;
+    private _privateKeyPem;
+    private _privateCertPem;
+    private _privateKeySerial;
+    private _privateAPIV3Key;
+    private _privateAPIKey;
+    private _wechatMchApiURL;
+    constructor(redisInstance:RedisClientType,config:any){
+        this._redisClient = redisInstance;
+        this._mchId = config.mchId;
+        this._appId = config.appId;
+        this._privateKeyPem = null;
+        this._privateCertPem = null;
+        this._privateKeySerial = config.privateKeySerial;
+        this._privateAPIV3Key = config.privateAPIV3Key;
+        this._privateAPIKey = config.privateAPIKey;
+        if(config.privateKeyFilePath){
+            this._privateKeyPem = FILE.readFileSync(config.privateKeyFilePath,'utf8');
+            this._privateCertPem = FILE.readFileSync(config.privateCertFilePath,'utf8');
+            if(!this._privateKeyPem){
+                throw new Error('[Wechat-Mch-SDK] Config private key pem file read error');
+            }
+            if(!this._privateCertPem){
+                throw new Error('[Wechat-Mch-SDK] Config private key pem file read error');
+            }
+        }
+        if(config.privateKeyPEM){
+            this._privateKeyPem = config.privateKeyPEM;
+        }
+        
+        if(!this._privateKeyPem){
+            throw new Error('[Wechat-Mch-SDK] Private Key read error');
+        }
+
+        this._wechatMchApiURL = {
+            orderTrade_JsAPI:`${WechatMchDomain}/v3/pay/transactions/jsapi`,
+            businessPay_To_Openid:`${WechatMchDomain}/mmpaymkttransfers/promotion/transfers`,
+            getPlatformCertificates:`${WechatMchDomain}/v3/certificates`,
+            
+        }
+
+    }
+
+    getPlatformCertificates(){
+        return new Promise(async (resolve,reject)=>{
+            const certificate = await this._redisClient.get(`WECHAT_MCH_${this._mchId}_PLATFORM_CERT`);
+            if(certificate) return resolve(certificate);
+            const result = await this._getNewPlatformCertificates();
+            const cert = result.cert;
+            
+            if(cert){
+                await this._redisClient.set(`WECHAT_MCH_${this._mchId}_PLATFORM_CERT`,cert.certificate);
+                await this._redisClient.expire(`WECHAT_MCH_${this._mchId}_PLATFORM_CERT`,7200);
+                resolve(cert.certificate);
+            }else{
+                resolve(null);
+            }
+        });
+    }
+    async _getNewPlatformCertificates(){
+        const signedObj = this.makeSignRequestData(this._wechatMchApiURL.getPlatformCertificates,'GET','');
+        const getPlatformCertsResult = await this._requestMchV3Api(this._wechatMchApiURL.getPlatformCertificates,'GET',signedObj.timestamp,signedObj.nonce_str,'',signedObj.signature) as AnyKeyString;
+        if(getPlatformCertsResult.statusCode==200){
+            const cert = getPlatformCertsResult.data.data[0];
+            const certContent = this._decryptByV3Key(cert.encrypt_certificate.ciphertext,cert.encrypt_certificate.nonce,cert.encrypt_certificate.associated_data);
+            const certSerial = cert.serial_no;
+            return({cert:{serial:certSerial,certificate:certContent}});
+        }else{
+            LOGGER.error('Get new platform certificates failed');
+            LOGGER.error(getPlatformCertsResult.toString());
+            return({cert:null});
+        }            
+    }
+
+    async orderTrade_JSAPI(openid:string,trade_no:string,amount:number,desc:string,expire_unix_timestamp:number,notify_url:string){
+        const postData = {
+            appid:this._appId,
+            mchid:this._mchId,
+            description:desc,
+            out_trade_no:trade_no,
+            time_expire:Moment.unix(expire_unix_timestamp).format(),
+            notify_url:notify_url,
+            amount:{
+                total:amount,
+                currency:'CNY'
+            },
+            payer:{
+                openid:openid
+            }
+        };
+        const originBody = JSON.stringify(postData);
+        const signedObj = this.makeSignRequestData(this._wechatMchApiURL.orderTrade_JsAPI,'POST',postData);
+        const result = await this._requestMchV3Api(this._wechatMchApiURL.orderTrade_JsAPI,'POST',signedObj.timestamp,signedObj.nonce_str,originBody,signedObj.signature) as AnyKeyString;
+        if(result.statusCode==200){
+            return result.data.prepay_id;
+        }else{
+            LOGGER.error('Wechat Mch orderTrade error:');
+            LOGGER.error(JSON.stringify(result));
+            return null;
+        }
+    }
+
+    businessPay_To_Openid(orderid:string,openid:string,amount:number,desc:string){
+        return new Promise(resolve=>{
+            const postDataArr:any[] = [];
+            const postData:AnyKeyString = {
+                mch_appid:  this._appId,
+                mchid:      this._mchId,
+                nonce_str:  randomStr(32).toUpperCase(),
+                partner_trade_no: orderid,
+                openid,
+                check_name: 'NO_CHECK',
+                amount,
+                desc
+            }
+            Object.keys(postData).forEach(key=>{
+                postDataArr.push(`${key}=${postData[key]}`);
+            });
+            postDataArr.sort();
+            let postStr = postDataArr.join('&');
+            postStr += `&key=${this._privateAPIKey}`;
+            const md5 = Crypto.createHash('md5')
+            postData.sign = md5.update(postStr).digest('hex').toUpperCase();
+
+            let postXml = '<xml>';
+            Object.keys(postData).forEach(key=>{
+                postXml += `<${key}>${postData[key]}</${key}>`;
+            });
+            postXml += '</xml>'
+
+            REQUEST({url:this._wechatMchApiURL.businessPay_To_Openid,method:'POST',body:postXml,encoding:'utf-8',cert:this._privateCertPem,key:this._privateKeyPem},(err:any,response:any,body:any)=>{
+                const x2jparser = XML2JS.parseString;
+                x2jparser(body, function (err:any, result:any) {
+                    if(result.xml && result.xml.result_code[0]!='SUCCESS'){
+                        return resolve({err:result.xml.err_code[0],data:result.xml.err_code_des[0]})
+                    }
+                    resolve({err:null,data:'SUCCESS'});
+                });
+            })
+        });
+        
+    }
+
+    makeSignPaymentData(prepayId:string){
+        const randStr = randomStr(32).toUpperCase(),timestamp = Moment().unix(),packageStr = `prepay_id=${prepayId}`;
+        let preStr = ''
+        preStr += `${this._appId}\n`;
+        preStr += `${timestamp}\n`;
+        preStr += `${randStr}\n`;
+        preStr += `${packageStr}\n`;
+        // console.log(preStr)
+        const signedStr = this._signWithRSASHA256(preStr);
+        // console.log(signedStr)
+        return {timestamp,nonce_str:randStr,signature:signedStr,package:packageStr,prepay_id:prepayId};
+    }
+
+    makeSignRequestData(requestUrl:string,method:string,content:AnyKeyString|string){
+        const randStr = randomStr(32).toUpperCase(),timestamp = Moment().unix();
+        const url = new URL(requestUrl);
+        const postData = (typeof content === 'object')?JSON.stringify(content):content;
+        let preStr = ''
+        preStr += `${method.toUpperCase()}\n`;
+        preStr += `${url.pathname}${url.search}\n`;
+        preStr += `${timestamp}\n`;
+        preStr += `${randStr}\n`;
+        preStr += `${postData}\n`;
+        // console.log(preStr)
+        const signedStr = this._signWithRSASHA256(preStr);
+        // console.log(signedStr)
+        return {origin:preStr,timestamp,nonce_str:randStr,signature:signedStr};
+    }
+
+    callbackDecrypt(ciphertext:string,nonce:string,associatedData:string){
+        const result = this._decryptByV3Key(ciphertext,nonce,associatedData);
+        return result;
+    }
+
+    _signWithRSASHA256(data:string){
+        const signObj = Crypto.createSign('RSA-SHA256')
+        signObj.update(data);
+        const signedStr = signObj.sign(this._privateKeyPem,'base64');
+        return signedStr;
+    }
+    _requestMchV3Api(url:string,method:string,timestamp:number,nonce_str:string,originBody:string|AnyKeyString,signature:string){
+        return new Promise((resolve,reject)=>{
+            const Authorization = `WECHATPAY2-SHA256-RSA2048 mchid="${this._mchId}",nonce_str="${nonce_str}",signature="${signature}",timestamp="${timestamp}",serial_no="${this._privateKeySerial}"`;
+            REQUEST({url:url,method,encoding:'utf-8',jsonReviver: true,body:originBody,headers: {
+                'Content-Type'  : 'application/json',
+                'Accept'        : 'application/json',
+                'User-Agent'    : 'WECHAT_MCH_SDK/v1',
+                'Authorization' : Authorization,
+            }},(err:any,response:any,body:any)=>{
+                // console.log(response.headers,body)
+                if(typeof body ==='string'){
+                    try{
+                        body = JSON.parse(body);
+                    }catch(e){}
+                }
+                resolve({statusCode:response.statusCode,data:body});
+            });
+        });
+    }
+
+    _decryptByV3Key(ciphertext:string,nonce:string,associatedData:string){
+        const ciphertextBuffer = Buffer.from(ciphertext, 'base64')
+        const authTag = ciphertextBuffer.slice(ciphertextBuffer.length - 16)
+        const data = ciphertextBuffer.slice(0, ciphertextBuffer.length - 16)
+        const decipherIv = Crypto.createDecipheriv('aes-256-gcm', this._privateAPIV3Key, nonce)
+        decipherIv.setAuthTag(Buffer.from(authTag))
+        decipherIv.setAAD(Buffer.from(associatedData))
+        let decryptStr = decipherIv.update(data, undefined, 'utf8')
+        decipherIv.final();
+        if(typeof decryptStr == 'string'){
+            try{
+                decryptStr = JSON.parse(decryptStr);
+            }catch(e){}
+        }
+        return decryptStr;
+    }
+    async _decryptByPlatfromKey(ciphertext:string,nonce:string,associatedData:string){
+        const platformKey = await this.getPlatformCertificates() as CipherKey;
+        const ciphertextBuffer = Buffer.from(ciphertext, 'base64');
+        const authTag = ciphertextBuffer.slice(ciphertextBuffer.length - 16)
+        const data = ciphertextBuffer.slice(0, ciphertextBuffer.length - 16)
+        const decipherIv = Crypto.createDecipheriv('aes-256-gcm', platformKey, nonce)
+        decipherIv.setAuthTag(Buffer.from(authTag))
+        decipherIv.setAAD(Buffer.from(associatedData))
+        const decryptStr = decipherIv.update(data, undefined, 'utf8')
+        decipherIv.final();
+        return decryptStr;
+    }
+}
+
+module.exports = WechatMchSDK;

+ 180 - 0
source/system/lib/helper/wechat/sdk/sdk_mp_redis.ts

@@ -0,0 +1,180 @@
+/**
+ * @Author  HonorLee (dev@honorlee.me)
+ * @Version 2.0 (2019-10-08)
+ */
+// 'use strict'
+//基础配置项
+import { RedisClientType } from '@redis/client';
+import sha1 from 'sha1'
+import wxerr from '../errcodes'
+// eslint-disable-next-line @typescript-eslint/no-var-requires
+// const random = require('string-random')
+
+const errMsg:AnyKeyString = wxerr;
+const randomStr = (length?:number,nonum?:boolean)=>{
+    let arr = '1234567890abcdefghijklmnopqrstuvwxyz';
+    if(nonum) arr = 'abcdefghijklmnopqrstuvwxyz';
+    let str = '';
+    length = length?length:3;
+    for(let i = 0;i<length;i++){
+        str += arr.substr(Math.floor(Math.random()*26),1);
+    }
+    return str;
+}
+
+const WechatDomain  = `https://api.weixin.qq.com`;
+class WechatSDK{
+    private _redisClient:RedisClientType;
+    private _appId;
+    private _token;
+    private _appSecret;
+    private _aesKey;
+    private _wechatApiURL
+    public constructor(redisInstance:RedisClientType,options:{appId:string,token:string,appSecret:string,aesKey:string}) {
+        this._redisClient = redisInstance;
+        this._appId = options.appId;
+        this._token = options.token;
+        this._appSecret = options.appSecret;
+        this._aesKey = options.aesKey;
+        this._wechatApiURL = {
+            getAccessToken:`${WechatDomain}/cgi-bin/token?grant_type=client_credential&appid=${this._appId}&secret=${this._appSecret}`,
+            getJsApiTicket:`${WechatDomain}/cgi-bin/ticket/getticket?type=jsapi&access_token=`,
+            getJsOauthCode:`https://open.weixin.qq.com/connect/oauth2/authorize?appid=${this._appId}`,
+            getOauthToken:`${WechatDomain}/sns/oauth2/access_token?appid=${this._appId}&secret=${this._appSecret}&grant_type=authorization_code`,
+            getOauthUserinfo:`${WechatDomain}/sns/userinfo?lang=zh_CN`,
+            getCode2Session:`${WechatDomain}/sns/jscode2session?appid=${this._appId}&secret=${this._appSecret}&grant_type=authorization_code&js_code=`
+        }
+    }
+    //验签
+    public checkSignature(signature:string,timestamp:string|number,nonce:string){
+        const arr = [this._token, timestamp, nonce];
+        arr.sort();
+        return sha1(arr.join('')) === signature;
+    }
+    public getAccessToken(){
+        return new Promise(async (resolve,reject)=>{
+            const token = await this._redisClient.get(`WECHAT_${this._appId}_ACCESSTOKEN`);
+            console.log(!!token)
+            if(token) return resolve({token});
+            //请求新的Token
+            LOGGER.debug('[Wechat] Get new token')
+            REQUEST({url:this._wechatApiURL.getAccessToken,encoding:'UTF-8',json:true},async (err:any,response:any,body:any)=>{
+                if(err || !body){
+                    LOGGER.error('Wechat getAccessToken error!');
+                    LOGGER.error(err.stack);
+                    return resolve({err:new Error('Wechat getAccessToken error!')});
+                }
+                if(body.errcode){
+                    LOGGER.debug(body.errmsg||'body.errcode');
+                    return resolve({err:new Error(`ERROR_CODE:${errMsg[body.errcode]}`)});
+                }
+                const _token = body.access_token;
+                const expires = body.expires_in - 5 * 60;
+                await this._redisClient.set(`WECHAT_${this._appId}_ACCESSTOKEN`,_token,{EX:expires});
+                resolve({token:_token});
+            });
+            
+        });
+    }
+    public async getJsApiTicket(){
+        const token:any = await this.getAccessToken();
+        if(token.err) return token;
+        return new Promise(async (resolve,reject)=>{
+            const ticket = await this._redisClient.get(`WECHAT_${this._appId}_JSAPITICKET`);
+            if(ticket) return resolve({ticket});
+            REQUEST({url:`${this._wechatApiURL.getJsApiTicket}${token.token}`,encoding:'UTF-8',json:true},(err:any,response:any,body:any)=>{
+                if(err || !body){
+                    LOGGER.error('Wechat getJsApiTicket error!');
+                    LOGGER.error(err.stack);
+                    return resolve({err:new Error('Wechat getJsApiTicket error!')});
+                }
+                if(body.errcode){
+                    return resolve({err:new Error(`ERROR_CODE:${errMsg[body.errcode]}`)});
+                }
+                const _ticket = body.ticket;
+                const expires = body.expires_in - 5;
+                this._redisClient.set(`WECHAT_${this._appId}_JSAPITICKET`,_ticket,{EX:expires});
+                resolve({ticket:_ticket});
+            })
+        });
+    }
+    public async getSignature(url:string){
+        if(!url) return {err:new Error('URL is empty!')};
+        const noncestr = randomStr(16);
+        const timestamp = Math.floor(new Date().getTime());
+        const ticket = await this.getJsApiTicket();
+        const combineStr = `jsapi_ticket=${ticket.ticket}&noncestr=${noncestr}&timestamp=${timestamp}&url=${url}`;
+        const signature = sha1(combineStr);
+        return {nonceStr:noncestr,timestamp:timestamp,signature:signature,appId:this._appId};
+    }
+    public getJsOauthCodeURL(redirectURL:string,Scope:string,State?:string){
+        if(!redirectURL || !redirectURL.match(/(https?):\/\/[-A-Za-z0-9+&@#\/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]/gi)){
+            return {err:new Error('redirectURL Error')};
+        }
+        if(Scope!='snsapi_base' && Scope!='snsapi_userinfo'){
+            return {err:new Error('Scope must be snsapi_base or snsapi_userinfo')};
+        }
+        if(!State) State = 'null';
+        redirectURL = encodeURI(redirectURL);
+        const urlString = `${this._wechatApiURL.getJsOauthCode}&redirect_uri=${redirectURL}&response_type=code&scope=${Scope}&state=${State}#wechat_redirect`;
+        return {url:urlString};
+    }
+    public async getOauthToken(code:string){
+        if(!code) return {err:new Error('Code is empty!')};
+        return new Promise((resolve,reject)=>{
+            REQUEST({url:`${this._wechatApiURL.getOauthToken}&code=${code}`,encoding:'UTF-8',json:true},(err:any,response:any,body:any)=>{
+                if(err || !body){
+                    LOGGER.error('Wechat getOauthToken error!');
+                    LOGGER.error(err.stack);
+                    return resolve({err:new Error('Wechat getOauthToken error!')});
+                }
+                if(body.errcode){
+                    return resolve({err:new Error(`ERROR_CODE:${errMsg[body.errcode]}`)});
+                }
+                resolve({token:body.access_token,openid:body.openid});
+            });
+        })
+    }
+    public getOauthUserinfo(oAuthToken:string,openid:string){
+        return new Promise((resolve,reject)=>{
+            REQUEST({url:`${this._wechatApiURL.getOauthUserinfo}&access_token=${oAuthToken}&openid=${openid}`,encoding:'UTF-8',json:true},(err:any,response:any,body:any)=>{
+                if(err || !body){
+                    LOGGER.error('Wechat getOauthUserinfo error!');
+                    LOGGER.error(err.stack);
+                    return resolve({err:new Error('Wechat getOauthUserinfo error!')});
+                }
+                if(body.errcode){
+                    return resolve({err:new Error(`ERROR_CODE:${errMsg[body.errcode]}`)});
+                }
+                resolve({userinfo:body});
+            });
+        })
+    }
+    public async getOauthUserinfoByCode(code:string){
+        const _authToken = await this.getOauthToken(code) as AnyKeyString;
+        if(_authToken && !_authToken.err){
+            const _userInfo = await this.getOauthUserinfo(_authToken.access_token,_authToken.openid);
+            return _userInfo;
+        }else{
+            return null;
+        }
+    }
+    public getCodeSession(code:string){
+        return new Promise((resolve,reject)=>{
+            REQUEST({url:`${this._wechatApiURL.getCode2Session}${code}`,encoding:'UTF-8',json:true},(err:any,response:any,body:any)=>{
+                // console.log(1,err,response,body)
+                if(err || !body){
+                    LOGGER.error('Wechat getCode2Session error!');
+                    LOGGER.error(err.stack);
+                    return resolve({err:new Error('Wechat getCode2Session error!')});
+                }
+                if(body.errcode){
+                    return resolve({err:new Error(`ERROR_CODE:${body.errcode} - ${errMsg[body.errcode]}`)});
+                }
+                resolve({openid:body.openid,unionid:body.unionid,session_key:body.session_key});
+            });
+        })
+    }
+}
+
+module.exports = WechatSDK;

+ 18 - 10
source/system/module/mvc/lib/controller.ts

@@ -7,18 +7,24 @@ export default class Controller{
     private _requestData:RequestData;
     private _Request:any;
     private _Response:any;
+    public REFERER:string;
     public COOKIE:any;
     public GET:any;
     public POST:any;
     public UPLOAD:any;
+    public SESSION:any;
+    public DATA:AnyKeyString;
     constructor(requestData:RequestData) {
         this._requestData = requestData;
         this._Request  = requestData.req;
         this._Response = requestData.res;
+        this.REFERER   = this._Request.headers.referer;
         this.COOKIE    = requestData.COOKIE;
         this.GET       = requestData.GET;
         this.POST      = requestData.POST;
         this.UPLOAD    = requestData.UPLOAD;
+        this.SESSION   = requestData.SESSION;
+        this.DATA      = {};
 
         if(this.GET._time) delete this.GET._time;
         if(this.POST._time) delete this.POST._time;
@@ -116,7 +122,7 @@ export default class Controller{
     //     }
     // }
 
-    setCookie(key:string,value:any,expireHour?:number|'forever',path?:string){
+    setCookie(key:string,value:any,expireHour?:number|'forever',path?:string,httpOnly?:boolean){
         let cookie,originCookie;
         if(this._Response.hasHeader('Set-Cookie')){
             originCookie = this._Response.getHeader('Set-Cookie');
@@ -124,16 +130,18 @@ export default class Controller{
         if(!originCookie) originCookie = [];
         if(typeof originCookie == 'string') originCookie = [originCookie];
         cookie = `${key}=${value}`;
-        if(path) cookie += ';path=' + path;
-        if(expireHour){
-            let expireTime;
-            if(expireHour=='forever'){
-                expireTime = new Date('9999/01/01 00:00:00').toUTCString();
-            }else{
-                expireTime = new Date(new Date().getTime()+Number(expireHour)*1000*60).toUTCString();
-            }
-            cookie += ';expires=' + expireTime;
+        cookie += ';path=' + (path||'/');
+        expireHour = expireHour!=undefined&&expireHour>=0?expireHour:'forever';
+        let expireTime;
+        if(expireHour=='forever'){
+            expireTime = new Date('9999/01/01 00:00:00').toUTCString();
+        }else if(expireHour==0){
+            expireTime = new Date(0).toUTCString();
+        }else{
+            expireTime = new Date(new Date().getTime()+Number(expireHour)*1000*60).toUTCString();
         }
+        cookie += ';expires=' + expireTime;
+        if(httpOnly) cookie += ';httpOnly=true';
         originCookie.push(cookie);
         this._Response.setHeader('Set-Cookie',cookie);
     }

+ 2 - 3
source/system/module/mvc/lib/module.ts

@@ -12,9 +12,8 @@
                 return null;
             }
             moduleName = moduleName.toLowerCase();
-            // let ext = moduleName.includes('.js')?'':'.js';
-            // let filePath = `${_MVCRootPath.module}/${moduleName}${ext}`
-            const filePath = `${SYSTEM.MVC.PATH.MODULE}/${moduleName}`;
+            const ext = moduleName.includes('.js')?'':'.js';
+            const filePath = `${SYSTEM.MVC.PATH.MODULE}/${moduleName}${ext}`;
             try{
                 FILE.statSync(filePath);
                 return require(filePath);

+ 32 - 2
source/system/module/mvc/lib/router.ts

@@ -6,11 +6,33 @@
 import PATH = require('path');
 
 export default class Router{
+    private static _midware:any[] = [];
+    public static addMidware(func:any){
+        Router._midware.push(func);
+    }
     public static async run(requestData:RequestData){
         let method  = 'index';
         let handlerFile;
         Object.keys(SYSTEM.MVC.ROUTER_MAP).forEach(path=>{
-            if(requestData.path && requestData.path.indexOf(path) == 0) requestData.path = `${SYSTEM.MVC.ROUTER_MAP[path]}${requestData.path.replace(path,'')}`;
+            if(requestData.path && requestData.path.indexOf(path) == 0){
+                if(SYSTEM.MVC.ROUTER_MAP[path].constructor==String){
+                    requestData.path = `${SYSTEM.MVC.ROUTER_MAP[path]}${requestData.path.replace(path,'')}`;
+                }else if(SYSTEM.MVC.ROUTER_MAP[path].constructor==Object){
+                    if(SYSTEM.MVC.ROUTER_MAP[path].method){
+                        if(requestData.method!=SYSTEM.MVC.ROUTER_MAP[path].method){
+                            if(requestData.res){
+                                requestData.res.statusCode = 400;
+                                requestData.res.write('Unauthorized request method!');
+                                requestData.res.end();
+                            }
+                            return
+                        }
+                    }
+                    if(SYSTEM.MVC.ROUTER_MAP[path].forward){
+                        requestData.path = `${SYSTEM.MVC.ROUTER_MAP[path].forward}${requestData.path.replace(path,'')}`;
+                    }
+                }
+            }
         })
         if(requestData.path == '/'){
             handlerFile = '/index.js'
@@ -72,6 +94,12 @@ export default class Router{
         
         if(typeof handler[method]==='function'){
             let returnSometing;
+            if(Router._midware.length){
+                for(const func of Router._midware){
+                    const ret = func(requestData);
+                    if(ret==false) return;
+                }
+            }
             if(typeof handler['__construct']==='function'){
                 try{
                     returnSometing = await handler['__construct'].call(handler);
@@ -80,9 +108,11 @@ export default class Router{
                     Router._error(403,e.stack,requestData.res);
                     return;
                 }
+                if(returnSometing == false) return;
             }
+            if(handler[method].prototype && handler[method].prototype.method && handler[method].prototype.method.toLowerCase()!=requestData.method) return handler.end('Unauthorized request method',400);
             try{
-                handler[method].call(handler,returnSometing);
+                await handler[method].call(handler,returnSometing);
             }catch(e:any){
                 LOGGER.error(`Function [${method}] in [${handlerFile}] called error:`);
                 Router._error(403,e.stack,requestData.res);

+ 295 - 0
source/system/module/mvc/lib/session.ts

@@ -0,0 +1,295 @@
+/*
+ * @Author: HonorLee
+ * @Version 1.0
+ * @LastUpdate 2018/6/19
+ * @License MIT
+*/
+import { RedisClientType } from '@redis/client';
+import MD5 from 'md5'
+
+export default class Session{
+    public static setStorageType(type:'file'|'redis',instance:RedisClientType|undefined){
+        SessionManager._storageType = type;
+        if(type=='redis') SessionManager._storageInstance = instance;
+    }
+
+    //Session实例
+    public sessionID:string;
+    private _sessionKey:string;
+    private _requestData:RequestData;
+    constructor(requestData:RequestData,sessionID?:string|undefined){
+        this.sessionID = sessionID?sessionID:MD5(new Date().getTime()+''+Math.floor(Math.random()*9000+1000));
+        this._sessionKey = `session_${this.sessionID}`;
+        this._requestData = requestData;
+        if(!sessionID && this._requestData.res){
+            this._requestData.res.setHeader('Set-Cookie',`SESSIONID=${this.sessionID};max-age=${7*24*60*60};path=/;httpOnly=true`);
+            this.set('sessionid',this.sessionID);
+            this.setExpire(7*24*60*60);
+        }
+    }
+    async set(key:string,value:any|null){
+        return await SessionManager.set(this._sessionKey,key,value);
+    }
+    async setExpire(expire:number,autoRenew?:boolean){
+        return await SessionManager.setExpire(this._sessionKey,expire,autoRenew)
+    }
+    async get(key:string){
+        return await SessionManager.get(this._sessionKey,key);
+    }
+    async getAll(){
+        return await SessionManager.getAll(this._sessionKey);
+    }
+    async clear(){
+        return await SessionManager.clear(this._sessionKey);
+    }
+}
+class SessionManager{
+    //全局存储控制
+    public static _storageType = 'file';   //默认以文件形式存储
+    public static _storageInstance:RedisClientType|undefined;
+
+    public static async set(sessionKey:string,key:string,value:any|null){
+        if(SessionManager._storageType=='redis' && SessionManager._storageInstance){
+            let ret;
+            if(value==null){
+                ret= await SessionManager._storageInstance.hDel(sessionKey,key);
+            }else{
+                ret= await SessionManager._storageInstance.hSet(sessionKey,key,value);
+            } 
+            if(ret) return true
+            else return false;
+        }else{
+
+        }
+        return true;
+    }
+    public static async setExpire(sessionKey:string,expire:number,autoRenew?:boolean){
+        if(SessionManager._storageType=='redis' && SessionManager._storageInstance){
+            const ret = await SessionManager._storageInstance?.expire(sessionKey,expire);
+            if(!ret) return false;
+        }else{
+        }
+        return true;
+    }
+    public static async get(sessionKey:string,key:string){
+        let ret;
+        if(SessionManager._storageType=='redis' && SessionManager._storageInstance){
+            ret = await SessionManager._storageInstance.hGet(sessionKey,key);
+        }else{
+        }
+        return ret;
+    }
+    public static async getAll(sessionKey:string){
+        let ret;
+        if(SessionManager._storageType=='redis' && SessionManager._storageInstance){
+            ret = await SessionManager._storageInstance.hGetAll(sessionKey);
+        }else{
+        }
+        return true;
+    }
+    public static async clear(sessionKey:string){
+        let ret;
+        if(SessionManager._storageType=='redis' && SessionManager._storageInstance){
+            ret = await SessionManager._storageInstance.del(sessionKey);
+        }else{
+        }
+        return ret;
+    }
+}
+/**
+    setWithSessionID:function(sessionID,key,value,callback){
+        callback = Manager.buildCallback(callback);
+        if(!key || value==null) return callback.call(this,'Session key or value is empty',null);
+        let _this = this;
+        let session = {};
+
+        session.id = sessionID;
+        session.data = {};
+        session.data[key] = value;
+        session.expire = Config.SessionExpire*60;
+        session.expireTime = new Date().getTime()+session.expire*1000;
+        session.autoRenewExpire = Config.SessionExpire*60;
+
+        Manager.set(session,function(err){
+            if(err) return callback.call(_this,'Session set err;',null);
+            callback.call(_this,null,session);
+        });
+    },
+    setExpireTime:function(sessionid,expire,autoRenewExpire,callback){
+        let _this = this;
+        callback = Manager.buildCallback(callback);
+        if(!sessionid) return callback.call(this,'Session id is empty',null);
+        if(!expire) return callback.call(this,'Session expire must bigger than 0',null);
+        Session.get(sessionid,function(err,data){
+            if(err || !data) return callback.call(this,'Session is gone',null);
+            let session = data;
+            session.expire = expire*60;
+            autoRenewExpire = autoRenewExpire*1;
+            if(autoRenewExpire>0) session.autoRenewExpire = autoRenewExpire*60;
+            Manager.set(session,function(err){
+                if(err){
+                    LOGGER.error(err);
+                    callback.call(_this,'Session set expire error',null);
+                }else{
+                    callback.call(_this,null,session);
+                }
+            })
+        });
+
+    },
+    update:function(sessionid,key,value,callback){
+        callback = Manager.buildCallback(callback);
+        if(!sessionid || !key || value==null) return callback.call(this,'Session id,key or value is empty',null);
+        let _this = this;
+        Manager.get(sessionid,function(err,result){
+            let session;
+            if(err || result == null){
+                session = {id:sessionid,data:{}};
+            }else{
+                session = result;
+            }
+
+            if(err || result == null || Config.Session.AutoRefresh){
+                session.expire = session.autoRenewExpire;
+                session.expireTime = new Date().getTime()+session.expire*1000;
+            }
+
+            session.data[key] = value;
+            Manager.set(session,function(err){
+                if(err) return callback.call(_this,'Session set error');
+                callback.call(_this,null,session)
+            });
+        });
+    },
+    get:function(sessionid,callback){
+        callback = Manager.buildCallback(callback);
+        if(!sessionid) return callback.call(this,'Session id is empty',null);
+        let _this = this;
+        Manager.get(sessionid,function(err,result){
+            callback.call(_this,null,result);
+        });
+    },
+    getKeyValue:function(sessionid,key,callback){
+        callback = Manager.buildCallback(callback);
+        if(!sessionid || !key) return callback.call(this,'Session id or key is empty',null);
+        let _this = this;
+        Session.get(sessionid,function(err,result){
+            if(err || !result) return callback.call(_this,null);
+            callback.call(_this,null,result.data[key]);
+        });
+    },
+    clear:function(sessionid){
+        if(!sessionid) return;
+        Manager.clear(sessionid);
+    },
+    instance:function(sessionID,callback){
+        return new Instance(sessionID,callback);
+    }
+};
+module.exports = Session;
+
+var Manager = {
+    get:function(sessionid,callback){
+        let session;
+        if(Config.Session.StoreType.toLowerCase()=='memcache' && Config.Database.Memcache.on && Memcache){
+            Memcache.get('session_'+sessionid,function(err,result){
+                if(err) return callback(err);
+                session = result;
+                callback(null,result);
+                if(session && Config.Session.AutoRefresh){
+                    session.expire = session.autoRenewExpire;
+                    session.expireTime = new Date().getTime()+session.expire*1000;
+                    Manager.set(session,null);
+                }
+            });
+        }else{
+            try{
+                session = JSON.parse(FILE.readFileSync(Core.Path.Session + '/' + sessionid,'UTF-8'));
+            }catch(e){}
+            if(session && session.expireTime){
+                if(new Date().getTime()>session.expireTime){
+                    if(Config.Session.AutoRefresh){
+                        session.expire = session.autoRenewExpire;
+                        session.expireTime = new Date().getTime()+session.expire*1000;
+                        Manager.set(session,null);
+                    }else{
+                        session = null;
+                        Manager.clear(sessionid);
+                    }
+                }
+            }
+            if(callback) callback(null,session);
+        }
+
+    },
+    set:function(session,callback){
+        if(Config.Session.StoreType.toLowerCase()=='memcache' && Config.Database.Memcache.on && Memcache){
+            Memcache.set('session_'+session.id,session,session.expire,function(err){
+                if(err){
+                    Logger.error(err);
+                    if(callback) callback(err);
+                    return;
+                }
+                if(callback) callback();
+            });
+        }else{
+            FILE.writeFileSync(Core.Path.Session + '/' + session.id,JSON.stringify(session),'UTF-8');
+            if(callback) callback();
+        }
+    },
+    clear:function(sessionid){
+        if(Config.Session.StoreType.toLowerCase()=='memcache' && Config.Database.Memcache.on && Memcache){
+            Memcache.del('session_'+sessionid);
+        }else{
+            try{
+                FILE.rmdirSync(Core.Path.Session + '/' + sessionid);
+            }catch(e){}
+        }
+    },
+    buildCallback:function(callback){
+        if(callback && typeof callback=='function') return callback;
+        return function(){};
+    }
+}
+
+var Instance = function(sessionID,callback){
+    var _data;
+    var _sessionID = sessionID;
+    var _this = this;
+    this.sessionID = _sessionID;
+    this.get = function(key){
+        return _data[key];
+    }
+    this.set = function(key,value){
+        _data[key] = value;
+        Session.update(_sessionID,key,value);
+    }
+    this.setExpireTime = function(expire,autoRenewExpire){
+        Session.setExpireTime(_sessionID,expire,autoRenewExpire);
+    }
+    if(sessionID){
+        Session.get(sessionID,function(err,session){
+            if(err || !session){
+                Session.setWithSessionID(sessionID,'status',0,function(err,new_session){
+                    _data = new_session.data;
+                    // _this.sessionID = new_session.id;
+                    if(callback) callback(sessionID,_this);
+                });
+            }else{
+                _data = session.data;
+                _this.sessionID = session.id;
+                if(callback) callback(session.id,_this);
+            }
+        });
+    }else{
+        Session.set('status',0,function(err,new_session){
+            _data = new_session.data;
+            _sessionID = new_session.id;
+            _this.sessionID = new_session.id;
+            if(callback) callback(new_session.id,_this);
+        });
+    }
+    return this;
+}
+
+**/ 

+ 21 - 10
source/system/module/mvc/mvc.ts

@@ -8,6 +8,9 @@ import formidable = require('formidable')
 import Router from './lib/router';
 //模型控制器
 import Module from './lib/module';
+//Session控制器
+import Session from './lib/session';
+//控制器基类
 import ControllerClass from './lib/controller';
 (global as any).CONTROLLER = ControllerClass;
 
@@ -25,7 +28,10 @@ class MVC {
                 VIEW:`${Root}/view`,
             },
             ROUTER_MAP:null,
-            EJS:require('ejs')
+            ROUTER:Router,
+            SESSION:Session,
+            EJS:require('ejs'),
+            start:()=>{this.start()}
         };
         //初始化Module控制器
         Module.init();
@@ -52,6 +58,8 @@ class MVC {
             }
             SYSTEM.MVC.ROUTER_MAP = {};
         }
+    }
+    public start(){
         try{
             HTTP.createServer(this._serverHandler).listen(SYSTEM.MVC.PORT);
             LOGGER.info(`Http MVC Server start at port [${SYSTEM.MVC.PORT}]`);
@@ -62,13 +70,15 @@ class MVC {
     }
     protected _serverHandler(req?:HTTP.IncomingMessage,res?:HTTP.ServerResponse){
         if(!req) return;
-        const RequestData:RequestData = {
+        const requestData:RequestData = {
             req,res,
             path:'' as string|null,
+            method:req.method?.toLowerCase()||'get',
             COOKIE:{} as any,
             GET:{},
             POST:{},
-            UPLOAD:{}
+            UPLOAD:{},
+            SESSION:{} as any
         }
         req.headers.cookie && req.headers.cookie.split(';').forEach((Cookie)=>{
             const parts:Array<string> = Cookie.split('=');
@@ -76,22 +86,23 @@ class MVC {
             if (key){
                 key = key.trim();
                 const value = parts.join('=').trim();
-                RequestData.COOKIE[key] = value;
+                requestData.COOKIE[key] = value;
             }
         });
+        requestData.SESSION = new Session(requestData,requestData.COOKIE.SESSIONID);
         const URLParse = URL.parse(req.url as string,true);
         if(URLParse){
-            RequestData.path = URLParse.pathname,
-            RequestData.GET = URLParse.query;
+            requestData.path = URLParse.pathname,
+            requestData.GET = URLParse.query;
         }
         if(req.method && req.method.toLowerCase()=='post'){
             new IncomingForm().parse(req, (err, fields, files)=>{
-                RequestData.POST = fields;
-                RequestData.UPLOAD = files;
-                Router.run(RequestData);
+                requestData.POST = fields;
+                requestData.UPLOAD = files;
+                Router.run(requestData);
             });
         }else{
-            Router.run(RequestData);
+            Router.run(requestData);
         }
     }
 }