├── public
├── swagger
│ ├── css
│ │ ├── typography.css
│ │ ├── reset.css
│ │ └── style.css
│ ├── images
│ │ ├── expand.gif
│ │ ├── collapse.gif
│ │ ├── favicon.ico
│ │ ├── throbber.gif
│ │ ├── logo_small.png
│ │ ├── wordnik_api.png
│ │ ├── explorer_icons.png
│ │ ├── favicon-16x16.png
│ │ ├── favicon-32x32.png
│ │ └── pet_store_api.png
│ ├── fonts
│ │ ├── DroidSans.ttf
│ │ └── DroidSans-Bold.ttf
│ ├── lib
│ │ ├── highlight.9.1.0.pack_extended.js
│ │ ├── object-assign-pollyfill.js
│ │ ├── jquery.slideto.min.js
│ │ ├── jquery.wiggle.min.js
│ │ ├── jquery.ba-bbq.min.js
│ │ ├── swagger-oauth.js
│ │ └── highlight.9.1.0.pack.js
│ ├── o2c.html
│ ├── lang
│ │ ├── translator.js
│ │ ├── ko-kr.js
│ │ ├── zh-cn.js
│ │ ├── ja.js
│ │ ├── tr.js
│ │ ├── pl.js
│ │ ├── pt.js
│ │ ├── en.js
│ │ ├── ru.js
│ │ ├── ca.js
│ │ ├── geo.js
│ │ ├── it.js
│ │ ├── es.js
│ │ ├── fr.js
│ │ └── el.js
│ ├── index.html
│ └── api.json
├── favicon.ico
├── static
│ └── libs
│ │ ├── bootstrap
│ │ ├── fonts
│ │ │ ├── glyphicons-halflings-regular.eot
│ │ │ ├── glyphicons-halflings-regular.ttf
│ │ │ ├── glyphicons-halflings-regular.woff
│ │ │ └── glyphicons-halflings-regular.woff2
│ │ └── js
│ │ │ └── npm.js
│ │ ├── html5shiv.min.js
│ │ └── respond.min.js
└── robots.txt
├── server
├── views
│ ├── partials
│ │ ├── sidebar.hbs
│ │ └── header.hbs
│ ├── index.hbs
│ ├── error.hbs
│ ├── layout.hbs
│ └── login.hbs
├── services
│ ├── users.js
│ └── thrift
│ │ ├── shared.thrift
│ │ └── tutorial
│ │ ├── tutorial.js
│ │ ├── gen
│ │ └── tutorial_types.js
│ │ └── tutorial.thrift
├── routes
│ ├── login.js
│ ├── index.js
│ └── rest
│ │ ├── token.js
│ │ └── user.js
├── utils
│ ├── md5.js
│ ├── redis.js
│ ├── aes.js
│ ├── easemob
│ │ ├── ChatHistory.js
│ │ ├── Token.js
│ │ ├── client.js
│ │ ├── Files.js
│ │ ├── request.js
│ │ ├── SendMessage.js
│ │ ├── ChatRoom.js
│ │ ├── Group.js
│ │ └── User.js
│ ├── hbs.js
│ ├── orm.js
│ ├── mongodb.js
│ ├── rabbitmq.js
│ ├── util.js
│ ├── token.js
│ ├── http.js
│ └── sql.js
├── middlewares
│ ├── interceptor.js
│ ├── compress.js
│ ├── auth.js
│ ├── logger.js
│ └── api.js
├── models
│ ├── UserORM.js
│ └── User.js
└── controllers
│ └── user.js
├── client
├── README.md
├── package.json
└── gulpfile.js
├── .gitignore
├── .eslintignore
├── config
├── error_code.js
├── redis.js
├── secret.js
├── testing.js
├── production.js
├── simulation.js
├── development.js
├── mongodb.js
├── easemob.js
├── rabbitmq.js
├── orm.js
├── pm2-gui.ini
├── pm2.config.js
├── db.sql
└── nginx.conf
├── .eslintrc.js
├── bin
├── start.sh
└── www
├── .node-inspectorrc
├── test
├── api
│ └── login.js
└── unit
│ └── sql.js
├── gulpfile.js
├── README.md
├── package.json
└── app.js
/public/swagger/css/typography.css:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/server/views/partials/sidebar.hbs:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/server/views/index.hbs:
--------------------------------------------------------------------------------
1 |
{{content}}
2 |
--------------------------------------------------------------------------------
/server/views/partials/header.hbs:
--------------------------------------------------------------------------------
1 | {{title}}
--------------------------------------------------------------------------------
/server/services/users.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 用户数据服务
3 | */
4 |
--------------------------------------------------------------------------------
/client/README.md:
--------------------------------------------------------------------------------
1 | # 前端源码目录
2 | > 可以使用gulp或webpack,对前端项目进行编译、打包和自动构建
3 |
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules/
3 | logs/
4 | npm-debug.log
5 | selenium-debug.log
6 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | # /node_modules ignored by default
2 |
3 | public/*
4 | config/*
5 | test/*
6 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoping6688/node-server-project/HEAD/public/favicon.ico
--------------------------------------------------------------------------------
/public/swagger/images/expand.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoping6688/node-server-project/HEAD/public/swagger/images/expand.gif
--------------------------------------------------------------------------------
/public/swagger/fonts/DroidSans.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoping6688/node-server-project/HEAD/public/swagger/fonts/DroidSans.ttf
--------------------------------------------------------------------------------
/public/swagger/images/collapse.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoping6688/node-server-project/HEAD/public/swagger/images/collapse.gif
--------------------------------------------------------------------------------
/public/swagger/images/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoping6688/node-server-project/HEAD/public/swagger/images/favicon.ico
--------------------------------------------------------------------------------
/public/swagger/images/throbber.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoping6688/node-server-project/HEAD/public/swagger/images/throbber.gif
--------------------------------------------------------------------------------
/public/swagger/images/logo_small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoping6688/node-server-project/HEAD/public/swagger/images/logo_small.png
--------------------------------------------------------------------------------
/public/swagger/images/wordnik_api.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoping6688/node-server-project/HEAD/public/swagger/images/wordnik_api.png
--------------------------------------------------------------------------------
/public/swagger/fonts/DroidSans-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoping6688/node-server-project/HEAD/public/swagger/fonts/DroidSans-Bold.ttf
--------------------------------------------------------------------------------
/public/swagger/images/explorer_icons.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoping6688/node-server-project/HEAD/public/swagger/images/explorer_icons.png
--------------------------------------------------------------------------------
/public/swagger/images/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoping6688/node-server-project/HEAD/public/swagger/images/favicon-16x16.png
--------------------------------------------------------------------------------
/public/swagger/images/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoping6688/node-server-project/HEAD/public/swagger/images/favicon-32x32.png
--------------------------------------------------------------------------------
/public/swagger/images/pet_store_api.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoping6688/node-server-project/HEAD/public/swagger/images/pet_store_api.png
--------------------------------------------------------------------------------
/config/error_code.js:
--------------------------------------------------------------------------------
1 | /**
2 | * API 错误码
3 | */
4 |
5 | // user
6 | exports.SIGNIN_ERROR = 10001
7 | exports.LOGOUT_ERROR = 10002
8 | exports.REGISTER_ERROR = 10003
9 |
--------------------------------------------------------------------------------
/public/static/libs/bootstrap/fonts/glyphicons-halflings-regular.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoping6688/node-server-project/HEAD/public/static/libs/bootstrap/fonts/glyphicons-halflings-regular.eot
--------------------------------------------------------------------------------
/public/static/libs/bootstrap/fonts/glyphicons-halflings-regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoping6688/node-server-project/HEAD/public/static/libs/bootstrap/fonts/glyphicons-halflings-regular.ttf
--------------------------------------------------------------------------------
/public/static/libs/bootstrap/fonts/glyphicons-halflings-regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoping6688/node-server-project/HEAD/public/static/libs/bootstrap/fonts/glyphicons-halflings-regular.woff
--------------------------------------------------------------------------------
/public/static/libs/bootstrap/fonts/glyphicons-halflings-regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoping6688/node-server-project/HEAD/public/static/libs/bootstrap/fonts/glyphicons-halflings-regular.woff2
--------------------------------------------------------------------------------
/config/redis.js:
--------------------------------------------------------------------------------
1 | /**
2 | * redis 参数配置
3 | * @see https://github.com/NodeRedis/node_redis
4 | */
5 |
6 | module.exports = {
7 | host: '127.0.0.1',
8 | port: 6379,
9 | password: null
10 | }
11 |
--------------------------------------------------------------------------------
/config/secret.js:
--------------------------------------------------------------------------------
1 | /**
2 | * JWT secret
3 | */
4 | exports.token_secret_key = 'bm9kZXNlcnZlckFQSWp3dHNlY3JldA=='
5 |
6 | /**
7 | * md5 secret
8 | */
9 | exports.md5_secret_key = 'servermd5key'
10 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | // https://github.com/feross/standard/blob/master/RULES.md#javascript-standard-style
3 | "extends": "standard",
4 | "plugins": [
5 | "standard",
6 | "promise"
7 | ]
8 | }
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | # The robots.txt file is used to control how search engines index your live URLs.
2 |
3 |
4 |
5 | # To prevent search engines from seeing the site altogether, uncomment the next two lines:
6 | # User-Agent: *
7 | # Disallow: /
8 |
--------------------------------------------------------------------------------
/config/testing.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 测试环境
3 | */
4 |
5 | module.exports = {
6 | port: 80,
7 | logging: {
8 | type: 'combined' // Standard Apache combined log output
9 | },
10 | NODE_ENV: 'testing',
11 | BASE_URI: 'http://ip/api'
12 | }
13 |
--------------------------------------------------------------------------------
/config/production.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 生产环境
3 | */
4 |
5 | module.exports = {
6 | port: 80,
7 | logging: {
8 | type: 'combined' // Standard Apache combined log output
9 | },
10 | NODE_ENV: 'production',
11 | BASE_URI: 'http://ip/api'
12 | }
13 |
--------------------------------------------------------------------------------
/config/simulation.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 仿真环境
3 | */
4 |
5 | module.exports = {
6 | port: 80,
7 | logging: {
8 | type: 'combined' // Standard Apache combined log output
9 | },
10 | NODE_ENV: 'simulation',
11 | BASE_URI: 'http://ip/api'
12 | }
13 |
--------------------------------------------------------------------------------
/bin/start.sh:
--------------------------------------------------------------------------------
1 | #! /bin/sh
2 | # 启动脚本,用于设置开机启动,可跟参数:prod(产品-默认) simu(仿真) testing(测试)
3 | # 也可使用 pm2 设置开机启动:
4 | # pm2 save
5 | # pm2 startup centos
6 |
7 | cd `dirname $0`
8 |
9 | if [ "$1" == "" ]; then
10 | npm run prod
11 | else
12 | npm run $1
13 | fi
--------------------------------------------------------------------------------
/server/routes/login.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 登录路由
3 | */
4 |
5 | var express = require('express')
6 | var router = express.Router()
7 |
8 | router.get('/', function(req, res, next) {
9 | res.render('login', { layout: false })
10 | })
11 |
12 | module.exports = router
13 |
--------------------------------------------------------------------------------
/server/utils/md5.js:
--------------------------------------------------------------------------------
1 | /**
2 | * md5加密(with secret-key)
3 | */
4 |
5 | var md5 = require('blueimp-md5')
6 |
7 | var secretKey = require('../../config/secret').md5_secret_key
8 |
9 | module.exports = function (value) {
10 | return md5(value, secretKey)
11 | }
12 |
--------------------------------------------------------------------------------
/config/development.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 开发环境
3 | */
4 |
5 | module.exports = {
6 | port: 3000,
7 | logging:{
8 | type: 'dev' // :method :url :status :response-time ms - :res[content-length]
9 | },
10 | NODE_ENV: 'development',
11 | BASE_URI: 'http://ip/api'
12 | }
13 |
--------------------------------------------------------------------------------
/config/mongodb.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | host: '127.0.0.1',
3 | port: 27017,
4 | database: 'nodeserver',
5 | options: {
6 | db: {
7 | native_parser: true
8 | },
9 | server: {
10 | auto_reconnect: true,
11 | poolSize: 5
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/server/routes/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 首页路由
3 | */
4 |
5 | var express = require('express')
6 | var router = express.Router()
7 |
8 | router.get('/', function(req, res, next) {
9 | res.render('index', { title: 'Server', content: new Date() })
10 | })
11 |
12 | module.exports = router
13 |
--------------------------------------------------------------------------------
/config/easemob.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 环信服务端集成配置
3 | */
4 |
5 | module.exports = {
6 | org_name: '企业ID',
7 | app_name: 'APP名称',
8 | client_id: 'your app client id',
9 | client_secret: 'youre app client secret',
10 | host: 'a1.easemob.com',
11 | ca: __dirname + '/cacert/easemob.pem'
12 | }
13 |
--------------------------------------------------------------------------------
/.node-inspectorrc:
--------------------------------------------------------------------------------
1 | {
2 | "web-port": 8080,
3 | "web-host": "0.0.0.0",
4 | "debug-port": 5858,
5 | "debug-brk": false,
6 | "save-live-edit": false,
7 | "preload": true,
8 | "hidden": ["test/", "node_modules/", "client/", "public/", "config/", "logs/"],
9 | "nodejs": [],
10 | "stack-trace-limit": 50
11 | }
12 |
--------------------------------------------------------------------------------
/public/swagger/lib/highlight.9.1.0.pack_extended.js:
--------------------------------------------------------------------------------
1 | "use strict";!function(){var h,l;h=hljs.configure,hljs.configure=function(l){var i=l.highlightSizeThreshold;hljs.highlightSizeThreshold=i===+i?i:null,h.call(this,l)},l=hljs.highlightBlock,hljs.highlightBlock=function(h){var i=h.innerHTML,g=hljs.highlightSizeThreshold;(null==g||g>i.length)&&l.call(hljs,h)}}();
--------------------------------------------------------------------------------
/public/swagger/lib/object-assign-pollyfill.js:
--------------------------------------------------------------------------------
1 | "function"!=typeof Object.assign&&!function(){Object.assign=function(n){"use strict";if(void 0===n||null===n)throw new TypeError("Cannot convert undefined or null to object");for(var t=Object(n),o=1;o
2 |
3 |
4 |
5 |
6 |
7 | Error
8 |
9 |
10 |
11 | {{message}}
12 | {{error.status}}
13 | {{error.stack}}
14 |
15 |
16 |
--------------------------------------------------------------------------------
/server/utils/redis.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Redis 缓存
3 | */
4 |
5 | var redis = require('redis')
6 | var redisOptions = require('../../config/redis')
7 |
8 | var redisClient = redis.createClient(redisOptions)
9 |
10 | redisClient.on('error', function (err) {
11 | console.log('Error ' + err)
12 | })
13 |
14 | redisClient.on('connect', function () {
15 | console.log('Redis is ready')
16 | })
17 |
18 | exports.redis = redis
19 | exports.redisClient = redisClient
20 |
--------------------------------------------------------------------------------
/server/middlewares/interceptor.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 拦截器
3 | */
4 |
5 | var tokenUtil = require('../utils/token')
6 |
7 | module.exports = function (req, res, next) {
8 | // 刷新页面Token(注:此处针对单一web项目)
9 | var oldToken = tokenUtil.getToken(req)
10 | if (oldToken && tokenUtil.verifyToken(oldToken)) {
11 | var newTokent = tokenUtil.refreshToken(oldToken)
12 | res.cookie('token', newTokent)
13 | }
14 |
15 | // console.log('intercept: ' + req.path)
16 | next()
17 | }
18 |
--------------------------------------------------------------------------------
/config/rabbitmq.js:
--------------------------------------------------------------------------------
1 | /**
2 | * amqp 参数配置
3 | * @see https://github.com/dial-once/node-bunnymq
4 | */
5 |
6 | module.exports = {
7 | host: 'amqp://localhost', // connect url
8 | prefetch: 5, // number of fetched messages at once on the channel
9 | requeue: true, // requeue put back message into the broker if consumer crashes/trigger exception
10 | timeout: 1000, // time between two reconnect (ms)
11 | rpcTimeout: 1000 // default timeout for RPC calls. If set to '0' there will be none.
12 | }
13 |
--------------------------------------------------------------------------------
/server/utils/aes.js:
--------------------------------------------------------------------------------
1 | const crypto = require('crypto')
2 |
3 | export function encrypt(data, key) {
4 | const cipher = crypto.createCipher('aes192', key)
5 | var crypted = cipher.update(data, 'utf8', 'hex')
6 | crypted += cipher.final('hex')
7 | return crypted
8 | }
9 |
10 | export function decrypt(encrypted, key) {
11 | const decipher = crypto.createDecipher('aes192', key)
12 | var decrypted = decipher.update(encrypted, 'hex', 'utf8')
13 | decrypted += decipher.final('utf8')
14 | return decrypted
15 | }
16 |
--------------------------------------------------------------------------------
/server/middlewares/compress.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 压缩中间件(gzip)
3 | * 注:生产环境配置nginx来处理压缩和静态文件
4 | */
5 |
6 | var compression = require('compression')
7 |
8 | var compressOptions = {
9 | threshold: 0,
10 | filter: shouldCompress
11 | }
12 |
13 | function shouldCompress (req, res) {
14 | if (req.headers['x-no-compression']) { // don't compress responses
15 | return false
16 | }
17 |
18 | // fallback to standard filter function
19 | return compression.filter(req, res)
20 | }
21 |
22 | module.exports = compression(compressOptions)
23 |
--------------------------------------------------------------------------------
/public/swagger/lib/jquery.wiggle.min.js:
--------------------------------------------------------------------------------
1 | jQuery.fn.wiggle=function(e){var a={speed:50,wiggles:3,travel:5,callback:null},e=jQuery.extend(a,e);return this.each(function(){var a=this,l=(jQuery(this).wrap('
').css("position","relative"),0);for(i=1;i<=e.wiggles;i++)jQuery(this).animate({left:"-="+e.travel},e.speed).animate({left:"+="+2*e.travel},2*e.speed).animate({left:"-="+e.travel},e.speed,function(){l++,jQuery(a).parent().hasClass("wiggle-wrap")&&jQuery(a).parent().replaceWith(a),l==e.wiggles&&jQuery.isFunction(e.callback)&&e.callback()})})};
--------------------------------------------------------------------------------
/public/static/libs/bootstrap/js/npm.js:
--------------------------------------------------------------------------------
1 | // This file is autogenerated via the `commonjs` Grunt task. You can require() this file in a CommonJS environment.
2 | require('../../js/transition.js')
3 | require('../../js/alert.js')
4 | require('../../js/button.js')
5 | require('../../js/carousel.js')
6 | require('../../js/collapse.js')
7 | require('../../js/dropdown.js')
8 | require('../../js/modal.js')
9 | require('../../js/tooltip.js')
10 | require('../../js/popover.js')
11 | require('../../js/scrollspy.js')
12 | require('../../js/tab.js')
13 | require('../../js/affix.js')
--------------------------------------------------------------------------------
/server/routes/rest/token.js:
--------------------------------------------------------------------------------
1 | /**
2 | * token 续期(一般针对非web项目,不依赖cookie)
3 | * TODO 检测刷新有效期,防止无限刷新永不过期?
4 | */
5 |
6 | var express = require('express')
7 | var router = express.Router()
8 | var tokenUtil = require('../../utils/token')
9 |
10 | router.get('/', function (req, res, next) {
11 | var oldToken = tokenUtil.getToken(req)
12 | if (oldToken) {
13 | var newTokent = tokenUtil.refreshToken(oldToken)
14 | res.api(newTokent)
15 | } else {
16 | res.api_error('No authorization token was found')
17 | }
18 | })
19 |
20 | module.exports = router
21 |
--------------------------------------------------------------------------------
/public/swagger/o2c.html:
--------------------------------------------------------------------------------
1 |
21 |
--------------------------------------------------------------------------------
/server/routes/rest/user.js:
--------------------------------------------------------------------------------
1 | var express = require('express')
2 | var userCtrl = require('../../controllers/user')
3 | var router = express.Router()
4 |
5 | // 用户登录
6 | router.get('/login', userCtrl.login)
7 |
8 | // 用户退出
9 | router.get('/logout', userCtrl.logout)
10 |
11 | // 查询所有用户
12 | // router.get('/', userCtrl.getUsers)
13 |
14 | // 查询用户
15 | router.get('/:id', userCtrl.getUser)
16 |
17 | // 更新用户
18 | router.put('/:id', userCtrl.updateUser)
19 |
20 | // 新增用户
21 | router.post('/regist', userCtrl.addUser)
22 |
23 | // 删除用户
24 | router.delete('/:id', userCtrl.delUser)
25 |
26 | module.exports = router
27 |
--------------------------------------------------------------------------------
/server/views/layout.hbs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | {{title}}
8 |
9 | {{{block "stylesheets"}}}
10 |
11 |
12 | {{> header }}
13 |
14 | {{{body}}}
15 |
16 |
17 | {{{block "scripts"}}}
18 |
19 |
20 |
--------------------------------------------------------------------------------
/test/api/login.js:
--------------------------------------------------------------------------------
1 | const assert = require('assert')
2 | const request = require('supertest')
3 | const app = require('../../app')
4 |
5 | describe('GET /rest/user/login', function() {
6 | it('respond with json', function(done) {
7 | request(app)
8 | .get('/rest/user/login')
9 | .send({ username: 'test', password: '123' })
10 | .type('application/json')
11 | .set('Accept', 'application/json')
12 | .expect(200)
13 | .end(function(err, res) {
14 | if (err) return done(err)
15 |
16 | console.log(JSON.stringify(res.body))
17 | assert.equal(res.body.status.code, 0)
18 | done()
19 | })
20 | })
21 | })
22 |
--------------------------------------------------------------------------------
/server/utils/easemob/ChatHistory.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 聊天历史记录
3 | */
4 |
5 | var client = require('./client')
6 |
7 | function ChatHistory () {
8 | //Get chat history
9 | this.getChatMessages = function (ql, limit, cursor, callback) {
10 | client.client({
11 | path: 'chatmessages',
12 | method: 'GET',
13 | query: { 'ql': ql, 'limit': limit, 'cursor': cursor },
14 | headers: {},
15 | callback: function (data) {
16 | // console.log(data)
17 | typeof callback == 'function' && callback(data)
18 | }
19 | })
20 | }
21 | }
22 |
23 | module.exports = ChatHistory
24 |
--------------------------------------------------------------------------------
/server/utils/hbs.js:
--------------------------------------------------------------------------------
1 | /**
2 | * handlebars 配置及扩展函数
3 | */
4 |
5 | var hbs = require('hbs')
6 | var path = require('path')
7 |
8 | var blocks = {}
9 |
10 | // 模版继承
11 | hbs.registerHelper('extend', function(name, context) {
12 | var block = blocks[name]
13 | if (!block) {
14 | block = blocks[name] = []
15 | }
16 |
17 | block.push(context.fn(this)) // for older versions of handlebars, use block.push(context(this));
18 | })
19 |
20 | hbs.registerHelper('block', function(name) {
21 | var val = (blocks[name] || []).join('\n')
22 |
23 | blocks[name] = [] // clear the block
24 | return val
25 | })
26 |
27 | // 注册子模版
28 | hbs.registerPartials(path.join(__dirname, '..', 'views', 'partials'))
29 |
--------------------------------------------------------------------------------
/server/models/UserORM.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 用户模型(orm)
3 | */
4 |
5 | var Sequelize = require('sequelize')
6 | var orm = require('../utils/orm')
7 |
8 | var UserModel = orm.define('UserModel', {
9 | id: {
10 | type : Sequelize.INTEGER,
11 | autoIncrement : true,
12 | primaryKey : true,
13 | unique : true
14 | },
15 | username: {
16 | type: Sequelize.STRING,
17 | allowNull: false,
18 | unique: true
19 | },
20 | password: {
21 | type: Sequelize.STRING,
22 | allowNull: false
23 | },
24 | avatar: {
25 | type: Sequelize.STRING,
26 | },
27 | created_at: {
28 | type: Sequelize.DATE,
29 | "defaultValue": Sequelize.NOW
30 | }
31 | })
32 |
33 | module.exports = UserModel
34 |
--------------------------------------------------------------------------------
/server/utils/orm.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 对象关系映射(ORM)
3 | * 基于Promise,支持 Postgres, MySQL, SQLite and Microsoft SQL Server
4 | */
5 |
6 | var Sequelize = require('sequelize')
7 |
8 | var env = process.env.NODE_ENV ? process.env.NODE_ENV : 'development'
9 | var config = require('../../config/orm')[env]
10 |
11 | // Setting up a connection
12 | var sequelize = new Sequelize(
13 | config.database,
14 | config.username,
15 | config.password,
16 | config.options
17 | )
18 |
19 | // Test the connection
20 | sequelize.authenticate().then(function(err) {
21 | console.log('Database connection has been established successfully.');
22 | }).catch(function (err) {
23 | console.log('Unable to connect to the database:', err);
24 | })
25 |
26 | module.exports = sequelize
27 |
--------------------------------------------------------------------------------
/server/middlewares/auth.js:
--------------------------------------------------------------------------------
1 | /**
2 | * JWT认证中间件
3 | */
4 |
5 | var jwt = require('express-jwt')
6 | var secret = require('../../config/secret').token_secret_key
7 | var tokenUtil = require('../utils/token')
8 |
9 | module.exports = jwt({
10 | secret: Buffer.from(secret, 'base64'),
11 | requestProperty: 'user', // By default, the decoded token is attached to req.user
12 | credentialsRequired: true, // You might want to use this module to identify registered users while still providing access to unregistered users
13 | getToken: tokenUtil.getToken // Where the token is
14 | }).unless({ // 排除路径
15 | path: [
16 | '/rest/token',
17 | '/rest/user/regist',
18 | '/rest/user/login',
19 | // /^(?!\/rest\/).*/ // 所有非rest路由
20 | '/login'
21 | ]
22 | })
23 |
--------------------------------------------------------------------------------
/public/swagger/css/reset.css:
--------------------------------------------------------------------------------
1 | a,abbr,acronym,address,applet,article,aside,audio,b,big,blockquote,body,canvas,caption,center,cite,code,dd,del,details,dfn,div,dl,dt,em,embed,fieldset,figcaption,figure,footer,form,h1,h2,h3,h4,h5,h6,header,hgroup,html,i,iframe,img,ins,kbd,label,legend,li,mark,menu,nav,object,ol,output,p,pre,q,ruby,s,samp,section,small,span,strike,strong,sub,summary,sup,table,tbody,td,tfoot,th,thead,time,tr,tt,u,ul,var,video{margin:0;padding:0;border:0;font-size:100%;font:inherit;vertical-align:baseline}article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section{display:block}body{line-height:1}ol,ul{list-style:none}blockquote,q{quotes:none}blockquote:after,blockquote:before,q:after,q:before{content:'';content:none}table{border-collapse:collapse;border-spacing:0}
--------------------------------------------------------------------------------
/server/utils/mongodb.js:
--------------------------------------------------------------------------------
1 | /**
2 | * MongoDB
3 | */
4 |
5 | var mongoose = require('mongoose')
6 | var config = require('../../config/mongodb')
7 |
8 | var uri = 'mongodb://' + config.host + ':' + config.port + '/' + config.database
9 |
10 | mongoose.connect(uri, config.options, function (err, res) {
11 | if (err) {
12 | console.log('[mongoose] Error connecting to: ' + connectionString + '. ' + err)
13 | return process.exit(1)
14 | } else {
15 | return console.log('[mongoose] Successfully connected to: ' + connectionString)
16 | }
17 | })
18 |
19 | mongoose.connection.on('error', console.error.bind(console, 'mongoose connection error:'))
20 | mongoose.connection.once('open', function() {
21 | return console.log('mongoose open success')
22 | })
23 |
24 | module.exports = mongoose
25 |
--------------------------------------------------------------------------------
/server/middlewares/logger.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 日志中间件
3 | */
4 |
5 | var morgan = require('morgan')
6 | var path = require('path')
7 | var fs = require('fs')
8 | var FileStreamRotator = require('file-stream-rotator')
9 |
10 | var logDirectory = path.join(__dirname, '..', '..', 'logs')
11 | var config = require('../../config/' + process.env.NODE_ENV)
12 |
13 | // ensure log directory exists
14 | fs.existsSync(logDirectory) || fs.mkdirSync(logDirectory)
15 |
16 | // create a rotating write stream
17 | var accessLogStream = FileStreamRotator.getStream({
18 | date_format: 'YYYYMMDD',
19 | filename: path.join(logDirectory, 'access-%DATE%.log'),
20 | frequency: 'daily',
21 | verbose: false
22 | })
23 |
24 | var logger = morgan(config.logging.type, { stream: accessLogStream })
25 |
26 | module.exports = logger
27 |
--------------------------------------------------------------------------------
/config/orm.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | development: {
3 | database: 'db_test',
4 | username: 'test',
5 | password: '*A0E2521E77EA33EF451BF2D1025F30B925D8F2F2',
6 | options: {
7 | host: '127.0.0.1',
8 | port: 3306,
9 | dialect: 'mysql', //mysql|sqlite|postgres|mssql
10 | pool: {
11 | max: 5,
12 | min: 0,
13 | idle: 10000
14 | },
15 | storage: 'path/to/database.sqlite' // SQLite only
16 | }
17 | },
18 | production: {
19 | database: 'qy_foreground',
20 | username: 'qyfdb',
21 | password: '*9BCABC927E66F185539F7748D1BA16341236BC2C',
22 | options: {
23 | host: '127.0.0.1',
24 | port: 3306,
25 | dialect: 'mysql', //mysql|sqlite|postgres|mssql
26 | pool: {
27 | max: 5,
28 | min: 0,
29 | idle: 10000
30 | }
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/client/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "client-project",
3 | "version": "1.0.0",
4 | "description": "前端项目",
5 | "author": "super_xp@126.com",
6 | "private": true,
7 | "scripts": {
8 | "start": "gulp default",
9 | "build": "gulp build",
10 | "watch": "gulp watch"
11 | },
12 | "dependencies": {},
13 | "devDependencies": {
14 | "del": "^2.2.2",
15 | "gulp": "^3.9.1",
16 | "gulp-autoprefixer": "^3.1.1",
17 | "gulp-clean-css": "^3.0.4",
18 | "gulp-concat": "^2.6.1",
19 | "gulp-copy": "^1.0.0",
20 | "gulp-css-spriter": "^0.4.0",
21 | "gulp-eslint": "^3.0.1",
22 | "gulp-imagemin": "^3.2.0",
23 | "gulp-livereload": "^3.8.1",
24 | "gulp-minify-html": "^1.0.6",
25 | "gulp-rename": "^1.2.2",
26 | "gulp-replace": "^0.5.4",
27 | "gulp-rev": "^7.1.2",
28 | "gulp-rev-collector": "^1.1.1",
29 | "gulp-sass": "^3.1.0",
30 | "gulp-sequence": "^0.4.6",
31 | "gulp-sourcemaps": "^2.6.0",
32 | "gulp-uglify": "^2.1.2",
33 | "imagemin-pngquant": "^5.0.0"
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/server/models/User.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 用户模型(mongodb)
3 | */
4 |
5 | var MongooseDao = require('mongoosedao')
6 | var mongodb = require('../utils/mongodb')
7 | var Schema = mongodb.Schema
8 |
9 | var UserSchema = new Schema({
10 | username: {
11 | type: String,
12 | required: true,
13 | index: {
14 | unique: true
15 | }
16 | },
17 | password: {
18 | type: String,
19 | required: true
20 | },
21 | avatar: String,
22 | created_at: {
23 | type: Date,
24 | "default": Date.now
25 | }
26 | })
27 |
28 | UserSchema.methods.find_by_name = function (cb) {
29 | return this.model('UserModel').find({
30 | username: this.username
31 | }, cb)
32 | }
33 |
34 | UserSchema.methods.is_exist = function (cb) {
35 | var query = {
36 | username: this.username,
37 | password: this.password
38 | }
39 | return this.model('UserModel').findOne(query, cb)
40 | }
41 |
42 | UserSchema.statics.delete_by_name = function(name, cb_succ, cb_fail) {
43 |
44 | }
45 |
46 | var UserModel = mongodb.model('UserModel', UserSchema)
47 |
48 | var UserDao = new MongooseDao(UserModel)
49 |
50 | module.exports = UserDao
51 |
--------------------------------------------------------------------------------
/server/controllers/user.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 用户逻辑控制器
3 | */
4 |
5 | var tokenUtil = require('../utils/token')
6 | var code = require('../../config/error_code')
7 |
8 | /**
9 | * 用户登录
10 | */
11 | exports.login = function(req, res) {
12 | var username = req.query.username || ''
13 | var password = req.query.password || ''
14 |
15 | if (username == '' || password == '') {
16 | return res.api(null, { code: code.SIGNIN_ERROR, msg:'账号或密码不能为空' })
17 | }
18 |
19 | // TODO
20 | var userInfo = {
21 | id: '123',
22 | name: '张三',
23 | gender: 0,
24 | age: 18
25 | }
26 |
27 | var token = tokenUtil.generateToken({ uid: userInfo.id })
28 | res.cookie('token', token)
29 | return res.api({ token: token, user: userInfo })
30 | }
31 |
32 | /**
33 | * 用户退出
34 | */
35 | exports.logout = function(req, res) {
36 | if (req.user) {
37 | delete req.user
38 | res.clearCookie('token')
39 | return res.sendStatus(200)
40 | } else {
41 | return res.sendStatus(401)
42 | }
43 | }
44 |
45 | /**
46 | * 用户查询
47 | */
48 | exports.getUser = function(req, res) {
49 |
50 | }
51 |
52 | /**
53 | * 用户注册
54 | */
55 | exports.addUser = function(req, res) {
56 |
57 | }
58 |
59 | exports.updateUser = function(req, res) {
60 |
61 | }
62 |
63 | exports.delUser = function(req, res) {
64 |
65 | }
66 |
--------------------------------------------------------------------------------
/server/utils/rabbitmq.js:
--------------------------------------------------------------------------------
1 | /**
2 | * RabbitMQ 消息队列,简单实现了消息订阅、发布和RPC调用
3 | * @see https://github.com/dial-once/node-bunnymq
4 | * 也可参考 https://github.com/tjmehta/amqplib-rpc 实现方式
5 | */
6 |
7 | var bunnymq = require('bunnymq')
8 | var config = require('../../config/rabbitmq')
9 |
10 | var conn = bunnymq(config)
11 | var producer = conn.producer
12 | var consumer = conn.consumer
13 |
14 | /**
15 | * Producer (publisher), can send messages to a named queue.
16 | */
17 | exports.publish = function (queueName, content) {
18 | producer.produce(queueName, content)
19 | }
20 |
21 | /**
22 | * Consumer (subscriber), can handle messages from a named queue.
23 | */
24 | exports.subscribe = function (queueName, callback) {
25 | consumer.consume(queueName, callback)
26 | }
27 |
28 | /**
29 | * RPC invoking
30 | * @param {String} queueName 队列名
31 | * @param {Object} content 传递的参数
32 | * @param {Function} callback 回调函数,参数为返回值
33 | */
34 | exports.rpcCall = function (queueName, content, callback) {
35 | producer.produce(queueName, content, { rpc: true }).then(callback)
36 | }
37 |
38 | /**
39 | * RPC provider
40 | * @param {String} queueName 队列名
41 | * @param {Function} handler 处理函数,其返回值可以是普通数据类型或Promise对象
42 | */
43 | exports.rpcReceive = function (queueName, handler) {
44 | consumer.consume(queueName, handler)
45 | }
46 |
--------------------------------------------------------------------------------
/server/utils/util.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 工具类、实用函数
3 | */
4 |
5 | const Sequelize = require('sequelize')
6 | const trimFunc = require('lodash/trim')
7 | const escapeFunc = require('lodash/escape')
8 | const isEmptyFunc = require('lodash/isEmpty')
9 |
10 | /**
11 | * 找出第一个符合条件的数组成员
12 | */
13 | exports.findItem = function (arr, key, value) {
14 | return arr.find(item => item[key] === value)
15 | }
16 |
17 | exports.findNameById = function (arr, id) {
18 | let item = findItem(arr, 'id', id)
19 | return item ? item.name : ''
20 | }
21 |
22 | exports.isObjectLike = function (value) {
23 | return !!value && typeof value == 'object'
24 | }
25 |
26 | exports.isNumber = function (value) {
27 | return typeof value == 'number' || (this.isObjectLike(value) && Object.prototype.toString.call(value) == '[object Number]')
28 | }
29 |
30 | /**
31 | * 转义sql参数防止注入攻击
32 | */
33 | exports.escapeSql = function (string) {
34 | // return Sequelize.escape(string) // XXX
35 | return escapeFunc(string)
36 | }
37 |
38 | /**
39 | * 去掉字符串前后空白或指定字符
40 | */
41 | exports.trim = function (string, chars) {
42 | return trimFunc(string, chars) // es6 String.trim 不支持 chars 参数
43 | }
44 |
45 | /**
46 | * Checks if value is an empty object, collection, map, or set.
47 | */
48 | exports.isEmpty = function (value) {
49 | return isEmptyFunc(value)
50 | }
51 |
--------------------------------------------------------------------------------
/server/utils/easemob/Token.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 请求Tocken
3 | */
4 |
5 | var config = require('../../../config/easemob')
6 | var request = require('./request')
7 |
8 | function Token () {
9 | var client_id = config.client_id
10 | var client_secret = config.client_secret
11 | var token = ''
12 | var expiredAt
13 |
14 | this.getToken = function () {
15 | return token
16 | }
17 |
18 | this.accessToken = function(callback) {
19 | var data = { grant_type: 'client_credentials', client_id: client_id, client_secret: client_secret }
20 | request.httpRequest({
21 | data: data,
22 | path: 'token',
23 | method: 'POST',
24 | header: { 'Content-Type': 'application/json' },
25 | callback: function (data) {
26 | var d = JSON.parse(data)
27 | token = d.access_token
28 | expiredAt = d.expires_in * 1000 + new Date().getMilliseconds()
29 | // console.log('token is: ' + token)
30 | if (typeof callback == 'function')
31 | callback(token)
32 | }
33 | })
34 | }
35 |
36 | //Check token is expired
37 | this.isExpire = function(){
38 | return new Date().getMilliseconds() > expiredAt
39 | }
40 | }
41 |
42 | module.exports = Token
43 |
--------------------------------------------------------------------------------
/gulpfile.js:
--------------------------------------------------------------------------------
1 | const gulp = require('gulp')
2 | const nodemon = require('gulp-nodemon')
3 | const browserSync = require('browser-sync').create()
4 | const config = require('./config/' + process.env.NODE_ENV)
5 |
6 | /**
7 | * 启动本地server
8 | */
9 | gulp.task("server", function(cb) {
10 | let started = false
11 | let stream = nodemon({
12 | script: './bin/www',
13 | ext: 'js',
14 | watch: ['server/', 'app.js'],
15 | env: {
16 | 'NODE_ENV': config.NODE_ENV
17 | }
18 | })
19 |
20 | stream.on('start', function () {
21 | if (!started) {
22 | cb()
23 | started = true
24 | }
25 | }).on('restart', function () {
26 | console.log('restarted!')
27 | }).on('crash', function() {
28 | console.error('Application has crashed!\n')
29 | stream.emit('restart', 3) // restart the server in 3 seconds
30 | })
31 | })
32 |
33 | /**
34 | * 同步浏览器
35 | */
36 | gulp.task('browser-sync', ['server'], function() {
37 | var files = [
38 | 'server/views/**/*.html',
39 | 'server/views/**/*.hbs',
40 | 'public/static/**/*.*'
41 | ]
42 |
43 | browserSync.init({
44 | files: files,
45 | proxy: 'http://localhost:' + config.port,
46 | // browser: 'google chrome',
47 | // notify: false,
48 | // ui: false,
49 | port: parseInt(config.port) + 1
50 | })
51 |
52 | gulp.watch(files).on('change', browserSync.reload)
53 | })
54 |
--------------------------------------------------------------------------------
/test/unit/sql.js:
--------------------------------------------------------------------------------
1 | const sql = require('../../server/utils/sql')
2 |
3 | console.log(sql.insert('table_name', {
4 | field1: '字段1',
5 | field2: '字段2',
6 | field3: '3'
7 | }))
8 |
9 | console.log(sql.insert('table_name', {
10 | field1: '字段1',
11 | field2: '字段2',
12 | field3: '3'
13 | }, [
14 | 'field1'
15 | ], {
16 | field2: '追加2',
17 | field3: 3
18 | }))
19 |
20 | console.log(sql.insertMore('table_name', [{
21 | field1: '字段1',
22 | field2: '字段2',
23 | field3: '3'
24 | },{
25 | field1: '字段1',
26 | field2: '字段2',
27 | field3: '3'
28 | }]))
29 |
30 | console.log(sql.update('table_name', {
31 | field1: '字段1',
32 | field2: '字段2',
33 | field3: '3'
34 | }, {
35 | id: '123'
36 | }))
37 |
38 | console.log(sql.update('table_name', null, {
39 | id: '123'
40 | }, {
41 | field3: '3'
42 | }))
43 |
44 | console.log(sql.select('table_name', ['field1', 'field2'], {
45 | id: '123'
46 | }))
47 |
48 | console.log(sql.select('table_name', [], {
49 | id: '123'
50 | }))
51 |
52 | console.log(sql.delete('table_name', {
53 | //id: '123'
54 | }, 'id2="1"'))
55 |
56 | console.log(sql.replace('table_name', {
57 | field1: '字段1',
58 | field2: '字段2',
59 | field3: '3'
60 | }))
61 |
62 | console.log(sql.replaceMore('table_name', [{
63 | field1: '字段1',
64 | field2: '字段2',
65 | field3: '3'
66 | },{
67 | field1: '字段1',
68 | field2: '字段2',
69 | field3: '3'
70 | }]))
71 |
--------------------------------------------------------------------------------
/server/services/thrift/shared.thrift:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one
3 | * or more contributor license agreements. See the NOTICE file
4 | * distributed with this work for additional information
5 | * regarding copyright ownership. The ASF licenses this file
6 | * to you under the Apache License, Version 2.0 (the
7 | * "License"); you may not use this file except in compliance
8 | * with the License. You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing,
13 | * software distributed under the License is distributed on an
14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | * KIND, either express or implied. See the License for the
16 | * specific language governing permissions and limitations
17 | * under the License.
18 | */
19 |
20 | /**
21 | * This Thrift file can be included by other Thrift files that want to share
22 | * these definitions.
23 | */
24 |
25 | namespace cpp shared
26 | namespace d share // "shared" would collide with the eponymous D keyword.
27 | namespace dart shared
28 | namespace java shared
29 | namespace perl shared
30 | namespace php shared
31 | namespace haxe shared
32 | namespace netcore shared
33 |
34 | struct SharedStruct {
35 | 1: i32 key
36 | 2: string value
37 | }
38 |
39 | service SharedService {
40 | SharedStruct getStruct(1: i32 key)
41 | }
--------------------------------------------------------------------------------
/server/utils/token.js:
--------------------------------------------------------------------------------
1 | /**
2 | * JWT token管理
3 | */
4 |
5 | var jwt = require('jsonwebtoken')
6 | var secretKey = require('../../config/secret').token_secret_key
7 |
8 | // 一般token过期策略:移动端按月,web端按周
9 | var TOKEN_EXPIRATION = 60 * 60 // 秒
10 |
11 | var secret = Buffer.from(secretKey, 'base64')
12 |
13 | exports.generateToken = function (payload) {
14 | var token = jwt.sign(payload, secret, { expiresIn: TOKEN_EXPIRATION })
15 | return token
16 | }
17 |
18 | exports.verifyToken = function (token) {
19 | try {
20 | var payload = jwt.verify(token, secret)
21 | return payload
22 |
23 | } catch (err) {
24 | return false
25 | }
26 | }
27 |
28 | exports.decodeToken = function (token) {
29 | var payload = jwt.decode(token)
30 | return payload
31 | }
32 |
33 | exports.refreshToken = function (token) {
34 | var payload = this.decodeToken(token)
35 | // console.dir(payload)
36 | var token = null
37 | if (payload) {
38 | token = jwt.sign({ uid: payload.uid }, secret, { expiresIn: TOKEN_EXPIRATION })
39 | }
40 |
41 | return token
42 | }
43 |
44 | exports.getToken = function (req) {
45 | if (req.headers.authorization && req.headers.authorization.split(' ')[0] === 'Bearer') { // Authorization: Bearer [token]
46 | return req.headers.authorization.split(' ')[1];
47 | } else if (req.query && req.query.token) {
48 | return req.query.token
49 | } else if (req.cookies && req.cookies.token) { // for page
50 | return req.cookies.token
51 | }
52 | return null
53 | }
54 |
--------------------------------------------------------------------------------
/public/swagger/lang/translator.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * Translator for documentation pages.
5 | *
6 | * To enable translation you should include one of language-files in your index.html
7 | * after .
8 | * For example -
9 | *
10 | * If you wish to translate some new texts you should do two things:
11 | * 1. Add a new phrase pair ("New Phrase": "New Translation") into your language file (for example lang/ru.js). It will be great if you add it in other language files too.
12 | * 2. Mark that text it templates this way New Phrase or .
13 | * The main thing here is attribute data-sw-translate. Only inner html, title-attribute and value-attribute are going to translate.
14 | *
15 | */
16 | window.SwaggerTranslator = {
17 |
18 | _words:[],
19 |
20 | translate: function(sel) {
21 | var $this = this;
22 | sel = sel || '[data-sw-translate]';
23 |
24 | $(sel).each(function() {
25 | $(this).html($this._tryTranslate($(this).html()));
26 |
27 | $(this).val($this._tryTranslate($(this).val()));
28 | $(this).attr('title', $this._tryTranslate($(this).attr('title')));
29 | });
30 | },
31 |
32 | _tryTranslate: function(word) {
33 | return this._words[$.trim(word)] !== undefined ? this._words[$.trim(word)] : word;
34 | },
35 |
36 | learn: function(wordsMap) {
37 | this._words = wordsMap;
38 | }
39 | };
40 |
--------------------------------------------------------------------------------
/server/utils/easemob/client.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 聊天室
3 | */
4 |
5 | var Token = require('./Token')
6 | var request = require('./request')
7 |
8 | var Initialized = false
9 | var token = new Token()
10 |
11 | function client (json, callback) {
12 | if (!Initialized || token.isExpire()) {
13 | token.accessToken(function () {
14 | Initialized = true
15 | if (typeof callback == 'function') {
16 | callback(json)
17 | }else {
18 | httpRequestWithToken(json)
19 | }
20 | })
21 |
22 | } else {
23 | if (typeof callback == 'function') {
24 | callback(json)
25 | }else {
26 | httpRequestWithToken(json)
27 | }
28 | }
29 |
30 | }
31 |
32 | function httpRequestWithToken (json) {
33 | if (token == null) {
34 | console.log('err: failed to access token!')
35 | } else {
36 | json.headers = json.headers || {}
37 | json.headers['Content-Type'] = 'application/json'
38 | json.headers['Authorization'] = 'Bearer ' + token.getToken()
39 | request.httpRequest(json)
40 | }
41 | }
42 |
43 | function uploadFileWithToken (json) {
44 | if (token == null) {
45 | console.log('err: failed to access token!')
46 | } else {
47 | json.headers = json.headers || {}
48 | json.headers['http'] = 'multipart/form-data'
49 | json.headers['Authorization'] = 'Bearer ' + token.getToken()
50 | request.uploadFile(json)
51 | }
52 | }
53 |
54 | module.exports = {
55 | client: client,
56 | httpRequestWithToken: httpRequestWithToken,
57 | uploadFileWithToken: uploadFileWithToken
58 | }
59 |
--------------------------------------------------------------------------------
/config/pm2-gui.ini:
--------------------------------------------------------------------------------
1 | ;
2 | ; Home directory of pm2.
3 | ;
4 | pm2 = ~/.pm2
5 | ;
6 | ; The monitor will fetch system CPU/Memory amount after this certain time interval.
7 | ; it could be milliseconds or various time formats(https://github.com/zeit/ms)
8 | ;
9 | refresh = 5s
10 | ;
11 | ; Port of Web server and socket agent.
12 | ;
13 | port = 8088
14 | ;
15 | ; A value indicates whether or not run the pm2-gui as damonization.
16 | ;
17 | daemonize = true
18 | ;
19 | ; A value indicates whether or not the action buttons (i.e. `restart`, `stop all`...) should be displayed on web page.
20 | ;
21 | readonly = false
22 | ;
23 | ; The monitor will fetch process CPU/Memory amount after this certain time interval.
24 | ; it could be milliseconds or various time formats(https://github.com/zeit/ms)
25 | ;
26 | process_refresh = 3s
27 |
28 | [log]
29 | ;
30 | ; Log directory.
31 | ;
32 | dir = ../logs
33 | ;
34 | ; A value indicates whether or not display the [INFO], [ERROR].. prefixes before log message.
35 | ;
36 | prefix = true
37 | ;
38 | ; A value indicates whether or not display the local date string before log message.
39 | ;
40 | date = false
41 | ;
42 | ; Log level, one of debug, log, info, warn, error.
43 | ;
44 | level = info
45 | ;
46 | ; Socket.io origins check, e.g.:
47 | ; origins = 'example.com:* http://example.com:* http://www.example.com:8088'
48 | ; By default:
49 | ; origins = *:*
50 |
51 | [agent]
52 | ;
53 | ; This authorization will be used to authorize socket / web connections if it's set.
54 | ;
55 | authorization = AuTh
56 | ;
57 | ; A value indicates whether agent offline or not.
58 | ;
59 | ; offline = true
60 | [remotes]
61 | ;
62 | ; the dashboard and web server will use this section to connect remoting socket server
63 | ; server_name = [authorization@]host:port
64 | ;
65 | ; pm2@171 = AuTh@https://192.168.1.171:9002/sockserv
66 | ; pm2@172 = 192.168.1.172:9001
67 | ; pm2@173 = 192.168.1.173:9000
68 | ;
--------------------------------------------------------------------------------
/server/services/thrift/tutorial/tutorial.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Apache Thrift 是 Facebook 开源的一种高效的、支持多种编程语言的远程服务调用的框架,
3 | * 采用二进制数据传输,适用于高并发、大数据量和多语言开发环境。
4 | * @see http://thrift.apache.org/
5 | *
6 | * tutorial.thrift 是我们定义好的目标语言对应的接口数据结构,
7 | * 然后通过thrift命令生成node端相应的引用文件,如下:
8 | *
9 | *
10 | * thrift --gen js:node -o ./server/services/thrift/tutorial -out ./server/services/thrift/tutorial/gen ./server/services/thrift/tutorial/tutorial.thrift
11 | *
12 | *
13 | * Java端参考:http://qifuguang.me/2015/09/11/Thrift%E5%85%A5%E9%97%A8%E6%95%99%E7%A8%8B/
14 | */
15 |
16 | var thrift = require('thrift')
17 | var Calculator = require('./gen/Calculator')
18 | var ttypes = require('./gen/tutorial_types')
19 |
20 | var transport = thrift.TBufferedTransport
21 | var protocol = thrift.TBinaryProtocol
22 |
23 | var connection = thrift.createConnection('localhost', 9090, {
24 | transport : transport,
25 | protocol : protocol
26 | })
27 |
28 | connection.on('error', function(err) {
29 | console.error(err)
30 | })
31 |
32 | // Create a Calculator client with the connection
33 | var client = thrift.createClient(Calculator, connection)
34 |
35 | var work = new ttypes.Work()
36 |
37 | module.exports = {
38 | ping: function() {
39 | client.ping(function(err, response) {
40 | console.log('ping()')
41 | })
42 | },
43 | add: function(arg1, arg2) {
44 | client.add(1,1, function(err, response) {
45 | console.log("1+1=" + response)
46 | })
47 | },
48 | subtract: function(num1, num2) {
49 | work.op = ttypes.Operation.SUBTRACT
50 | work.num1 = num1
51 | work.num2 = num2
52 |
53 | client.calculate(1, work, function(err, message) {
54 | console.log(`${num1}-${num2}=${message}`)
55 |
56 | client.getStruct(1, function(err, message){
57 | console.log('Check log: ' + message.value)
58 | })
59 | })
60 | },
61 | close: function () { //close the connection once we're done
62 | connection.end()
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/bin/www:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | /**
4 | * Module dependencies.
5 | */
6 |
7 | var app = require('../app')
8 | var http = require('http')
9 |
10 | var config = require('../config/' + app.get('env'))
11 |
12 | /**
13 | * Get port from environment and store in Express.
14 | */
15 |
16 | var port = normalizePort(process.env.PORT || config.port)
17 | app.set('port', port)
18 |
19 | /**
20 | * Create HTTP server.
21 | */
22 |
23 | var server = http.createServer(app)
24 |
25 | /**
26 | * Listen on provided port, on all network interfaces.
27 | */
28 |
29 | server.listen(port)
30 | server.on('error', onError)
31 | server.on('listening', onListening)
32 |
33 | console.log('env: ' + config.NODE_ENV)
34 |
35 | /**
36 | * Normalize a port into a number, string, or false.
37 | */
38 |
39 | function normalizePort(val) {
40 | var port = parseInt(val, 10)
41 |
42 | if (isNaN(port)) {
43 | // named pipe
44 | return val
45 | }
46 |
47 | if (port >= 0) {
48 | // port number
49 | return port
50 | }
51 |
52 | return false
53 | }
54 |
55 | /**
56 | * Event listener for HTTP server "error" event.
57 | */
58 |
59 | function onError(error) {
60 | if (error.syscall !== 'listen') {
61 | throw error
62 | }
63 |
64 | var bind = typeof port === 'string' ? 'Pipe ' + port : 'Port ' + port
65 |
66 | // handle specific listen errors with friendly messages
67 | switch (error.code) {
68 | case 'EACCES':
69 | console.error(bind + ' requires elevated privileges')
70 | process.exit(1)
71 | break
72 | case 'EADDRINUSE':
73 | console.error(bind + ' is already in use')
74 | process.exit(1)
75 | break
76 | default:
77 | throw error
78 | }
79 | }
80 |
81 | /**
82 | * Event listener for HTTP server "listening" event.
83 | */
84 |
85 | function onListening() {
86 | var addr = server.address()
87 | var bind = typeof addr === 'string' ? 'pipe ' + addr : 'port ' + addr.port
88 | console.log('Listening on ' + bind)
89 | }
90 |
--------------------------------------------------------------------------------
/public/swagger/lang/ko-kr.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /* jshint quotmark: double */
4 | window.SwaggerTranslator.learn({
5 | "Warning: Deprecated":"경고:폐기예정됨",
6 | "Implementation Notes":"구현 노트",
7 | "Response Class":"응답 클래스",
8 | "Status":"상태",
9 | "Parameters":"매개변수들",
10 | "Parameter":"매개변수",
11 | "Value":"값",
12 | "Description":"설명",
13 | "Parameter Type":"매개변수 타입",
14 | "Data Type":"데이터 타입",
15 | "Response Messages":"응답 메세지",
16 | "HTTP Status Code":"HTTP 상태 코드",
17 | "Reason":"원인",
18 | "Response Model":"응답 모델",
19 | "Request URL":"요청 URL",
20 | "Response Body":"응답 본문",
21 | "Response Code":"응답 코드",
22 | "Response Headers":"응답 헤더",
23 | "Hide Response":"응답 숨기기",
24 | "Headers":"헤더",
25 | "Try it out!":"써보기!",
26 | "Show/Hide":"보이기/숨기기",
27 | "List Operations":"목록 작업",
28 | "Expand Operations":"전개 작업",
29 | "Raw":"원본",
30 | "can't parse JSON. Raw result":"JSON을 파싱할수 없음. 원본결과:",
31 | "Model Schema":"모델 스키마",
32 | "Model":"모델",
33 | "apply":"적용",
34 | "Username":"사용자 이름",
35 | "Password":"암호",
36 | "Terms of service":"이용약관",
37 | "Created by":"작성자",
38 | "See more at":"추가정보:",
39 | "Contact the developer":"개발자에게 문의",
40 | "api version":"api버전",
41 | "Response Content Type":"응답Content Type",
42 | "fetching resource":"리소스 가져오기",
43 | "fetching resource list":"리소스 목록 가져오기",
44 | "Explore":"탐색",
45 | "Show Swagger Petstore Example Apis":"Swagger Petstore 예제 보기",
46 | "Can't read from server. It may not have the appropriate access-control-origin settings.":"서버로부터 읽어들일수 없습니다. access-control-origin 설정이 올바르지 않을수 있습니다.",
47 | "Please specify the protocol for":"다음을 위한 프로토콜을 정하세요",
48 | "Can't read swagger JSON from":"swagger JSON 을 다음으로 부터 읽을수 없습니다",
49 | "Finished Loading Resource Information. Rendering Swagger UI":"리소스 정보 불러오기 완료. Swagger UI 랜더링",
50 | "Unable to read api":"api를 읽을 수 없습니다.",
51 | "from path":"다음 경로로 부터",
52 | "server returned":"서버 응답함."
53 | });
54 |
--------------------------------------------------------------------------------
/public/swagger/lang/zh-cn.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /* jshint quotmark: double */
4 | window.SwaggerTranslator.learn({
5 | "Warning: Deprecated":"警告:已过时",
6 | "Implementation Notes":"实现备注",
7 | "Response Class":"响应类",
8 | "Status":"状态",
9 | "Parameters":"参数",
10 | "Parameter":"参数",
11 | "Value":"值",
12 | "Description":"描述",
13 | "Parameter Type":"参数类型",
14 | "Data Type":"数据类型",
15 | "Response Messages":"响应消息",
16 | "HTTP Status Code":"HTTP状态码",
17 | "Reason":"原因",
18 | "Response Model":"响应模型",
19 | "Request URL":"请求URL",
20 | "Response Body":"响应体",
21 | "Response Code":"响应码",
22 | "Response Headers":"响应头",
23 | "Hide Response":"隐藏响应",
24 | "Headers":"头",
25 | "Try it out!":"试一下!",
26 | "Show/Hide":"显示/隐藏",
27 | "List Operations":"显示操作",
28 | "Expand Operations":"展开操作",
29 | "Raw":"原始",
30 | "can't parse JSON. Raw result":"无法解析JSON. 原始结果",
31 | "Example Value":"示例",
32 | "Click to set as parameter value":"点击设置参数",
33 | "Model Schema":"模型架构",
34 | "Model":"模型",
35 | "apply":"应用",
36 | "Username":"用户名",
37 | "Password":"密码",
38 | "Terms of service":"服务条款",
39 | "Created by":"创建者",
40 | "See more at":"查看更多:",
41 | "Contact the developer":"联系开发者",
42 | "api version":"api版本",
43 | "Response Content Type":"响应Content Type",
44 | "Parameter content type:":"参数类型:",
45 | "fetching resource":"正在获取资源",
46 | "fetching resource list":"正在获取资源列表",
47 | "Explore":"浏览",
48 | "Show Swagger Petstore Example Apis":"显示 Swagger Petstore 示例 Apis",
49 | "Can't read from server. It may not have the appropriate access-control-origin settings.":"无法从服务器读取。可能没有正确设置access-control-origin。",
50 | "Please specify the protocol for":"请指定协议:",
51 | "Can't read swagger JSON from":"无法读取swagger JSON于",
52 | "Finished Loading Resource Information. Rendering Swagger UI":"已加载资源信息。正在渲染Swagger UI",
53 | "Unable to read api":"无法读取api",
54 | "from path":"从路径",
55 | "server returned":"服务器返回"
56 | });
57 |
--------------------------------------------------------------------------------
/server/utils/easemob/Files.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 文件操作
3 | */
4 |
5 | var fs = require('fs')
6 | var FormData = require('form-data')
7 | var client = require('./client')
8 |
9 | function Files() {
10 |
11 | //Upload file
12 | //Warning: File cannot be over 10MB, otherwise will fail.
13 | this.uploadFile = function (json, callback) {
14 | var form = new FormData()
15 | form.append('file', fs.createReadStream(json.filePath))
16 | client.client({
17 | path: 'chatfiles',
18 | method: 'POST',
19 | form: form,
20 | headers: {'restrict-access': json.restrictAccess},
21 | callback: function (data) {
22 | console.log(data)
23 | if (typeof callback == 'function')
24 | callback(data)
25 | }
26 | }, client.uploadFileWithToken)
27 | }
28 |
29 | //Download file
30 | this.downloadFile = function downloadFile(json, callback) {
31 | json = json || {}
32 | client.client({
33 | path: 'chatfiles/' + json.uuid,
34 | method: 'GET',
35 | headers: { 'accept': ' application/octet-stream', 'share-secret': json.shareSecret },
36 | callback: function (data) {
37 | console.log(data)
38 | if (typeof callback == 'function')
39 | callback(data)
40 | }
41 | })
42 | }
43 |
44 | //Download thumbnail
45 | this.downloadThumbnail = function downloadThumbnail(json) {
46 | json = json || {}
47 | client.client({
48 | path: 'chatfiles/' + json.uuid,
49 | method: 'GET',
50 | headers: {
51 | 'accept': ' application/octet-stream',
52 | 'share-secret': json.shareSecret,
53 | 'thumbnail': json.thumbnail
54 | },
55 | callback: function (data) {
56 | // console.log(data)
57 | typeof json.callback == 'function' && json.callback(data)
58 | }
59 | })
60 | }
61 | }
62 |
63 | module.exports = Files
64 |
--------------------------------------------------------------------------------
/public/swagger/lang/ja.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /* jshint quotmark: double */
4 | window.SwaggerTranslator.learn({
5 | "Warning: Deprecated":"警告: 廃止予定",
6 | "Implementation Notes":"実装メモ",
7 | "Response Class":"レスポンスクラス",
8 | "Status":"ステータス",
9 | "Parameters":"パラメータ群",
10 | "Parameter":"パラメータ",
11 | "Value":"値",
12 | "Description":"説明",
13 | "Parameter Type":"パラメータタイプ",
14 | "Data Type":"データタイプ",
15 | "Response Messages":"レスポンスメッセージ",
16 | "HTTP Status Code":"HTTPステータスコード",
17 | "Reason":"理由",
18 | "Response Model":"レスポンスモデル",
19 | "Request URL":"リクエストURL",
20 | "Response Body":"レスポンスボディ",
21 | "Response Code":"レスポンスコード",
22 | "Response Headers":"レスポンスヘッダ",
23 | "Hide Response":"レスポンスを隠す",
24 | "Headers":"ヘッダ",
25 | "Try it out!":"実際に実行!",
26 | "Show/Hide":"表示/非表示",
27 | "List Operations":"操作一覧",
28 | "Expand Operations":"操作の展開",
29 | "Raw":"未加工",
30 | "can't parse JSON. Raw result":"JSONへ解釈できません. 未加工の結果",
31 | "Example Value":"値の例",
32 | "Model Schema":"モデルスキーマ",
33 | "Model":"モデル",
34 | "Click to set as parameter value":"パラメータ値と設定するにはクリック",
35 | "apply":"実行",
36 | "Username":"ユーザ名",
37 | "Password":"パスワード",
38 | "Terms of service":"サービス利用規約",
39 | "Created by":"Created by",
40 | "See more at":"詳細を見る",
41 | "Contact the developer":"開発者に連絡",
42 | "api version":"APIバージョン",
43 | "Response Content Type":"レスポンス コンテンツタイプ",
44 | "Parameter content type:":"パラメータコンテンツタイプ:",
45 | "fetching resource":"リソースの取得",
46 | "fetching resource list":"リソース一覧の取得",
47 | "Explore":"調査",
48 | "Show Swagger Petstore Example Apis":"SwaggerペットストアAPIの表示",
49 | "Can't read from server. It may not have the appropriate access-control-origin settings.":"サーバから読み込めません. 適切なaccess-control-origin設定を持っていない可能性があります.",
50 | "Please specify the protocol for":"プロトコルを指定してください",
51 | "Can't read swagger JSON from":"次からswagger JSONを読み込めません",
52 | "Finished Loading Resource Information. Rendering Swagger UI":"リソース情報の読み込みが完了しました. Swagger UIを描画しています",
53 | "Unable to read api":"APIを読み込めません",
54 | "from path":"次のパスから",
55 | "server returned":"サーバからの返答"
56 | });
57 |
--------------------------------------------------------------------------------
/server/utils/http.js:
--------------------------------------------------------------------------------
1 | /**
2 | * HTTP数据通信模块
3 | */
4 |
5 | var request = require('request-promise')
6 | var querystring = require('querystring')
7 |
8 | // 缺省请求头
9 | var defaultHeaders = {
10 | 'Accept': 'application/json',
11 | 'Content-Type': 'application/json' // application/x-www-form-urlencoded
12 | }
13 |
14 | // 请求参数加工
15 | function mutate (uri, options) {
16 | options = options || {}
17 | options.headers = options.headers || {}
18 | options.uri = uri
19 |
20 | Object.assign(options.headers, defaultHeaders)
21 |
22 | if (options.body) {
23 | if (typeof options.body === 'object') {
24 | options.body = JSON.stringify(options.body)
25 | }
26 | }
27 |
28 | if (options.qs) {
29 | if (typeof options.qs === 'object') {
30 | options.qs = querystring.stringify(options.qs)
31 | }
32 | uri += (uri.indexOf('?') !== -1) ? '&' : '?'
33 | options.uri = uri + options.qs
34 | options.qs = null
35 | }
36 |
37 | options.json = true
38 |
39 | console.log(`Request ${options.uri}` + (options.body ? ' : ' + options.body : ''))
40 |
41 | return options
42 | }
43 |
44 | /**
45 | * 接口调用服务
46 | * @param {String} uri 接口API(必填)
47 | * @param {Object} options 请求参数(选填){headers, body, query, ...options}
48 | * @return {Object} Promise
49 | * @throws {Error}
50 | */
51 | var callService = function (uri, options = {}) {
52 | return request(mutate(uri, options)).then(response => {
53 | console.log(`Response ${uri} :`, response)
54 | return response
55 | })
56 | }
57 |
58 | exports.callService = callService
59 |
60 | exports.get = function (url, args, options = {}) {
61 | options.method = 'GET'
62 | options.qs = args
63 | return callService(url, options)
64 | }
65 |
66 | exports.post = function (url, args, options = {}) {
67 | options.method = 'POST'
68 | options.body = args
69 | return callService(url, options)
70 | }
71 |
72 | exports.put = function (url, args, options = {}) {
73 | options.method = 'PUT'
74 | options.body = args
75 | return callService(url, options)
76 | }
77 |
78 | exports.patch = function (url, args, options = {}) {
79 | options.method = 'PATCH'
80 | options.body = args
81 | return callService(url, options)
82 | }
83 |
84 | exports.del = function (url, args, options = {}) {
85 | options.method = 'DELETE'
86 | options.qs = args
87 | return callService(url, options)
88 | }
89 |
--------------------------------------------------------------------------------
/public/swagger/lang/tr.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /* jshint quotmark: double */
4 | window.SwaggerTranslator.learn({
5 | "Warning: Deprecated":"Uyarı: Deprecated",
6 | "Implementation Notes":"Gerçekleştirim Notları",
7 | "Response Class":"Dönen Sınıf",
8 | "Status":"Statü",
9 | "Parameters":"Parametreler",
10 | "Parameter":"Parametre",
11 | "Value":"Değer",
12 | "Description":"Açıklama",
13 | "Parameter Type":"Parametre Tipi",
14 | "Data Type":"Veri Tipi",
15 | "Response Messages":"Dönüş Mesajı",
16 | "HTTP Status Code":"HTTP Statü Kodu",
17 | "Reason":"Gerekçe",
18 | "Response Model":"Dönüş Modeli",
19 | "Request URL":"İstek URL",
20 | "Response Body":"Dönüş İçeriği",
21 | "Response Code":"Dönüş Kodu",
22 | "Response Headers":"Dönüş Üst Bilgileri",
23 | "Hide Response":"Dönüşü Gizle",
24 | "Headers":"Üst Bilgiler",
25 | "Try it out!":"Dene!",
26 | "Show/Hide":"Göster/Gizle",
27 | "List Operations":"Operasyonları Listele",
28 | "Expand Operations":"Operasyonları Aç",
29 | "Raw":"Ham",
30 | "can't parse JSON. Raw result":"JSON çözümlenemiyor. Ham sonuç",
31 | "Model Schema":"Model Şema",
32 | "Model":"Model",
33 | "apply":"uygula",
34 | "Username":"Kullanıcı Adı",
35 | "Password":"Parola",
36 | "Terms of service":"Servis şartları",
37 | "Created by":"Oluşturan",
38 | "See more at":"Daha fazlası için",
39 | "Contact the developer":"Geliştirici ile İletişime Geçin",
40 | "api version":"api versiyon",
41 | "Response Content Type":"Dönüş İçerik Tipi",
42 | "fetching resource":"kaynak getiriliyor",
43 | "fetching resource list":"kaynak listesi getiriliyor",
44 | "Explore":"Keşfet",
45 | "Show Swagger Petstore Example Apis":"Swagger Petstore Örnek Api'yi Gör",
46 | "Can't read from server. It may not have the appropriate access-control-origin settings.":"Sunucudan okuma yapılamıyor. Sunucu access-control-origin ayarlarınızı kontrol edin.",
47 | "Please specify the protocol for":"Lütfen istenen adres için protokol belirtiniz",
48 | "Can't read swagger JSON from":"Swagger JSON bu kaynaktan okunamıyor",
49 | "Finished Loading Resource Information. Rendering Swagger UI":"Kaynak baglantısı tamamlandı. Swagger UI gösterime hazırlanıyor",
50 | "Unable to read api":"api okunamadı",
51 | "from path":"yoldan",
52 | "server returned":"sunucuya dönüldü"
53 | });
54 |
--------------------------------------------------------------------------------
/config/pm2.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | /**
3 | * Application configuration section
4 | * http://pm2.keymetrics.io/docs/usage/application-declaration/
5 | */
6 | apps: [
7 | {
8 | name: "node-server",
9 | script: "./bin/www",
10 | watch: true,
11 | ignore_watch: [
12 | "client",
13 | "public",
14 | "test",
15 | "logs",
16 | "node_modules"
17 | ],
18 | instances: 0,
19 | exec_mode: "cluster",
20 | max_memory_restart: "1G",
21 | error_file: "./logs/err.log",
22 | out_file: "./logs/out.log",
23 | merge_logs: false,
24 | log_date_format: 'YYYY-MM-DD HH:mm:ss',
25 | env: {
26 | PM2: "true"
27 | },
28 | env_production: {
29 | NODE_ENV: "production"
30 | },
31 | env_simulation: {
32 | NODE_ENV: "simulation"
33 | },
34 | env_testing: {
35 | NODE_ENV: "testing"
36 | },
37 | env_development: {
38 | NODE_ENV: "development"
39 | }
40 | }
41 | ],
42 |
43 | /**
44 | * Deployment section
45 | * http://pm2.keymetrics.io/docs/usage/deployment/
46 | */
47 | deploy: {
48 | production: {
49 | user: "node",
50 | host: ["212.83.163.1", "212.83.163.2"],
51 | ref: "origin/master",
52 | repo: "git@github.com:repo.git",
53 | path: "/home/node/node-server-project",
54 | "post-deploy": "npm install && npm run prod",
55 | env: {
56 | NODE_ENV: "production"
57 | }
58 | },
59 | simulation: {
60 | user: "node",
61 | host: ["212.83.163.3"],
62 | ref: "origin/master",
63 | repo: "git@github.com:repo.git",
64 | path: "/home/node/node-server-project",
65 | "post-setup": "cnpm install && npm run simu",
66 | "post-deploy": "cnpm install && npm run simu",
67 | env: {
68 | NODE_ENV: "simulation"
69 | }
70 | },
71 | testing: {
72 | user: "node",
73 | host: "212.83.163.1",
74 | ref: "origin/develop",
75 | repo: "git@github.com:repo.git",
76 | path: "/home/node/node-server-project",
77 | ssh_options: ["StrictHostKeyChecking=no", "PasswordAuthentication=no"],
78 | "post-setup": "cnpm install && npm run testing",
79 | "post-deploy": "cnpm install && npm run testing",
80 | env: {
81 | NODE_ENV: "testing"
82 | }
83 | }
84 | }
85 | }
86 |
87 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # node-server-project
2 | > 基于 node.js + express 技术栈,采用MVC结构设计、JWT + RESTful API、PM2服务监控的Node Web项目框架。
3 |
4 | 技术栈
5 |
6 | - node.js(>7.0,已原生支持绝大部分ES6/ES7语法)
7 | - express(成熟稳定的Web框架)
8 | - hbs(handlebars后端模版引擎,语法简洁高效、实现模版继承和内嵌功能等)
9 | - RESTful(API架构风格,并提供统一的接口输出结构)
10 | - JWT(Json Web Token 认证协议,用于页面和API的验证,包括token续期方案等)
11 | - ORM(数据库对象关系映射)
12 | - TEST(集成在线API文档生成和测试工具[Swagger-ui](https://github.com/swagger-api/swagger-ui),public/swagger目录下)
13 | - RabbitMQ & Thrift & 环信服务端 集成等
14 | - PM2(Node服务自动部署和监控)
15 |
16 | 关于API接口文档管理及线上线下测试,推荐:[SosoApi](http://www.sosoapi.com/)
17 |
18 | ## Build Setup @see package.json#scripts
19 |
20 | ### Install dependencies, use cnpm:
21 | npm install -g cnpm --registry=https://registry.npm.taobao.org
22 | ```
23 | cnpm install
24 | ```
25 |
26 | ### Start server for development or production (pm2)
27 |
28 | ```
29 | npm start
30 | ```
31 |
32 | ### Auto restarting server and reloading browsers for development
33 |
34 | ```
35 | npm run live:client // 客户端源码变动实时监测
36 | npm run live:server // 服务端源码变动实时监测
37 | ```
38 |
39 | ### For unit test, such as:
40 |
41 | ```
42 | npm test ./test/api/login.js
43 | ```
44 |
45 | ### Debug node code
46 |
47 | Please install 'npm install -g node-inspector' at first
48 |
49 | ```
50 | npm run debug
51 | ```
52 |
53 | ### Check update for npm packages
54 |
55 | Please install 'npm install npm-check-updates -g' at first
56 |
57 | ```
58 | npm run update
59 | ```
60 |
61 | ### PM2 operations and deploy(基于Git)
62 |
63 | First of all, please install node.js and git on the server and set $PATH env in ~/.bashrc
64 | ```
65 | export NODE_HOME=/data/node-v7.7.4-linux-x64
66 | export PATH=$NODE_HOME/bin:$PATH
67 | ```
68 |
69 | Host key verification after you execute ssh-keygen on server, and set ssh-key to gitlab.
70 | ```
71 | ssh-keyscan -t rsa yourGitServer >> ~/.ssh/known_hosts
72 | ```
73 |
74 | For client ssh password-less logon
75 | ```
76 | ssh-keygen -t rsa
77 | ssh-copy-id -i ~/.ssh/id_rsa.pub node@192.168.1.10
78 | ```
79 |
80 | then, use ·npm run setup:test· for the first time, other deployment use ·npm run deploy:test·
81 | ```
82 | npm run setup:test // 测试环境远程部署(第一次安装)
83 | npm run setup:simu // 仿真环境远程部署(第一次安装)
84 | npm run setup:prod // 生产环境远程部署(第一次安装)
85 | npm run deploy:test // 测试环境远程部署(后期更新)
86 | npm run deploy:simu // 仿真环境远程部署(后期更新)
87 | npm run deploy:prod // 生产环境远程部署(后期更新)
88 | npm run stop
89 | npm run reload
90 | npm run list
91 | npm run monit
92 | npm run logs
93 | ```
94 |
--------------------------------------------------------------------------------
/public/swagger/lang/pl.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /* jshint quotmark: double */
4 | window.SwaggerTranslator.learn({
5 | "Warning: Deprecated":"Uwaga: Wycofane",
6 | "Implementation Notes":"Uwagi Implementacji",
7 | "Response Class":"Klasa Odpowiedzi",
8 | "Status":"Status",
9 | "Parameters":"Parametry",
10 | "Parameter":"Parametr",
11 | "Value":"Wartość",
12 | "Description":"Opis",
13 | "Parameter Type":"Typ Parametru",
14 | "Data Type":"Typ Danych",
15 | "Response Messages":"Wiadomości Odpowiedzi",
16 | "HTTP Status Code":"Kod Statusu HTTP",
17 | "Reason":"Przyczyna",
18 | "Response Model":"Model Odpowiedzi",
19 | "Request URL":"URL Wywołania",
20 | "Response Body":"Treść Odpowiedzi",
21 | "Response Code":"Kod Odpowiedzi",
22 | "Response Headers":"Nagłówki Odpowiedzi",
23 | "Hide Response":"Ukryj Odpowiedź",
24 | "Headers":"Nagłówki",
25 | "Try it out!":"Wypróbuj!",
26 | "Show/Hide":"Pokaż/Ukryj",
27 | "List Operations":"Lista Operacji",
28 | "Expand Operations":"Rozwiń Operacje",
29 | "Raw":"Nieprzetworzone",
30 | "can't parse JSON. Raw result":"nie można przetworzyć pliku JSON. Nieprzetworzone dane",
31 | "Model Schema":"Schemat Modelu",
32 | "Model":"Model",
33 | "apply":"użyj",
34 | "Username":"Nazwa użytkownika",
35 | "Password":"Hasło",
36 | "Terms of service":"Warunki używania",
37 | "Created by":"Utworzone przez",
38 | "See more at":"Zobacz więcej na",
39 | "Contact the developer":"Kontakt z deweloperem",
40 | "api version":"wersja api",
41 | "Response Content Type":"Typ Zasobu Odpowiedzi",
42 | "fetching resource":"ładowanie zasobu",
43 | "fetching resource list":"ładowanie listy zasobów",
44 | "Explore":"Eksploruj",
45 | "Show Swagger Petstore Example Apis":"Pokaż Przykładowe Api Swagger Petstore",
46 | "Can't read from server. It may not have the appropriate access-control-origin settings.":"Brak połączenia z serwerem. Może on nie mieć odpowiednich ustawień access-control-origin.",
47 | "Please specify the protocol for":"Proszę podać protokół dla",
48 | "Can't read swagger JSON from":"Nie można odczytać swagger JSON z",
49 | "Finished Loading Resource Information. Rendering Swagger UI":"Ukończono Ładowanie Informacji o Zasobie. Renderowanie Swagger UI",
50 | "Unable to read api":"Nie można odczytać api",
51 | "from path":"ze ścieżki",
52 | "server returned":"serwer zwrócił"
53 | });
54 |
--------------------------------------------------------------------------------
/public/swagger/lang/pt.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /* jshint quotmark: double */
4 | window.SwaggerTranslator.learn({
5 | "Warning: Deprecated":"Aviso: Depreciado",
6 | "Implementation Notes":"Notas de Implementação",
7 | "Response Class":"Classe de resposta",
8 | "Status":"Status",
9 | "Parameters":"Parâmetros",
10 | "Parameter":"Parâmetro",
11 | "Value":"Valor",
12 | "Description":"Descrição",
13 | "Parameter Type":"Tipo de parâmetro",
14 | "Data Type":"Tipo de dados",
15 | "Response Messages":"Mensagens de resposta",
16 | "HTTP Status Code":"Código de status HTTP",
17 | "Reason":"Razão",
18 | "Response Model":"Modelo resposta",
19 | "Request URL":"URL requisição",
20 | "Response Body":"Corpo da resposta",
21 | "Response Code":"Código da resposta",
22 | "Response Headers":"Cabeçalho da resposta",
23 | "Headers":"Cabeçalhos",
24 | "Hide Response":"Esconder resposta",
25 | "Try it out!":"Tente agora!",
26 | "Show/Hide":"Mostrar/Esconder",
27 | "List Operations":"Listar operações",
28 | "Expand Operations":"Expandir operações",
29 | "Raw":"Cru",
30 | "can't parse JSON. Raw result":"Falha ao analisar JSON. Resulto cru",
31 | "Model Schema":"Modelo esquema",
32 | "Model":"Modelo",
33 | "apply":"Aplicar",
34 | "Username":"Usuário",
35 | "Password":"Senha",
36 | "Terms of service":"Termos do serviço",
37 | "Created by":"Criado por",
38 | "See more at":"Veja mais em",
39 | "Contact the developer":"Contate o desenvolvedor",
40 | "api version":"Versão api",
41 | "Response Content Type":"Tipo de conteúdo da resposta",
42 | "fetching resource":"busca recurso",
43 | "fetching resource list":"buscando lista de recursos",
44 | "Explore":"Explorar",
45 | "Show Swagger Petstore Example Apis":"Show Swagger Petstore Example Apis",
46 | "Can't read from server. It may not have the appropriate access-control-origin settings.":"Não é possível ler do servidor. Pode não ter as apropriadas configurações access-control-origin",
47 | "Please specify the protocol for":"Por favor especifique o protocolo",
48 | "Can't read swagger JSON from":"Não é possível ler o JSON Swagger de",
49 | "Finished Loading Resource Information. Rendering Swagger UI":"Carregar informação de recurso finalizada. Renderizando Swagger UI",
50 | "Unable to read api":"Não foi possível ler api",
51 | "from path":"do caminho",
52 | "server returned":"servidor retornou"
53 | });
54 |
--------------------------------------------------------------------------------
/public/swagger/lang/en.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /* jshint quotmark: double */
4 | window.SwaggerTranslator.learn({
5 | "Warning: Deprecated":"Warning: Deprecated",
6 | "Implementation Notes":"Implementation Notes",
7 | "Response Class":"Response Class",
8 | "Status":"Status",
9 | "Parameters":"Parameters",
10 | "Parameter":"Parameter",
11 | "Value":"Value",
12 | "Description":"Description",
13 | "Parameter Type":"Parameter Type",
14 | "Data Type":"Data Type",
15 | "Response Messages":"Response Messages",
16 | "HTTP Status Code":"HTTP Status Code",
17 | "Reason":"Reason",
18 | "Response Model":"Response Model",
19 | "Request URL":"Request URL",
20 | "Response Body":"Response Body",
21 | "Response Code":"Response Code",
22 | "Response Headers":"Response Headers",
23 | "Hide Response":"Hide Response",
24 | "Headers":"Headers",
25 | "Try it out!":"Try it out!",
26 | "Show/Hide":"Show/Hide",
27 | "List Operations":"List Operations",
28 | "Expand Operations":"Expand Operations",
29 | "Raw":"Raw",
30 | "can't parse JSON. Raw result":"can't parse JSON. Raw result",
31 | "Example Value":"Example Value",
32 | "Model Schema":"Model Schema",
33 | "Model":"Model",
34 | "Click to set as parameter value":"Click to set as parameter value",
35 | "apply":"apply",
36 | "Username":"Username",
37 | "Password":"Password",
38 | "Terms of service":"Terms of service",
39 | "Created by":"Created by",
40 | "See more at":"See more at",
41 | "Contact the developer":"Contact the developer",
42 | "api version":"api version",
43 | "Response Content Type":"Response Content Type",
44 | "Parameter content type:":"Parameter content type:",
45 | "fetching resource":"fetching resource",
46 | "fetching resource list":"fetching resource list",
47 | "Explore":"Explore",
48 | "Show Swagger Petstore Example Apis":"Show Swagger Petstore Example Apis",
49 | "Can't read from server. It may not have the appropriate access-control-origin settings.":"Can't read from server. It may not have the appropriate access-control-origin settings.",
50 | "Please specify the protocol for":"Please specify the protocol for",
51 | "Can't read swagger JSON from":"Can't read swagger JSON from",
52 | "Finished Loading Resource Information. Rendering Swagger UI":"Finished Loading Resource Information. Rendering Swagger UI",
53 | "Unable to read api":"Unable to read api",
54 | "from path":"from path",
55 | "server returned":"server returned"
56 | });
57 |
--------------------------------------------------------------------------------
/public/swagger/lang/ru.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /* jshint quotmark: double */
4 | window.SwaggerTranslator.learn({
5 | "Warning: Deprecated":"Предупреждение: Устарело",
6 | "Implementation Notes":"Заметки",
7 | "Response Class":"Пример ответа",
8 | "Status":"Статус",
9 | "Parameters":"Параметры",
10 | "Parameter":"Параметр",
11 | "Value":"Значение",
12 | "Description":"Описание",
13 | "Parameter Type":"Тип параметра",
14 | "Data Type":"Тип данных",
15 | "HTTP Status Code":"HTTP код",
16 | "Reason":"Причина",
17 | "Response Model":"Структура ответа",
18 | "Request URL":"URL запроса",
19 | "Response Body":"Тело ответа",
20 | "Response Code":"HTTP код ответа",
21 | "Response Headers":"Заголовки ответа",
22 | "Hide Response":"Спрятать ответ",
23 | "Headers":"Заголовки",
24 | "Response Messages":"Что может прийти в ответ",
25 | "Try it out!":"Попробовать!",
26 | "Show/Hide":"Показать/Скрыть",
27 | "List Operations":"Операции кратко",
28 | "Expand Operations":"Операции подробно",
29 | "Raw":"В сыром виде",
30 | "can't parse JSON. Raw result":"Не удается распарсить ответ:",
31 | "Example Value":"Пример",
32 | "Model Schema":"Структура",
33 | "Model":"Описание",
34 | "Click to set as parameter value":"Нажмите, чтобы испльзовать в качестве значения параметра",
35 | "apply":"применить",
36 | "Username":"Имя пользователя",
37 | "Password":"Пароль",
38 | "Terms of service":"Условия использования",
39 | "Created by":"Разработано",
40 | "See more at":"Еще тут",
41 | "Contact the developer":"Связаться с разработчиком",
42 | "api version":"Версия API",
43 | "Response Content Type":"Content Type ответа",
44 | "Parameter content type:":"Content Type параметра:",
45 | "fetching resource":"Получение ресурса",
46 | "fetching resource list":"Получение ресурсов",
47 | "Explore":"Показать",
48 | "Show Swagger Petstore Example Apis":"Показать примеры АПИ",
49 | "Can't read from server. It may not have the appropriate access-control-origin settings.":"Не удается получить ответ от сервера. Возможно, проблема с настройками доступа",
50 | "Please specify the protocol for":"Пожалуйста, укажите протокол для",
51 | "Can't read swagger JSON from":"Не получается прочитать swagger json из",
52 | "Finished Loading Resource Information. Rendering Swagger UI":"Загрузка информации о ресурсах завершена. Рендерим",
53 | "Unable to read api":"Не удалось прочитать api",
54 | "from path":"по адресу",
55 | "server returned":"сервер сказал"
56 | });
57 |
--------------------------------------------------------------------------------
/public/swagger/lang/ca.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /* jshint quotmark: double */
4 | window.SwaggerTranslator.learn({
5 | "Warning: Deprecated":"Advertència: Obsolet",
6 | "Implementation Notes":"Notes d'implementació",
7 | "Response Class":"Classe de la Resposta",
8 | "Status":"Estatus",
9 | "Parameters":"Paràmetres",
10 | "Parameter":"Paràmetre",
11 | "Value":"Valor",
12 | "Description":"Descripció",
13 | "Parameter Type":"Tipus del Paràmetre",
14 | "Data Type":"Tipus de la Dada",
15 | "Response Messages":"Missatges de la Resposta",
16 | "HTTP Status Code":"Codi d'Estatus HTTP",
17 | "Reason":"Raó",
18 | "Response Model":"Model de la Resposta",
19 | "Request URL":"URL de la Sol·licitud",
20 | "Response Body":"Cos de la Resposta",
21 | "Response Code":"Codi de la Resposta",
22 | "Response Headers":"Capçaleres de la Resposta",
23 | "Hide Response":"Amagar Resposta",
24 | "Try it out!":"Prova-ho!",
25 | "Show/Hide":"Mostrar/Amagar",
26 | "List Operations":"Llista Operacions",
27 | "Expand Operations":"Expandir Operacions",
28 | "Raw":"Cru",
29 | "can't parse JSON. Raw result":"no puc analitzar el JSON. Resultat cru",
30 | "Example Value":"Valor d'Exemple",
31 | "Model Schema":"Esquema del Model",
32 | "Model":"Model",
33 | "apply":"aplicar",
34 | "Username":"Nom d'usuari",
35 | "Password":"Contrasenya",
36 | "Terms of service":"Termes del servei",
37 | "Created by":"Creat per",
38 | "See more at":"Veure més en",
39 | "Contact the developer":"Contactar amb el desenvolupador",
40 | "api version":"versió de la api",
41 | "Response Content Type":"Tipus de Contingut de la Resposta",
42 | "fetching resource":"recollint recurs",
43 | "fetching resource list":"recollins llista de recursos",
44 | "Explore":"Explorant",
45 | "Show Swagger Petstore Example Apis":"Mostrar API d'Exemple Swagger Petstore",
46 | "Can't read from server. It may not have the appropriate access-control-origin settings.":"No es pot llegir del servidor. Potser no teniu la configuració de control d'accés apropiada.",
47 | "Please specify the protocol for":"Si us plau, especifiqueu el protocol per a",
48 | "Can't read swagger JSON from":"No es pot llegir el JSON de swagger des de",
49 | "Finished Loading Resource Information. Rendering Swagger UI":"Finalitzada la càrrega del recurs informatiu. Renderitzant Swagger UI",
50 | "Unable to read api":"No es pot llegir l'api",
51 | "from path":"des de la ruta",
52 | "server returned":"el servidor ha retornat"
53 | });
54 |
--------------------------------------------------------------------------------
/public/swagger/lang/geo.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /* jshint quotmark: double */
4 | window.SwaggerTranslator.learn({
5 | "Warning: Deprecated":"ყურადღება: აღარ გამოიყენება",
6 | "Implementation Notes":"იმპლემენტაციის აღწერა",
7 | "Response Class":"რესპონს კლასი",
8 | "Status":"სტატუსი",
9 | "Parameters":"პარამეტრები",
10 | "Parameter":"პარამეტრი",
11 | "Value":"მნიშვნელობა",
12 | "Description":"აღწერა",
13 | "Parameter Type":"პარამეტრის ტიპი",
14 | "Data Type":"მონაცემის ტიპი",
15 | "Response Messages":"პასუხი",
16 | "HTTP Status Code":"HTTP სტატუსი",
17 | "Reason":"მიზეზი",
18 | "Response Model":"რესპონს მოდელი",
19 | "Request URL":"მოთხოვნის URL",
20 | "Response Body":"პასუხის სხეული",
21 | "Response Code":"პასუხის კოდი",
22 | "Response Headers":"პასუხის ჰედერები",
23 | "Hide Response":"დამალე პასუხი",
24 | "Headers":"ჰედერები",
25 | "Try it out!":"ცადე !",
26 | "Show/Hide":"გამოჩენა/დამალვა",
27 | "List Operations":"ოპერაციების სია",
28 | "Expand Operations":"ოპერაციები ვრცლად",
29 | "Raw":"ნედლი",
30 | "can't parse JSON. Raw result":"JSON-ის დამუშავება ვერ მოხერხდა. ნედლი პასუხი",
31 | "Example Value":"მაგალითი",
32 | "Model Schema":"მოდელის სტრუქტურა",
33 | "Model":"მოდელი",
34 | "Click to set as parameter value":"პარამეტრისთვის მნიშვნელობის მისანიჭებლად, დააკლიკე",
35 | "apply":"გამოყენება",
36 | "Username":"მოხმარებელი",
37 | "Password":"პაროლი",
38 | "Terms of service":"მომსახურების პირობები",
39 | "Created by":"შექმნა",
40 | "See more at":"ნახე ვრცლად",
41 | "Contact the developer":"დაუკავშირდი დეველოპერს",
42 | "api version":"api ვერსია",
43 | "Response Content Type":"პასუხის კონტენტის ტიპი",
44 | "Parameter content type:":"პარამეტრის კონტენტის ტიპი:",
45 | "fetching resource":"რესურსების მიღება",
46 | "fetching resource list":"რესურსების სიის მიღება",
47 | "Explore":"ნახვა",
48 | "Show Swagger Petstore Example Apis":"ნახე Swagger Petstore სამაგალითო Api",
49 | "Can't read from server. It may not have the appropriate access-control-origin settings.":"სერვერთან დაკავშირება ვერ ხერხდება. შეამოწმეთ access-control-origin.",
50 | "Please specify the protocol for":"მიუთითეთ პროტოკოლი",
51 | "Can't read swagger JSON from":"swagger JSON წაკითხვა ვერ მოხერხდა",
52 | "Finished Loading Resource Information. Rendering Swagger UI":"რესურსების ჩატვირთვა სრულდება. Swagger UI რენდერდება",
53 | "Unable to read api":"api წაკითხვა ვერ მოხერხდა",
54 | "from path":"მისამართიდან",
55 | "server returned":"სერვერმა დააბრუნა"
56 | });
57 |
--------------------------------------------------------------------------------
/public/swagger/lang/it.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /* jshint quotmark: double */
4 | window.SwaggerTranslator.learn({
5 | "Warning: Deprecated":"Attenzione: Deprecato",
6 | "Implementation Notes":"Note di implementazione",
7 | "Response Class":"Classe della risposta",
8 | "Status":"Stato",
9 | "Parameters":"Parametri",
10 | "Parameter":"Parametro",
11 | "Value":"Valore",
12 | "Description":"Descrizione",
13 | "Parameter Type":"Tipo di parametro",
14 | "Data Type":"Tipo di dato",
15 | "Response Messages":"Messaggi della risposta",
16 | "HTTP Status Code":"Codice stato HTTP",
17 | "Reason":"Motivo",
18 | "Response Model":"Modello di risposta",
19 | "Request URL":"URL della richiesta",
20 | "Response Body":"Corpo della risposta",
21 | "Response Code":"Oggetto della risposta",
22 | "Response Headers":"Intestazioni della risposta",
23 | "Hide Response":"Nascondi risposta",
24 | "Try it out!":"Provalo!",
25 | "Show/Hide":"Mostra/Nascondi",
26 | "List Operations":"Mostra operazioni",
27 | "Expand Operations":"Espandi operazioni",
28 | "Raw":"Grezzo (raw)",
29 | "can't parse JSON. Raw result":"non è possibile parsare il JSON. Risultato grezzo (raw).",
30 | "Model Schema":"Schema del modello",
31 | "Model":"Modello",
32 | "apply":"applica",
33 | "Username":"Nome utente",
34 | "Password":"Password",
35 | "Terms of service":"Condizioni del servizio",
36 | "Created by":"Creato da",
37 | "See more at":"Informazioni aggiuntive:",
38 | "Contact the developer":"Contatta lo sviluppatore",
39 | "api version":"versione api",
40 | "Response Content Type":"Tipo di contenuto (content type) della risposta",
41 | "fetching resource":"recuperando la risorsa",
42 | "fetching resource list":"recuperando lista risorse",
43 | "Explore":"Esplora",
44 | "Show Swagger Petstore Example Apis":"Mostra le api di esempio di Swagger Petstore",
45 | "Can't read from server. It may not have the appropriate access-control-origin settings.":"Non è possibile leggere dal server. Potrebbe non avere le impostazioni di controllo accesso origine (access-control-origin) appropriate.",
46 | "Please specify the protocol for":"Si prega di specificare il protocollo per",
47 | "Can't read swagger JSON from":"Impossibile leggere JSON swagger da:",
48 | "Finished Loading Resource Information. Rendering Swagger UI":"Lettura informazioni risorse termianta. Swagger UI viene mostrata",
49 | "Unable to read api":"Impossibile leggere la api",
50 | "from path":"da cartella",
51 | "server returned":"il server ha restituito"
52 | });
53 |
--------------------------------------------------------------------------------
/public/swagger/lang/es.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /* jshint quotmark: double */
4 | window.SwaggerTranslator.learn({
5 | "Warning: Deprecated":"Advertencia: Obsoleto",
6 | "Implementation Notes":"Notas de implementación",
7 | "Response Class":"Clase de la Respuesta",
8 | "Status":"Status",
9 | "Parameters":"Parámetros",
10 | "Parameter":"Parámetro",
11 | "Value":"Valor",
12 | "Description":"Descripción",
13 | "Parameter Type":"Tipo del Parámetro",
14 | "Data Type":"Tipo del Dato",
15 | "Response Messages":"Mensajes de la Respuesta",
16 | "HTTP Status Code":"Código de Status HTTP",
17 | "Reason":"Razón",
18 | "Response Model":"Modelo de la Respuesta",
19 | "Request URL":"URL de la Solicitud",
20 | "Response Body":"Cuerpo de la Respuesta",
21 | "Response Code":"Código de la Respuesta",
22 | "Response Headers":"Encabezados de la Respuesta",
23 | "Hide Response":"Ocultar Respuesta",
24 | "Try it out!":"Pruébalo!",
25 | "Show/Hide":"Mostrar/Ocultar",
26 | "List Operations":"Listar Operaciones",
27 | "Expand Operations":"Expandir Operaciones",
28 | "Raw":"Crudo",
29 | "can't parse JSON. Raw result":"no puede parsear el JSON. Resultado crudo",
30 | "Example Value":"Valor de Ejemplo",
31 | "Model Schema":"Esquema del Modelo",
32 | "Model":"Modelo",
33 | "apply":"aplicar",
34 | "Username":"Nombre de usuario",
35 | "Password":"Contraseña",
36 | "Terms of service":"Términos de Servicio",
37 | "Created by":"Creado por",
38 | "See more at":"Ver más en",
39 | "Contact the developer":"Contactar al desarrollador",
40 | "api version":"versión de la api",
41 | "Response Content Type":"Tipo de Contenido (Content Type) de la Respuesta",
42 | "fetching resource":"buscando recurso",
43 | "fetching resource list":"buscando lista del recurso",
44 | "Explore":"Explorar",
45 | "Show Swagger Petstore Example Apis":"Mostrar Api Ejemplo de Swagger Petstore",
46 | "Can't read from server. It may not have the appropriate access-control-origin settings.":"No se puede leer del servidor. Tal vez no tiene la configuración de control de acceso de origen (access-control-origin) apropiado.",
47 | "Please specify the protocol for":"Por favor, especificar el protocola para",
48 | "Can't read swagger JSON from":"No se puede leer el JSON de swagger desde",
49 | "Finished Loading Resource Information. Rendering Swagger UI":"Finalizada la carga del recurso de Información. Mostrando Swagger UI",
50 | "Unable to read api":"No se puede leer la api",
51 | "from path":"desde ruta",
52 | "server returned":"el servidor retornó"
53 | });
54 |
--------------------------------------------------------------------------------
/public/swagger/lang/fr.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /* jshint quotmark: double */
4 | window.SwaggerTranslator.learn({
5 | "Warning: Deprecated":"Avertissement : Obsolète",
6 | "Implementation Notes":"Notes d'implémentation",
7 | "Response Class":"Classe de la réponse",
8 | "Status":"Statut",
9 | "Parameters":"Paramètres",
10 | "Parameter":"Paramètre",
11 | "Value":"Valeur",
12 | "Description":"Description",
13 | "Parameter Type":"Type du paramètre",
14 | "Data Type":"Type de données",
15 | "Response Messages":"Messages de la réponse",
16 | "HTTP Status Code":"Code de statut HTTP",
17 | "Reason":"Raison",
18 | "Response Model":"Modèle de réponse",
19 | "Request URL":"URL appelée",
20 | "Response Body":"Corps de la réponse",
21 | "Response Code":"Code de la réponse",
22 | "Response Headers":"En-têtes de la réponse",
23 | "Hide Response":"Cacher la réponse",
24 | "Headers":"En-têtes",
25 | "Try it out!":"Testez !",
26 | "Show/Hide":"Afficher/Masquer",
27 | "List Operations":"Liste des opérations",
28 | "Expand Operations":"Développer les opérations",
29 | "Raw":"Brut",
30 | "can't parse JSON. Raw result":"impossible de décoder le JSON. Résultat brut",
31 | "Example Value":"Exemple la valeur",
32 | "Model Schema":"Définition du modèle",
33 | "Model":"Modèle",
34 | "apply":"appliquer",
35 | "Username":"Nom d'utilisateur",
36 | "Password":"Mot de passe",
37 | "Terms of service":"Conditions de service",
38 | "Created by":"Créé par",
39 | "See more at":"Voir plus sur",
40 | "Contact the developer":"Contacter le développeur",
41 | "api version":"version de l'api",
42 | "Response Content Type":"Content Type de la réponse",
43 | "fetching resource":"récupération de la ressource",
44 | "fetching resource list":"récupération de la liste de ressources",
45 | "Explore":"Explorer",
46 | "Show Swagger Petstore Example Apis":"Montrer les Apis de l'exemple Petstore de Swagger",
47 | "Can't read from server. It may not have the appropriate access-control-origin settings.":"Impossible de lire à partir du serveur. Il se peut que les réglages access-control-origin ne soient pas appropriés.",
48 | "Please specify the protocol for":"Veuillez spécifier un protocole pour",
49 | "Can't read swagger JSON from":"Impossible de lire le JSON swagger à partir de",
50 | "Finished Loading Resource Information. Rendering Swagger UI":"Chargement des informations terminé. Affichage de Swagger UI",
51 | "Unable to read api":"Impossible de lire l'api",
52 | "from path":"à partir du chemin",
53 | "server returned":"réponse du serveur"
54 | });
55 |
--------------------------------------------------------------------------------
/public/static/libs/html5shiv.min.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @preserve HTML5 Shiv 3.7.3 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed
3 | */
4 | !function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=t.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=t.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),t.elements=c+" "+a,j(b)}function f(a){var b=s[a[q]];return b||(b={},r++,a[q]=r,s[r]=b),b}function g(a,c,d){if(c||(c=b),l)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():p.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||o.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),l)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return t.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(t,b.frag)}function j(a){a||(a=b);var d=f(a);return!t.shivCSS||k||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),l||i(a,d),a}var k,l,m="3.7.3",n=a.html5||{},o=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,p=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,q="_html5shiv",r=0,s={};!function(){try{var a=b.createElement("a");a.innerHTML=" ",k="hidden"in a,l=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){k=!0,l=!0}}();var t={elements:n.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:m,shivCSS:n.shivCSS!==!1,supportsUnknownElements:l,shivMethods:n.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=t,j(b),"object"==typeof module&&module.exports&&(module.exports=t)}("undefined"!=typeof window?window:this,document);
--------------------------------------------------------------------------------
/public/swagger/lang/el.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /* jshint quotmark: double */
4 | window.SwaggerTranslator.learn({
5 | "Warning: Deprecated":"Προειδοποίηση: Έχει αποσυρθεί",
6 | "Implementation Notes":"Σημειώσεις Υλοποίησης",
7 | "Response Class":"Απόκριση",
8 | "Status":"Κατάσταση",
9 | "Parameters":"Παράμετροι",
10 | "Parameter":"Παράμετρος",
11 | "Value":"Τιμή",
12 | "Description":"Περιγραφή",
13 | "Parameter Type":"Τύπος Παραμέτρου",
14 | "Data Type":"Τύπος Δεδομένων",
15 | "Response Messages":"Μηνύματα Απόκρισης",
16 | "HTTP Status Code":"Κωδικός Κατάστασης HTTP",
17 | "Reason":"Αιτιολογία",
18 | "Response Model":"Μοντέλο Απόκρισης",
19 | "Request URL":"URL Αιτήματος",
20 | "Response Body":"Σώμα Απόκρισης",
21 | "Response Code":"Κωδικός Απόκρισης",
22 | "Response Headers":"Επικεφαλίδες Απόκρισης",
23 | "Hide Response":"Απόκρυψη Απόκρισης",
24 | "Headers":"Επικεφαλίδες",
25 | "Try it out!":"Δοκιμάστε το!",
26 | "Show/Hide":"Εμφάνιση/Απόκρυψη",
27 | "List Operations":"Λίστα Λειτουργιών",
28 | "Expand Operations":"Ανάπτυξη Λειτουργιών",
29 | "Raw":"Ακατέργαστο",
30 | "can't parse JSON. Raw result":"αδυναμία ανάλυσης JSON. Ακατέργαστο αποτέλεσμα",
31 | "Example Value":"Παράδειγμα Τιμής",
32 | "Model Schema":"Σχήμα Μοντέλου",
33 | "Model":"Μοντέλο",
34 | "Click to set as parameter value":"Πατήστε για να θέσετε τιμή παραμέτρου",
35 | "apply":"εφαρμογή",
36 | "Username":"Όνομα χρήση",
37 | "Password":"Κωδικός πρόσβασης",
38 | "Terms of service":"Όροι χρήσης",
39 | "Created by":"Δημιουργήθηκε από",
40 | "See more at":"Δείτε περισσότερα στο",
41 | "Contact the developer":"Επικοινωνήστε με τον προγραμματιστή",
42 | "api version":"έκδοση api",
43 | "Response Content Type":"Τύπος Περιεχομένου Απόκρισης",
44 | "Parameter content type:":"Τύπος περιεχομένου παραμέτρου:",
45 | "fetching resource":"παραλαβή πόρου",
46 | "fetching resource list":"παραλαβή λίστας πόρων",
47 | "Explore":"Εξερεύνηση",
48 | "Show Swagger Petstore Example Apis":"Εμφάνιση Api Δειγμάτων Petstore του Swagger",
49 | "Can't read from server. It may not have the appropriate access-control-origin settings.":"Αδυναμία ανάγνωσης από τον εξυπηρετητή. Μπορεί να μην έχει κατάλληλες ρυθμίσεις για access-control-origin.",
50 | "Please specify the protocol for":"Παρακαλώ προσδιορίστε το πρωτόκολλο για",
51 | "Can't read swagger JSON from":"Αδυναμία ανάγνωσης swagger JSON από",
52 | "Finished Loading Resource Information. Rendering Swagger UI":"Ολοκλήρωση Φόρτωσης Πληροφορικών Πόρου. Παρουσίαση Swagger UI",
53 | "Unable to read api":"Αδυναμία ανάγνωσης api",
54 | "from path":"από το μονοπάτι",
55 | "server returned":"ο εξυπηρετηρής επέστρεψε"
56 | });
57 |
--------------------------------------------------------------------------------
/config/db.sql:
--------------------------------------------------------------------------------
1 | -- MySQL数据库,需管理员权限导入
2 |
3 | --
4 | -- 数据库:db_test
5 | -- 编码:utf8
6 | --
7 | DROP DATABASE IF EXISTS `db_test`;
8 | CREATE DATABASE `db_test` DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci;
9 | USE `db_test`;
10 |
11 | --
12 | -- 授权:本地连接,增删改查
13 | -- 帐号:test 密码:*** (SELECT PASSWORD('***');)
14 | --
15 | CREATE USER 'test'@'127.0.0.1' IDENTIFIED BY '*A0E2521E77EA33EF451BF2D1025F30B925D8F2F2';
16 | GRANT SELECT,INSERT,UPDATE,DELETE ON `db_test`.* TO 'test'@'127.0.0.1';
17 |
18 | -- --------------------------------------------------------
19 |
20 | --
21 | -- 表结构 前缀b(branch)表示分表,前缀s(single)表示单表
22 | --
23 |
24 | /*--------------------------------------------------------------------------*
25 | NAME: 用户帐号表 - 变化频繁
26 | *--------------------------------------------------------------------------*/
27 | CREATE TABLE b_account_0 (
28 | uid INT UNSIGNED NOT NULL COMMENT '用户ID',
29 | gold INT UNSIGNED DEFAULT 0 COMMENT '金币',
30 |
31 | ext VARCHAR(255) DEFAULT '' COMMENT '扩展字段',
32 | ctime TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
33 | PRIMARY KEY(uid)
34 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
35 |
36 | /*--------------------------------------------------------------------------*
37 | NAME: 用户帐号基本信息表 - 变化不频繁
38 | *--------------------------------------------------------------------------*/
39 | CREATE TABLE b_account2_0 (
40 | uid INT UNSIGNED NOT NULL COMMENT '用户ID',
41 | realname VARCHAR(20) NOT NULL COMMENT '姓名',
42 | nickname VARCHAR(40) DEFAULT '' COMMENT '昵称',
43 | gender TINYINT DEFAULT 0 COMMENT '性别',
44 | avatar VARCHAR(255) DEFAULT '' COMMENT '头像',
45 | birthday DATE COMMENT '生日',
46 | phone VARCHAR(11) DEFAULT '' COMMENT '电话',
47 | email VARCHAR(45) DEFAULT '' COMMENT '邮箱',
48 | wechat VARCHAR(40) DEFAULT '' COMMENT '微信',
49 | qq VARCHAR(20) DEFAULT '' COMMENT 'QQ',
50 | province VARCHAR(20) DEFAULT '' COMMENT '省份',
51 | city VARCHAR(20) DEFAULT '' COMMENT '城市',
52 | address VARCHAR(255) DEFAULT '' COMMENT '住址',
53 | ext VARCHAR(255) DEFAULT '' COMMENT '扩展字段',
54 | ctime TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
55 | PRIMARY KEY(uid)
56 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
57 |
58 | /*--------------------------------------------------------------------------*
59 | NAME: 来源渠道
60 | *--------------------------------------------------------------------------*/
61 | CREATE TABLE s_origin_channel (
62 | id INT NOT NULL AUTO_INCREMENT COMMENT '渠道ID',
63 | name VARCHAR(40) NOT NULL COMMENT '名称',
64 | PRIMARY KEY(id)
65 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
66 |
--------------------------------------------------------------------------------
/public/swagger/css/style.css:
--------------------------------------------------------------------------------
1 | .swagger-section #header a#logo{font-size:1.5em;font-weight:700;text-decoration:none;padding:20px 0 20px 40px}#text-head{font-size:80px;font-family:Roboto,sans-serif;color:#fff;float:right;margin-right:20%}.navbar-fixed-top .navbar-brand,.navbar-fixed-top .navbar-nav,.navbar-header{height:auto}.navbar-inverse{background-color:#000;border-color:#000}#navbar-brand{margin-left:20%}.navtext{font-size:10px}.h1,h1{font-size:60px}.navbar-default .navbar-header .navbar-brand{color:#a2dfee}.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading h2 a{color:#393939;font-family:Arvo,serif;font-size:1.5em}.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading h2 a:hover{color:#000}.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading h2{color:#525252;padding-left:0;display:block;clear:none;float:left;font-family:Arvo,serif;font-weight:700}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#0a0a0a}.container1{width:1500px;margin:auto;margin-top:0;background-repeat:no-repeat;background-position:-40px -20px;margin-bottom:210px}.container-inner{width:1200px;margin:auto;background-color:hsla(192,8%,88%,.75);padding-bottom:40px;padding-top:40px;border-radius:15px}.header-content{padding:0;width:1000px}.title1{font-size:80px;font-family:Vollkorn,serif;color:#404040;text-align:center;padding-top:40px;padding-bottom:100px}#icon{margin-top:-18px}.subtext{font-size:25px;font-style:italic;color:#08b;text-align:right;padding-right:250px}.bg-primary{background-color:#00468b}.navbar-default .nav>li>a,.navbar-default .nav>li>a:focus,.navbar-default .nav>li>a:focus:hover,.navbar-default .nav>li>a:hover{color:#08b}.text-faded{font-size:25px;font-family:Vollkorn,serif}.section-heading{font-family:Vollkorn,serif;font-size:45px;padding-bottom:10px}hr{border-color:#00468b;padding-bottom:10px}.description{margin-top:20px;padding-bottom:200px}.description li{font-family:Vollkorn,serif;font-size:25px;color:#525252;margin-left:28%;padding-top:5px}.gap{margin-top:200px}.troubleshootingtext{color:hsla(0,0%,100%,.7);padding-left:30%}.troubleshootingtext li{list-style-type:circle;font-size:25px;padding-bottom:5px}.overlay{position:absolute;top:0;left:0;width:100%;height:100%;z-index:1}.block.response_body.json:hover{cursor:pointer}.backdrop{color:blue}#myModal{height:100%}.modal-backdrop{bottom:0;position:fixed}.curl{padding:10px;font-family:Anonymous Pro,Menlo,Consolas,Bitstream Vera Sans Mono,Courier New,monospace;font-size:.9em;max-height:400px;margin-top:5px;overflow-y:auto;background-color:#fcf6db;border:1px solid #e5e0c6;border-radius:4px}.curl_title{font-size:1.1em;margin:0;padding:15px 0 5px;font-family:Open Sans,Helvetica Neue,Arial,sans-serif;font-weight:500;line-height:1.1}.footer{display:none}.swagger-section .swagger-ui-wrap h2{padding:0}h2{margin:0;margin-bottom:5px}.markdown p,.swagger-section .swagger-ui-wrap .code{font-size:15px;font-family:Arvo,serif}.swagger-section .swagger-ui-wrap b{font-family:Arvo,serif}#signin:hover{cursor:pointer}.dropdown-menu{padding:15px}.navbar-right .dropdown-menu{left:0;right:auto}#signinbutton{width:100%;height:32px;font-size:13px;font-weight:700;color:#08b}.navbar-default .nav>li .details{color:#000;text-transform:none;font-size:15px;font-weight:400;font-family:Open Sans,sans-serif;font-style:italic;line-height:20px;top:-2px}.navbar-default .nav>li .details:hover{color:#000}#signout{width:100%;height:32px;font-size:13px;font-weight:700;color:#08b}
--------------------------------------------------------------------------------
/server/middlewares/api.js:
--------------------------------------------------------------------------------
1 | /**
2 | * res.api middleware
3 | *
4 | * @output
5 | *
6 | * {
7 | * "data": {},
8 | * "status": {
9 | * "code": 0,
10 | * "msg": "success"
11 | * }
12 | * }
13 | *
14 | *
15 | * @usage
16 | *
17 | * return res.api(data)
18 | * return res.api_error(err)
19 | *
20 | * return res.api(500, err, {
21 | * code: 1,
22 | * msg: 'delete failed!'
23 | * })
24 | *
25 | * return res.api(null, {
26 | * code: 10000,
27 | * msg: 'delete failed!'
28 | * })
29 | *
30 | */
31 |
32 | // API 基本状态码
33 | const API_SUCCESS_CODE = 0
34 | const API_ERROR_CODE = -1
35 |
36 | module.exports = function (req, res, next) {
37 | // set api header
38 | // res.setHeader('Access-Control-Allow-Origin', '*')
39 | // res.setHeader('Access-Control-Allow-Methods', 'GET, POST')
40 | // res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type, Authorization')
41 |
42 | res.api = api
43 | res.api_error = api_error
44 |
45 | next()
46 | }
47 |
48 | function api() {
49 | var _res = this
50 |
51 | if (typeof(_res) != "object" && _is_not_has_prototype('end')) {
52 | arguments = []
53 | console.dir('not a object')
54 | }
55 |
56 | if (arguments.length == 1) {
57 | var http_code = 200
58 | var api_data = arguments[0]
59 | var api_status = {
60 | code: API_SUCCESS_CODE,
61 | msg: 'success'
62 | }
63 |
64 | return _api(http_code, api_data, api_status)
65 |
66 | } else if (arguments.length == 2) {
67 | var http_code = 200
68 | var api_data = arguments[0]
69 | var api_status = arguments[1]
70 |
71 | return _api(http_code, api_data, api_status)
72 |
73 | } else if (arguments.length == 3) {
74 | var http_code = arguments[0]
75 | var api_data = arguments[1]
76 | var api_status = arguments[2]
77 |
78 | return _api(http_code, api_data, api_status)
79 |
80 | } else {
81 | var http_code = 200
82 | var api_data = {}
83 | var api_status = {
84 | code: -2,
85 | msg: 'res.api params error or res is not a express.response object!'
86 | }
87 |
88 | return _api(http_code, api_data, api_status)
89 | }
90 |
91 | function _is_not_has_prototype(name) {
92 | console.dir(_res)
93 | return !_res.hasOwnProperty(name) && (name in _res)
94 | }
95 |
96 | function _api (http_code, data, status) {
97 | if (_res.is_jsonp && _res.is_jsonp == true) {
98 | return _res.status(http_code).jsonp({
99 | data: data,
100 | status: status
101 | })
102 | } else {
103 | return _res.status(http_code).json({
104 | data: data,
105 | status: status
106 | })
107 | }
108 | }
109 | }
110 |
111 | function api_error(data){
112 | var _res = this
113 | var _error_code = 200
114 | var _error_status_code = API_ERROR_CODE
115 | var _error_status_msg = 'api error'
116 |
117 | if (_res.api_error_code) {
118 | _error_code = _res.api_error_code
119 | }
120 |
121 | if (_res.api_error_status_code) {
122 | _error_status_code = _res.api_error_status_code
123 | }
124 |
125 | if (_res.api_error_status_msg) {
126 | _error_status_msg = _res.api_error_status_msg
127 | }
128 |
129 | _res.api(_error_code, data, {
130 | code: _error_status_code,
131 | msg: _error_status_msg
132 | })
133 | }
134 |
--------------------------------------------------------------------------------
/public/swagger/lib/jquery.ba-bbq.min.js:
--------------------------------------------------------------------------------
1 | !function(e,t){function n(e){return"string"==typeof e}function r(e){var t=g.call(arguments,1);return function(){return e.apply(this,t.concat(g.call(arguments)))}}function o(e){return e.replace(/^[^#]*#?(.*)$/,"$1")}function a(e){return e.replace(/(?:^[^?#]*\?([^#]*).*$)?.*/,"$1")}function i(r,o,a,i,c){var u,s,p,h,d;return i!==f?(p=a.match(r?/^([^#]*)\#?(.*)$/:/^([^#?]*)\??([^#]*)(#?.*)/),d=p[3]||"",2===c&&n(i)?s=i.replace(r?R:E,""):(h=l(p[2]),i=n(i)?l[r?A:w](i):i,s=2===c?i:1===c?e.extend({},i,h):e.extend({},h,i),s=b(s),r&&(s=s.replace(m,y))),u=p[1]+(r?"#":s||!p[1]?"?":"")+s+d):u=o(a!==f?a:t[S][q]),u}function c(e,t,r){return t===f||"boolean"==typeof t?(r=t,t=b[e?A:w]()):t=n(t)?t.replace(e?R:E,""):t,l(t,r)}function u(t,r,o,a){return n(o)||"object"==typeof o||(a=o,o=r,r=f),this.each(function(){var n=e(this),i=r||v()[(this.nodeName||"").toLowerCase()]||"",c=i&&n.attr(i)||"";n.attr(i,b[t](c,o,a))})}var f,s,l,p,h,d,v,m,g=Array.prototype.slice,y=decodeURIComponent,b=e.param,$=e.bbq=e.bbq||{},x=e.event.special,j="hashchange",w="querystring",A="fragment",N="elemUrlAttr",S="location",q="href",C="src",E=/^.*\?|#.*$/g,R=/^.*\#/,U={};b[w]=r(i,0,a),b[A]=s=r(i,1,o),s.noEscape=function(t){t=t||"";var n=e.map(t.split(""),encodeURIComponent);m=new RegExp(n.join("|"),"g")},s.noEscape(",/"),e.deparam=l=function(t,n){var r={},o={"true":!0,"false":!1,"null":null};return e.each(t.replace(/\+/g," ").split("&"),function(t,a){var i,c=a.split("="),u=y(c[0]),s=r,l=0,p=u.split("]["),h=p.length-1;if(/\[/.test(p[0])&&/\]$/.test(p[h])?(p[h]=p[h].replace(/\]$/,""),p=p.shift().split("[").concat(p),h=p.length-1):h=0,2===c.length)if(i=y(c[1]),n&&(i=i&&!isNaN(i)?+i:"undefined"===i?f:o[i]!==f?o[i]:i),h)for(;l<=h;l++)u=""===p[l]?s.length:p[l],s=s[u]=l ').hide().insertAfter("body")[0].contentWindow,s=function(){return r(a.document[i][u])},(f=function(e,t){if(e!==t){var n=a.document;n.open().close(),n[i].hash="#"+e}})(r()))}var o,a,f,s,p={};return p.start=function(){if(!o){var a=r();f||n(),function l(){var n=r(),p=s(a);n!==a?(f(a=n,p),e(t).trigger(c)):p!==a&&(t[i][u]=t[i][u].replace(/#.*/,"")+"#"+p),o=setTimeout(l,e[c+"Delay"])}()}},p.stop=function(){a||(o&&clearTimeout(o),o=0)},p}()}(jQuery,this);
--------------------------------------------------------------------------------
/server/utils/easemob/request.js:
--------------------------------------------------------------------------------
1 | /**
2 | * https请求
3 | */
4 |
5 | var https = require('https')
6 | var config = require('../../../config/easemob')
7 | var fs = require('fs')
8 | var fetch = require('node-fetch')
9 |
10 | var host = config.host
11 | var org_name = config.org_name
12 | var app_name = config.app_name
13 |
14 | exports.httpRequest = function (json) {
15 | json = json || {}
16 | json.data = json.data || {}
17 | json.method = json.method || 'GET'
18 | json.headers = json.headers || {}
19 | json.query = json.query || {}
20 |
21 | var postData = JSON.stringify(json.data)
22 | var ca = fs.readFileSync(config.ca, 'utf-8')
23 | //request parameters
24 | var options = {
25 | host: host,
26 | path: '/' + org_name + '/' + app_name + '/' + json.path,
27 | method: json.method,
28 | headers: json.headers,
29 | ca: [ca],
30 | agent: false
31 | }
32 | //connect with query parameters
33 | if (json.query != null) {
34 | options.path += '?'
35 | for (var key in json.query) {
36 | if (json.query[key] != null) {
37 | options.path += key + '=' + json.query[key] + '&'
38 | }
39 | }
40 | options.path = options.path.substring(0, options.path.length - 1)
41 | }
42 | //send request
43 | var req = https.request(options, function (res) {
44 | var chunks = ''
45 | var size = 0
46 | res.setEncoding('utf8')
47 | // console.log('------------------------------request--------------------------------')
48 | // console.log('host: ' + options.host + '\n' + 'path: ' + options.path + '\n' + 'method: ' + options.method)
49 |
50 | res.on('data', function (chunk) {
51 | chunks += chunk
52 | size += chunk.length
53 | })
54 | res.on('end', function () {
55 | //get response data
56 | //var data = JSON.parse(Buffer.concat(chunks, size).toString())
57 | // console.log('------------------------------response--------------------------------')
58 | // console.log('StatusCode: ' + res.statusCode)
59 | if (typeof json.callback == 'function')
60 | json.callback(chunks)
61 | })
62 | })
63 |
64 | //print error message
65 | req.on('error', function (e) {
66 | console.log('problem with request: ' + e.message)
67 | })
68 |
69 | // write data to request body
70 | req.write(postData)
71 | req.end()
72 | }
73 |
74 | exports.uploadFile = function (json) {
75 | json = json || {}
76 | json.data = json.data || {}
77 | json.method = json.method || 'POST'
78 | json.headers = json.headers || {}
79 | json.query = json.query || {}
80 | json.form = json.form || {}
81 | var ca = fs.readFileSync(config.ca, 'utf-8')
82 | // console.log('------------------------------request--------------------------------')
83 | // console.log('host: ' + host + '\n' + 'path: ' + json.path + '\n' + 'method: ' + json.method)
84 | fetch('https://' + host + '/' + org_name + '/' + app_name + '/' + json.path, {
85 | method: json.method,
86 | body: json.form,
87 | headers: json.headers,
88 | ca: [ca]
89 | }).then(function (res) {
90 | // console.log('------------------------------response--------------------------------')
91 | // console.log('StatusCode: ' + res.status)
92 | return res.json()
93 | }).then(function (json) {
94 | console.log(json)
95 | }).catch(function (err) {
96 | console.log(err)
97 | })
98 | }
99 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "node-server",
3 | "version": "1.0.0",
4 | "description": "基于node.js技术栈的服务器端项目框架示例",
5 | "author": "super_xp@126.com",
6 | "keywords": [
7 | "node.js",
8 | "express",
9 | "restful api",
10 | "node-frameworek"
11 | ],
12 | "repository": {
13 | "type": "git",
14 | "url": "https://github.com/xiaoping6688/node-server-project"
15 | },
16 | "license": "MIT",
17 | "private": false,
18 | "scripts": {
19 | "installall": "(cnpm install) && (cd client && cnpm install)",
20 | "dev": "cross-env NODE_ENV=development supervisor -w server,app.js ./bin/www",
21 | "testing": "pm2 startOrRestart ./config/pm2.config.js --env testing",
22 | "simu": "pm2 startOrRestart ./config/pm2.config.js --env simulation",
23 | "prod": "pm2 startOrRestart ./config/pm2.config.js --env production",
24 | "setup:test": "pm2 deploy ./config/pm2.config.js testing setup",
25 | "setup:simu": "pm2 deploy ./config/pm2.config.js simulation setup",
26 | "setup:prod": "pm2 deploy ./config/pm2.config.js production setup",
27 | "deploy:test": "pm2 deploy ./config/pm2.config.js testing --force",
28 | "deploy:simu": "pm2 deploy ./config/pm2.config.js simulation",
29 | "deploy:prod": "pm2 deploy ./config/pm2.config.js production",
30 | "stop": "pm2 stop ./config/pm2.config.js",
31 | "reload": "pm2 reload ./config/pm2.config.js",
32 | "list": "pm2 list",
33 | "monit": "pm2 monit",
34 | "logs": "pm2 logs",
35 | "gui": "./node_modules/.bin/pm2-gui start ../../config/pm2-gui.ini",
36 | "debug": "node-debug ./bin/www",
37 | "client": "cd client && npm build",
38 | "live:client": "cd client && npm start",
39 | "live:server": "cross-env NODE_ENV=development gulp browser-sync",
40 | "test": "./node_modules/mocha/bin/mocha",
41 | "lint": "./node_modules/.bin/eslint app.js server",
42 | "update": "ncu -u -a"
43 | },
44 | "dependencies": {
45 | "amqplib": "^0.5.1",
46 | "amqplib-rpc": "^2.0.4",
47 | "blueimp-md5": "^2.7.0",
48 | "body-parser": "~1.17.1",
49 | "bunnymq": "^2.2.2",
50 | "compression": "^1.6.2",
51 | "cookie-parser": "~1.4.3",
52 | "cors": "^2.8.1",
53 | "express": "~4.15.2",
54 | "express-jwt": "^5.1.0",
55 | "file-stream-rotator": "0.1.0",
56 | "form-data": "^2.1.2",
57 | "hbs": "~4.0.1",
58 | "html-minifier": "^3.4.2",
59 | "jsonwebtoken": "^7.3.0",
60 | "lodash": "^4.17.4",
61 | "memory-cache": "^0.1.6",
62 | "mongoose": "^4.8.6",
63 | "mongoosedao": "^1.0.13",
64 | "morgan": ">=1.9.1",
65 | "mount-routes": "^1.0.6",
66 | "multer": "^1.3.0",
67 | "mysql": "^2.13.0",
68 | "mysql2": "^1.2.0",
69 | "node-fetch": "^1.6.3",
70 | "pg": "^6.1.4",
71 | "pg-hstore": "^2.3.2",
72 | "redis": "^2.7.0",
73 | "request": "^2.81.0",
74 | "request-promise": "^4.1.1",
75 | "sequelize": "^5.3.0",
76 | "serve-favicon": "~2.4.1",
77 | "sqlite3": "^3.1.8",
78 | "thrift": "^0.10.0"
79 | },
80 | "devDependencies": {
81 | "browser-sync": "^2.18.8",
82 | "cross-env": "^3.2.3",
83 | "eslint": "^3.17.1",
84 | "eslint-config-standard": "^7.0.1",
85 | "eslint-plugin-promise": "^3.5.0",
86 | "eslint-plugin-standard": "^2.1.1",
87 | "gulp": "^3.9.1",
88 | "gulp-nodemon": "^2.2.1",
89 | "if-env": "^1.0.0",
90 | "mocha": "^3.2.0",
91 | "pm2": "^2.4.2",
92 | "pm2-gui": "^0.1.4",
93 | "supertest": "^3.0.0",
94 | "supervisor": "^0.12.0"
95 | },
96 | "engines": {
97 | "node": ">= 7.0.0",
98 | "npm": ">= 3.10.0"
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/server/views/login.hbs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | 管理系统 | 登录
7 |
8 |
9 |
10 |
11 |
51 |
52 |
53 |
54 |
58 |
59 |
60 |
61 |
62 |
65 |
66 |
67 |
账号登录
68 |
86 |
87 |
忘记密码
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
117 |
118 |
119 |
--------------------------------------------------------------------------------
/app.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 主入口程序
3 | */
4 |
5 | var express = require('express')
6 | var favicon = require('serve-favicon')
7 | var cookieParser = require('cookie-parser')
8 | var bodyParser = require('body-parser')
9 | var mountRoutes = require('mount-routes')
10 | var cors = require('cors')
11 | var path = require('path')
12 |
13 | var config = require('./package.json')
14 |
15 | var logger = require('./server/middlewares/logger')
16 | var authorization = require('./server/middlewares/auth')
17 | var compression = require('./server/middlewares/compress')
18 | var resApi = require('./server/middlewares/api')
19 | var interceptor = require('./server/middlewares/interceptor')
20 |
21 | // require('./server/utils/mongodb') // init mongodb
22 | // require('./server/utils/orm') // init orm
23 | require('./server/utils/hbs') // init hbs
24 |
25 | var app = express()
26 |
27 | // view engine setup
28 | app.set('views', path.join(__dirname, 'server', 'views'))
29 | app.set('view engine', 'hbs')
30 |
31 | app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')))
32 | app.use(bodyParser.json()) // application/json, any Unicode, gzip/deflate
33 | app.use(bodyParser.urlencoded({ extended: false })) // application/x-www-form-urlencoded, UTF-8, gzip/deflate
34 | app.use(cookieParser())
35 | app.use(express.static(path.join(__dirname, 'public')))
36 |
37 | // set resouces root url
38 | app.locals.resoucePath = '/static'
39 | // set resouces version
40 | app.locals.resouceVersion = config.version
41 |
42 | // log middleware
43 | app.use(logger)
44 |
45 | // api output middleware
46 | app.use(resApi)
47 |
48 | // authorization middleware
49 | app.use(authorization)
50 |
51 | // interceptor middleware
52 | app.use(interceptor)
53 |
54 | // compression middleware
55 | app.use(compression)
56 |
57 | // This is CORS-enabled for all origins; For a single route: app.get('/api', cors(), rooter)
58 | // var corsOptions = {
59 | // origin: '*',
60 | // optionsSuccessStatus: 200 // some legacy browsers (IE11, various SmartTVs) choke on 204
61 | // }
62 | // app.use(cors())
63 |
64 | // auto mount routes with routes_folder_path, 'false': dont dump list
65 | mountRoutes(app, path.join(__dirname, 'server', 'routes'), false)
66 |
67 | // catch 404 and forward to error handler
68 | app.use(function (req, res, next) {
69 | if (req.path.startsWith('/rest/')) { // for api
70 | return res.api_error({
71 | message: 'Not Found'
72 | })
73 | } else { // for page
74 | var err = new Error('Not Found')
75 | err.status = 404
76 | next(err)
77 | }
78 | })
79 |
80 | // error handler
81 | // catch unauthorized error and other forward to error handler
82 | app.use(function (err, req, res, next) {
83 | if (err.name === 'UnauthorizedError') {
84 | if (req.path.startsWith('/rest/')) { // for api
85 | return res.api_error({
86 | message: 'Invalid Token',
87 | error: err.message
88 | })
89 | } else { // for page
90 | res.redirect('/login')
91 | }
92 | } else {
93 | next(err)
94 | }
95 | })
96 |
97 | // error handler
98 | // no stacktraces leaked to user for production,
99 | // and will print stacktrace for development
100 | app.use(function (err, req, res, next) {
101 | if (req.path.startsWith('/rest/')) { // for api
102 | return res.api_error({
103 | message: err.message,
104 | error: app.get('env') === 'development' ? err : {}
105 | })
106 | } else { // for page
107 | res.status(err.status || 500)
108 | res.render('error', {
109 | layout: false,
110 | message: err.message,
111 | error: app.get('env') === 'development' ? err : {}
112 | })
113 | }
114 | })
115 |
116 | // Node全局异常捕获
117 | process.on('uncaughtException', function (err) {
118 | console.error('An uncaught error occurred!')
119 | console.error(err.stack)
120 | // Recommend: restart the server
121 | });
122 |
123 | module.exports = app
124 |
--------------------------------------------------------------------------------
/server/utils/easemob/SendMessage.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 发送消息
3 | */
4 |
5 | var client = require('./client')
6 |
7 | function SendMessage () {
8 | //Send text message
9 | this.sendText = function (json) {
10 | var json = json || {}
11 | var data = {
12 | target_type: json.type,
13 | target: json.target,
14 | msg: { type: 'txt', msg: json.content },
15 | from: json.from
16 | }
17 | json.ext && (data.ext = json.ext)
18 | client.client({
19 | data: data,
20 | path: 'messages',
21 | method: 'POST',
22 | callback: function (data) {
23 | // console.log(data)
24 | typeof json.callback == 'function' && json.callback(data)
25 | }
26 | })
27 | }
28 |
29 | //Send image message
30 | this.sendImage = function (json) {
31 | var json = json || {}
32 | var data = {
33 | target_type: json.type,
34 | target: json.target,
35 | msg: {
36 | type: 'img',
37 | url: json.url,
38 | filename: json.filename,
39 | secret: json.secret,
40 | size: {width: 480, height: 720}
41 | },
42 | from: json.from,
43 | }
44 | json.ext && (data.ext = json.ext)
45 | client.client({
46 | data: data,
47 | path: 'messages',
48 | method: 'POST',
49 | callback: function (data) {
50 | // console.log(data)
51 | typeof json.callback == 'function' && json.callback(data)
52 | }
53 | })
54 | }
55 |
56 | //Send audio message
57 | this.sendAudio = function (json) {
58 | var json = json || {}
59 | var data = {
60 | target_type: json.type,
61 | target: json.target,
62 | msg: { type: 'audio', url: json.url, filename: json.filename, length: json.length, secret: json.secret },
63 | from: json.from,
64 | }
65 | json.ext && (data.ext = json.ext)
66 | client.client({
67 | data: data,
68 | path: 'messages',
69 | method: 'POST',
70 | callback: function (data) {
71 | // console.log(data)
72 | typeof json.callback == 'function' && json.callback(data)
73 | }
74 | })
75 | }
76 |
77 | //Send video message
78 | this.sendVideo = function (json) {
79 | var json = json || {}
80 | var data = {
81 | target_type: json.type,
82 | target: json.target,
83 | msg: {
84 | type: 'video',
85 | url: json.url,
86 | filename: json.filename,
87 | thumb: json.thumb,
88 | length: json.length,
89 | file_length: json.file_length,
90 | thumb_secret: json.thumb_secret,
91 | secret: json.secret
92 | },
93 | from: json.from,
94 | }
95 | json.ext && (data.ext = json.ext)
96 | client.client({
97 | data: data,
98 | path: 'messages',
99 | method: 'POST',
100 | callback: function (data) {
101 | // console.log(data)
102 | typeof json.callback == 'function' && json.callback(data)
103 | }
104 | })
105 | }
106 |
107 | //Send commend message
108 | this.sendCmd = function (json) {
109 | var json = json || {}
110 | var data = {
111 | target_type: json.type,
112 | target: json.target,
113 | msg: { type: 'cmd', action: json.action },
114 | from: json.from,
115 | }
116 | json.ext && (data.ext = json.ext)
117 | client.client({
118 | data: data,
119 | path: 'messages',
120 | method: 'POST',
121 | callback: function (data) {
122 | // console.log(data)
123 | typeof json.callback == 'function' && json.callback(data)
124 | }
125 | })
126 | }
127 | }
128 |
129 | module.exports = SendMessage
130 |
--------------------------------------------------------------------------------
/public/static/libs/respond.min.js:
--------------------------------------------------------------------------------
1 | /*! Respond.js v1.4.2: min/max-width media query polyfill
2 | * Copyright 2014 Scott Jehl
3 | * Licensed under MIT
4 | * https://j.mp/respondjs */
5 |
6 | !function(a){"use strict";a.matchMedia=a.matchMedia||function(a){var b,c=a.documentElement,d=c.firstElementChild||c.firstChild,e=a.createElement("body"),f=a.createElement("div");return f.id="mq-test-1",f.style.cssText="position:absolute;top:-100em",e.style.background="none",e.appendChild(f),function(a){return f.innerHTML='',c.insertBefore(e,d),b=42===f.offsetWidth,c.removeChild(e),{matches:b,media:a}}}(a.document)}(this),function(a){"use strict";function b(){v(!0)}var c={};a.respond=c,c.update=function(){};var d=[],e=function(){var b=!1;try{b=new a.XMLHttpRequest}catch(c){b=new a.ActiveXObject("Microsoft.XMLHTTP")}return function(){return b}}(),f=function(a,b){var c=e();c&&(c.open("GET",a,!0),c.onreadystatechange=function(){4!==c.readyState||200!==c.status&&304!==c.status||b(c.responseText)},4!==c.readyState&&c.send(null))},g=function(a){return a.replace(c.regex.minmaxwh,"").match(c.regex.other)};if(c.ajax=f,c.queue=d,c.unsupportedmq=g,c.regex={media:/@media[^\{]+\{([^\{\}]*\{[^\}\{]*\})+/gi,keyframes:/@(?:\-(?:o|moz|webkit)\-)?keyframes[^\{]+\{(?:[^\{\}]*\{[^\}\{]*\})+[^\}]*\}/gi,comments:/\/\*[^*]*\*+([^/][^*]*\*+)*\//gi,urls:/(url\()['"]?([^\/\)'"][^:\)'"]+)['"]?(\))/g,findStyles:/@media *([^\{]+)\{([\S\s]+?)$/,only:/(only\s+)?([a-zA-Z]+)\s?/,minw:/\(\s*min\-width\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/,maxw:/\(\s*max\-width\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/,minmaxwh:/\(\s*m(in|ax)\-(height|width)\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/gi,other:/\([^\)]*\)/g},c.mediaQueriesSupported=a.matchMedia&&null!==a.matchMedia("only all")&&a.matchMedia("only all").matches,!c.mediaQueriesSupported){var h,i,j,k=a.document,l=k.documentElement,m=[],n=[],o=[],p={},q=30,r=k.getElementsByTagName("head")[0]||l,s=k.getElementsByTagName("base")[0],t=r.getElementsByTagName("link"),u=function(){var a,b=k.createElement("div"),c=k.body,d=l.style.fontSize,e=c&&c.style.fontSize,f=!1;return b.style.cssText="position:absolute;font-size:1em;width:1em",c||(c=f=k.createElement("body"),c.style.background="none"),l.style.fontSize="100%",c.style.fontSize="100%",c.appendChild(b),f&&l.insertBefore(c,l.firstChild),a=b.offsetWidth,f?l.removeChild(c):c.removeChild(b),l.style.fontSize=d,e&&(c.style.fontSize=e),a=j=parseFloat(a)},v=function(b){var c="clientWidth",d=l[c],e="CSS1Compat"===k.compatMode&&d||k.body[c]||d,f={},g=t[t.length-1],p=(new Date).getTime();if(b&&h&&q>p-h)return a.clearTimeout(i),i=a.setTimeout(v,q),void 0;h=p;for(var s in m)if(m.hasOwnProperty(s)){var w=m[s],x=w.minw,y=w.maxw,z=null===x,A=null===y,B="em";x&&(x=parseFloat(x)*(x.indexOf(B)>-1?j||u():1)),y&&(y=parseFloat(y)*(y.indexOf(B)>-1?j||u():1)),w.hasquery&&(z&&A||!(z||e>=x)||!(A||y>=e))||(f[w.media]||(f[w.media]=[]),f[w.media].push(n[w.rules]))}for(var C in o)o.hasOwnProperty(C)&&o[C]&&o[C].parentNode===r&&r.removeChild(o[C]);o.length=0;for(var D in f)if(f.hasOwnProperty(D)){var E=k.createElement("style"),F=f[D].join("\n");E.type="text/css",E.media=D,r.insertBefore(E,g.nextSibling),E.styleSheet?E.styleSheet.cssText=F:E.appendChild(k.createTextNode(F)),o.push(E)}},w=function(a,b,d){var e=a.replace(c.regex.comments,"").replace(c.regex.keyframes,"").match(c.regex.media),f=e&&e.length||0;b=b.substring(0,b.lastIndexOf("/"));var h=function(a){return a.replace(c.regex.urls,"$1"+b+"$2$3")},i=!f&&d;b.length&&(b+="/"),i&&(f=1);for(var j=0;f>j;j++){var k,l,o,p;i?(k=d,n.push(h(a))):(k=e[j].match(c.regex.findStyles)&&RegExp.$1,n.push(RegExp.$2&&h(RegExp.$2))),o=k.split(","),p=o.length;for(var q=0;p>q;q++)l=o[q],g(l)||m.push({media:l.split("(")[0].match(c.regex.only)&&RegExp.$2||"all",rules:n.length-1,hasquery:l.indexOf("(")>-1,minw:l.match(c.regex.minw)&&parseFloat(RegExp.$1)+(RegExp.$2||""),maxw:l.match(c.regex.maxw)&&parseFloat(RegExp.$1)+(RegExp.$2||"")})}v()},x=function(){if(d.length){var b=d.shift();f(b.href,function(c){w(c,b.href,b.media),p[b.href]=!0,a.setTimeout(function(){x()},0)})}},y=function(){for(var b=0;b
2 |
3 |
4 |
5 |
6 | Swagger UI
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
91 |
92 |
93 |
94 |
104 |
105 |
106 |
107 |
108 |
109 |
--------------------------------------------------------------------------------
/server/utils/easemob/ChatRoom.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 聊天室
3 | */
4 |
5 | var client = require('./client')
6 |
7 | function ChatRoom () {
8 |
9 | //Create a chat room
10 | this.createChatRoom = function (json, callback) {
11 | var data = {
12 | name: json.name,
13 | description: json.description,
14 | maxusers: json.maxusers,
15 | owner: json.owner,
16 | members: json.members
17 | }
18 | client.client({
19 | data: data,
20 | path: 'chatrooms',
21 | method: 'POST',
22 | callback: function (data) {
23 | console.log(data)
24 | typeof callback == 'function' && callback(data)
25 | }
26 | })
27 | }
28 |
29 | //Update chat room details
30 | this.modifyChatRoom = function (json, callback) {
31 | var data = {
32 | name: json.name,
33 | description: json.description,
34 | maxusers: json.maxusers
35 | }
36 | client.client({
37 | data: data,
38 | path: 'chatrooms/' + json.chatroom_id,
39 | method: 'PUT',
40 | callback: function (data) {
41 | console.log(data)
42 | typeof callback == 'function' && callback(data)
43 | }
44 | })
45 | }
46 |
47 | //Delete a chat room
48 | this.deleteChatRoom = function (chatroom_id, callback) {
49 | client.client({
50 | path: 'chatrooms/' + chatroom_id,
51 | method: 'DELETE',
52 | callback: function (data) {
53 | console.log(data)
54 | typeof callback == 'function' && callback(data)
55 | }
56 | })
57 | }
58 |
59 | //Get all chat rooms
60 | this.getChatRooms = function (callback) {
61 | client.client({
62 | path: 'chatrooms',
63 | method: 'GET',
64 | callback: function (data) {
65 | console.log(data)
66 | typeof callback == 'function' && callback(data)
67 | }
68 | })
69 | }
70 |
71 | //Get chat room detail
72 | this.getChatRoomDetail = function (chatroom_id, callback) {
73 | client.client({
74 | path: 'chatrooms/' + chatroom_id,
75 | method: 'GET',
76 | callback: function (data) {
77 | console.log(data)
78 | typeof callback == 'function' && callback(data)
79 | }
80 | })
81 | }
82 |
83 | //Get all chat room of user joined
84 | this.getChatRoomJoined = function (username, callback) {
85 | client.client({
86 | path: 'users/' + username + '/joined_chatrooms',
87 | method: 'GET',
88 | callback: function (data) {
89 | console.log(data)
90 | typeof callback == 'function' && callback(data)
91 | }
92 | })
93 | }
94 | //Add a member to chat room
95 | this.addChatRoomMember = function (chatroomid, username, callback) {
96 | client.client({
97 | path: 'chatrooms/' + chatroomid + '/users/' + username,
98 | method: 'POST',
99 | callback: function (data) {
100 | console.log(data)
101 | typeof callback == 'function' && callback(data)
102 | }
103 | })
104 | }
105 | //Add multiple members to chat room
106 | this.addChatRoomMembers = function (chatroomid, json, callback) {
107 | var data = {usernames: json}
108 | client.client({
109 | path: 'chatrooms/' + chatroomid + '/users/',
110 | method: 'POST',
111 | data: data,
112 | callback: function (data) {
113 | console.log(data)
114 | typeof callback == 'function' && callback(data)
115 | }
116 | })
117 | }
118 |
119 | //Remove a member from chat room
120 | this.deleteChatRoomMember = function (chatroomid, username, callback) {
121 | client.client({
122 | path: 'chatrooms/' + chatroomid + '/users/' + username,
123 | method: 'DELETE',
124 | callback: function (data) {
125 | console.log(data)
126 | typeof callback == 'function' && callback(data)
127 | }
128 | })
129 | }
130 |
131 | //Remove multiple member from chat room
132 | this.deleteChatRoomMembers = function (chatroomid, usernames, callback) {
133 | client.client({
134 | path: 'chatrooms/' + chatroomid + '/users/' + usernames,
135 | method: 'DELETE',
136 | callback: function (data) {
137 | console.log(data)
138 | typeof callback == 'function' && callback(data)
139 | }
140 | })
141 | }
142 | }
143 |
144 | module.exports = ChatRoom
145 |
--------------------------------------------------------------------------------
/config/nginx.conf:
--------------------------------------------------------------------------------
1 | http {
2 | # 启用 gzip 压缩功能
3 | gzip on;
4 |
5 | # 默认值是1.1,就是说对HTTP/1.1协议的请求才会进行gzip压缩
6 | gzip_http_version 1.1;
7 |
8 | gzip_vary on;
9 |
10 | # 压缩级别,1压缩比最小处理速度最快,9压缩比最大但处理最慢,同时也最消耗CPU,一般设置为3就可以了
11 | gzip_comp_level 6;
12 |
13 | # nginx 做前端代理时启用该选项,表示无论后端服务器的headers头返回什么信息,都无条件启用压缩
14 | gzip_proxied any;
15 |
16 | # 什么类型的页面或文档启用压缩
17 | gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript image/jpeg image/gif image/png;
18 |
19 | # 最小压缩的页面,如果页面过于小,可能会越压越大,这里规定大于1K的页面才启用压缩
20 | gzip_min_length 1024;
21 |
22 | # 设置系统获取几个单位的缓存用于存储gzip的压缩结果数据流
23 | gzip_buffers 16 8k;
24 |
25 | # 禁用IE6的gzip压缩
26 | gzip_disable "MSIE [1-6].(?!.*SV1)";
27 |
28 |
29 | server {
30 | listen 80;
31 | server_name example.com www.example.com;
32 | root /data/www/node-server/public;
33 | set $node_port 3000;
34 |
35 | location = / {
36 | proxy_http_version 1.1;
37 | proxy_set_header X-Real-IP $remote_addr;
38 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
39 | proxy_set_header Host $http_host;
40 | proxy_set_header X-NginX-Proxy true;
41 | proxy_set_header Upgrade $http_upgrade;
42 | proxy_set_header Connection "upgrade";
43 | proxy_pass http://127.0.0.1:$node_port$request_uri;
44 | proxy_redirect off;
45 | }
46 |
47 | ## 前端路由的 history 模式
48 | # location / {
49 | # try_files $uri $uri/ /index.html;
50 | # }
51 |
52 | location = /swagger/ {
53 | deny all;
54 | }
55 |
56 | location ~ /static/ {
57 | etag on;
58 | expires max;
59 | }
60 |
61 | location ~ ^/(images/|img/|javascript/|js/|css/|stylesheets/|flash/|media/|static/|robots.txt|humans.txt|favicon.ico) {
62 | root /data/www/node-server/public;
63 | access_log off;
64 | expires max;
65 | }
66 | }
67 | }
68 |
69 |
70 |
71 |
72 | ## http/2 nginx conf
73 |
74 | # server {
75 | # listen 80;
76 | # server_name example.com www.example.com;
77 | # rewrite ^(.*) https://example.com$1 permanent;
78 | # }
79 | #
80 | # server {
81 | # listen 443 ssl http2 fastopen=3 reuseport;
82 | # server_name www.thinkjs.org thinkjs.org;
83 | # set $node_port 3000;
84 | #
85 | # root /data/www/node-server/public;
86 | #
87 | # keepalive_timeout 70;
88 | #
89 | # ssl_certificate /path/to/certificate;
90 | # ssl_certificate_key /path/to/certificate.key;
91 | # ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
92 | # ssl_ciphers "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA";
93 | # ssl_prefer_server_ciphers on;
94 |
95 | # # openssl dhparam -out dhparams.pem 2048
96 | # ssl_dhparam /path/to/dhparams.pem;
97 | #
98 | # ssl_session_cache shared:SSL:10m;
99 | # ssl_session_timeout 10m;
100 | #
101 | # ssl_session_ticket_key /path/to/tls_session_ticket.key;
102 | # ssl_session_tickets on;
103 | #
104 | # ssl_stapling on;
105 | # ssl_stapling_verify on;
106 | # ssl_trusted_certificate /path/to/startssl_trust_chain.crt;
107 | #
108 | #
109 | # add_header x-Content-Type-Options nosniff;
110 | # add_header X-Frame-Options deny;
111 | # add_header Strict-Transport-Security "max-age=16070400";
112 | #
113 | # index index.html index.htm;
114 | # if ( -f $request_filename/index.html ){
115 | # rewrite (.*) $1/index.html break;
116 | # }
117 | # if ( !-f $request_filename ){
118 | # rewrite (.*) /;
119 | # }
120 | # location = / {
121 | # proxy_http_version 1.1;
122 | # proxy_set_header X-Real-IP $remote_addr;
123 | # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
124 | # proxy_set_header Host $http_host;
125 | # proxy_set_header X-NginX-Proxy true;
126 | # proxy_set_header Upgrade $http_upgrade;
127 | # proxy_set_header Connection "upgrade";
128 | # proxy_pass http://127.0.0.1:$node_port$request_uri;
129 | # proxy_redirect off;
130 | # }
131 | #
132 | # location = /swagger/ {
133 | # deny all;
134 | # }
135 | #
136 | # location ~ /static/ {
137 | # etag on;
138 | # expires max;
139 | # }
140 | #}
141 |
142 |
--------------------------------------------------------------------------------
/client/gulpfile.js:
--------------------------------------------------------------------------------
1 | const gulp = require('gulp')
2 | const copy = require('gulp-copy')
3 | const concat = require('gulp-concat')
4 | const sass = require('gulp-sass')
5 | const minifycss = require('gulp-clean-css')
6 | const autoprefixer = require('gulp-autoprefixer')
7 | const spriter = require('gulp-css-spriter')
8 | const uglify = require('gulp-uglify')
9 | const imagemin = require('gulp-imagemin')
10 | const pngquant = require('imagemin-pngquant')
11 | const minifyhtml = require('gulp-minify-html')
12 | const rev = require('gulp-rev')
13 | const revcollector = require('gulp-rev-collector')
14 | const eslint = require('gulp-eslint')
15 | const sequence = require('gulp-sequence')
16 | const sourcemaps = require('gulp-sourcemaps')
17 | const del = require('del')
18 |
19 | let paths = {
20 | jsComSrc: './src/js/common/*.js',
21 | jsAppSrc: './src/js/*.js',
22 | jsDest: '../public/static/js',
23 | cssSrc: './src/css/**/*',
24 | cssDest: '../public/static/css',
25 | imgSrc: './src/img/**/*',
26 | imgDest: '../public/static/img',
27 | htmlSrc: './src/html/**/*',
28 | htmlDest: '../public/static/html',
29 | libSrc: './src/libs/**/*',
30 | libDest: '../public/static',
31 | dist: '../public/static/**/*',
32 | // manifestFile: './rev-manifest.json'
33 | }
34 |
35 | gulp.task('scripts', ['scripts-common', 'scripts-app'])
36 |
37 | gulp.task('scripts-common', function() {
38 | return gulp.src(paths.jsComSrc)
39 | .pipe(sourcemaps.init())
40 | .pipe(concat('common.min.js'))
41 | .pipe(uglify())
42 | // .pipe(rev()) // 文件名加MD5后缀
43 | .pipe(sourcemaps.write('./'))
44 | .pipe(gulp.dest(paths.jsDest))
45 | // .pipe(rev.manifest()) // 生成一个rev-manifest.json
46 | // .pipe(gulp.dest('./')) // 将 rev-manifest.json 保存到 ./ 目录内
47 | })
48 |
49 | gulp.task('scripts-app', function() {
50 | return gulp.src(paths.jsAppSrc)
51 | .pipe(sourcemaps.init())
52 | .pipe(concat('app.min.js'))
53 | .pipe(uglify())
54 | // .pipe(rev()) // 文件名加MD5后缀
55 | .pipe(sourcemaps.write('./'))
56 | .pipe(gulp.dest(paths.jsDest))
57 | // .pipe(rev.manifest()) // 生成一个rev-manifest.json
58 | // .pipe(gulp.dest('./')) // 将 rev-manifest.json 保存到 ./ 目录内
59 | })
60 |
61 | // gulp.task('rev', ['scripts'], function() {
62 | // gulp.src(['./rev-manifest.json', '../server/views/index.hbs']) // 读取 rev-manifest.json 文件以及需要进行文件名替换的文件
63 | // .pipe(revcollector()) // 执行文件内文件名的替换
64 | // .pipe(gulp.dest('../server/views')) // 替换后的文件输出的目录
65 | // })
66 |
67 | gulp.task('images', function() {
68 | return gulp.src(paths.imgSrc)
69 | .pipe(imagemin({
70 | optimizationLevel: 5,
71 | progressive: true,
72 | use: [pngquant()]
73 | }))
74 | .pipe(gulp.dest(paths.imgDest))
75 | })
76 |
77 | gulp.task('styles', function() {
78 | return gulp.src(paths.cssSrc)
79 | .pipe(sass()) // 编译scss
80 | .pipe(concat('app.min.css')) // 合并scss
81 | .pipe(autoprefixer()) // 浏览器厂商前缀 {browsers:["> 1%","Firefox >= 10","ie >= 9","iOS >= 4","Chrome >= 10"],cascade:false}
82 | // .pipe(spriter({
83 | // // The path and file name of where we will save the sprite sheet
84 | // 'spriteSheet': paths.imgDest + '/spritesheet.png',
85 | // // Because we don't know where you will end up saving the CSS file at this point in the pipe,
86 | // // we need a litle help identifying where it will be.
87 | // 'pathToSpriteSheetFromCSS': '../img/spritesheet.png'
88 | // }))
89 | .pipe(minifycss()) // 压缩css
90 | .pipe(gulp.dest(paths.cssDest))
91 | })
92 |
93 | gulp.task('htmls', function() {
94 | gulp.src(paths.htmlSrc)
95 | .pipe(minifyhtml({ comments: false }))
96 | .pipe(gulp.dest(paths.htmlDest))
97 | })
98 |
99 | gulp.task('lint', function () {
100 | return gulp.src(['./src/js/**/*', '!node_modules/**'])
101 | .pipe(eslint())
102 | .pipe(eslint.format())
103 | .pipe(eslint.failAfterError())
104 | })
105 |
106 | gulp.task('clean', function(){
107 | del([paths.dist], { force: true })
108 | })
109 |
110 | gulp.task('libs', function() {
111 | gulp.src(paths.libSrc)
112 | .pipe(copy(paths.libDest, { prefix: 1 }))
113 | .pipe(gulp.dest(paths.libDest + '/libs'))
114 | })
115 |
116 | gulp.task('watch', function() {
117 | gulp.watch(paths.jsComSrc, ['scripts-common'])
118 | gulp.watch(paths.jsAppSrc, ['scripts-app'])
119 | gulp.watch(paths.cssSrc, ['styles'])
120 | gulp.watch(paths.imgSrc, ['images'])
121 | gulp.watch(paths.htmlSrc, ['htmls'])
122 | gulp.watch(paths.libSrc, ['libs'])
123 | })
124 |
125 | gulp.task('build', ['clean'], function (cb) {
126 | // gulp.start('scripts', 'styles', 'images', 'htmls', 'libs')
127 | sequence('scripts', 'styles', 'images', 'htmls', 'libs')(cb)
128 | })
129 |
130 | gulp.task('build-no-clean', function (cb) {
131 | gulp.start('scripts', 'styles', 'images', 'htmls', 'libs')
132 | })
133 |
134 | gulp.task('default', sequence('build', 'watch'))
135 |
136 |
137 | // function SpriterGroup(pathArr) {
138 | // for (let i = 0; i < pathArr.length; i++) {
139 | // gulp.src(pathArr[i])
140 | // .pipe(spriter({
141 | // 'spriteSheet' : paths.imgDest + '/spriteSheet_' + i +'.png',
142 | // 'pathToSpriteSheetFormCss' : '../img/spriteSheet_' + i + '.png'
143 | // }))
144 | // .pipe(gulp.dest(paths.cssDest))
145 | // }
146 | // }
147 |
--------------------------------------------------------------------------------
/server/services/thrift/tutorial/gen/tutorial_types.js:
--------------------------------------------------------------------------------
1 | //
2 | // Autogenerated by Thrift Compiler (0.10.0)
3 | //
4 | // DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
5 | //
6 | "use strict";
7 |
8 | var thrift = require('thrift');
9 | var Thrift = thrift.Thrift;
10 | var Q = thrift.Q;
11 |
12 | var shared_ttypes = require('./shared_types');
13 |
14 |
15 | var ttypes = module.exports = {};
16 | ttypes.Operation = {
17 | 'ADD' : 1,
18 | 'SUBTRACT' : 2,
19 | 'MULTIPLY' : 3,
20 | 'DIVIDE' : 4
21 | };
22 | var Work = module.exports.Work = function(args) {
23 | this.num1 = 0;
24 | this.num2 = null;
25 | this.op = null;
26 | this.comment = null;
27 | if (args) {
28 | if (args.num1 !== undefined && args.num1 !== null) {
29 | this.num1 = args.num1;
30 | }
31 | if (args.num2 !== undefined && args.num2 !== null) {
32 | this.num2 = args.num2;
33 | }
34 | if (args.op !== undefined && args.op !== null) {
35 | this.op = args.op;
36 | }
37 | if (args.comment !== undefined && args.comment !== null) {
38 | this.comment = args.comment;
39 | }
40 | }
41 | };
42 | Work.prototype = {};
43 | Work.prototype.read = function(input) {
44 | input.readStructBegin();
45 | while (true)
46 | {
47 | var ret = input.readFieldBegin();
48 | var fname = ret.fname;
49 | var ftype = ret.ftype;
50 | var fid = ret.fid;
51 | if (ftype == Thrift.Type.STOP) {
52 | break;
53 | }
54 | switch (fid)
55 | {
56 | case 1:
57 | if (ftype == Thrift.Type.I32) {
58 | this.num1 = input.readI32();
59 | } else {
60 | input.skip(ftype);
61 | }
62 | break;
63 | case 2:
64 | if (ftype == Thrift.Type.I32) {
65 | this.num2 = input.readI32();
66 | } else {
67 | input.skip(ftype);
68 | }
69 | break;
70 | case 3:
71 | if (ftype == Thrift.Type.I32) {
72 | this.op = input.readI32();
73 | } else {
74 | input.skip(ftype);
75 | }
76 | break;
77 | case 4:
78 | if (ftype == Thrift.Type.STRING) {
79 | this.comment = input.readString();
80 | } else {
81 | input.skip(ftype);
82 | }
83 | break;
84 | default:
85 | input.skip(ftype);
86 | }
87 | input.readFieldEnd();
88 | }
89 | input.readStructEnd();
90 | return;
91 | };
92 |
93 | Work.prototype.write = function(output) {
94 | output.writeStructBegin('Work');
95 | if (this.num1 !== null && this.num1 !== undefined) {
96 | output.writeFieldBegin('num1', Thrift.Type.I32, 1);
97 | output.writeI32(this.num1);
98 | output.writeFieldEnd();
99 | }
100 | if (this.num2 !== null && this.num2 !== undefined) {
101 | output.writeFieldBegin('num2', Thrift.Type.I32, 2);
102 | output.writeI32(this.num2);
103 | output.writeFieldEnd();
104 | }
105 | if (this.op !== null && this.op !== undefined) {
106 | output.writeFieldBegin('op', Thrift.Type.I32, 3);
107 | output.writeI32(this.op);
108 | output.writeFieldEnd();
109 | }
110 | if (this.comment !== null && this.comment !== undefined) {
111 | output.writeFieldBegin('comment', Thrift.Type.STRING, 4);
112 | output.writeString(this.comment);
113 | output.writeFieldEnd();
114 | }
115 | output.writeFieldStop();
116 | output.writeStructEnd();
117 | return;
118 | };
119 |
120 | var InvalidOperation = module.exports.InvalidOperation = function(args) {
121 | Thrift.TException.call(this, "InvalidOperation");
122 | this.name = "InvalidOperation";
123 | this.whatOp = null;
124 | this.why = null;
125 | if (args) {
126 | if (args.whatOp !== undefined && args.whatOp !== null) {
127 | this.whatOp = args.whatOp;
128 | }
129 | if (args.why !== undefined && args.why !== null) {
130 | this.why = args.why;
131 | }
132 | }
133 | };
134 | Thrift.inherits(InvalidOperation, Thrift.TException);
135 | InvalidOperation.prototype.name = 'InvalidOperation';
136 | InvalidOperation.prototype.read = function(input) {
137 | input.readStructBegin();
138 | while (true)
139 | {
140 | var ret = input.readFieldBegin();
141 | var fname = ret.fname;
142 | var ftype = ret.ftype;
143 | var fid = ret.fid;
144 | if (ftype == Thrift.Type.STOP) {
145 | break;
146 | }
147 | switch (fid)
148 | {
149 | case 1:
150 | if (ftype == Thrift.Type.I32) {
151 | this.whatOp = input.readI32();
152 | } else {
153 | input.skip(ftype);
154 | }
155 | break;
156 | case 2:
157 | if (ftype == Thrift.Type.STRING) {
158 | this.why = input.readString();
159 | } else {
160 | input.skip(ftype);
161 | }
162 | break;
163 | default:
164 | input.skip(ftype);
165 | }
166 | input.readFieldEnd();
167 | }
168 | input.readStructEnd();
169 | return;
170 | };
171 |
172 | InvalidOperation.prototype.write = function(output) {
173 | output.writeStructBegin('InvalidOperation');
174 | if (this.whatOp !== null && this.whatOp !== undefined) {
175 | output.writeFieldBegin('whatOp', Thrift.Type.I32, 1);
176 | output.writeI32(this.whatOp);
177 | output.writeFieldEnd();
178 | }
179 | if (this.why !== null && this.why !== undefined) {
180 | output.writeFieldBegin('why', Thrift.Type.STRING, 2);
181 | output.writeString(this.why);
182 | output.writeFieldEnd();
183 | }
184 | output.writeFieldStop();
185 | output.writeStructEnd();
186 | return;
187 | };
188 |
189 | ttypes.INT32CONSTANT = 9853;
190 | ttypes.MAPCONSTANT = {
191 | 'hello' : 'world',
192 | 'goodnight' : 'moon'
193 | };
194 |
--------------------------------------------------------------------------------
/server/services/thrift/tutorial/tutorial.thrift:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one
3 | * or more contributor license agreements. See the NOTICE file
4 | * distributed with this work for additional information
5 | * regarding copyright ownership. The ASF licenses this file
6 | * to you under the Apache License, Version 2.0 (the
7 | * "License"); you may not use this file except in compliance
8 | * with the License. You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing,
13 | * software distributed under the License is distributed on an
14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | * KIND, either express or implied. See the License for the
16 | * specific language governing permissions and limitations
17 | * under the License.
18 | */
19 |
20 | # Thrift Tutorial
21 | # Mark Slee (mcslee@facebook.com)
22 | #
23 | # This file aims to teach you how to use Thrift, in a .thrift file. Neato. The
24 | # first thing to notice is that .thrift files support standard shell comments.
25 | # This lets you make your thrift file executable and include your Thrift build
26 | # step on the top line. And you can place comments like this anywhere you like.
27 | #
28 | # Before running this file, you will need to have installed the thrift compiler
29 | # into /usr/local/bin.
30 |
31 | /**
32 | * The first thing to know about are types. The available types in Thrift are:
33 | *
34 | * bool Boolean, one byte
35 | * i8 (byte) Signed 8-bit integer
36 | * i16 Signed 16-bit integer
37 | * i32 Signed 32-bit integer
38 | * i64 Signed 64-bit integer
39 | * double 64-bit floating point value
40 | * string String
41 | * binary Blob (byte array)
42 | * map Map from one type to another
43 | * list Ordered list of one type
44 | * set Set of unique elements of one type
45 | *
46 | * Did you also notice that Thrift supports C style comments?
47 | */
48 |
49 | // Just in case you were wondering... yes. We support simple C comments too.
50 |
51 | /**
52 | * Thrift files can reference other Thrift files to include common struct
53 | * and service definitions. These are found using the current path, or by
54 | * searching relative to any paths specified with the -I compiler flag.
55 | *
56 | * Included objects are accessed using the name of the .thrift file as a
57 | * prefix. i.e. shared.SharedObject
58 | */
59 | include "../shared.thrift"
60 |
61 | /**
62 | * Thrift files can namespace, package, or prefix their output in various
63 | * target languages.
64 | */
65 | namespace cpp tutorial
66 | namespace d tutorial
67 | namespace dart tutorial
68 | namespace java tutorial
69 | namespace php tutorial
70 | namespace perl tutorial
71 | namespace haxe tutorial
72 | namespace netcore tutorial
73 |
74 | /**
75 | * Thrift lets you do typedefs to get pretty names for your types. Standard
76 | * C style here.
77 | */
78 | typedef i32 MyInteger
79 |
80 | /**
81 | * Thrift also lets you define constants for use across languages. Complex
82 | * types and structs are specified using JSON notation.
83 | */
84 | const i32 INT32CONSTANT = 9853
85 | const map MAPCONSTANT = {'hello':'world', 'goodnight':'moon'}
86 |
87 | /**
88 | * You can define enums, which are just 32 bit integers. Values are optional
89 | * and start at 1 if not supplied, C style again.
90 | */
91 | enum Operation {
92 | ADD = 1,
93 | SUBTRACT = 2,
94 | MULTIPLY = 3,
95 | DIVIDE = 4
96 | }
97 |
98 | /**
99 | * Structs are the basic complex data structures. They are comprised of fields
100 | * which each have an integer identifier, a type, a symbolic name, and an
101 | * optional default value.
102 | *
103 | * Fields can be declared "optional", which ensures they will not be included
104 | * in the serialized output if they aren't set. Note that this requires some
105 | * manual management in some languages.
106 | */
107 | struct Work {
108 | 1: i32 num1 = 0,
109 | 2: i32 num2,
110 | 3: Operation op,
111 | 4: optional string comment,
112 | }
113 |
114 | /**
115 | * Structs can also be exceptions, if they are nasty.
116 | */
117 | exception InvalidOperation {
118 | 1: i32 whatOp,
119 | 2: string why
120 | }
121 |
122 | /**
123 | * Ahh, now onto the cool part, defining a service. Services just need a name
124 | * and can optionally inherit from another service using the extends keyword.
125 | */
126 | service Calculator extends shared.SharedService {
127 |
128 | /**
129 | * A method definition looks like C code. It has a return type, arguments,
130 | * and optionally a list of exceptions that it may throw. Note that argument
131 | * lists and exception lists are specified using the exact same syntax as
132 | * field lists in struct or exception definitions.
133 | */
134 |
135 | void ping(),
136 |
137 | i32 add(1:i32 num1, 2:i32 num2),
138 |
139 | i32 calculate(1:i32 logid, 2:Work w) throws (1:InvalidOperation ouch),
140 |
141 | /**
142 | * This method has a oneway modifier. That means the client only makes
143 | * a request and does not listen for any response at all. Oneway methods
144 | * must be void.
145 | */
146 | oneway void zip()
147 |
148 | }
149 |
150 | /**
151 | * That just about covers the basics. Take a look in the test/ folder for more
152 | * detailed examples. After you run this file, your generated code shows up
153 | * in folders with names gen-. The generated code isn't too scary
154 | * to look at. It even has pretty indentation.
155 | */
--------------------------------------------------------------------------------
/server/utils/sql.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 生成SQL语句
3 | */
4 |
5 | const util = require('./util')
6 |
7 | /**
8 | * 根据参数生成SQL插入语句
9 | *
10 | * @param table 表名(字符串)
11 | * @param record 要插入的记录行(对象)【字段名=>值...】
12 | * @param updatefields 要更新的字段(数组),更新方式是直接给字段赋值,【字段名1,字段名2...】
13 | * @param changefields 要更新的字段(对象),更新方式是在原字段值基础上追加,【字段名=>追加值...】
14 | * @return 返回sql插入语句(字符串)
15 | */
16 | exports.insert = function (table, record, updatefields = [], changefield = {}) {
17 | let sql = `INSERT INTO ${table} (`
18 | sql += Object.keys(record).join(', ')
19 | sql += ") VALUES("
20 | sql += Object.values(record).map(v => `'${util.escapeSql(v)}'`).join(', ')
21 | sql += ")"
22 |
23 | //在插入记录的时候先判断记录是否存在(唯一索引或主键),如果不存在则插入,否则更新
24 | if (!util.isEmpty(updatefields) || !util.isEmpty(changefield)) {
25 | sql += " ON DUPLICATE KEY UPDATE "
26 |
27 | sql += updatefields.map(v => `${v}='${util.escapeSql(record[v])}'`).join(', ')
28 | // or
29 | let flag = 0
30 | if (!util.isEmpty(updatefields)) {
31 | flag = 1
32 | }
33 |
34 | for (let k in changefield) {
35 | let v = changefield[k]
36 | if (util.isNumber(v)) {
37 | sql += `${flag == 0 ? "" : ", "}${k}=${k}${v >= 0 ? "+" : ""}${v}`
38 | } else {
39 | sql += `${flag == 0 ? "" : ", "}${k}=CONCAT(${k},'${util.escapeSql(v)}')`
40 | }
41 | flag = 1
42 | }
43 | }
44 |
45 | return sql
46 | }
47 |
48 | /**
49 | * 向同一个表批量插入大量数据的时候,用这个函数效率高
50 | *
51 | * @param table 表名(字符串)
52 | * @param records 要插入的多行记录(对象数组)【【字段名=>值...】...】
53 | * @return 返回sql多行插入语句(字符串)
54 | * @see #insert()
55 | */
56 | exports.insertMore = function (table, records) {
57 | let sql = `INSERT INTO ${table} (`
58 | sql += Object.keys(records[0]).join(', ')
59 | sql += ") VALUES"
60 |
61 | for (let record of records) {
62 | sql += "("
63 | sql += Object.values(record).map(v => `'${util.escapeSql(v)}'`).join(', ')
64 | sql += "),"
65 | }
66 |
67 | sql = util.trim(sql, ",")
68 |
69 | return sql
70 | }
71 |
72 | /**
73 | * 根据参数生成SQL更新语句
74 | *
75 | * @param table 表名(字符串)
76 | * @param updatefields 要更新的字段(对象),更新方式是直接给字段赋值,【字段名=>值...】
77 | * @param where 删除条件(对象),只判断相等条件,其他条件请用exwhere参数 【键=>值...】
78 | * @param changefields 要更新的字段(对象),更新方式是在原字段值基础上追加,【字段名=>追加值...】
79 | * @param exwhere 扩展条件(字符串),不含"where"关键字
80 | * @return 返回sql更新语句(字符串)
81 | */
82 | exports.update = function (table, updatefield, where, changefield = {}, exwhere = '') {
83 | let sql = `UPDATE ${table} SET `
84 | let flag = 0
85 | for (let k in updatefield) {
86 | let v = updatefield[k]
87 | sql += `${flag == 0 ? "" : ", "}${k}='${util.escapeSql(v)}'`
88 | flag = 1
89 | }
90 |
91 | flag = 0
92 | if (!util.isEmpty(updatefield)) {
93 | flag = 1
94 | }
95 | for (let k in changefield) {
96 | let v = changefield[k]
97 | if (util.isNumber(v)) {
98 | sql += `${flag == 0 ? "" : ", "}${k}=${k}${v >= 0 ? "+" : ""}${v}`
99 | } else {
100 | sql += `${flag == 0 ? "" : ", "}${k}=CONCAT(${k},'${util.escapeSql(v)}')`
101 | }
102 | flag = 1
103 | }
104 |
105 | flag = 0
106 | for (let k in where) {
107 | let v = where[k]
108 | sql += `${flag == 0 ? " WHERE " : " AND "}${k}='${util.escapeSql(v)}'`
109 | flag = 1
110 | }
111 |
112 | if (exwhere.length > 0) {
113 | sql += (flag == 0 ? " WHERE " : " AND ") + exwhere
114 | }
115 |
116 | return sql
117 | }
118 |
119 | /**
120 | * 根据参数生成SQL查询语句
121 | *
122 | * @param table 表名(字符串)
123 | * @param fields 要查询的字段(数组),【字段名1,字段名2...】
124 | * @param where 删除条件(对象),只判断相等条件,其他条件请用exwhere参数 【键=>值...】
125 | * @param exwhere 扩展条件(字符串),不含"where"关键字
126 | * @param other 其他语句(字符串),如limit、order by、group by等 一般不建议使用
127 | * @return 返回sql删除语句(字符串)
128 | */
129 | exports.select = function (table, fields, where, exwhere = "", other = "") {
130 | let sql = `SELECT ${util.isEmpty(fields) ? '*' : fields.join(", ")} FROM ${table}`
131 | let flag = 0
132 |
133 | for (let k in where) {
134 | let v = where[k]
135 | sql += `${flag == 0 ? " WHERE " : " AND "}${k}='${util.escapeSql(v)}'`
136 | flag = 1
137 | }
138 |
139 | if (exwhere.length > 0) {
140 | sql += (flag == 0 ? " WHERE " : " AND ") + exwhere
141 | }
142 |
143 | if (other.length > 0) {
144 | sql += " " + other
145 | }
146 |
147 | return sql
148 | }
149 |
150 | /**
151 | *
152 | * 根据参数生成SQL替换语句
153 | * REPLACE的运行与INSERT很相像。只有一点除外,如果表中的一个旧记录与一个用于PRIMARY KEY或一个UNIQUE索引的新记录具有相同的值,则在新记录被插入之前,旧记录被删除。
154 | * 注意,除非表有一个PRIMARY KEY或UNIQUE索引,否则,使用一个REPLACE语句没有意义。该语句会与INSERT相同,因为没有索引被用于确定是否新行复制了其它的行。
155 | *
156 | *
157 | * @param table 表名(字符串)
158 | * @param record 要插入或替换的记录行(对象)【字段名=>值...】
159 | * @return 返回sql替换语句(字符串)
160 | */
161 | exports.replace = function (table, record) {
162 | let sql = `REPLACE INTO ${table} (`
163 | sql += Object.keys(record).join(', ')
164 | sql += ") VALUES("
165 | sql += Object.values(record).map(v => `'${util.escapeSql(v)}'`).join(', ')
166 | sql += ")"
167 |
168 | return sql
169 | }
170 |
171 | /**
172 | * 向同一个表批量插入或替换大量数据的时候,用这个函数效率高
173 | *
174 | * @param table 表名(字符串)
175 | * @param records 要插入或替换的多行记录(对象数组)【【字段名=>值...】...】
176 | * @return 返回sql多行插入或替换语句(字符串)
177 | * @see #replace()
178 | */
179 | exports.replaceMore = function (table, records) {
180 | let sql = `REPLACE INTO ${table} (`
181 | sql += Object.keys(records[0]).join(', ')
182 | sql += ") VALUES"
183 |
184 | for (let record of records) {
185 | sql += "("
186 | sql += Object.values(record).map(v => `'${util.escapeSql(v)}'`).join(', ')
187 | sql += "),"
188 | }
189 |
190 | sql = util.trim(sql, ",")
191 |
192 | return sql
193 | }
194 |
195 | /**
196 | * 根据参数生成SQL删除语句
197 | *
198 | * @param table 表名(字符串)
199 | * @param where 删除条件(对象),只判断相等条件,其他条件请用exwhere参数 【键=>值...】
200 | * @param exwhere 扩展条件(字符串),不含"where"关键字
201 | * @return 返回sql删除语句(字符串)
202 | */
203 | exports.delete = function (table, where, exwhere = "") {
204 | let sql = `DELETE FROM ${table}`
205 | let flag = 0
206 |
207 | for (let k in where) {
208 | let v = where[k]
209 | sql += `${flag == 0 ? " WHERE " : " AND "}${k}='${util.escapeSql(v)}'`
210 | flag = 1
211 | }
212 |
213 | if (exwhere.length > 0) {
214 | sql += (flag == 0 ? " WHERE " : " AND ") + exwhere
215 | }
216 |
217 | return sql
218 | }
219 |
--------------------------------------------------------------------------------
/public/swagger/lib/swagger-oauth.js:
--------------------------------------------------------------------------------
1 | function handleLogin(){var e=[],o=window.swaggerUiAuth.authSchemes||window.swaggerUiAuth.securityDefinitions;if(o){var i,n=o;for(i in n){var a=n[i];if("oauth2"===a.type&&a.scopes){var t;if(Array.isArray(a.scopes)){var p;for(p=0;p