diff --git a/.gitignore b/.gitignore index 8aa9de1..eedf527 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ -/logs/ -/node_modules/ +/logs/ +/node_modules/ /test/ \ No newline at end of file diff --git a/.vs/VSWorkspaceState.json b/.vs/VSWorkspaceState.json new file mode 100644 index 0000000..5ddea5d --- /dev/null +++ b/.vs/VSWorkspaceState.json @@ -0,0 +1,7 @@ +{ + "ExpandedNodes": [ + "" + ], + "SelectedNode": "\\.gitignore", + "PreviewInSolutionExplorer": false +} \ No newline at end of file diff --git a/.vs/slnx.sqlite b/.vs/slnx.sqlite new file mode 100644 index 0000000..d147d27 Binary files /dev/null and b/.vs/slnx.sqlite differ diff --git a/.vs/web-node/v16/.suo b/.vs/web-node/v16/.suo new file mode 100644 index 0000000..9943823 Binary files /dev/null and b/.vs/web-node/v16/.suo differ diff --git a/LICENSE b/LICENSE index 8bc601b..6b10557 100644 --- a/LICENSE +++ b/LICENSE @@ -1,21 +1,21 @@ -MIT License - -Copyright (c) 2020 happybit - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +MIT License + +Copyright (c) 2020 happybit + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index 9f05374..7e503d4 100644 --- a/README.md +++ b/README.md @@ -1,21 +1,21 @@ -# web-node -node web by koa2 - -项目使用koa2框架开发mvc模式的web引用 - -使用pm2管理多进程 - -登录session信息使用redis服务器单独存储 - -普通数据使用mysql,sequelize进行对象关系映射 - -包含websocket引用、测试程序 - -提供rest接口 - -引入mongoose,尚未定义对应表规则 - -使用长连接:redis、mysql、mongodb - -查看MySQL通信连接信息 -netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}' +# web-node +node web by koa2 + +项目使用koa2框架开发mvc模式的web引用 + +使用pm2管理多进程 + +登录session信息使用redis服务器单独存储 + +普通数据使用mysql,sequelize进行对象关系映射 + +包含websocket引用、测试程序 + +提供rest接口 + +引入mongoose,尚未定义对应表规则 + +使用长连接:redis、mysql、mongodb + +查看MySQL通信连接信息 +netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}' diff --git a/assets/js/websocket.js b/assets/js/websocket.js index 45dfa04..61a404e 100644 --- a/assets/js/websocket.js +++ b/assets/js/websocket.js @@ -1,37 +1,37 @@ -var host = location.host;//本地域名 -var port = 32772;//与docker 容器中web端口对应的本地端口 -var wsServer = 'ws://'+host+':'+port+'/wechat'; -var websocket = createWebSocket(); - -function createWebSocket(){ - var websocket = new WebSocket(wsServer); - websocket.onopen = function (evt) { onOpen(evt) }; - websocket.onclose = function (evt) { onClose(evt) }; - websocket.onmessage = function (evt) { onMessage(evt) }; - websocket.onerror = function (evt) { onError(evt) }; - return websocket; -} -function onOpen(evt) { - websocket.send('_SYN_'+new Date().getTime()); - console.log("Connected to ",websocket.url); - websocket.HeartBeat = setInterval(() => { - websocket.send('_SYN_'+new Date().getTime()); - }, 40000); -} -function onClose(evt) { - console.log("Disconnected"); - clearInterval(websocket.HeartBeat); - websocket.HeartBeat = undefined; -} -function onError(evt) { - console.log('Error occured: ' , evt); - clearInterval(websocket.HeartBeat); - websocket.HeartBeat = undefined; - setTimeout(() => { - websocket = createWebSocket();//重新连接 - }, 6000); -} - -function onMessage(evt) { - console.log('Retrieved data from server: ' , evt.data); -} +var host = location.host;//本地域名 +var port = 32772;//与docker 容器中web端口对应的本地端口 +var wsServer = 'ws://'+host+':'+port+'/wechat'; +var websocket = createWebSocket(); + +function createWebSocket(){ + var websocket = new WebSocket(wsServer); + websocket.onopen = function (evt) { onOpen(evt) }; + websocket.onclose = function (evt) { onClose(evt) }; + websocket.onmessage = function (evt) { onMessage(evt) }; + websocket.onerror = function (evt) { onError(evt) }; + return websocket; +} +function onOpen(evt) { + websocket.send('_SYN_'+new Date().getTime()); + console.log("Connected to ",websocket.url); + websocket.HeartBeat = setInterval(() => { + websocket.send('_SYN_'+new Date().getTime()); + }, 40000); +} +function onClose(evt) { + console.log("Disconnected"); + clearInterval(websocket.HeartBeat); + websocket.HeartBeat = undefined; +} +function onError(evt) { + console.log('Error occured: ' , evt); + clearInterval(websocket.HeartBeat); + websocket.HeartBeat = undefined; + setTimeout(() => { + websocket = createWebSocket();//重新连接 + }, 6000); +} + +function onMessage(evt) { + console.log('Retrieved data from server: ' , evt.data); +} diff --git a/biz/UserBiz.js b/biz/UserBiz.js index 442e5cb..8d71347 100644 --- a/biz/UserBiz.js +++ b/biz/UserBiz.js @@ -1,7 +1,7 @@ -class UserBiz{ - static a(){ - - } -} - +class UserBiz{ + static a(){ + + } +} + module.exports = UserBiz; \ No newline at end of file diff --git a/config/params.mongodb.js b/config/params.mongodb.js index e450f90..06b3bcc 100644 --- a/config/params.mongodb.js +++ b/config/params.mongodb.js @@ -1,7 +1,7 @@ -module.exports = { - host: '127.0.0.1', - port:27017, - username:'root', - password:'mnbvcxz_123', - db:'node' +module.exports = { + host: '127.0.0.1', + port:27017, + username:'root', + password:'mnbvcxz_123', + db:'node' } \ No newline at end of file diff --git a/config/params.mysql.js b/config/params.mysql.js index 5fe4302..8856e0a 100644 --- a/config/params.mysql.js +++ b/config/params.mysql.js @@ -1,7 +1,7 @@ -module.exports = { - host:'172.17.0.3', - port:'3306', - username:'root', - password:'mnbvcxz@123', - database:'test' +module.exports = { + host:'172.17.0.2', + port:'3306', + username:'root', + password:'mnbvcxz@123', + database:'test' } \ No newline at end of file diff --git a/config/params.redis.js b/config/params.redis.js index 3fa7094..f06614b 100644 --- a/config/params.redis.js +++ b/config/params.redis.js @@ -1,5 +1,5 @@ -module.exports = { - host:'172.17.0.4', - port: 6379, - auth_pass:'mnbvcxz_123' +module.exports = { + host:'172.17.0.4', + port: 6379, + auth_pass:'mnbvcxz_123' } \ No newline at end of file diff --git a/controller/api.js b/controller/api.js index 170139b..4073845 100644 --- a/controller/api.js +++ b/controller/api.js @@ -1,15 +1,15 @@ - -module.exports = { - "GET /api/test":async (ctx, next) => { - ctx.rest({name:'wlz','test':true,'api':'test'}); - }, - "GET /api/test1":async (ctx, next) => { - ctx.rest({name:'wlz','test':true,'api':'test1'}); - }, - "GET /api/test2":async (ctx, next) => { - ctx.rest({name:'wlz','test':true,'api':'test2'}); - }, - "GET /api/testerr":async (ctx, next) => { - ctx.restError('test:testerr','测试错误接口1'); - } + +module.exports = { + "GET /api/test":async (ctx, next) => { + ctx.rest({name:'wlz','test':true,'api':'test'}); + }, + "GET /api/test1":async (ctx, next) => { + ctx.rest({name:'wlz','test':true,'api':'test1'}); + }, + "GET /api/test2":async (ctx, next) => { + ctx.rest({name:'wlz','test':true,'api':'test2'}); + }, + "GET /api/testerr":async (ctx, next) => { + ctx.restError('test:testerr','测试错误接口1'); + } } \ No newline at end of file diff --git a/controller/cookie.js b/controller/cookie.js index ea7ae05..eea429e 100644 --- a/controller/cookie.js +++ b/controller/cookie.js @@ -1,10 +1,10 @@ - - -module.exports = { - "GET /testcookie":async (ctx, next) => { - ctx.set('Set-Cookie', 'foo=bar; Path=/; HttpOnly;maxAge:0'); - ctx.cookies.set('name', 'tobi', { signed: true }); - ctx.response.body = 'ok'; - await next(); - } + + +module.exports = { + "GET /testcookie":async (ctx, next) => { + ctx.set('Set-Cookie', 'foo=bar; Path=/; HttpOnly;maxAge:0'); + ctx.cookies.set('name', 'tobi', { signed: true }); + ctx.response.body = 'ok'; + await next(); + } } \ No newline at end of file diff --git a/controller/index.js b/controller/index.js index 72a5977..41ab655 100644 --- a/controller/index.js +++ b/controller/index.js @@ -1,25 +1,25 @@ -const {Op} = require('sequelize'); -const path = require('path'); - -module.exports = { - "GET /":async ( ctx, next )=>{ - try{ - ctx.state.where = { - 'is':'adc' - } - await ctx.render('index.html',{test:{time:new Date().getTime()}}); - }catch(e){ - ctx.response.body = e.message; - } - await next(); - }, - "GET /wechat":async ( ctx, next )=>{ - try{ - await ctx.render('wechat.html',{}); - }catch(e){ - ctx.response.body = e.message; - } - await next(); - } - +const {Op} = require('sequelize'); +const path = require('path'); + +module.exports = { + "GET /":async ( ctx, next )=>{ + try{ + ctx.state.where = { + 'is':'adc' + } + await ctx.render('index.html',{test:{time:new Date().getTime()}}); + }catch(e){ + ctx.response.body = e.message; + } + await next(); + }, + "GET /wechat":async ( ctx, next )=>{ + try{ + await ctx.render('wechat.html',{}); + }catch(e){ + ctx.response.body = e.message; + } + await next(); + } + } \ No newline at end of file diff --git a/controller/needle.js b/controller/needle.js index 26c20a0..cf8be05 100644 --- a/controller/needle.js +++ b/controller/needle.js @@ -1,12 +1,12 @@ -const Needle = require('needle'); -module.exports = { - "GET /sinaimg":async ( ctx, next )=>{ - await Needle('get','https://wx4.sinaimg.cn/large/60718250ly1gflpmgpk77j20bv0bvjrp.jpg').then((res)=>{ - ctx.response.type = 'image/jpg'; - ctx.response.body = res.body; - }).catch((err)=>{ - ctx.response.type = 'ico'; - ctx.response.body = fs.createReadStream('./favicon.ico'); - }) - } +const Needle = require('needle'); +module.exports = { + "GET /sinaimg":async ( ctx, next )=>{ + await Needle('get','https://wx4.sinaimg.cn/large/60718250ly1gflpmgpk77j20bv0bvjrp.jpg').then((res)=>{ + ctx.response.type = 'image/jpg'; + ctx.response.body = res.body; + }).catch((err)=>{ + ctx.response.type = 'ico'; + ctx.response.body = fs.createReadStream('./favicon.ico'); + }) + } } \ No newline at end of file diff --git a/controller/user.js b/controller/user.js index 7241889..aa58f6c 100644 --- a/controller/user.js +++ b/controller/user.js @@ -1,100 +1,100 @@ - -/** - * todo fix me - * 注册登录页面应该具有独立的页面,不至于未登录状态和登录状态的逻辑处理重叠,比如首页会增加ctx.state.User - */ -const createError = require('http-errors'); -module.exports = { - "POST /signup": async (ctx, next)=>{ - const body = ctx.request.body; - let email = body.email.trim(); - let password = body.password.trim(); - let timestamp = new Date().getTime(); - - if(!email || !password){ - throw createError(400, 'params less'); - } - await ModelUser.findOne({ where: {email: email} }).then(user => { - if(user){ - console.log('findOne user',user.get({ - plain: true - })) - throw createError(400, '邮箱已存在'); - } - }).then(()=>{ - return ModelUser.create({ - namenick: 'User'+timestamp, - email: email, - password:password, - gender: 1, - birth: '10-01' - }).then(user => { - let user_plain = user.get({ - plain: true - }); - session.user_id = user_plain.id; - DB_Redis.getClient().set(session.id, JSON.stringify(session)); - DB_Redis.getClient().expire(session.id, 20 * 60 ); - ctx.redirect('/'); - }).catch((err)=>{ - throw createError(500,'注册失败'); - }) - }) - }, - - "POST /signin": async (ctx, next)=>{ - const body = ctx.request.body; - let email = body.email.trim(); - let password = body.password.trim(); - - await ModelUser.findOne({ where: {email: email, password: password} }).then(user => { - if(user){ - let user_plain = user.get({ - plain: true - }); - session.user_id = user_plain.id; - DB_Redis.getClient().set(session.id, JSON.stringify(session)); - DB_Redis.getClient().expire(session.id, 20 * 60 ); - ctx.redirect('/'); - }else{ - throw createError(400, '用户不存在或密码错误'); - } - }); - await next(); - }, - - "GET /signout": async (ctx, next)=>{ - if(!session.user_id){ - throw createError(400, '错误请求'); - } - await ModelUser.findByPk(parseInt(session.user_id)).then(user => { - if(user){ - let user_plain = user.get({plain: true}); - DB_Redis.getClient().expire(session.id, 0 ); - ctx.cookies.set(session_name, '', { signed: true , expires :0 }); - session = null; - ctx.state.User = null; - ctx.redirect('/'); - }else{ - throw createError(400, '用户不存在或密码错误'); - } - }); - await next(); - }, - - - "POST /consultSubmit": async (ctx, next)=>{ - const request = ctx.request; - - console.log('body', request.body ) - console.log('files',request.files) - - const body = request.body || {}; - - // if (!body.age) ctx.throw(400, '.age required'); - - ctx.body = { age: body.age || '---' }; - - await next(); - } + +/** + * todo fix me + * 注册登录页面应该具有独立的页面,不至于未登录状态和登录状态的逻辑处理重叠,比如首页会增加ctx.state.User + */ +const createError = require('http-errors'); +module.exports = { + "POST /signup": async (ctx, next)=>{ + const body = ctx.request.body; + let email = body.email.trim(); + let password = body.password.trim(); + let timestamp = new Date().getTime(); + + if(!email || !password){ + throw createError(400, 'params less'); + } + await ModelUser.findOne({ where: {email: email} }).then(user => { + if(user){ + console.log('findOne user',user.get({ + plain: true + })) + throw createError(400, '邮箱已存在'); + } + }).then(()=>{ + return ModelUser.create({ + namenick: 'User'+timestamp, + email: email, + password:password, + gender: 1, + birth: '10-01' + }).then(user => { + let user_plain = user.get({ + plain: true + }); + session.user_id = user_plain.id; + DB_Redis.getClient().set(session.id, JSON.stringify(session)); + DB_Redis.getClient().expire(session.id, 20 * 60 ); + ctx.redirect('/'); + }).catch((err)=>{ + throw createError(500,'注册失败'); + }) + }) + }, + + "POST /signin": async (ctx, next)=>{ + const body = ctx.request.body; + let email = body.email.trim(); + let password = body.password.trim(); + + await ModelUser.findOne({ where: {email: email, password: password} }).then(user => { + if(user){ + let user_plain = user.get({ + plain: true + }); + session.user_id = user_plain.id; + DB_Redis.getClient().set(session.id, JSON.stringify(session)); + DB_Redis.getClient().expire(session.id, 20 * 60 ); + ctx.redirect('/'); + }else{ + throw createError(400, '用户不存在或密码错误'); + } + }); + await next(); + }, + + "GET /signout": async (ctx, next)=>{ + if(!session.user_id){ + throw createError(400, '错误请求'); + } + await ModelUser.findByPk(parseInt(session.user_id)).then(user => { + if(user){ + let user_plain = user.get({plain: true}); + DB_Redis.getClient().expire(session.id, 0 ); + ctx.cookies.set(session_name, '', { signed: true , expires :0 }); + session = null; + ctx.state.User = null; + ctx.redirect('/'); + }else{ + throw createError(400, '用户不存在或密码错误'); + } + }); + await next(); + }, + + + "POST /consultSubmit": async (ctx, next)=>{ + const request = ctx.request; + + console.log('body', request.body ) + console.log('files',request.files) + + const body = request.body || {}; + + // if (!body.age) ctx.throw(400, '.age required'); + + ctx.body = { age: body.age || '---' }; + + await next(); + } } \ No newline at end of file diff --git a/db/DBManager.js b/db/DBManager.js index 81ea495..7657271 100644 --- a/db/DBManager.js +++ b/db/DBManager.js @@ -1,28 +1,28 @@ -/** - * 根据不同的驱动连接不同的客户端 - */ - -class DBConnection{ - constructor(){ - this.client = null; - } - static createDriver(name){ - if(Array.isArray(name)){ - - }else{ - - } - - } - createClient(){ - - } - quitClient(){ - - } - getClient(){ - - } -} - +/** + * 根据不同的驱动连接不同的客户端 + */ + +class DBConnection{ + constructor(){ + this.client = null; + } + static createDriver(name){ + if(Array.isArray(name)){ + + }else{ + + } + + } + createClient(){ + + } + quitClient(){ + + } + getClient(){ + + } +} + module.exports = DBConnection; \ No newline at end of file diff --git a/db/mongodb/client.js b/db/mongodb/client.js index ed5a435..5420982 100644 --- a/db/mongodb/client.js +++ b/db/mongodb/client.js @@ -1,40 +1,40 @@ - - -//固定mongodb数据库 -const path = require('path'); -const mongoose = require('mongoose'); -mongoose.Promise = global.Promise; - -const config = require(path.join(BasePath,'config','params.mongodb.js')); - -class Mongodb{ - constructor(){ - this.client = null; - } - createClient(){ - return new Promise((resolve, reject)=>{ - let uri = 'mongodb://'+config.username+':'+config.password+'@'+config.host+':'+config.port+'/'+config.db+'?authSource=node' ; - let tt = mongoose.connect(uri, {useNewUrlParser: true, useUnifiedTopology: true}); - this.client = mongoose.connection; - this.client.setMaxListeners(0); - this.client.on('connected',(a)=>{ - resolve(); - }); - this.client.on('error',(err)=>{ - reject(err); - }); - }) - } - quitClient(){ - if(this.client){ - this.client.close((err)=>{ - this.client = null; - }); - } - } - getClient(){ - return this.client; - } -} - + + +//固定mongodb数据库 +const path = require('path'); +const mongoose = require('mongoose'); +mongoose.Promise = global.Promise; + +const config = require(path.join(BasePath,'config','params.mongodb.js')); + +class Mongodb{ + constructor(){ + this.client = null; + } + createClient(){ + return new Promise((resolve, reject)=>{ + let uri = 'mongodb://'+config.username+':'+config.password+'@'+config.host+':'+config.port+'/'+config.db+'?authSource=node' ; + let tt = mongoose.connect(uri, {useNewUrlParser: true, useUnifiedTopology: true}); + this.client = mongoose.connection; + this.client.setMaxListeners(0); + this.client.on('connected',(a)=>{ + resolve(); + }); + this.client.on('error',(err)=>{ + reject(err); + }); + }) + } + quitClient(){ + if(this.client){ + this.client.close((err)=>{ + this.client = null; + }); + } + } + getClient(){ + return this.client; + } +} + module.exports = Mongodb; \ No newline at end of file diff --git a/db/mysql/client.js b/db/mysql/client.js index a8d438c..180146f 100644 --- a/db/mysql/client.js +++ b/db/mysql/client.js @@ -1,89 +1,89 @@ - - -//固定mongodb数据库 -const path = require('path'); -const Sequelize = require('sequelize'); -const config = require(path.join(BasePath,'config','params.mysql.js')); - -class Mysql{ - constructor(){ - this.client = null; - } - createClient(){ - this.client = new Sequelize(config.database, config.username, config.password, { - host: config.host, - port: config.port, - dialect: 'mysql', - pool: { - max: 10, - min: 0, - acquire: 30000, - idle: 10000 - } - }); - return this.client.authenticate(); - } - quitClient(){ - if(this.client){ - this.client.close().then(()=>{ - this.client = null; - }) - } - } - getClient(){ - return this.client; - } - - defineSQLModel(name, attributes) { - let attrs = {}; - for (let key in attributes) { - let value = attributes[key]; - if (typeof value === 'object' && value['type']) { - value.allowNull = value.allowNull || false; - attrs[key] = value; - } else { - attrs[key] = { - type: value, - allowNull: false - }; - } - } - attrs.id = { - type: Sequelize.INTEGER(11), - primaryKey: true, - autoIncrement:true - }; - attrs.createdAt = { - type: Sequelize.BIGINT, - allowNull: false - }; - attrs.updatedAt = { - type: Sequelize.BIGINT, - allowNull: false - }; - attrs.version = { - type: Sequelize.BIGINT, - allowNull: false - }; - return this.client.define(name, attrs, { - tableName: name, - timestamps: false, - hooks: { - beforeValidate: function (obj) { - let now = Date.now(); - if (obj.isNewRecord) { - obj.createdAt = now; - obj.updatedAt = now; - obj.version = 0; - } else { - obj.updatedAt = now; - obj.version++; - } - } - } - }); - } - -} - + + +//固定mongodb数据库 +const path = require('path'); +const Sequelize = require('sequelize'); +const config = require(path.join(BasePath,'config','params.mysql.js')); + +class Mysql{ + constructor(){ + this.client = null; + } + createClient(){ + this.client = new Sequelize(config.database, config.username, config.password, { + host: config.host, + port: config.port, + dialect: 'mysql', + timezone:'+08:00', + pool: { + max: 10, + min: 0, + acquire: 30000, + idle: 10000 + } + }); + } + quitClient(){ + if(this.client){ + this.client.close().then(()=>{ + this.client = null; + }) + } + } + getClient(){ + return this.client; + } + + defineSQLModel(name, attributes) { + let attrs = {}; + for (let key in attributes) { + let value = attributes[key]; + if (typeof value === 'object' && value['type']) { + value.allowNull = value.allowNull || false; + attrs[key] = value; + } else { + attrs[key] = { + type: value, + allowNull: false + }; + } + } + attrs.id = { + type: Sequelize.INTEGER(11), + primaryKey: true, + autoIncrement:true + }; + attrs.createdAt = { + type: Sequelize.BIGINT, + allowNull: false + }; + attrs.updatedAt = { + type: Sequelize.BIGINT, + allowNull: false + }; + attrs.version = { + type: Sequelize.BIGINT, + allowNull: false + }; + return this.client.define(name, attrs, { + tableName: name, + timestamps: false, + hooks: { + beforeValidate: function (obj) { + let now = Date.now(); + if (obj.isNewRecord) { + obj.createdAt = now; + obj.updatedAt = now; + obj.version = 0; + } else { + obj.updatedAt = now; + obj.version++; + } + } + } + }); + } + +} + module.exports = Mysql; \ No newline at end of file diff --git a/db/redis/client.js b/db/redis/client.js index 1a55a69..7a32a5d 100644 --- a/db/redis/client.js +++ b/db/redis/client.js @@ -1,34 +1,34 @@ - -//测试和高并发( ab -c 1000 -n 10000 http://127.0.0.1:9000/) - -const path = require('path'); -const redis = require('redis'); -const params = require(path.join(BasePath,'config','params.redis.js')); -const config = Object.assign({}, params, { detect_buffers: true }, {}); - -class Redis{ - constructor(){ - this.client = null; - } - createClient(){ - return new Promise((resolve, reject)=>{ - this.client = redis.createClient(config); - this.client.setMaxListeners(0); - this.client.on('connect',()=>{ - resolve(); - }); - this.client.on('error',(err)=>{ - reject(err); - }); - }) - } - quitClient(){ - if(this.client){ - this.client.quit(); - } - } - getClient(){ - return this.client; - } -} + +//测试和高并发( ab -c 1000 -n 10000 http://127.0.0.1:9000/) + +const path = require('path'); +const redis = require('redis'); +const params = require(path.join(BasePath,'config','params.redis.js')); +const config = Object.assign({}, params, { detect_buffers: true }, {}); + +class Redis{ + constructor(){ + this.client = null; + } + createClient(){ + return new Promise((resolve, reject)=>{ + this.client = redis.createClient(config); + this.client.setMaxListeners(0); + this.client.on('connect',()=>{ + resolve(); + }); + this.client.on('error',(err)=>{ + reject(err); + }); + }) + } + quitClient(){ + if(this.client){ + this.client.quit(); + } + } + getClient(){ + return this.client; + } +} module.exports = Redis; \ No newline at end of file diff --git a/framework/controller.js b/framework/controller.js index 5fccd29..557ed83 100644 --- a/framework/controller.js +++ b/framework/controller.js @@ -1,25 +1,25 @@ - -const fs = require('fs'); -const path = require('path'); -const createError = require('http-errors'); - -module.exports = function (controller) { - let router = require('koa-router')(); - fs.readdirSync(path.join(BasePath , 'controller')).filter((f) => { - return f.endsWith('.js'); - }).map((v,i)=>{ - let mapping = require(path.join(BasePath , 'controller', v) ); - for (let url in mapping) { - if (url.startsWith('GET ')) { - let pathname = url.substring(4); - router.get(pathname, mapping[url]); - } else if (url.startsWith('POST ')) { - let pathname = url.substring(5); - router.post(pathname, mapping[url]); - } else { - throw createError(500, `invalid URL: ${url}`); - } - } - }) - return router.routes(); + +const fs = require('fs'); +const path = require('path'); +const createError = require('http-errors'); + +module.exports = function (controller) { + let router = require('koa-router')(); + fs.readdirSync(path.join(BasePath , 'controller')).filter((f) => { + return f.endsWith('.js'); + }).map((v,i)=>{ + let mapping = require(path.join(BasePath , 'controller', v) ); + for (let url in mapping) { + if (url.startsWith('GET ')) { + let pathname = url.substring(4); + router.get(pathname, mapping[url]); + } else if (url.startsWith('POST ')) { + let pathname = url.substring(5); + router.post(pathname, mapping[url]); + } else { + throw createError(500, `invalid URL: ${url}`); + } + } + }) + return router.routes(); } \ No newline at end of file diff --git a/framework/model.js b/framework/model.js index 3aa0e52..c73332d 100644 --- a/framework/model.js +++ b/framework/model.js @@ -1,58 +1,63 @@ - -const fs = require('fs'); -const path = require('path'); -const createError = require('http-errors'); - -const DBMysql = require(path.join(BasePath, 'db', 'mysql', 'client.js')); -const DBMongo = require(path.join(BasePath, 'db', 'mongodb', 'client.js')); - -//输出模型 -module.exports = { - sql(dialect='mysql'){ - return async (ctx, next)=>{ - if(!global.MysqlClient || !global.MysqlClient.client){ - global.MysqlClient= new DBMysql(); - await MysqlClient.createClient().then(()=>{ - // 加载所有模型数据文件 - let dir = 'model'; - let model_names = fs.readdirSync(path.join(BasePath , dir)).filter((f) => { - return f.endsWith('.js'); - }); - for (let filename of model_names) { - let name = filename.substring(0, filename.length - 3); - let model = require(path.join(BasePath , dir, filename )); - let _model = MysqlClient.defineSQLModel(model.name, model.attributes); - // if(!ENV_Production){ - // await _model.sync({force: true}); - // } - global['Model'+name] = _model; // 老生代内存 - } - }).catch(async (err)=>{ - throw createError(500, 'Unable to connect to the database'+dialect, {expose:true}); - }) - } - await next(); - } - }, - nosql(dialect='mongodb'){ - return async (ctx, next)=>{ - if(!global.MongodbClient || !global.MongodbClient.client){ - global.MongodbClient = new DBMongo(); - await global.MongodbClient.createClient().then(()=>{ - // 加载所有模型数据文件 - let dir = 'model'; - let model_names = fs.readdirSync(path.join(BasePath , dir)).filter((f) => { - return f.endsWith('.js'); - }); - for (let filename of model_names) { - let name = filename.substring(0, filename.length - 3); - let model = require(path.join(BasePath , dir, filename )); - } - }).catch(async (err)=>{ - throw createError(500, 'Unable to connect to the database '+dialect, {expose:true}); - }); - } - await next(); - } - } + +const fs = require('fs'); +const path = require('path'); +const createError = require('http-errors'); + +const DBMysql = require(path.join(BasePath, 'db', 'mysql', 'client.js')); +const DBMongo = require(path.join(BasePath, 'db', 'mongodb', 'client.js')); + +//输出模型 +module.exports = { + sql(dialect='mysql'){ + return async (ctx, next)=>{ + if(!global.MysqlClient || !global.MysqlClient.client){ + global.MysqlClient= new DBMysql(); + MysqlClient.createClient() + } + await MysqlClient.getClient().authenticate().catch(async (err)=>{ + console.log(err) + throw createError(500, 'Unable to connect to the database '+dialect, {expose:true}); + }); + + // 加载所有模型数据文件 + let dir = 'model'; + let model_names = fs.readdirSync(path.join(BasePath , dir)).filter((f) => { + return f.endsWith('.js'); + }); + for (let filename of model_names) { + let name = filename.substring(0, filename.length - 3); + let model = require(path.join(BasePath , dir, filename )); + let _model = MysqlClient.defineSQLModel(model.name, model.attributes); + // if(!ENV_Production){ + // await _model.sync({force: true}); + // } + if(!global['Model'+name]){ + global['Model'+name] = _model; // 老生代内存 + } + } + + await next(); + } + }, + nosql(dialect='mongodb'){ + return async (ctx, next)=>{ + if(!global.MongodbClient || !global.MongodbClient.client){ + global.MongodbClient = new DBMongo(); + await global.MongodbClient.createClient().then(()=>{ + // 加载所有模型数据文件 + let dir = 'model'; + let model_names = fs.readdirSync(path.join(BasePath , dir)).filter((f) => { + return f.endsWith('.js'); + }); + for (let filename of model_names) { + let name = filename.substring(0, filename.length - 3); + let model = require(path.join(BasePath , dir, filename )); + } + }).catch(async (err)=>{ + throw createError(500, 'Unable to connect to the database '+dialect, {expose:true}); + }); + } + await next(); + } + } } \ No newline at end of file diff --git a/framework/rest.js b/framework/rest.js index 5e1cd19..e0c9c4f 100644 --- a/framework/rest.js +++ b/framework/rest.js @@ -1,30 +1,30 @@ - -module.exports = { - restify: (pathPrefix) => { - // REST API前缀,默认为/api/: - pathPrefix = pathPrefix || '/api/'; - return async (ctx, next) => { - // 是否是REST API前缀? - if (ctx.request.path.startsWith(pathPrefix)) { - // 绑定rest()方法: - ctx.rest = (data) => { - ctx.response.type = 'application/json'; - ctx.response.body = data; - } - ctx.restError = (code,message) => { - code = code || 'internal:unknown_error'; - message = message || ''; - ctx.response.status = 400; - ctx.response.type = 'application/json'; - ctx.response.body = { - code, - message - } - } - await next(); - } else { - await next(); - } - } - } + +module.exports = { + restify: (pathPrefix) => { + // REST API前缀,默认为/api/: + pathPrefix = pathPrefix || '/api/'; + return async (ctx, next) => { + // 是否是REST API前缀? + if (ctx.request.path.startsWith(pathPrefix)) { + // 绑定rest()方法: + ctx.rest = (data) => { + ctx.response.type = 'application/json'; + ctx.response.body = data; + } + ctx.restError = (code,message) => { + code = code || 'internal:unknown_error'; + message = message || ''; + ctx.response.status = 400; + ctx.response.type = 'application/json'; + ctx.response.body = { + code, + message + } + } + await next(); + } else { + await next(); + } + } + } } \ No newline at end of file diff --git a/framework/view.js b/framework/view.js index 3088188..cb836a4 100644 --- a/framework/view.js +++ b/framework/view.js @@ -1,40 +1,40 @@ - -const nunjucks = require('nunjucks'); - -function createEnv(path, opts) { - var - autoescape = opts.autoescape === undefined ? true : opts.autoescape, - noCache = opts.noCache || false, - watch = opts.watch || false, - throwOnUndefined = opts.throwOnUndefined || false, - env = new nunjucks.Environment( - new nunjucks.FileSystemLoader(path || 'view', { - noCache: noCache, - watch: watch, - }), { - autoescape: autoescape, - throwOnUndefined: throwOnUndefined - }); - if (opts.filters) { - for (var f in opts.filters) { - env.addFilter(f, opts.filters[f]); - } - } - return env; -} - -module.exports = (path, opts)=>{ - // 创建Nunjucks的env对象: - var env = createEnv(path, opts); - return async (ctx, next) => { - // 给ctx绑定render函数: - ctx.render = function (view, model) { - // 把render后的内容赋值给response.body: - ctx.response.body = env.render(view, Object.assign({}, ctx.state || {}, model || {})); - // 设置Content-Type: - ctx.response.type = 'text/html'; - }; - // 继续处理请求: - await next(); - }; + +const nunjucks = require('nunjucks'); + +function createEnv(path, opts) { + var + autoescape = opts.autoescape === undefined ? true : opts.autoescape, + noCache = opts.noCache || false, + watch = opts.watch || false, + throwOnUndefined = opts.throwOnUndefined || false, + env = new nunjucks.Environment( + new nunjucks.FileSystemLoader(path || 'view', { + noCache: noCache, + watch: watch, + }), { + autoescape: autoescape, + throwOnUndefined: throwOnUndefined + }); + if (opts.filters) { + for (var f in opts.filters) { + env.addFilter(f, opts.filters[f]); + } + } + return env; +} + +module.exports = (path, opts)=>{ + // 创建Nunjucks的env对象: + var env = createEnv(path, opts); + return async (ctx, next) => { + // 给ctx绑定render函数: + ctx.render = function (view, model) { + // 把render后的内容赋值给response.body: + ctx.response.body = env.render(view, Object.assign({}, ctx.state || {}, model || {})); + // 设置Content-Type: + ctx.response.type = 'text/html'; + }; + // 继续处理请求: + await next(); + }; }; \ No newline at end of file diff --git a/model/Pet.js b/model/Pet.js index 7b6b00a..db3d277 100644 --- a/model/Pet.js +++ b/model/Pet.js @@ -1,14 +1,14 @@ - -const Sequelize = require('sequelize'); - -module.exports = { - name : "pet" , - attributes:{ - name: Sequelize.STRING(100), - gender: Sequelize.TINYINT, - birth: Sequelize.STRING(10), - createdAt: Sequelize.BIGINT, - updatedAt: Sequelize.BIGINT, - version: Sequelize.BIGINT - } + +const Sequelize = require('sequelize'); + +module.exports = { + name : "pet" , + attributes:{ + name: Sequelize.STRING(100), + gender: Sequelize.TINYINT, + birth: Sequelize.STRING(10), + createdAt: Sequelize.BIGINT, + updatedAt: Sequelize.BIGINT, + version: Sequelize.BIGINT + } } \ No newline at end of file diff --git a/model/User.js b/model/User.js index 834bdc2..a14fccc 100644 --- a/model/User.js +++ b/model/User.js @@ -1,13 +1,13 @@ - -const Sequelize = require('sequelize'); - -module.exports = { - name : "user" , - attributes:{ - namenick: Sequelize.STRING(200), - email: Sequelize.STRING(100), - password:Sequelize.STRING(500), - gender: Sequelize.TINYINT, - birth: Sequelize.STRING(10) - } + +const Sequelize = require('sequelize'); + +module.exports = { + name : "user" , + attributes:{ + namenick: Sequelize.STRING(200), + email: Sequelize.STRING(100), + password:Sequelize.STRING(500), + gender: Sequelize.TINYINT, + birth: Sequelize.STRING(10) + } } \ No newline at end of file diff --git a/pm2.json b/pm2.json index 973b96d..6d921c1 100644 --- a/pm2.json +++ b/pm2.json @@ -1,38 +1,38 @@ -{ - "apps": { - "name": "web-node", - "script": "app.js", - "cwd": "./", - "args": "--env=dev", - "interpreter": "", - "interpreter_args": "", - "watch": true, - "ignore_watch": [ - "node_modules", - "logs" - ], - "exec_mode": "cluster", - "instances": 3, - "max_memory_restart": "1024M", - "error_file": "./logs/web-err.log", - "out_file": "./logs/web-out.log", - "merge_logs": true, - "log_date_format": "YYYY-MM-DD HH:mm:ss", - "min_uptime": "60s", - "max_restarts": 1000, - "force":true, - "autorestart": true, - "cron_restart": "", - "restart_delay": 1000, - "instance_var":"NODE_APP_INSTANCE", - "env": { - "NODE_ENV": "production" - }, - "env_dev": { - "NODE_ENV": "development" - }, - "env_test": { - "NODE_ENV": "test" - } - } -} +{ + "apps": { + "name": "web-node", + "script": "app.js", + "cwd": "./", + "args": "--env=dev", + "interpreter": "", + "interpreter_args": "", + "watch": true, + "ignore_watch": [ + "node_modules", + "logs" + ], + "exec_mode": "cluster", + "instances": 3, + "max_memory_restart": "1024M", + "error_file": "./logs/web-err.log", + "out_file": "./logs/web-out.log", + "merge_logs": true, + "log_date_format": "YYYY-MM-DD HH:mm:ss", + "min_uptime": "60s", + "max_restarts": 1000, + "force":true, + "autorestart": true, + "cron_restart": "", + "restart_delay": 1000, + "instance_var":"NODE_APP_INSTANCE", + "env": { + "NODE_ENV": "production" + }, + "env_dev": { + "NODE_ENV": "development" + }, + "env_test": { + "NODE_ENV": "test" + } + } +} diff --git a/pm2.json.default b/pm2.json.default index 1d5e008..a900c18 100644 --- a/pm2.json.default +++ b/pm2.json.default @@ -1,39 +1,39 @@ -// { -// "apps": { -// "name": "web-node", // 项目名 -// "script": "app.js", // 执行文件 -// "cwd": "./", // 根目录 -// "args": "--env_dev", // 传递给脚本的参数 -// "interpreter": "", // 指定的脚本解释器 -// "interpreter_args": "", // 传递给解释器的参数 -// "watch": true, // 是否监听文件变动然后重启 -// "ignore_watch": [ // 不用监听的文件 -// "node_modules", -// "logs" -// ], -// "exec_mode": "cluster", // 应用启动模式,支持fork和cluster模式 -// "instances": 3, // 应用启动实例个数,仅在cluster模式有效 默认为fork;或者 max -// "max_memory_restart": 8, // 最大内存限制数,超出自动重启 -// "error_file": "./logs/web-err.log", // 错误日志文件 -// "out_file": "./logs/web-out.log", // 正常日志文件 -// "merge_logs": true, // 设置追加日志而不是新建日志 -// "log_date_format": "YYYY-MM-DD HH:mm:ss", // 指定日志文件的时间格式 -// "min_uptime": "60s", // 应用运行少于时间被认为是异常启动 -// "max_restarts": 100, // 最大异常重启次数,即小于min_uptime运行时间重启次数; -// "autorestart": true, // 默认为true, 发生异常的情况下自动重启 -// "cron_restart": "", // crontab时间格式重启应用,目前只支持cluster模式; -// "restart_delay": 1, // 异常重启情况下,延时重启时间 -// "env": { -// "NODE_ENV": "production", // 环境参数,当前指定为生产环境 process.env.NODE_ENV -// "REMOTE_ADDR": "a.b.c.d" // process.env.REMOTE_ADDR -// }, -// "env_dev": { -// "NODE_ENV": "development", // 环境参数,当前指定为开发环境 pm2 start app.js --env_dev -// "REMOTE_ADDR": "127.0.0.1" -// }, -// "env_test": { // 环境参数,当前指定为测试环境 pm2 start app.js --env_test -// "NODE_ENV": "test", -// "REMOTE_ADDR": "" -// } -// } +// { +// "apps": { +// "name": "web-node", // 项目名 +// "script": "app.js", // 执行文件 +// "cwd": "./", // 根目录 +// "args": "--env_dev", // 传递给脚本的参数 +// "interpreter": "", // 指定的脚本解释器 +// "interpreter_args": "", // 传递给解释器的参数 +// "watch": true, // 是否监听文件变动然后重启 +// "ignore_watch": [ // 不用监听的文件 +// "node_modules", +// "logs" +// ], +// "exec_mode": "cluster", // 应用启动模式,支持fork和cluster模式 +// "instances": 3, // 应用启动实例个数,仅在cluster模式有效 默认为fork;或者 max +// "max_memory_restart": 8, // 最大内存限制数,超出自动重启 +// "error_file": "./logs/web-err.log", // 错误日志文件 +// "out_file": "./logs/web-out.log", // 正常日志文件 +// "merge_logs": true, // 设置追加日志而不是新建日志 +// "log_date_format": "YYYY-MM-DD HH:mm:ss", // 指定日志文件的时间格式 +// "min_uptime": "60s", // 应用运行少于时间被认为是异常启动 +// "max_restarts": 100, // 最大异常重启次数,即小于min_uptime运行时间重启次数; +// "autorestart": true, // 默认为true, 发生异常的情况下自动重启 +// "cron_restart": "", // crontab时间格式重启应用,目前只支持cluster模式; +// "restart_delay": 1, // 异常重启情况下,延时重启时间 +// "env": { +// "NODE_ENV": "production", // 环境参数,当前指定为生产环境 process.env.NODE_ENV +// "REMOTE_ADDR": "a.b.c.d" // process.env.REMOTE_ADDR +// }, +// "env_dev": { +// "NODE_ENV": "development", // 环境参数,当前指定为开发环境 pm2 start app.js --env_dev +// "REMOTE_ADDR": "127.0.0.1" +// }, +// "env_test": { // 环境参数,当前指定为测试环境 pm2 start app.js --env_test +// "NODE_ENV": "test", +// "REMOTE_ADDR": "" +// } +// } // } \ No newline at end of file diff --git a/view/base.html b/view/base.html index 2d2d5d2..7f69b12 100644 --- a/view/base.html +++ b/view/base.html @@ -1,10 +1,10 @@ - -
- - - - {% block header %}
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/view/wechat.html b/view/wechat.html
index c593a0e..63f4905 100644
--- a/view/wechat.html
+++ b/view/wechat.html
@@ -1,23 +1,23 @@
-
-
-
-
-
-
-
-
- {% if User %}
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+ {% if User %}
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ws.js b/ws.js
index 864629b..8513bb8 100644
--- a/ws.js
+++ b/ws.js
@@ -1,37 +1,37 @@
-const WebSocket = require('ws');
-
-class Wechat{
- constructor(){
- this.connected = false;
- let ws = new WebSocket('ws://127.0.0.1:9000/test');
- ws.on('open',()=>{
- this.connected = true;
- console.log('client connect wss ok');
- this.send('Hi');
- });
- ws.on('message',(message)=>{
- console.log('client received data:',message)
- });
- this.ws = ws;
- }
-
- send(message){
- if(this.connected){
- this.ws.send(message);
- }
- }
-
- /**
- * 渲染、绑定聊天窗口
- * @param {Object} jq_element jquery 对象
- */
- render(jq_element){
- if(this.connected){
-
- }else{
- //开始渲染连接中,
- //开启定时检查是否已经连接
- //如果已经连接就绑定dom事件
- }
- }
+const WebSocket = require('ws');
+
+class Wechat{
+ constructor(){
+ this.connected = false;
+ let ws = new WebSocket('ws://127.0.0.1:9000/test');
+ ws.on('open',()=>{
+ this.connected = true;
+ console.log('client connect wss ok');
+ this.send('Hi');
+ });
+ ws.on('message',(message)=>{
+ console.log('client received data:',message)
+ });
+ this.ws = ws;
+ }
+
+ send(message){
+ if(this.connected){
+ this.ws.send(message);
+ }
+ }
+
+ /**
+ * 渲染、绑定聊天窗口
+ * @param {Object} jq_element jquery 对象
+ */
+ render(jq_element){
+ if(this.connected){
+
+ }else{
+ //开始渲染连接中,
+ //开启定时检查是否已经连接
+ //如果已经连接就绑定dom事件
+ }
+ }
}
\ No newline at end of file
diff --git a/wss.js b/wss.js
index 5407baa..be1ba6d 100644
--- a/wss.js
+++ b/wss.js
@@ -1,40 +1,40 @@
-
-// 将聊天室中发送的消息都放置到mongodb中
-
-const WebSocket = require('ws');
-const Cookies = require('cookies');
-
-module.exports = function WebSocketServer(http_server){
- const wss = new WebSocket.Server({
- server : http_server
- });
- wss.on('connection',(ws,request)=>{
- let url = request.url;
- if(url !== '/wechat'){
- return ws.close(4001, 'Invalid url');
- }
- let headers = request.headers;
- if(!headers){
- return ws.close(4001, 'Invalid headers');
- }
- let cookies = new Cookies(request,{},{keys:CookieKeys});
- let session_nid = cookies.get(session_name, { signed: true });
- if(!session_nid){
- return ws.close(4001, 'Invalid cookie');
- }
-
- ws.user = global.User || undefined;
- ws.wss = wss;
-
- ws.on('message', function (message) {
- ws.wss.clients.forEach(function (client) {
- client.send('data from broadcast:'+message, (err)=>{
- if (err) {
- console.log('broadcast err',err);
- }
- });
- });
- });
-
- });
+
+// 将聊天室中发送的消息都放置到mongodb中
+
+const WebSocket = require('ws');
+const Cookies = require('cookies');
+
+module.exports = function WebSocketServer(http_server){
+ const wss = new WebSocket.Server({
+ server : http_server
+ });
+ wss.on('connection',(ws,request)=>{
+ let url = request.url;
+ if(url !== '/wechat'){
+ return ws.close(4001, 'Invalid url');
+ }
+ let headers = request.headers;
+ if(!headers){
+ return ws.close(4001, 'Invalid headers');
+ }
+ let cookies = new Cookies(request,{},{keys:CookieKeys});
+ let session_nid = cookies.get(session_name, { signed: true });
+ if(!session_nid){
+ return ws.close(4001, 'Invalid cookie');
+ }
+
+ ws.user = global.User || undefined;
+ ws.wss = wss;
+
+ ws.on('message', function (message) {
+ ws.wss.clients.forEach(function (client) {
+ client.send('data from broadcast:'+message, (err)=>{
+ if (err) {
+ console.log('broadcast err',err);
+ }
+ });
+ });
+ });
+
+ });
}
\ No newline at end of file