|
|
/*
|
|
|
* @Author: ch
|
|
|
* @Date: 2022-05-18 14:54:47
|
|
|
* @LastEditors: ch
|
|
|
* @LastEditTime: 2022-05-21 19:32:49
|
|
|
* @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
|
|
|
}]
|
|
|
}
|
|
|
this.setSessionData(newData)
|
|
|
|
|
|
}
|
|
|
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
|
|
|
});
|
|
|
let newData = this.sessionData.map(item => {
|
|
|
if (item.id == params.content.sessionId) {
|
|
|
item.unreadCount = 0;
|
|
|
}
|
|
|
return item;
|
|
|
});
|
|
|
|
|
|
this.setSessionData(newData);
|
|
|
}
|
|
|
/**
|
|
|
* 发送消息
|
|
|
* @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);
|
|
|
}
|
|
|
|
|
|
|
|
|
} |