diff --git a/index.js b/index.js index bd523ff..9df8d76 100644 --- a/index.js +++ b/index.js @@ -6,30 +6,23 @@ */ import 'es.shim' // 加载拓展方法 -import init from './lib/reg-init.js' - import http from 'http' import path from 'path' -import Request from '../request/index.js' -import Response from '../response/index.js' - -// import Smarty from 'smartyx' //模板引擎 -import Log from './module/log.js' //基础日志记录工具 -import Email from './module/sendmail.js' //加载email发送类 -import Mysql from 'mysqli' //加载mysql操作类 -import Ioredis from 'ioredis' - -import sec from 'crypto.js' -import url from 'url' import fs from 'iofs' -import child from 'child_process' +import Ioredis from 'ioredis' +import Request from '@gm5/request' +import Response from '@gm5/response' +import Cookie from '@gm5/cookie' +import Session from '@gm5/session' + +import init from './lib/reg-init.js' +import Log from './lib/log.js' //基础日志记录工具 -import Controller from './lib/controller.js' import routerWare from './middleware/router.js' -import cookieWare from './middleware/cookie.js' -import sessionWare from './middleware/session.js' import credentialsWare from './middleware/credentials.js' +// import cookieWare from './middleware/cookie.js' +// import sessionWare from './module/session.js' var log = console.log @@ -61,7 +54,7 @@ export default class Five { hideProperty( this, '__SESSION_STORE__', - new libs.Ioredis({ + new Ioredis({ host: session.db.host || '127.0.0.1', port: session.db.port || 6379, db: session.db.db || 0 @@ -73,8 +66,8 @@ export default class Five { // 将session和cookie的中间件提到最前 // 以便用户自定义的中间件可以直接操作session和cookie - this.__MIDDLEWARE__.unshift(sessionWare) - this.__MIDDLEWARE__.unshift(cookieWare) + // this.__MIDDLEWARE__.unshift(sessionWare) + this.__MIDDLEWARE__.unshift(Cookie) this.__MIDDLEWARE__.unshift(credentialsWare) this.use(routerWare) @@ -106,9 +99,7 @@ export default class Five { get(key) { try { return new Function('o', `return o.${key}`)(this.__FIVE__) - } catch (err) { - return - } + } catch (err) {} } // 加载中间件/缓存模块 @@ -168,10 +159,11 @@ export default class Five { // 启动http服务 listen(port) { var _this = this + var server this.__init__() - var server = http.createServer(function(req, res) { + server = http.createServer(function(req, res) { var response = new Response(req, res) var request = new Request(req, res) diff --git a/lib/controller.js b/lib/controller.js deleted file mode 100644 index 031f5b8..0000000 --- a/lib/controller.js +++ /dev/null @@ -1,78 +0,0 @@ -/** - * 控制器基类 - * @authors yutent (yutent@doui.cc) - * @date 2016-01-02 23:19:16 - * - */ - -import Smarty from 'smartyx' //模板引擎 - -import { sign, verify } from '../module/jwt.js' - -const smarty = new Smarty() - -export default class Controller { - constructor({ ctx, req, res }) { - this.ctx = ctx - this.name = req.app - this.request = req - this.response = res - - this.jwt = { - sign: sign.bind(this), - result: verify.call(this) - } - - smarty.config('path', this.ctx.get('VIEWS')) - smarty.config('ext', this.ctx.get('temp_ext')) - smarty.config('cache', !!this.ctx.get('temp_cache')) - - this.cookie = this.ctx.ins('cookie') - this.session = this.ctx.ins('session') - } - - //定义一个变量,类似于smarty,把该 - assign(key, val) { - key += '' - if (!key) { - return - } - - if (val === undefined || val === null) { - val = '' - } - - smarty.assign(key, val) - } - - //模板渲染, 参数是模板名, 可不带后缀, 默认是 .tpl - render(file, noParse = false) { - smarty - .render(file, noParse) - .then(html => { - this.response.render(html) - }) - .catch(err => { - this.response.error(err) - }) - } - - // RESFULL-API规范的纯API返回 - send(status = 200, msg = 'success', data = {}) { - if (typeof msg === 'object') { - data = msg - msg = 'success' - } - this.response.send(status, msg, data) - } - - //针对框架定制的debug信息输出 - xdebug(err) { - let msg = err - if (this.ctx.get('debug')) { - msg = err.stack || err - } - - this.response.append('X-debug', msg + '') - } -} diff --git a/module/log.js b/lib/log.js similarity index 66% rename from module/log.js rename to lib/log.js index 98d5267..1ffee17 100644 --- a/module/log.js +++ b/lib/log.js @@ -1,10 +1,11 @@ /** - * - * @authors yutent (yutent@doui.cc) - * @date 2015-11-25 17:48:17 - * + * 简单的日志封装 + * @author yutent + * @date 2020/09/18 16:07:26 */ -'use strict' + +import fs from 'iofs' +import path from 'path' export default class Log { constructor(file = 'run_time.log', dir) { @@ -12,11 +13,11 @@ export default class Log { throw new Error(`agument dir must be a string, but ${typeof dir} given.`) } - if (!Util.fs.exists(dir)) { - Util.fs.mkdir(dir) + if (!fs.exists(dir)) { + fs.mkdir(dir) } - this.file = Util.path.resolve(dir, file) + this.file = path.resolve(dir, file) } error(str) { @@ -38,9 +39,10 @@ export default class Log { //写入日志文件 save(str, type) { type = type || 'debug' - Util.fs.origin.appendFile( + fs.echo( `[${type}] ${new Date().format('Y-m-d_H:i:s')} ${str} \n`, - this.file + this.file, + true ) } } diff --git a/lib/reg-init.js b/lib/reg-init.js index d29b017..2a8c0cf 100644 --- a/lib/reg-init.js +++ b/lib/reg-init.js @@ -23,7 +23,7 @@ export default { website: 'localhost', domain: '', // cookie域, 默认等于website port: 3000, - routeMode: 1, + routeMode: 'action', // action | __main__ env: process.env.NODE_ENV === 'production' ? 'production' : 'development', debug: process.env.NODE_ENV !== 'production', // debug模式 smtp: { diff --git a/middleware/cookie.js b/middleware/cookie.js deleted file mode 100644 index 34a8cda..0000000 --- a/middleware/cookie.js +++ /dev/null @@ -1,38 +0,0 @@ -/** - * - * @authors yutent (yutent@doui.cc) - * @date 2018-05-26 00:01:00 - * @version $Id$ - */ - -import Cookie from 'http.cookie' - -export default function(req, res, next) { - var cookie = new Cookie(req.origin.req, req.origin.res) - var domain = this.get('domain') - this.__INSTANCE__.cookie = function(key, val, opt) { - if (typeof key !== 'string') { - throw new Error( - `argument key must be a string in cookie() ${typeof key} given` - ) - } - - if (arguments.length === 1) { - return cookie.get(key) - } - - if (!opt) { - opt = {} - } - opt.domain = opt.domain || domain - - val += '' - - if (!val) { - opt.expires = opt.maxAge = -1 - } - - cookie.set(key, val, opt) - } - next() -} diff --git a/middleware/credentials.js b/middleware/credentials.js index 6bf578c..9190289 100644 --- a/middleware/credentials.js +++ b/middleware/credentials.js @@ -1,10 +1,10 @@ /** - * - * @authors yutent (yutent@doui.cc) - * @date 2018-09-03 22:26:51 + * 跨域中间件 + * @author yutent + * @date 2020/09/18 14:55:49 */ -'use strict' +import url from 'url' export default function(req, res, next) { var supportCredentials = this.get('supportCredentials') @@ -14,7 +14,7 @@ export default function(req, res, next) { if (supportCredentials) { var origin = req.header('origin') || req.header('referer') || '' var headers = req.header('access-control-request-headers') - origin = Util.url.parse(origin) + origin = url.parse(origin) if (credentialsRule && origin.hostname) { if (!credentialsRule.test(origin.hostname)) { diff --git a/middleware/router.js b/middleware/router.js index ef27b60..5af491f 100644 --- a/middleware/router.js +++ b/middleware/router.js @@ -1,55 +1,59 @@ /** - * 路由 - * @authors yutent (yutent@doui.cc) - * @date 2015-10-01 19:11:19 - * + * 路由中间件 + * @author yutent + * @date 2020/09/18 15:16:29 */ -'use strict' export default function(req, res, next) { + var debug = this.get('debug') + + // 1. 先判断控制器是否存在 if (!this.__MODULES__[req.app]) { - if (!this.__MODULES__.__error__) { - res.error(`The app [${req.app}] not found`, 404) - } else { + if (this.__MODULES__.__error__) { res.error( - this.get('debug') - ? this.__MODULES__.__error__.stack - : this.__MODULES__.__error__, + debug ? this.__MODULES__.__error__.stack : this.__MODULES__.__error__, 500 ) + } else { + res.error(`Controller [${req.app}] not found`, 404) } return } - try { - if (req.path.length < 1) { - req.path.push('index') - } + // 2. 默认二级路由为index + if (req.path.length < 1) { + req.path.push('index') + } - this.__MODULES__[req.app].then(Mod => { + // 3. 实例化控制器 + this.__MODULES__[req.app] + .then(({ default: Mod }) => { var app = new Mod({ ctx: this, req, res }) + var err = '' - if (this.get('routeMode') === 1) { - var act = req.path.shift() + // action模式, 则路由自动调用对应的action方法 + // __main__模式, 则路由全部走__main__方法 + if (this.get('routeMode') === 'action') { + var route = req.path.shift() + var act = route + 'Action' - if (app[act + 'Action']) { - app[act + 'Action'].apply(app, req.path).catch(err => { - res.error(this.get('debug') ? err.stack || err : err, 500) - }) + if (app[act]) { + return app[act].apply(app, req.path) } else { - res.error(`Action[${act}] not found`, 404) + err = new Error(`Route [${route}] not found`) } } else { - if (app.indexAction) { - app.indexAction.apply(app, req.path).catch(err => { - res.error(this.get('debug') ? err.stack || err : err, 500) - }) + if (app.__main__) { + return app.__main__.apply(app, req.path) } else { - res.error(`Default Action not found`, 404) + err = new Error('__main__() not found') } } + + err.status = 404 + return Promise.reject(err) + }) + .catch(err => { + res.error(debug ? err.stack || err : err, err.status || 500) }) - } catch (err) { - res.error(this.get('debug') ? err.stack || err : err, 500) - } } diff --git a/middleware/session.js b/middleware/session.js deleted file mode 100644 index f1b5641..0000000 --- a/middleware/session.js +++ /dev/null @@ -1,65 +0,0 @@ -/** - * - * @authors yutent (yutent@doui.cc) - * @date 2018-07-26 15:50:25 - * @version $Id$ - */ -import redisStore from '../module/redis-store.js' -import nativeStore from '../module/native-store.js' - -export default function(req, res, next) { - var opt = this.get('session') - var jwt = this.get('jwt') - var cookie = this.ins('cookie') - var session = null - var uuid = Util.sec.uuid() - var ssid = '' - - opt.jwt = jwt - - if (req.method === 'OPTIONS') { - return next() - } - - if (jwt) { - var auth = req.header('authorization') - if (auth) { - ssid = auth.split('.').pop() - uuid = auth - } - } else { - ssid = cookie('NODESSID') - // 校验级别为1, 则混入ua - if (opt.level > 0) { - uuid += req.header('user-agent') - } - // 校验级别为2, 则混入ip - if (opt.level > 1) { - uuid += req.ip() - } - } - uuid = Util.sec.sha1(uuid) - - if (opt.type === 'redis') { - session = new redisStore(this.__SESSION_STORE__, opt, uuid) - } else { - session = new nativeStore(this.__SESSION_STORE__, opt, uuid) - } - - // 启用SESSION - // ssid非法或过期时,需要重写 - if (!ssid || ssid !== session.start(ssid)) { - ssid = session.start(ssid) - if (!jwt) { - cookie('NODESSID', ssid, { - httpOnly: true, - expires: opt.ttl, - domain: opt.domain - }) - } - } - - this.__INSTANCE__.session = session - - next() -} diff --git a/module/jwt.js b/module/jwt.js deleted file mode 100644 index e5a8793..0000000 --- a/module/jwt.js +++ /dev/null @@ -1,58 +0,0 @@ -/** - * - * @authors yutent (yutent@doui.cc) - * @date 2018-08-24 15:24:56 - */ - -'use strict' - -const sha256 = (str, secret) => { - return Util.sec - .hmac('sha256', str, secret, 'base64') - .replace(/[+\/]/g, m => { - return m === '+' ? '-' : '_' - }) - .replace(/=/g, '') -} - -export const sign = function(token) { - // "{"typ":"JWT","alg":"HS256"}" - // 这里固定使用sha256 - var header = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9' - var opt = this.ctx.get('session') - var secret = this.ctx.get('jwt') - // 加入过期时间, 同session.ttl - var payload = { token, expires: Date.now() + opt.ttl * 1000 } - payload = JSON.stringify(payload) - - payload = Util.sec.base64encode(payload, true) - var auth = sha256(`${header}.${payload}`, secret) - this.ctx.ins('session').start(auth) - return `${header}.${payload}.${auth}` -} - -export const verify = function() { - var jwt = this.request.header('authorization') || '' - var secret = this.ctx.get('jwt') - var auth, token, payload - - jwt = jwt.split('.') - - if (!secret || jwt.length !== 3) { - return false - } - - auth = jwt.pop() - token = JSON.parse(Util.sec.base64decode(jwt[1], true)) - - // 如果已经过期, 则不再校验hash - if (Date.now() > token.expires) { - return 'expired' - } - payload = jwt.join('.') - - if (sha256(payload, secret) === auth) { - return token.token - } - return false -} diff --git a/module/native-store.js b/module/native-store.js deleted file mode 100644 index 0a59f73..0000000 --- a/module/native-store.js +++ /dev/null @@ -1,81 +0,0 @@ -/** - * - * @authors yutent (yutent@doui.cc) - * @date 2016-03-15 16:01:38 - * - */ -'use strict' - -function hideProperty(host, name, value) { - Object.defineProperty(host, name, { - value: value, - writable: true, - enumerable: false, - configurable: true - }) -} - -export default class Session { - constructor(store, opt, uuid) { - this.opt = opt - this.uuid = uuid - this.store = store - } - - createSsid(ssid) { - if (ssid) { - if (!this.opt.jwt && this.opt.level > 0 && ssid !== this.uuid) { - ssid = this.uuid - } - } else { - ssid = this.uuid - } - this.ssid = ssid - - if ( - !this.store.hasOwnProperty(ssid) || - this.store[ssid].__EXPIRES__ < Date.now() - ) { - this.store[ssid] = {} - } - //设置session有效期 - hideProperty( - this.store[ssid], - '__EXPIRES__', - Date.now() + this.opt.ttl * 1000 - ) - } - - start(ssid) { - this.createSsid(ssid) - return this.ssid - } - - // 获取session字段值 - get(key) { - return key ? this.store[this.ssid][key] || null : this.store[this.ssid] - } - - // 设置session字段值 - set(key, val) { - if (typeof key === 'object') { - for (let i in key) { - this.store[this.ssid][i] = key[i] - } - } else { - this.store[this.ssid][key] = val - } - } - - // 删除单个字段 - unset(key) { - if (this.store[this.ssid].hasOwnProperty(key)) { - delete this.store[this.ssid][key] - } - } - - // 清除个人session - clear() { - this.store[this.ssid] = {} - } -} diff --git a/module/redis-store.js b/module/redis-store.js deleted file mode 100644 index d9cd12c..0000000 --- a/module/redis-store.js +++ /dev/null @@ -1,81 +0,0 @@ -/** - * Session类, 存入store - * @authors yutent (yutent@doui.cc) - * @date 2016-03-14 16:08:57 - * - */ -'use strict' - -export default class Session { - constructor(store, opt, uuid) { - this.store = store - this.opt = opt - this.uuid = uuid - } - - createSsid(ssid) { - if (ssid) { - if (!this.opt.jwt && this.opt.level > 0 && ssid !== this.uuid) { - ssid = this.uuid - } - } else { - ssid = this.uuid - } - - this.ssid = ssid - // 设置session有效期 - this.store.expire(ssid, this.opt.ttl) - } - - start(ssid) { - this.createSsid(ssid) - return this.ssid - } - - // 获取session字段值, 需要await指令 - get(key) { - var defer = Promise.defer() - - this.store.hgetall(this.ssid, (err, obj) => { - if (err) { - return defer.reject(err) - } - - for (let i in obj) { - if (!obj[i]) { - continue - } - - obj[i] = Number.parse(obj[i]) - } - //不传key时,直接返回全部字段 - if (!key) { - defer.resolve(obj) - } else { - defer.resolve(obj.hasOwnProperty(key) ? obj[key] : null) - } - }) - return defer.promise - } - - //设置session字段值 - set(key, val) { - if (typeof key === 'object') { - for (let i in key) { - this.store.hset(this.ssid, i, key[i]) - } - } else { - this.store.hset(this.ssid, key, val) - } - } - - //删除单个字段 - unset(key) { - this.store.hdel(this.ssid, key) - } - - //清除个人session - clear() { - this.store.del(this.ssid) - } -} diff --git a/module/sendmail.js b/module/sendmail.js deleted file mode 100644 index 3209c0a..0000000 --- a/module/sendmail.js +++ /dev/null @@ -1,47 +0,0 @@ -/** - * - * @authors yutent (yutent@doui.cc) - * @date 2015-11-27 10:50:16 - * - */ -'use strict' - -import mailx from 'mailx' - -export default class Sendmail { - constructor({ host, port, mail, passwd } = {}) { - if (!host || !port || !mail || !passwd) { - throw new Error('smtp options [host, port, mail, passwd] is required.') - } - this.smtp = mailx.transport(host, port, mail, passwd) - this.mail = mailx.message() - } - - // 发件人 - from(info) { - this.mail.setFrom(info.name, info.mail) - return this - } - - // 收件人 - to(info) { - this.mail.addTo(info.name, info.mail) - - return this - } - - // 发送正文 - send(mail) { - this.mail.setSubject(mail.subject) - this.mail.setHtml(mail.content) - var defer = Promise.defer() - this.smtp.send(this.mail, function(err, res) { - if (err) { - defer.reject(err) - } else { - defer.resolve(res) - } - }) - return defer.promise - } -} diff --git a/package.json b/package.json index cf6ed33..3083d07 100644 --- a/package.json +++ b/package.json @@ -6,24 +6,23 @@ "author": "yutent ", "main": "index.js", "dependencies": { - "crypto.js": "^2.0.1", - "@bytedo/es.shim": "^1.0.0", - "iofs": "^1.3.2", - "mysqli": "^3.0.11", + "@gm5/cookie": "^1.0.0", + "@gm5/session": "^1.0.0", "@gm5/request": "^1.0.0", "@gm5/response": "^1.0.0", - "@gm5/cookie": "^1.0.0", - "smartyx": "^1.3.1", - "ioredis": "^3.2.2" + "crypto.js": "^2.0.1", + "es.shim": "^2.0.0", + "iofs": "^2.0.0" + // "ioredis": "^3.2.2", + // "mysqli": "^3.0.11", + // "smartyx": "^1.3.1" }, "devDependencies": {}, "repository": { "type": "git", "url": "https://github.com/bytedo/gmf.core.git" }, - "keywords": [ - "five, fivejs, node-five, five.js, nodejs, mvc, koa, express" - ], + "keywords": ["five, fivejs, node-five, five.js, nodejs, mvc, koa, express"], "engines": { "node": ">=10.0.0" },