From 62a96632a01820a832ac2fcbbfe09511c8bb7b87 Mon Sep 17 00:00:00 2001 From: kobepeng Date: Tue, 10 Jul 2018 18:27:59 +0800 Subject: [PATCH 01/10] fix: should not call diconnect at server end --- app/io/middleware/auth.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/app/io/middleware/auth.ts b/app/io/middleware/auth.ts index e54ac77..458184e 100644 --- a/app/io/middleware/auth.ts +++ b/app/io/middleware/auth.ts @@ -1,7 +1,4 @@ 'use strict'; -/** - * TODO: 增加 AUTH 逻辑 - */ import { Application, Context } from 'egg'; module.exports = (app: Application) => { @@ -12,7 +9,7 @@ module.exports = (app: Application) => { app['redis'].expire(token, 3 * 24 * 60 * 60); await next; } else { - ctx.socket.disconnect(); + ctx.socket.emit('verify_failed', {}); } ctx.logger.info('disconnect!'); }; From 21aefe1f2a1d9a0310b2f120014f0b7a9c10de54 Mon Sep 17 00:00:00 2001 From: kobepeng Date: Wed, 11 Jul 2018 14:34:35 +0800 Subject: [PATCH 02/10] chore: chinese comments to english commets --- app/controller/base.ts | 38 ++++++++++---------- app/controller/message.ts | 4 +-- app/controller/other.ts | 2 +- app/controller/task.ts | 6 ++-- app/controller/tomato.ts | 7 ++-- app/controller/user.ts | 24 +++++++------ app/controller/userFriend.ts | 8 ++--- app/controller/version.ts | 2 +- app/extend/helper.ts | 18 +++++----- app/io/controller/chat.ts | 63 +++++++++++++++++---------------- app/io/controller/tomatobang.ts | 24 ++++++------- app/io/middleware/auth.ts | 1 - app/middleware/errorhandler.ts | 2 +- app/middleware/jwt.ts | 4 +-- app/middleware/ratelimit.ts | 8 ++--- 15 files changed, 105 insertions(+), 106 deletions(-) diff --git a/app/controller/base.ts b/app/controller/base.ts index d35afec..1ef2e7d 100644 --- a/app/controller/base.ts +++ b/app/controller/base.ts @@ -4,30 +4,30 @@ import { Controller } from 'egg'; export default class BaseController extends Controller { select_field; validateRule; + /** - * 按条件查找 + * search with conditions */ async list() { const { ctx } = this; - let conditions:any; + let conditions: any; conditions = {}; const query = ctx.request.query; ctx.logger.info('ctx.request:', ctx.request['currentUser']); - // 按用户筛选 + // filter with logged userinfo if (ctx.request['currentUser']) { - conditions.userid =ctx.request['currentUser'].username; + conditions.userid = ctx.request['currentUser'].username; } if (query.conditions) { conditions = JSON.parse(query.conditions); } const result = await this.service.findAll(query, conditions); - // ctx.logger.info('message', result); ctx.body = result; ctx.status = 200; } /** - * 按 id 查找 + * search by id */ async findById() { const { ctx } = this; @@ -38,13 +38,13 @@ export default class BaseController extends Controller { } /** - * 创建 + * create record */ async create() { const { ctx, app } = this; - // 存储用户编号/username + // filter with logged userinfo if (ctx.request['currentUser']) { - ctx.request.body.userid =ctx.request['currentUser'].username; + ctx.request.body.userid = ctx.request['currentUser'].username; } if (this.validateRule) { const invalid = app['validator'].validate( @@ -61,7 +61,7 @@ export default class BaseController extends Controller { } /** - * 删除 + * delete record by id */ async deleteById() { const { ctx } = this; @@ -71,7 +71,7 @@ export default class BaseController extends Controller { } /** - * 按 id 更新 + * update record by id */ async updateById() { const { ctx } = this; @@ -82,7 +82,7 @@ export default class BaseController extends Controller { } /** - * 按 id 替换 + * replace record by id */ async replaceById() { const { ctx } = this; @@ -94,14 +94,14 @@ export default class BaseController extends Controller { } /** - * 关键词查找 + * load record by pagination */ async pagination() { const { ctx } = this; const current = ctx.request.body.current; let userid = ''; if (ctx.request['currentUser']) { - userid =ctx.request['currentUser'].username; + userid = ctx.request['currentUser'].username; } if (!this.select_field) { ctx.status = 403; @@ -133,16 +133,16 @@ export default class BaseController extends Controller { } /** - * 统一错误处理 - * @param {*} type 错误类型 - * @param {*} message 错误消息 + * error util function + * @param {*} type error type + * @param {*} message error message */ async throwBizError(type, message) { if (type === 'DB:ERR') { - throw new Error('发生了数据库错误'); + throw new Error('DB:ERR'); } if (type === 'FILE:ERR') { - throw new Error('发生了文件类型错误'); + throw new Error('FILE:ERR'); } else { throw new Error(message); } diff --git a/app/controller/message.ts b/app/controller/message.ts index 642a814..63b59e7 100644 --- a/app/controller/message.ts +++ b/app/controller/message.ts @@ -7,7 +7,7 @@ export default class MessageController extends BaseController { } /** - * 加载用户未读消息 + * load user unread messages */ async loadUnreadMessages() { const { ctx, app } = this; @@ -47,7 +47,7 @@ export default class MessageController extends BaseController { } /** - * 更新消息已读状态 + * update user messages state by message id */ async updateMessageState() { const { ctx } = this; diff --git a/app/controller/other.ts b/app/controller/other.ts index 9cc2d4a..ce5e33b 100644 --- a/app/controller/other.ts +++ b/app/controller/other.ts @@ -2,7 +2,7 @@ import { Controller } from 'egg'; export default class OtherController extends Controller { /** - * 获取七牛客户端上传 token + * load qi-niu upload token */ async getQiniuUploadToken() { const { ctx, app } = this; diff --git a/app/controller/task.ts b/app/controller/task.ts index c51569a..ef3f520 100644 --- a/app/controller/task.ts +++ b/app/controller/task.ts @@ -10,6 +10,9 @@ export default class TaskController extends BaseController { this.validateRule = taskValidationRule; } + /** + * update task voice media url + */ async updateVoiceUrl() { const { ctx, app } = this; const invalid = app['validator'].validate( @@ -19,14 +22,13 @@ export default class TaskController extends BaseController { if (invalid) { ctx.body = { status: 'fail', - description: '请求参数错误!', + description: 'request parame(s) error!', }; return; } const taskid = ctx.request.body.taskid; const relateUrl = ctx.request.body.relateUrl; await ctx.service.task.updateVoiceUrl(taskid, relateUrl); - // 此处写法待重构 ctx.status = 200; ctx.body = { success: true, diff --git a/app/controller/tomato.ts b/app/controller/tomato.ts index 4eda5a4..f6e7895 100644 --- a/app/controller/tomato.ts +++ b/app/controller/tomato.ts @@ -23,9 +23,7 @@ export default class TomatoController extends BaseController { ctx.status = 200; ctx.body = []; } - // 获取本月的第一天 const starDate = ctx.helper.dateHelper.getCurrentMonthFirst(date); - // 获取本月的最后一天 const endDate = ctx.helper.dateHelper.getNextMonthFirst(date); const ret = await ctx.service.tomato.statistics( userid, @@ -43,7 +41,7 @@ export default class TomatoController extends BaseController { } /** - * 筛选今日番茄钟 + * load today tomatoes */ async tomatoToday() { const { ctx } = this; @@ -73,13 +71,12 @@ export default class TomatoController extends BaseController { } /** - * 关键词查找 + * search by keyword */ async search() { const { ctx } = this; let keywords = ctx.request.body.keywords; keywords = ctx.helper.escape(keywords); - ctx.logger.info('keywords2', keywords); const ret = await ctx.service.tomato.findAll( {}, { diff --git a/app/controller/user.ts b/app/controller/user.ts index 2d85b12..fb7dd1f 100644 --- a/app/controller/user.ts +++ b/app/controller/user.ts @@ -16,7 +16,7 @@ export default class UserController extends BaseController { } /** - * 查找用户 + * search user by keyword */ async searchUsers() { const { ctx } = this; @@ -37,6 +37,9 @@ export default class UserController extends BaseController { ctx.body = users; } + /** + * to see is user has login + */ async auth() { const { ctx } = this; if (ctx.request['currentUser']) { @@ -50,8 +53,9 @@ export default class UserController extends BaseController { }; } } + /** - * 登录 + * login */ async login() { const { ctx, app } = this; @@ -117,7 +121,7 @@ export default class UserController extends BaseController { } /** - * 登出 + * logout */ async logout() { const { ctx, app } = this; @@ -131,7 +135,7 @@ export default class UserController extends BaseController { } /** - * 邮箱验证 + * validate username and email */ async emailUserNameVerify() { const { ctx, app } = this; @@ -176,7 +180,7 @@ export default class UserController extends BaseController { } /** - * 更新头像路径 + * update head image( file url ) */ async updateHeadImg() { const { ctx } = this; @@ -191,7 +195,7 @@ export default class UserController extends BaseController { } /** - * 更新性别 + * update sex info */ async updateSex() { const { ctx, app } = this; @@ -213,7 +217,7 @@ export default class UserController extends BaseController { } /** - * 更新昵称 + * update nick name */ async updateDisplayName() { const { ctx } = this; @@ -224,7 +228,7 @@ export default class UserController extends BaseController { } /** - * 更新邮箱 + * update email */ async updateEmail() { const { ctx, app } = this; @@ -247,7 +251,7 @@ export default class UserController extends BaseController { } /** - * 更新位置 + * update position */ async updateLocation() { const { ctx } = this; @@ -258,7 +262,7 @@ export default class UserController extends BaseController { } /** - * 更新签名 + * update bio */ async updateBio() { const { ctx } = this; diff --git a/app/controller/userFriend.ts b/app/controller/userFriend.ts index 6cb6643..a8ebd14 100644 --- a/app/controller/userFriend.ts +++ b/app/controller/userFriend.ts @@ -13,7 +13,7 @@ export default class User_friendController extends BaseController { } /** - * @api {getFriendReqList} /api/user_friend [获取好友列表] + * @api {getFriendReqList} /api/user_friend [load user friend list] */ async getUserFriends() { const { ctx } = this; @@ -36,7 +36,7 @@ export default class User_friendController extends BaseController { } /** - * @api {getFriendReqList} /api/user_friend/request_add_friend [请求添加为好友] + * @api {getFriendReqList} /api/user_friend/request_add_friend [request friend list] */ async getFriendReqList() { const { ctx } = this; @@ -55,7 +55,7 @@ export default class User_friendController extends BaseController { } /** - * @api {requestAddFriend} /api/user_friend/request_add_friend [请求添加为好友] + * @api {requestAddFriend} /api/user_friend/request_add_friend [request add friend] */ async requestAddFriend() { const { ctx, app } = this; @@ -105,7 +105,7 @@ export default class User_friendController extends BaseController { } /** - * @api {responseAddFriend} /api/user_friend/response_add_friend [回复添加好友请求] + * @api {responseAddFriend} /api/user_friend/response_add_friend [response friend request] */ async responseAddFriend() { const { ctx, app } = this; diff --git a/app/controller/version.ts b/app/controller/version.ts index ce03a3d..1005bdf 100644 --- a/app/controller/version.ts +++ b/app/controller/version.ts @@ -7,7 +7,7 @@ export default class VersionController extends BaseController { } /** - * 查找最新版本信息 + * find latest version info */ async findLatestVersion() { const { ctx } = this; diff --git a/app/extend/helper.ts b/app/extend/helper.ts index b3bec74..5989aa6 100644 --- a/app/extend/helper.ts +++ b/app/extend/helper.ts @@ -4,7 +4,7 @@ import * as moment from 'moment'; exports.relativeTime = time => moment(new Date(time * 1000)).fromNow(); /** - * 日期处理 Util + * date Util */ exports.dateHelper = { getCurrentMonthFirst(date) { @@ -28,16 +28,16 @@ exports.dateHelper = { const nextMonthFirstDay = new Date(date.getFullYear(), nextMonth, 1); return this.format(new Date(nextMonthFirstDay), 'yyyy-MM-dd'); }, - // 参考: https://www.cnblogs.com/tugenhua0707/p/3776808.html + // refer: https://www.cnblogs.com/tugenhua0707/p/3776808.html format(datetime, fmt) { const o = { - 'M+': datetime.getMonth() + 1, // 月份 - 'd+': datetime.getDate(), // 日 - 'h+': datetime.getHours(), // 小时 - 'm+': datetime.getMinutes(), // 分 - 's+': datetime.getSeconds(), // 秒 - 'q+': Math.floor((datetime.getMonth() + 3) / 3), // 季度 - S: datetime.getMilliseconds(), // 毫秒 + 'M+': datetime.getMonth() + 1, + 'd+': datetime.getDate(), + 'h+': datetime.getHours(), + 'm+': datetime.getMinutes(), + 's+': datetime.getSeconds(), + 'q+': Math.floor((datetime.getMonth() + 3) / 3), // quarter + S: datetime.getMilliseconds(), }; if (/(y+)/.test(fmt)) { fmt = fmt.replace( diff --git a/app/io/controller/chat.ts b/app/io/controller/chat.ts index 2158fb0..38e613b 100644 --- a/app/io/controller/chat.ts +++ b/app/io/controller/chat.ts @@ -1,7 +1,7 @@ 'use strict'; /** - * 消息服务 + * chat message service */ import { user_friendValidationRule, @@ -15,6 +15,9 @@ module.exports = (app: Application) => { return; } + /** + * user login + */ async login() { const obj = this.ctx.args[0]; const socket = this.ctx.socket; @@ -22,18 +25,18 @@ module.exports = (app: Application) => { if (!userid) { this.failRes(socket.id, '用户编号不合法!'); } - // 存储登录信息 const userLoginEnds = await app.redis.smembers( 'chat:user:socket:' + userid ); + // save login info if (userLoginEnds && userLoginEnds.length > 0) { - // TODO:多终端登录或重复登录 + // TODO: support multi client login await app.redis.sadd('chat:user:socket:' + userid, socket.id); await app.redis.set('chat:socket:user:' + socket.id, userid); } else { await app.redis.sadd('chat:user:socket:' + userid, socket.id); await app.redis.set('chat:socket:user:' + socket.id, userid); - // 加载好友列表并置状态 + // load friend list and set online state const friends = await this.ctx.service.userFriend.findAll( { sort: '{"response_time": -1 }' }, { @@ -60,14 +63,14 @@ module.exports = (app: Application) => { 'chat:user:friends:' + friendid, userid ); - // 置用户在线标识 + // update friend online list if (score === '0') { await app.redis.zincrby( 'chat:user:friends:' + friendid, 1, userid ); - // 向好友终端推送离线消息 + // push message to friend this.notify(friendid, 'friend_online', { userid }); } } else { @@ -79,7 +82,7 @@ module.exports = (app: Application) => { } /** - * 发送消息 + * send message api */ async sendMessage() { const obj = this.ctx.args[0]; @@ -100,14 +103,12 @@ module.exports = (app: Application) => { to: to, content: message, }); - // console.log('newMsg', newMsg); - // 向各个终端推送消息 this.notify(to, 'message_received', newMsg); } } /** - * 加载好友列表 + * load user online friend list */ async loadOnlineFriendList() { const obj = this.ctx.args[0]; @@ -119,7 +120,7 @@ module.exports = (app: Application) => { if (!userid) { this.failRes(socket.id, '用户编号不合法!'); } - // 查询所有好友在线列表 + // load friend online states const friends = await app.redis.zrange( 'chat:user:friends:' + userid, 0, @@ -137,7 +138,7 @@ module.exports = (app: Application) => { } /** - * 发送好友请求 + * send friend request */ async requestAddFriend() { /** @@ -186,7 +187,7 @@ module.exports = (app: Application) => { request_time: new Date().valueOf(), state: 1, }; - // TODO: 不能重复发送好友请求( 目前使用逐渐验证 ) + // TODO: filter repeat request. now we are using db primary key await ctx.service.userFriend.create(user_friend); this.notify(to, 'receive_friend_request', from); @@ -197,6 +198,9 @@ module.exports = (app: Application) => { .emit('requestAddFriend_success', {}); } + /** + * response friend request + */ async responseAddFriend() { const { ctx, app } = this; const socket = this.ctx.socket; @@ -244,7 +248,7 @@ module.exports = (app: Application) => { } /** - * 断开连接 + * user disconnect */ async disconnect() { const { ctx, app } = this; @@ -255,7 +259,7 @@ module.exports = (app: Application) => { } /** - * 登出 + * user logout */ async logout() { const { ctx, app } = this; @@ -266,15 +270,14 @@ module.exports = (app: Application) => { } /** - * 辅助方法:清除用户信息 - * @param {string} ctx 上下文 - * @param {string} socket 当前socket - * @param {string} userid 用户编号 + * clear userinfo in redis and cache + * @param {string} ctx app context + * @param {string} socket current socket + * @param {string} userid userid */ async clearUserInfo(ctx, socket, userid) { ctx.logger.info('userid!', userid); if (userid) { - // 查询所有好友在线列表 const friends = await app.redis.zrange( 'chat:user:friends:' + userid, 0, @@ -282,12 +285,12 @@ module.exports = (app: Application) => { 'WITHSCORES' ); let fid = ''; + // update user online list for (const end of friends) { - // TODO: 格式需要做验证 if (end.length > 10) { fid = end; } - // 好友在线 + // user online if (end === '1') { const score = await app.redis.zscore( 'chat:user:friends:' + fid, @@ -296,7 +299,6 @@ module.exports = (app: Application) => { if (score !== 0) { await app.redis.zincrby('chat:user:friends:' + fid, -1, userid); } - // 向好友终端推送离线消息 this.notify(fid, 'friend_offline', { userid }); } } @@ -308,13 +310,12 @@ module.exports = (app: Application) => { } /** - * 辅助方法:发送通知 - * @param {string} userid 用户编号 - * @param {string} evtName 事件名称 - * @param {string} message 消息 + * send message + * @param {string} userid userid + * @param {string} evtName socket.io event name + * @param {string} message message */ async notify(userid, evtName, message) { - // 向好友终端推送离线消息 const loginEnds = await app.redis.smembers('chat:user:socket:' + userid); if (loginEnds && loginEnds.length > 0) { for (const end of loginEnds) { @@ -329,9 +330,9 @@ module.exports = (app: Application) => { } /** - * 失败返回 - * @param {string} socketid 套接字编号 - * @param {string} message 消息 + * fail response + * @param {string} socketid socket id + * @param {string} message message */ async failRes(socketid, message) { await app.io diff --git a/app/io/controller/tomatobang.ts b/app/io/controller/tomatobang.ts index dde1332..a17743f 100644 --- a/app/io/controller/tomatobang.ts +++ b/app/io/controller/tomatobang.ts @@ -1,15 +1,11 @@ 'use strict'; -/** - * TODO: - * 错误处理 - */ - +// TODO: TIME_OUT_PAIRS may not support mutil-server deploy const TIME_OUT_PAIRS = {}; import { Application, Controller } from 'egg'; module.exports = (app: Application) => { /** - * 消息订阅测试 + * TEST: redis message quene */ app.redis.on('message', (channel, message) => { console.log('Receive message %s from channel %s', message, channel); @@ -17,7 +13,7 @@ module.exports = (app: Application) => { class TBController extends Controller { /** - * 加载已有番茄钟 + * load current tomato list */ async loadTomato() { const obj = this.ctx.args[0]; @@ -25,7 +21,7 @@ module.exports = (app: Application) => { const { userid } = obj; const tomato = await app.redis.get(userid + ':tomato'); - // 需要事先移除关联的用户, 用户切换时有必要 + // remove old-user info as it may switch user at client end const old_userid = await app.redis.get(socket.id); await app.redis.srem(old_userid + ':socket', socket.id); await app.redis.sadd(userid + ':socket', socket.id); @@ -39,7 +35,7 @@ module.exports = (app: Application) => { } /** - * 开启番茄钟 + * start tomato */ async startTomato() { const obj = this.ctx.args[0]; @@ -48,7 +44,7 @@ module.exports = (app: Application) => { const { userid, tomato, countdown } = obj; tomato.startTime = new Date(); - // 添加过期处理机制, 过期后自动清空, 10s 用来确保番茄钟被保存 + // save toamto info. 10s after it finished await app.redis.set( userid + ':tomato', JSON.stringify(tomato), @@ -100,7 +96,7 @@ module.exports = (app: Application) => { } /** - * 中断番茄钟 + * tomato breaked */ async breakTomato() { const obj = this.ctx.args[0]; @@ -120,7 +116,6 @@ module.exports = (app: Application) => { const TIME_OUT_ID = TIME_OUT_PAIRS[userid + ':TIME_OUT_ID']; clearTimeout(TIME_OUT_ID); const result = await this.service.tomato.create(tomato_doing); - this.ctx.logger.info('创建一个TOMATO: UNFINISHED!'); await app.redis.del(userid + ':tomato'); if (result) { const socketList = await app.redis.smembers(userid + ':socket'); @@ -135,6 +130,9 @@ module.exports = (app: Application) => { } } + /** + * user disconnect + */ async disconnect() { const socket = this.ctx.socket; app.redis.get(socket.id).then(async userid => { @@ -147,7 +145,7 @@ module.exports = (app: Application) => { } /** - * 登出 + * user logout */ async logout() { const { ctx, app } = this; diff --git a/app/io/middleware/auth.ts b/app/io/middleware/auth.ts index 458184e..70f0798 100644 --- a/app/io/middleware/auth.ts +++ b/app/io/middleware/auth.ts @@ -11,6 +11,5 @@ module.exports = (app: Application) => { } else { ctx.socket.emit('verify_failed', {}); } - ctx.logger.info('disconnect!'); }; }; diff --git a/app/middleware/errorhandler.ts b/app/middleware/errorhandler.ts index cead907..131ccea 100644 --- a/app/middleware/errorhandler.ts +++ b/app/middleware/errorhandler.ts @@ -8,7 +8,7 @@ export default function errorhandlerMiddleware(option, app: Application) { } catch (err) { app.emit('error', err, this); const status = err.status || 500; - // 生产环境时 500 错误的详细错误内容不返回给客户端 + // error in production env should not show to users const error = status === 500 && app.env === 'prod' ? 'Internal Server Error' diff --git a/app/middleware/jwt.ts b/app/middleware/jwt.ts index 73d5109..7f7aff7 100644 --- a/app/middleware/jwt.ts +++ b/app/middleware/jwt.ts @@ -1,6 +1,6 @@ 'use strict'; /** - * 接口请求前验证 + * verify */ import { Context, Application } from 'egg'; @@ -44,7 +44,7 @@ export default function jwtMiddleware(option, app: Application) { console.log('当前用户:', reply); if (reply) { - // 若有登录则过期时间延长 + // prolong token app['redis'].expire(token, 3 * 24 * 60 * 60); const currentUser = JSON.parse(reply); ctx.request['currentUser'] = currentUser; diff --git a/app/middleware/ratelimit.ts b/app/middleware/ratelimit.ts index 798269a..2ef6cfb 100644 --- a/app/middleware/ratelimit.ts +++ b/app/middleware/ratelimit.ts @@ -1,13 +1,11 @@ 'use strict'; // app/middleware/ratelimit.js -// 参考:https://github.com/koajs/ratelimit +// refer:https://github.com/koajs/ratelimit import * as koaRatelimit from 'koa-ratelimit'; import { Application, Context } from 'egg'; import { BizConfig } from '../../config/config.default'; -/** - * 接口请求前验证 - */ + export default function ratelimitMiddleware( option: BizConfig['ratelimit'], app: Application @@ -23,7 +21,7 @@ export default function ratelimitMiddleware( db: app['redis'], duration: option.duration, errorMessage: option.errorMessage, - throw: option.throw, // 是否抛出异常 + throw: option.throw, // throw error id: ctx => ctx.ip, headers: { remaining: 'Rate-Limit-Remaining', From 59c6b6f4662c92ba12141525eb3ea44565e74a05 Mon Sep 17 00:00:00 2001 From: kobepeng Date: Wed, 11 Jul 2018 20:16:51 +0800 Subject: [PATCH 03/10] fix: module export to es6-way --- app/util/{jpush.js => jpush.ts} | 6 +++--- app/util/jwt.ts | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) rename app/util/{jpush.js => jpush.ts} (88%) diff --git a/app/util/jpush.js b/app/util/jpush.ts similarity index 88% rename from app/util/jpush.js rename to app/util/jpush.ts index ac1411b..a035e73 100644 --- a/app/util/jpush.js +++ b/app/util/jpush.ts @@ -1,14 +1,14 @@ 'use strict'; /** - * 极光推送服务 + * jpush util */ const JPush = require('jpush-sdk'); const jpushClient = JPush.buildClient( 'f240850b36aea20535b81df8', '189cbc42a1044b1ac2f2ddb1' ); -exports.pushMessage = (alias, alert, title) => { +export function pushMessage(alias, alert, title) { jpushClient .push() .setPlatform(JPush.ALL) @@ -25,4 +25,4 @@ exports.pushMessage = (alias, alert, title) => { console.log('Msg_id: ' + res.msg_id); } }); -}; +} diff --git a/app/util/jwt.ts b/app/util/jwt.ts index 9a58afe..a363066 100644 --- a/app/util/jwt.ts +++ b/app/util/jwt.ts @@ -1,13 +1,13 @@ 'use strict'; /** - * token 服务 + * token util */ import * as jwt from 'jsonwebtoken'; import config from '../../config/config.default'; const secret = config().token.tokenSecret; const expiresIn = config().token.tokenExpiresIn; -exports.tokenService = { +export default { createToken(userinfo) { const token = jwt.sign(userinfo, secret, { expiresIn, @@ -26,5 +26,5 @@ exports.tokenService = { return false; } }, - expiresIn, -}; + expiresIn +} From 9403512523f89d4894409a5b070317741f7fbbcb Mon Sep 17 00:00:00 2001 From: kobepeng Date: Wed, 11 Jul 2018 20:18:14 +0800 Subject: [PATCH 04/10] refactor: promise to aysnc/await --- app/io/controller/chat.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/app/io/controller/chat.ts b/app/io/controller/chat.ts index 38e613b..f971361 100644 --- a/app/io/controller/chat.ts +++ b/app/io/controller/chat.ts @@ -253,16 +253,17 @@ module.exports = (app: Application) => { async disconnect() { const { ctx, app } = this; const socket = ctx.socket; - app.redis.get('chat:socket:user:' + socket.id).then(async userid => { + const userid = await app.redis.get('chat:socket:user:' + socket.id); + if (userid) { this.clearUserInfo(ctx, socket, userid); - }); + } } /** * user logout */ async logout() { - const { ctx, app } = this; + const { ctx } = this; const socket = ctx.socket; const obj = ctx.args[0]; const { userid } = obj; From 73de02d782a08441c3f88933bff544db324be255 Mon Sep 17 00:00:00 2001 From: kobepeng Date: Wed, 11 Jul 2018 20:18:59 +0800 Subject: [PATCH 05/10] feat: add redis util --- app/util/redis.ts | 84 ++++++++++++++++++++++++++++++++++++++++++++++ typings/index.d.ts | 22 ++++++++++-- 2 files changed, 103 insertions(+), 3 deletions(-) create mode 100644 app/util/redis.ts diff --git a/app/util/redis.ts b/app/util/redis.ts new file mode 100644 index 0000000..7648e87 --- /dev/null +++ b/app/util/redis.ts @@ -0,0 +1,84 @@ +/** + * redis util + */ +import { Application } from 'egg'; + +const ChAT_USER_SOCKET_KEY_PREFIX = 'chat:user:socket:'; +const ChAT_SOCKET_USER_KEY_PREFIX = 'chat:socket:user:'; +const ChAT_USER_FRIENDS_KEY_PREFIX = 'chat:user:friends:'; + +export class RedisChatService { + async addUserSocket(app: Application, userid, socket) { + await app.redis.sadd(ChAT_USER_SOCKET_KEY_PREFIX + userid, socket.id); + } + + async findUserSocket(app: Application, userid) { + const userLoginEnds = await app.redis.smembers( + ChAT_USER_SOCKET_KEY_PREFIX + userid + ); + return userLoginEnds; + } + + async deleteUserSocket(app: Application, userid, socket) { + await app.redis.srem(ChAT_USER_SOCKET_KEY_PREFIX + userid, socket.id); + } + + async addSocketUser(app: Application, socket, userid) { + await app.redis.set(ChAT_SOCKET_USER_KEY_PREFIX + socket.id, userid); + } + + async findSocketUser(app: Application, socket) { + const userid = await app.redis.get(ChAT_SOCKET_USER_KEY_PREFIX + socket.id); + return userid; + } + + async deleteSocketUser(app: Application, socket) { + await app.redis.del(ChAT_SOCKET_USER_KEY_PREFIX + socket.id); + } + + async getUserFriends(app: Application, userid) { + const friends = await app.redis.zrange( + ChAT_USER_FRIENDS_KEY_PREFIX + userid, + 0, + -1, + 'WITHSCORES' + ); + + return friends; + } + + async addUserFriend(app: Application, userid, score, friendid) { + await app.redis.zadd( + ChAT_USER_FRIENDS_KEY_PREFIX + userid, + score, + friendid + ); + } + + async getUserFriendScore(app: Application, userid, friendid) { + const score = await app.redis.zscore( + ChAT_USER_FRIENDS_KEY_PREFIX + userid, + friendid + ); + + return score; + } + + async updateUserFriendScore(app: Application, userid, friendid, score) { + await app.redis.zincrby( + ChAT_USER_FRIENDS_KEY_PREFIX + userid, + score, + friendid + ); + } + + async deleteUserFriend(app: Application, userid) { + await app.redis.del(ChAT_USER_FRIENDS_KEY_PREFIX + userid); + } +} + +export const redisChatService = new RedisChatService(); + +export class RedisTomatoService {} + +export const redisTomatoService = new RedisTomatoService(); diff --git a/typings/index.d.ts b/typings/index.d.ts index 011b400..9a877da 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -1,9 +1,25 @@ +import { RedisChatService } from '../app/util/redis'; +import tokenService from '../app/util/jwt'; + declare module 'egg' { - // 扩展 app interface Application { redis: any; - mongoose:any; + mongoose: any; validator: any; - util: any; + util: { + redis: { + redisChatService: RedisChatService; + }; + jpush: { + pushMessage(alias, alert, title): any; + }; + jwt: { + tokenService: { + createToken(userinfo): any; + verifyToken(token): any; + expiresIn; + }; + }; + }; } } From 77870d224ea77e7c8ba708e7392eaee01eb37ef7 Mon Sep 17 00:00:00 2001 From: kobepeng Date: Fri, 13 Jul 2018 14:18:44 +0800 Subject: [PATCH 06/10] fix: wrong module refer --- app/util/jwt.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/app/util/jwt.ts b/app/util/jwt.ts index a363066..125d2d8 100644 --- a/app/util/jwt.ts +++ b/app/util/jwt.ts @@ -7,7 +7,8 @@ import * as jwt from 'jsonwebtoken'; import config from '../../config/config.default'; const secret = config().token.tokenSecret; const expiresIn = config().token.tokenExpiresIn; -export default { + +export const tokenService = { createToken(userinfo) { const token = jwt.sign(userinfo, secret, { expiresIn, @@ -26,5 +27,5 @@ export default { return false; } }, - expiresIn -} + expiresIn, +}; From 0bcd35a2643d9ccb759c0b987c65912629db3570 Mon Sep 17 00:00:00 2001 From: kobepeng Date: Fri, 13 Jul 2018 14:19:17 +0800 Subject: [PATCH 07/10] refactor: chat io with redis util --- app/io/controller/chat.ts | 122 +++++++++++++++++++++++++------------- 1 file changed, 82 insertions(+), 40 deletions(-) diff --git a/app/io/controller/chat.ts b/app/io/controller/chat.ts index f971361..b959135 100644 --- a/app/io/controller/chat.ts +++ b/app/io/controller/chat.ts @@ -25,17 +25,34 @@ module.exports = (app: Application) => { if (!userid) { this.failRes(socket.id, '用户编号不合法!'); } - const userLoginEnds = await app.redis.smembers( - 'chat:user:socket:' + userid + const userLoginEnds = await app.util.redis.redisChatService.findUserSocket( + app, + userid ); // save login info if (userLoginEnds && userLoginEnds.length > 0) { // TODO: support multi client login - await app.redis.sadd('chat:user:socket:' + userid, socket.id); - await app.redis.set('chat:socket:user:' + socket.id, userid); + await app.util.redis.redisChatService.addUserSocket( + app, + userid, + socket + ); + await app.util.redis.redisChatService.addSocketUser( + app, + socket, + userid + ); } else { - await app.redis.sadd('chat:user:socket:' + userid, socket.id); - await app.redis.set('chat:socket:user:' + socket.id, userid); + await app.util.redis.redisChatService.addUserSocket( + app, + userid, + socket + ); + await app.util.redis.redisChatService.addSocketUser( + app, + socket, + userid + ); // load friend list and set online state const friends = await this.ctx.service.userFriend.findAll( { sort: '{"response_time": -1 }' }, @@ -54,27 +71,40 @@ module.exports = (app: Application) => { } else { friendid = element.to.toString(); } - const fsockets = await app.redis.smembers( - 'chat:user:socket:' + friendid + const fsockets = await app.util.redis.redisChatService.findUserSocket( + app, + friendid ); if (fsockets && fsockets.length > 0) { - await app.redis.zadd('chat:user:friends:' + userid, 1, friendid); - const score = await app.redis.zscore( - 'chat:user:friends:' + friendid, + await app.util.redis.redisChatService.addUserFriend( + app, + userid, + 1, + friendid + ); + const score = await app.util.redis.redisChatService.getUserFriendScore( + app, + friendid, userid ); // update friend online list if (score === '0') { - await app.redis.zincrby( - 'chat:user:friends:' + friendid, - 1, - userid + await app.util.redis.redisChatService.updateUserFriendScore( + app, + friendid, + userid, + 1 ); // push message to friend this.notify(friendid, 'friend_online', { userid }); } } else { - await app.redis.zadd('chat:user:friends:' + userid, 0, friendid); + await app.util.redis.redisChatService.addUserFriend( + app, + userid, + 0, + friendid + ); } } } @@ -121,11 +151,9 @@ module.exports = (app: Application) => { this.failRes(socket.id, '用户编号不合法!'); } // load friend online states - const friends = await app.redis.zrange( - 'chat:user:friends:' + userid, - 0, - -1, - 'WITHSCORES' + const friends = await app.util.redis.redisChatService.getUserFriends( + app, + userid ); if (userid) { await app.io @@ -219,12 +247,13 @@ module.exports = (app: Application) => { } await ctx.service.userFriend.updateState(recordId, state); if (state === 2) { - const userLoginEnds = await app.redis.smembers( - 'chat:user:socket:' + to + const userLoginEnds = await app.util.redis.redisChatService.findUserSocket( + app, + to ); if (userLoginEnds && userLoginEnds.length > 0) { - await app.redis.zadd('chat:user:friends:' + from, 1, to); - await app.redis.zadd('chat:user:friends:' + to, 1, from); + await app.util.redis.redisChatService.addUserFriend(app, from, 1, to); + await app.util.redis.redisChatService.addUserFriend(app, to, 1, from); this.notify(to, 'new_added_friend', { friendid: from, state: 'online', @@ -234,7 +263,7 @@ module.exports = (app: Application) => { state: 'online', }); } else { - await app.redis.zadd('chat:user:friends:' + from, 0, to); + await app.util.redis.redisChatService.addUserFriend(app, from, 0, to); this.notify(from, 'new_added_friend', { friendid: to, state: 'offline', @@ -253,7 +282,10 @@ module.exports = (app: Application) => { async disconnect() { const { ctx, app } = this; const socket = ctx.socket; - const userid = await app.redis.get('chat:socket:user:' + socket.id); + const userid = await app.util.redis.redisChatService.findSocketUser( + app, + socket + ); if (userid) { this.clearUserInfo(ctx, socket, userid); } @@ -279,11 +311,9 @@ module.exports = (app: Application) => { async clearUserInfo(ctx, socket, userid) { ctx.logger.info('userid!', userid); if (userid) { - const friends = await app.redis.zrange( - 'chat:user:friends:' + userid, - 0, - -1, - 'WITHSCORES' + const friends = await app.util.redis.redisChatService.getUserFriends( + app, + userid ); let fid = ''; // update user online list @@ -293,20 +323,29 @@ module.exports = (app: Application) => { } // user online if (end === '1') { - const score = await app.redis.zscore( - 'chat:user:friends:' + fid, + const score = await app.util.redis.redisChatService.getUserFriendScore( + app, + fid, userid ); if (score !== 0) { - await app.redis.zincrby('chat:user:friends:' + fid, -1, userid); + await app.util.redis.redisChatService.updateUserFriendScore( + app, + fid, + userid, + -1 + ); } this.notify(fid, 'friend_offline', { userid }); } } - - await app.redis.del('chat:user:friends:' + userid); - await app.redis.srem('chat:user:socket:' + userid, socket.id); - await app.redis.del('chat:socket:user:' + socket.id); + await app.util.redis.redisChatService.deleteSocketUser(app, socket); + await app.util.redis.redisChatService.deleteUserSocket( + app, + userid, + socket + ); + await app.util.redis.redisChatService.deleteUserFriend(app, userid); } } @@ -317,7 +356,10 @@ module.exports = (app: Application) => { * @param {string} message message */ async notify(userid, evtName, message) { - const loginEnds = await app.redis.smembers('chat:user:socket:' + userid); + const loginEnds = await app.util.redis.redisChatService.findUserSocket( + app, + userid + ); if (loginEnds && loginEnds.length > 0) { for (const end of loginEnds) { if (end) { From f16a7997714e90cb2dc7854f8b9f641cac9b748c Mon Sep 17 00:00:00 2001 From: kobepeng Date: Mon, 16 Jul 2018 09:02:54 +0800 Subject: [PATCH 08/10] refactor: tb io with redis util --- app/io/controller/chat.ts | 100 ++++++--------------- app/io/controller/tomatobang.ts | 151 +++++++++++++++++--------------- app/util/redis.ts | 52 ++++++++++- typings/index.d.ts | 3 +- 4 files changed, 163 insertions(+), 143 deletions(-) diff --git a/app/io/controller/chat.ts b/app/io/controller/chat.ts index b959135..ecf00a8 100644 --- a/app/io/controller/chat.ts +++ b/app/io/controller/chat.ts @@ -25,34 +25,16 @@ module.exports = (app: Application) => { if (!userid) { this.failRes(socket.id, '用户编号不合法!'); } - const userLoginEnds = await app.util.redis.redisChatService.findUserSocket( - app, - userid - ); + const redisChatService = app.util.redis.redisChatService; + const userLoginEnds = await redisChatService.findUserSocket(app, userid); // save login info if (userLoginEnds && userLoginEnds.length > 0) { // TODO: support multi client login - await app.util.redis.redisChatService.addUserSocket( - app, - userid, - socket - ); - await app.util.redis.redisChatService.addSocketUser( - app, - socket, - userid - ); + await redisChatService.addUserSocket(app, userid, socket); + await redisChatService.addSocketUser(app, socket, userid); } else { - await app.util.redis.redisChatService.addUserSocket( - app, - userid, - socket - ); - await app.util.redis.redisChatService.addSocketUser( - app, - socket, - userid - ); + await redisChatService.addUserSocket(app, userid, socket); + await redisChatService.addSocketUser(app, socket, userid); // load friend list and set online state const friends = await this.ctx.service.userFriend.findAll( { sort: '{"response_time": -1 }' }, @@ -71,25 +53,20 @@ module.exports = (app: Application) => { } else { friendid = element.to.toString(); } - const fsockets = await app.util.redis.redisChatService.findUserSocket( + const fsockets = await redisChatService.findUserSocket( app, friendid ); if (fsockets && fsockets.length > 0) { - await app.util.redis.redisChatService.addUserFriend( - app, - userid, - 1, - friendid - ); - const score = await app.util.redis.redisChatService.getUserFriendScore( + await redisChatService.addUserFriend(app, userid, 1, friendid); + const score = await redisChatService.getUserFriendScore( app, friendid, userid ); // update friend online list if (score === '0') { - await app.util.redis.redisChatService.updateUserFriendScore( + await redisChatService.updateUserFriendScore( app, friendid, userid, @@ -99,12 +76,7 @@ module.exports = (app: Application) => { this.notify(friendid, 'friend_online', { userid }); } } else { - await app.util.redis.redisChatService.addUserFriend( - app, - userid, - 0, - friendid - ); + await redisChatService.addUserFriend(app, userid, 0, friendid); } } } @@ -151,10 +123,8 @@ module.exports = (app: Application) => { this.failRes(socket.id, '用户编号不合法!'); } // load friend online states - const friends = await app.util.redis.redisChatService.getUserFriends( - app, - userid - ); + const redisChatService = app.util.redis.redisChatService; + const friends = await redisChatService.getUserFriends(app, userid); if (userid) { await app.io .of('/chat') @@ -247,13 +217,11 @@ module.exports = (app: Application) => { } await ctx.service.userFriend.updateState(recordId, state); if (state === 2) { - const userLoginEnds = await app.util.redis.redisChatService.findUserSocket( - app, - to - ); + const redisChatService = app.util.redis.redisChatService; + const userLoginEnds = await redisChatService.findUserSocket(app, to); if (userLoginEnds && userLoginEnds.length > 0) { - await app.util.redis.redisChatService.addUserFriend(app, from, 1, to); - await app.util.redis.redisChatService.addUserFriend(app, to, 1, from); + await redisChatService.addUserFriend(app, from, 1, to); + await redisChatService.addUserFriend(app, to, 1, from); this.notify(to, 'new_added_friend', { friendid: from, state: 'online', @@ -263,7 +231,7 @@ module.exports = (app: Application) => { state: 'online', }); } else { - await app.util.redis.redisChatService.addUserFriend(app, from, 0, to); + await redisChatService.addUserFriend(app, from, 0, to); this.notify(from, 'new_added_friend', { friendid: to, state: 'offline', @@ -282,10 +250,8 @@ module.exports = (app: Application) => { async disconnect() { const { ctx, app } = this; const socket = ctx.socket; - const userid = await app.util.redis.redisChatService.findSocketUser( - app, - socket - ); + const redisChatService = app.util.redis.redisChatService; + const userid = await redisChatService.findSocketUser(app, socket); if (userid) { this.clearUserInfo(ctx, socket, userid); } @@ -310,11 +276,9 @@ module.exports = (app: Application) => { */ async clearUserInfo(ctx, socket, userid) { ctx.logger.info('userid!', userid); + const redisChatService = app.util.redis.redisChatService; if (userid) { - const friends = await app.util.redis.redisChatService.getUserFriends( - app, - userid - ); + const friends = await redisChatService.getUserFriends(app, userid); let fid = ''; // update user online list for (const end of friends) { @@ -323,13 +287,13 @@ module.exports = (app: Application) => { } // user online if (end === '1') { - const score = await app.util.redis.redisChatService.getUserFriendScore( + const score = await redisChatService.getUserFriendScore( app, fid, userid ); if (score !== 0) { - await app.util.redis.redisChatService.updateUserFriendScore( + await redisChatService.updateUserFriendScore( app, fid, userid, @@ -339,13 +303,9 @@ module.exports = (app: Application) => { this.notify(fid, 'friend_offline', { userid }); } } - await app.util.redis.redisChatService.deleteSocketUser(app, socket); - await app.util.redis.redisChatService.deleteUserSocket( - app, - userid, - socket - ); - await app.util.redis.redisChatService.deleteUserFriend(app, userid); + await redisChatService.deleteSocketUser(app, socket); + await redisChatService.deleteUserSocket(app, userid, socket); + await redisChatService.deleteUserFriend(app, userid); } } @@ -356,10 +316,8 @@ module.exports = (app: Application) => { * @param {string} message message */ async notify(userid, evtName, message) { - const loginEnds = await app.util.redis.redisChatService.findUserSocket( - app, - userid - ); + const redisChatService = app.util.redis.redisChatService; + const loginEnds = await redisChatService.findUserSocket(app, userid); if (loginEnds && loginEnds.length > 0) { for (const end of loginEnds) { if (end) { diff --git a/app/io/controller/tomatobang.ts b/app/io/controller/tomatobang.ts index a17743f..7013bc1 100644 --- a/app/io/controller/tomatobang.ts +++ b/app/io/controller/tomatobang.ts @@ -19,13 +19,13 @@ module.exports = (app: Application) => { const obj = this.ctx.args[0]; const socket = this.ctx.socket; const { userid } = obj; - - const tomato = await app.redis.get(userid + ':tomato'); + const redisTomatoService = app.util.redis.redisTomatoService; + const tomato = await redisTomatoService.findUserTomato(app, userid); // remove old-user info as it may switch user at client end - const old_userid = await app.redis.get(socket.id); - await app.redis.srem(old_userid + ':socket', socket.id); - await app.redis.sadd(userid + ':socket', socket.id); - await app.redis.set(socket.id, userid); + const old_userid = await redisTomatoService.findSocketUser(app, socket); + await redisTomatoService.deleteUserSocket(app, old_userid, socket); + await redisTomatoService.addUserSocket(app, userid, socket); + await redisTomatoService.addSocketUser(app, socket, userid); console.log('send load tomato', tomato); await app.io @@ -39,40 +39,30 @@ module.exports = (app: Application) => { */ async startTomato() { const obj = this.ctx.args[0]; - const socket = this.ctx.socket; this.ctx.logger.info('start_tomato', obj); const { userid, tomato, countdown } = obj; tomato.startTime = new Date(); - // save toamto info. 10s after it finished - await app.redis.set( - userid + ':tomato', + // save toamto info until it finished +10s + const redisTomatoService = app.util.redis.redisTomatoService; + await redisTomatoService.addUserTomato( + app, + userid, JSON.stringify(tomato), - 'EX', countdown * 60 + 10 ); - - let TIME_OUT_ID = TIME_OUT_PAIRS[userid + ':TIME_OUT_ID']; - if (TIME_OUT_ID) { - clearTimeout(TIME_OUT_ID); - } - TIME_OUT_ID = setTimeout( + this.clearTomatoTimeout(userid); + const TIME_OUT_ID = setTimeout( async userid => { - let tomato = await app.redis.get(userid + ':tomato'); + let tomato = await redisTomatoService.findUserTomato(app, userid); if (tomato) { tomato = JSON.parse(tomato); } tomato.endTime = new Date(); tomato.succeed = 1; await this.service.tomato.create(tomato); - await app.redis.del(userid + ':tomato'); - const socketList = await app.redis.smembers(userid + ':socket'); - for (const item of socketList) { - await app.io - .of('/tomatobang') - .to(item) - .emit('new_tomate_added', tomato); - } + await redisTomatoService.deleteUserTomato(app, userid); + this.notify(userid, 'new_tomate_added', tomato); app.util.jpush.pushMessage( userid, '你完成了一个番茄钟', @@ -83,16 +73,7 @@ module.exports = (app: Application) => { userid ); TIME_OUT_PAIRS[userid + ':TIME_OUT_ID'] = TIME_OUT_ID; - - const socketList = await app.redis.smembers(userid + ':socket'); - for (const so of socketList) { - if (so !== socket.id) { - await app.io - .of('/tomatobang') - .to(so) - .emit('other_end_start_tomato', tomato); - } - } + this.notify(userid, 'other_end_start_tomato', tomato); } /** @@ -100,33 +81,24 @@ module.exports = (app: Application) => { */ async breakTomato() { const obj = this.ctx.args[0]; - const socket = this.ctx.socket; const { userid, tomato } = obj; - - let tomato_doing = await app.redis.get(userid + ':tomato'); - if (!tomato_doing) { + const redisTomatoService = app.util.redis.redisTomatoService; + let tomato_ongoing = await redisTomatoService.findUserTomato(app, userid); + if (!tomato_ongoing) { return; } - tomato_doing = JSON.parse(tomato_doing); - tomato_doing.endTime = new Date(); - tomato_doing.succeed = 0; - tomato_doing.breakReason = tomato.breakReason; + tomato_ongoing = JSON.parse(tomato_ongoing); + tomato_ongoing.endTime = new Date(); + tomato_ongoing.succeed = 0; + tomato_ongoing.breakReason = tomato.breakReason; const TIME_OUT_ID = TIME_OUT_PAIRS[userid + ':TIME_OUT_ID']; clearTimeout(TIME_OUT_ID); - const result = await this.service.tomato.create(tomato_doing); - await app.redis.del(userid + ':tomato'); + const result = await this.service.tomato.create(tomato_ongoing); + await redisTomatoService.deleteUserTomato(app, userid); if (result) { - const socketList = await app.redis.smembers(userid + ':socket'); - for (const so of socketList) { - if (so !== socket.id) { - await app.io - .of('/tomatobang') - .to(so) - .emit('other_end_break_tomato', tomato_doing); - } - } + this.notify(userid, 'other_end_break_tomato', tomato_ongoing); } } @@ -135,13 +107,14 @@ module.exports = (app: Application) => { */ async disconnect() { const socket = this.ctx.socket; - app.redis.get(socket.id).then(async userid => { - this.ctx.logger.info('userid!', userid); - if (userid) { - await app.redis.srem(userid + ':socket', socket.id); - await app.redis.del(socket.id); - } - }); + const redisTomatoService = app.util.redis.redisTomatoService; + const userid = await redisTomatoService.findSocketUser(app, socket); + this.ctx.logger.info('userid!', userid); + if (userid) { + await redisTomatoService.deleteUserSocket(app, userid, socket); + await redisTomatoService.deleteSocketUser(app, socket); + this.clearTomatoTimeout(userid); + } } /** @@ -150,16 +123,54 @@ module.exports = (app: Application) => { async logout() { const { ctx, app } = this; const socket = ctx.socket; + const redisTomatoService = app.util.redis.redisTomatoService; // TODO: username to userid - // const obj = ctx.args[0]; - // const { userid } = obj; - app.redis.get(socket.id).then(async userid => { - this.ctx.logger.info('userid!', userid); - if (userid) { - await app.redis.srem(userid + ':socket', socket.id); - await app.redis.del(socket.id); + const userid = await redisTomatoService.findSocketUser(app, socket); + this.ctx.logger.info('userid!', userid); + if (userid) { + await redisTomatoService.deleteUserSocket(app, userid, socket); + await redisTomatoService.deleteSocketUser(app, socket); + this.clearTomatoTimeout(userid); + } + } + + /** + * send message + * @param {string} userid userid + * @param {string} evtName socket.io event name + * @param {string} message message + */ + async notify(userid, evtName, message) { + const loginEnds = await this.findUserSocket(userid); + if (loginEnds && loginEnds.length > 0) { + for (const end of loginEnds) { + if (end) { + await app.io + .of('/tomatobang') + .to(end) + .emit(evtName, message); + } } - }); + } + } + + /** + * util: find user sockets + * @param userid user id + */ + async findUserSocket(userid) { + const socketList = await app.util.redis.redisTomatoService.findUserSocket( + app, + userid + ); + return socketList; + } + + clearTomatoTimeout(userid) { + let TIME_OUT_ID = TIME_OUT_PAIRS[userid + ':TIME_OUT_ID']; + if (TIME_OUT_ID) { + clearTimeout(TIME_OUT_ID); + } } } return TBController; diff --git a/app/util/redis.ts b/app/util/redis.ts index 7648e87..918d068 100644 --- a/app/util/redis.ts +++ b/app/util/redis.ts @@ -79,6 +79,56 @@ export class RedisChatService { export const redisChatService = new RedisChatService(); -export class RedisTomatoService {} + +const TB_USER_SOCKET_KEY_PREFIX = 'tb:user:socket:'; +const TB_SOCKET_USER_KEY_PREFIX = 'tb:socket:user:'; +const TB_USER_TOMATO_KEY_PREFIX = 'tb:user:tomato:'; +export class RedisTomatoService { + async addUserSocket(app: Application, userid, socket) { + await app.redis.sadd(TB_USER_SOCKET_KEY_PREFIX + userid, socket.id); + } + + async findUserSocket(app: Application, userid) { + const userLoginEnds = await app.redis.smembers( + TB_USER_SOCKET_KEY_PREFIX + userid + ); + return userLoginEnds; + } + + async deleteUserSocket(app: Application, userid, socket) { + await app.redis.srem(TB_USER_SOCKET_KEY_PREFIX + userid, socket.id); + } + + async addSocketUser(app: Application, socket, userid) { + await app.redis.set(TB_SOCKET_USER_KEY_PREFIX + socket.id, userid); + } + + async findSocketUser(app: Application, socket) { + const userid = await app.redis.get(TB_SOCKET_USER_KEY_PREFIX + socket.id); + return userid; + } + + async deleteSocketUser(app: Application, socket) { + await app.redis.del(TB_SOCKET_USER_KEY_PREFIX + socket.id); + } + + async addUserTomato(app: Application, userid, tomato, EX) { + await app.redis.set( + TB_USER_TOMATO_KEY_PREFIX + userid, + tomato, + 'EX', + EX + ); + } + + async findUserTomato(app: Application, userid) { + const tomato = await app.redis.get(TB_USER_TOMATO_KEY_PREFIX + userid); + return tomato; + } + + async deleteUserTomato(app: Application, userid) { + await app.redis.del(TB_USER_TOMATO_KEY_PREFIX + userid); + } +} export const redisTomatoService = new RedisTomatoService(); diff --git a/typings/index.d.ts b/typings/index.d.ts index 9a877da..899c66c 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -1,4 +1,4 @@ -import { RedisChatService } from '../app/util/redis'; +import { RedisChatService, RedisTomatoService } from '../app/util/redis'; import tokenService from '../app/util/jwt'; declare module 'egg' { @@ -9,6 +9,7 @@ declare module 'egg' { util: { redis: { redisChatService: RedisChatService; + redisTomatoService: RedisTomatoService; }; jpush: { pushMessage(alias, alert, title): any; From c8ec5c2afe927ee341d3d798342b1db79d688333 Mon Sep 17 00:00:00 2001 From: kobepeng Date: Wed, 18 Jul 2018 19:16:09 +0800 Subject: [PATCH 09/10] feat: init rsmq --- app/util/rsmq.ts | 62 ++++++++++++++++++++++++++++++++++++++++++++++++ package.json | 11 +++++---- 2 files changed, 68 insertions(+), 5 deletions(-) create mode 100644 app/util/rsmq.ts diff --git a/app/util/rsmq.ts b/app/util/rsmq.ts new file mode 100644 index 0000000..5103216 --- /dev/null +++ b/app/util/rsmq.ts @@ -0,0 +1,62 @@ +/** + * remq d.ts see: https://github.com/smrchy/rsmq/blob/master/index.d.ts + */ + +import * as RedisSMQ from 'rsmq'; +let rsmq = new RedisSMQ({ host: '127.0.0.1', port: 6379, ns: 'rsmq' }); + +export const mqUtil = { + create: (name: string): Promise => { + return new Promise((resolve, reject) => { + rsmq.createQueue({ qname: name }, (err, resp) => { + if (err) { + reject(err); + } + if (resp === 1) { + resolve(true); + console.log('queue created'); + } + }); + }); + }, + + send: (name, msg): Promise => { + return new Promise((resolve, reject) => { + rsmq.sendMessage( + { + message: msg, + qname: name, + }, + (err, mesgID) => { + if (err) { + reject(err); + } + if (mesgID) { + resolve(mesgID); + console.log('Message sent. ID:', mesgID); + } + } + ); + }); + }, + + receive: (name): Promise => { + return new Promise((resolve, reject) => { + rsmq.receiveMessage( + { qname: name }, + (err, resp: RedisSMQ.QueueMessage) => { + if (err) { + reject(err); + } + if (resp.id) { + resolve(resp); + console.log('Message received.', resp); + } else { + resolve(''); + console.log('No messages for me...'); + } + } + ); + }); + }, +}; diff --git a/package.json b/package.json index dfe19c7..bd6d704 100644 --- a/package.json +++ b/package.json @@ -42,12 +42,14 @@ "dependencies": { "bcryptjs": "^2.4.3", "co": "^4.6.0", + "egg": "^2.8.1", "egg-alinode": "^2.0.1", "egg-cors": "^2.0.0", "egg-mock": "^3.14.0", "egg-mongoose": "^2.1.1", "egg-redis": "^1.0.2", "egg-scripts": "^2.5.0", + "egg-sequelize": "^3.1.4", "egg-socket.io": "^4.0.8", "egg-static": "^2.0.0", "egg-validate": "^1.0.0", @@ -57,16 +59,15 @@ "jsonwebtoken": "^8.1.0", "koa-ratelimit": "^4.0.0", "koa-send": "^4.1.2", + "moment": "^2.20.1", "qiniu": "^7.1.1", + "rsmq": "^0.9.1", + "snyk": "^1.82.1", "socket.io-client": "^2.0.4", - "egg": "^2.8.1", - "egg-sequelize": "^3.1.4", - "moment": "^2.20.1", "source-map-support": "^0.5.0", "tslib": "^1.8.1", "typescript": "^2.8.0", - "uuid": "^3.2.1", - "snyk": "^1.82.1" + "uuid": "^3.2.1" }, "devDependencies": { "autod": "^3.0.1", From a4033bfc2f7a14b31da4e16a164b679daa6fa5e4 Mon Sep 17 00:00:00 2001 From: kobepeng Date: Thu, 19 Jul 2018 20:43:07 +0800 Subject: [PATCH 10/10] feat: add rsmq-worker --- app/util/rsmq.ts | 57 ++++++++++++++++++++++++++++++++++++++++++++++-- package.json | 1 + 2 files changed, 56 insertions(+), 2 deletions(-) diff --git a/app/util/rsmq.ts b/app/util/rsmq.ts index 5103216..01cb9ce 100644 --- a/app/util/rsmq.ts +++ b/app/util/rsmq.ts @@ -1,9 +1,10 @@ /** * remq d.ts see: https://github.com/smrchy/rsmq/blob/master/index.d.ts */ - +import { Application } from 'egg'; import * as RedisSMQ from 'rsmq'; -let rsmq = new RedisSMQ({ host: '127.0.0.1', port: 6379, ns: 'rsmq' }); +const RSMQWorker = require('rsmq-worker'); +const rsmq = new RedisSMQ({ host: '127.0.0.1', port: 6379, ns: 'rsmq' }); export const mqUtil = { create: (name: string): Promise => { @@ -59,4 +60,56 @@ export const mqUtil = { ); }); }, + + listen: (name, app: Application) => { + var worker = new RSMQWorker(name); + + worker.on('message', async (msg, next, id) => { + console.log('Message id : ' + id); + console.log(msg); + /** + * msg: + * { + * evtName, + * message, + * } + */ + await notify(name, msg.evtName, msg.messagge); + + next(); + }); + + worker.on('error', (err, msg) => { + console.log('ERROR', err, msg.id); + }); + worker.on('exceeded', msg => { + console.log('EXCEEDED', msg.id); + }); + worker.on('timeout', msg => { + console.log('TIMEOUT', msg.id, msg.rc); + }); + + worker.start(); + + /** + * send message + * @param {string} userid userid + * @param {string} evtName socket.io event name + * @param {string} message message + */ + async function notify(userid, evtName, message) { + const redisChatService = app.util.redis.redisChatService; + const loginEnds = await redisChatService.findUserSocket(app, userid); + if (loginEnds && loginEnds.length > 0) { + for (const end of loginEnds) { + if (end) { + await app.io + .of('/chat') + .to(end) + .emit(evtName, message); + } + } + } + } + }, }; diff --git a/package.json b/package.json index bd6d704..c20e07e 100644 --- a/package.json +++ b/package.json @@ -62,6 +62,7 @@ "moment": "^2.20.1", "qiniu": "^7.1.1", "rsmq": "^0.9.1", + "rsmq-worker": "^0.5.2", "snyk": "^1.82.1", "socket.io-client": "^2.0.4", "source-map-support": "^0.5.0",