/* * @Author: ch * @Date: 2022-05-18 14:54:47 * @LastEditors: ch * @LastEditTime: 2022-05-21 15:27:05 * @Description: file content */ import { CreateUUID, FormatDate, ToAsyncAwait } from "@/common/utils"; const connect = Symbol('connect'), send = Symbol('send'), onResponse = Symbol('onResponse'), onMessage = Symbol('onMessage'), updateData = Symbol('updateData') ; export default class MsbIm { option = { ioKey : 'traceId', reconnect: true, logout : false } socket = null; queue = {}; interceptors = { dataChangeBefore: null, dataChangeAfter: null, onLogout : null, onMessage: null }; sessionData = []; curSessionId = null; constructor(option) { this.option = { ...this.option, ...option } } /** * 创建连接返回一个Promise 创建成功并成功打开连接算连接成功 * @param {*} option */ [connect](option) { return new Promise((resolve, reject) => { this.socket = uni.connectSocket({ ...option, fail(e){ reject(e); } }); this.socket.onOpen(() => { this.socket.onMessage(async (res) => { const result = JSON.parse(res.data); // 401主动退出 if (result.code === 401) { this.logout(); return false; } this.interceptors.onMessage && this.interceptors.onMessage(result); // 处理服务端主动推送的消息 this[onMessage](result); // 如果再消息堆里有此消息回调,则执行回调,并删除 const cbk = this.queue[result[this.option.ioKey]]; if (cbk) { cbk(result.code !== 200 ? {error:result} : {result:result}); delete this.queue[result[this.option.ioKey]]; } }) resolve(this.socket); }); this.socket.onClose(() => { if (this.option.reconnect && !this.option.logout) { this[connect](); } this.option.logout = false; }); }); } /** * 向服务端发送消息||请求,返回一个Promise对象,收到ioKey对应的消息会算一个同步完成 * @param {*} data */ [send](data) { return new Promise((resolve, reject) => { this.queue[data[this.option.ioKey]] = ({result, error}) => { if (result) { resolve(result); } else { reject(error); } }; this.socket.send({ data : JSON.stringify(data), fail(e) { reject({error : e}); } }); }) } /** * 服务端推送消息,只处理服务端主动推送的消息 * @param {*} data */ [onMessage](data) { // 判断非服务端主动推送消息不做处理 if (data[this.option.ioKey] || data.code !== 200) { return false; } let ctx = data.content; ctx.payload = JSON.parse(ctx.payload || {}); let historyData = this.sessionData, newData = []; const hisIndex = historyData.findIndex(i => i.id === ctx.sessionId); if(hisIndex >= 0){ // 存在会话往现有会话增加一条消息,并修改最后一条消息为当前消息 const curHisData = historyData[hisIndex]; curHisData.messageList.push(ctx); curHisData.lastMessage = ctx; // 不在当前会话窗口则向会话消息加1条未读 if(ctx.sessionId !== this.curSessionId){ curHisData.unreadCount++; } newData = historyData; }else{ // 会话列表不存在,则创建一个会话 newData = [...historyData, { fromAvatar : ctx.fromAvatar, fromId : ctx.fromId, fromNickname : ctx.fromNickname, id : ctx.id, lastMessage : ctx, messageList : [ctx], unreadCount : 1 }] } } init (config) { return new Promise((resolve, reject) => { const heart = () => { setTimeout(async () => { await this[send]({ traceId: CreateUUID(), traceType: '0', content: { text: "ping" } }).catch((e)=>{}); heart(); },5000) } this[connect]({ ...config, }).then(() => { heart(); resolve(this); }).catch((e)=>{}); }) } logout() { this.option.logout = true; this.socket.close(); this.interceptors.onLogout && this.interceptors.onLogout(); } /** * 设置数据 */ setSessionData(data) { this.interceptors.dataChangeBefore && this.interceptors.dataChangeBefore(data, this.sessionData); this.sessionData = data; this.interceptors.dataChangeAfter && this.interceptors.dataChangeAfter(this.sessionData); } /** * 设置当前聊天窗口 * Data为Session数据 * @param {*} data */ setCurSessionId(id) { this.curSessionId = id; } /** * 获取会话列表 * @param {*} params */ async getSessionList(params) { let {error, result} = await ToAsyncAwait(this[send]({ traceId: CreateUUID(), traceType : 1, ...params })); if (error) { return Promise.reject(error); } const { content } = result; content.sessionVOS.forEach(item => { if (item.lastMessage) { item.lastMessage.payload = JSON.parse(item.lastMessage.payload || {}); } let historyData = this.sessionData; let hisIndex = historyData.findIndex(i => i.id === item.id); if(hisIndex >= 0){ historyData[hisIndex].lastMessage = item.lastMessage; historyData[hisIndex].unreadCount++; this.setSessionData(historyData) }else{ item.messageList = []; const newData = [...historyData, item] this.setSessionData(newData); } }); return Promise.resolve(result); } /** * 获取会话的历史消息记录 * @param {*} params */ async getHistoryMsg(params) { const {error, result} = await ToAsyncAwait(this[send]({ traceId: CreateUUID(), traceType: 23, ...params })); if (error) { return Promise.reject(error); } const { content } = result; if (content.length) { let newData = this.sessionData; const hisIdx = newData.findIndex(i => i.id === content[0].sessionId); content.forEach(item => { item.payload = JSON.parse(item.payload) }) newData[hisIdx].messageList = newData[hisIdx].messageList.concat(content); this.setSessionData(newData); } return Promise.resolve(result); } /** * 会话已读 * @param {*} params */ async setRead (params){ await this[send]({ traceId : CreateUUID(), traceType : "6", ...params }); for (let item of this.sessionData) { if (item.sessionId === params.content.sessionId) { item.unreadCount = 0; break; } } } /** * 发送消息 * @param {*} params */ async sendMsg(params) { let curSession = this.sessionData.find(i => i.id === this.curSessionId); curSession.messageList.push({ ...params.content, fromId: params.fromId, createTimeStamp : (new Date()).getTime(), sendStatus : 'loading' }); const { error, result } = await ToAsyncAwait(this[send]({ traceId: CreateUUID(), traceType: 20, ...params })); for (let item of curSession.messageList) { if (item[this.option.ioKey] === params[this.option.ioKey]) { item.sendStatus = error ? 'fail' : 'success'; break; } } if (error) { return Promise.reject(error); } return Promise.resolve(result); } /** * 主动创建会话 * @param {*} params */ async createSession (params){ const { result, error } = await ToAsyncAwait(this[send]({ traceId : CreateUUID(), traceType : 21, ...params })); if (error) { return Promise.reject(error); } const { content } = result; let historyData = this.sessionData; let curSession = historyData.find(i => i.id === content.id); if (!curSession) { curSession = { ...content, unreadCount: 0, messageList : [] } const newData = [...historyData, curSession]; this.setSessionData(newData); } return Promise.resolve(result); } }