/app/extend/context.js
// app/extend/context.js var qr = require('qr-image'); module.exports = { // 成功提示 apiSuccess(data = '', msg = 'ok', code = 200) { this.body = { msg, data }; this.status = code; }, // 失败提示 apiFail(data = '', msg = 'fail', code = 400) { this.body = { msg, data }; this.status = code; }, // 生成token getToken(value) { return this.app.jwt.sign(value, this.app.config.jwt.secret); }, // 验证token checkToken(token) { return this.app.jwt.verify(token, this.app.config.jwt.secret); }, // 发送或者存到消息队列中 async sendAndSaveMessage(to_id, message, msg = 'ok') { const { app, service } = this; let current_user_id = this.authUser.id; // 拿到接受用户所在子进程 let pid = await service.cache.get('online_' + to_id); if (pid) { // 消息推送 app.messenger.sendTo(pid, 'send', { to_id, message, msg }); // 存到历史记录当中 if (msg === 'ok') { service.cache.setList(`chatlog_${to_id}_${message.chat_type}_${current_user_id}`, message); } } else { service.cache.setList('getmessage_' + to_id, { message, msg }); } // 拿到对方的socket // let socket = app.ws.user[to_id]; // 验证对方是否在线?不在线记录到待接收消息队列中;在线,消息推送,存储到对方的聊天记录中 chatlog_对方用户id_user_当前用户id // if (app.ws.user && app.ws.user[to_id]) { // // 消息推送 // app.ws.user[to_id].send(JSON.stringify({ // msg, // data: message // })); // // 存到历史记录当中 // if (msg === 'ok') { // service.cache.setList(`chatlog_${to_id}_${message.chat_type}_${current_user_id}`, message); // } // } else { // service.cache.setList('getmessage_' + to_id, { // message, // msg // }); // } }, // 发送消息 async send(to_id, message, msg = 'ok') { const { app, service } = this; let current_user_id = this.authUser.id; // 拿到接受用户所在子进程 let pid = await service.cache.get('online_' + to_id); if (pid) { // 消息推送 app.messenger.sendTo(pid, 'send', { to_id, message, msg }); } }, // 生成二维码 qrcode(url){ var img = qr.image(url,{size:10}); this.response.type = 'image/png'; this.body = img; }, // 生成唯一id genID(length) { return Number(Math.random().toString().substr(3, length) + Date.now()).toString(36); }, // 用户上线 async online(user_id) { const { service, app } = this; let pid = process.pid; // 下线其他设备 let opid = await service.cache.get('online_' + user_id); if (opid) { // 通知对应进程用户下线 app.messenger.sendTo(opid, 'offline', user_id); } // 存储上线状态 service.cache.set('online_' + user_id, pid); } };
/app/controller/chat.js
// app/controller/chat.js const Controller = require('egg').Controller; class ChatController extends Controller { // 连接socket async connect() { const { ctx, app, service } = this; if (!ctx.websocket) { ctx.throw(400, '非法访问'); } // console.log(`clients: ${app.ws.clients.size}`); // 监听接收消息和关闭socket ctx.websocket .on('message', msg => { // console.log('接收消息', msg); }) .on('close', (code, reason) => { // 用户下线 console.log('用户下线', code, reason); let user_id = ctx.websocket.user_id; // 移除redis中的用户上线记录 service.cache.remove('online_' + user_id); if (app.ws.user && app.ws.user[user_id]) { delete app.ws.user[user_id]; } }); } // 发送消息 async send() { const { ctx, app, service } = this; // 拿到当前用户id let current_user_id = ctx.authUser.id; // 验证参数 ctx.validate({ to_id: { type: 'int', required: true, desc: '接收人/群id' }, chat_type: { type: 'string', required: true, range: { in: ['user', 'group'] }, desc: '接收类型' }, type: { type: 'string', required: true, range: { in: ['text', 'image', 'video', 'audio', 'emoticon', 'card'] }, desc: '消息类型' }, data: { type: 'string', required: true, desc: '消息内容' }, options: { type: 'string', required: true } }); // 获取参数 let { to_id, chat_type, type, data, options } = ctx.request.body; // 单聊 if (chat_type === 'user') { // 验证好友是否存在,并且对方没有把你拉黑 let Friend = await app.model.Friend.findOne({ where: { user_id: to_id, friend_id: current_user_id, isblack: 0 }, include: [{ model: app.model.User, as: "userInfo" }, { model: app.model.User, as: "friendInfo" }] }); if (!Friend) { return ctx.apiFail('对方不存在或者已经把你拉黑'); } // 验证好友是否被禁用 if (!Friend.userInfo.status) { return ctx.apiFail('对方已被禁用'); } // 构建消息格式 let from_name = Friend.friendInfo.nickname ? Friend.friendInfo.nickname : Friend.friendInfo.username; if (Friend.nickname) { from_name = Friend.nickname; } let message = { id: (new Date()).getTime(), // 唯一id,后端生成唯一id from_avatar: Friend.friendInfo.avatar,// 发送者头像 from_name, // 发送者昵称 from_id: current_user_id, // 发送者id to_id, // 接收人/群 id to_name: Friend.userInfo.nickname ? Friend.userInfo.nickname : Friend.userInfo.username, // 接收人/群 名称 to_avatar: Friend.userInfo.avatar, // 接收人/群 头像 chat_type: 'user', // 接收类型 type,// 消息类型 data, // 消息内容 options: {}, // 其他参数 create_time: (new Date()).getTime(), // 创建时间 isremove: 0, // 是否撤回 } // 视频,截取封面 if (message.type === 'video') { message.options.poster = message.data + '?x-oss-process=video/snapshot,t_10,m_fast,w_300,f_png'; } // 音频,带上音频时长 if (message.type === 'audio') { options = JSON.parse(options); message.options.time = options.time || 1; } // 名片 if (message.type === 'card') { // 验证名片用户是否存在 message.options = JSON.parse(options) } ctx.sendAndSaveMessage(to_id, message); // 存储到自己的聊天记录中 chatlog_当前用户id_user_对方用户id service.cache.setList(`chatlog_${current_user_id}_${message.chat_type}_${to_id}`, message); // 返回成功 return ctx.apiSuccess(message); } // 群聊 // 验证群聊是否存在,且你是否在该群中 let group = await app.model.Group.findOne({ where: { status: 1, id: to_id }, include: [{ model: app.model.GroupUser, attributes: ['user_id', 'nickname'] }] }); if (!group) { return ctx.apiFail('该群聊不存在或者已被封禁'); } let index = group.group_users.findIndex(item => item.user_id === current_user_id); if (index === -1) { return ctx.apiFail('你不是该群的成员'); } // 组织数据格式 let from_name = group.group_users[index].nickname; let message = { id: (new Date()).getTime(), // 唯一id,后端生成唯一id from_avatar: ctx.authUser.avatar,// 发送者头像 from_name: from_name || ctx.authUser.nickname || ctx.authUser.username, // 发送者昵称 from_id: current_user_id, // 发送者id to_id, // 接收人/群 id to_name: group.name, // 接收人/群 名称 to_avatar: group.avatar, // 接收人/群 头像 chat_type: 'group', // 接收类型 type,// 消息类型 data, // 消息内容 options: {}, // 其他参数 create_time: (new Date()).getTime(), // 创建时间 isremove: 0, // 是否撤回 group: group } // 视频,截取封面 if (message.type === 'video') { message.options.poster = message.data + '?x-oss-process=video/snapshot,t_10,m_fast,w_300,f_png'; } // 音频,带上音频时长 if (message.type === 'audio') { options = JSON.parse(options); message.options.time = options.time || 1; } // 名片 if (message.type === 'card') { // 验证名片用户是否存在 message.options = JSON.parse(options) } // 推送消息 group.group_users.forEach(item => { if (item.user_id !== current_user_id) { ctx.sendAndSaveMessage(item.user_id, message); } }); ctx.apiSuccess(message); } // 获取离线消息 async getmessage() { const { ctx, app, service } = this; let current_user_id = ctx.authUser.id; let key = 'getmessage_' + current_user_id; let list = await service.cache.getList(key); // 清除离线消息 await service.cache.remove(key); // 批量推送 list.forEach(async (message) => { let d = JSON.parse(message); ctx.sendAndSaveMessage(current_user_id, d.message, d.msg); }); } // 撤回 async recall() { const { ctx, app } = this; let current_user_id = ctx.authUser.id; ctx.validate({ to_id: { type: 'int', required: true, desc: '接收人/群id' }, chat_type: { type: 'string', required: true, range: { in: ['user', 'group'] }, desc: '接收类型' }, id: { type: 'int', required: true, desc: '消息id' } }); let { to_id, chat_type, id } = ctx.request.body; let message = { from_id: current_user_id, to_id, chat_type, id } // 单聊 if (chat_type === 'user') { ctx.sendAndSaveMessage(to_id, message, 'recall'); return ctx.apiSuccess(message); } // 群聊 let group = await app.model.Group.findOne({ where: { id: to_id, status: 1 }, include: [{ model: app.model.GroupUser, attributes: ['user_id'] }] }); if (group) { group.group_users.forEach(item => { if (item.user_id !== current_user_id) { ctx.sendAndSaveMessage(item.user_id, message, 'recall'); } }); } return ctx.apiSuccess(message); } } module.exports = ChatController;
感谢大家观看,我们下次见