652 lines
21 KiB
JavaScript
652 lines
21 KiB
JavaScript
import axios from 'axios';
|
|
import { appConfig } from '@/config';
|
|
|
|
function randomId() {
|
|
if (crypto && crypto.randomUUID) {
|
|
return crypto.randomUUID().replaceAll('-', '');
|
|
}
|
|
return `${Date.now()}${Math.random().toString(16).slice(2)}`;
|
|
}
|
|
|
|
function getAllowedDevice(mobile) {
|
|
const allowedDevices = {
|
|
'18301902119': '67072d37062c4f31b1165073552933ba',
|
|
'18301902118': 'de89fb2f2a61480a8c381f6c16e28bd8',
|
|
'18301902117': 'd117f480faa64145b6162107b1b49617'
|
|
};
|
|
return allowedDevices[mobile] || '';
|
|
}
|
|
|
|
function getUniqueEquipment(mobile, fallback) {
|
|
return getAllowedDevice(mobile) || localStorage.getItem('uniqueEquipment') || fallback;
|
|
}
|
|
|
|
function normalizeStatus(message) {
|
|
if (message.direction !== 0) {
|
|
return 'sent';
|
|
}
|
|
if (message.status === 0 || message.status === 'sending') {
|
|
return 'sending';
|
|
}
|
|
if (message.status === 2 || message.status === 'failed' || message.status === -1) {
|
|
return 'failed';
|
|
}
|
|
return 'sent';
|
|
}
|
|
|
|
function sendErrorText(errorCode) {
|
|
const messages = {
|
|
'-1': '连接不可用或发送超时',
|
|
1: '密钥不匹配',
|
|
2: '无效数据',
|
|
4: '服务端错误',
|
|
6: 'token错误',
|
|
7: '账号被踢下线',
|
|
8: '用户被禁用',
|
|
9: '不在群组中',
|
|
10: '无效消息',
|
|
22: '服务未授权',
|
|
28: 'WebSocket未配置',
|
|
30: '服务器时间不同步',
|
|
245: '用户被拉黑',
|
|
246: '在黑名单中',
|
|
247: '禁止发送消息',
|
|
248: '无权限',
|
|
249: '服务端超时',
|
|
250: '发送过于频繁',
|
|
251: '参数无效',
|
|
253: '目标不存在',
|
|
254: '服务未实现'
|
|
};
|
|
return messages[errorCode] || `错误码 ${errorCode}`;
|
|
}
|
|
|
|
function resolveConversationTarget(conversation) {
|
|
if (!conversation) {
|
|
return '';
|
|
}
|
|
return conversation.target
|
|
|| conversation.raw?.target
|
|
|| String(conversation.id || '').replace(/^single-/, '').replace(/^0-/, '').replace(/-0$/, '');
|
|
}
|
|
|
|
export class ImClient {
|
|
constructor() {
|
|
this.listeners = new Map();
|
|
this.connected = false;
|
|
this.currentUser = null;
|
|
this.sdkReady = false;
|
|
this.sdk = null;
|
|
this.sdkModules = null;
|
|
this.sdkEventsBound = false;
|
|
this.pendingOutgoingMessages = new Map();
|
|
this.loginClientId = '';
|
|
}
|
|
|
|
getClientId() {
|
|
if (this.sdkReady && this.sdk) {
|
|
return this.sdk.getClientId();
|
|
}
|
|
let clientId = localStorage.getItem(appConfig.clientIdStorageKey);
|
|
if (!clientId) {
|
|
clientId = randomId();
|
|
localStorage.setItem(appConfig.clientIdStorageKey, clientId);
|
|
}
|
|
return clientId;
|
|
}
|
|
|
|
getSdkVersion() {
|
|
if (!this.sdkReady || !this.sdk || typeof this.sdk.getVersion !== 'function') {
|
|
return '';
|
|
}
|
|
return this.sdk.getVersion() || '';
|
|
}
|
|
|
|
prepareClientIdForLogin(mobile) {
|
|
const pinnedClientId = getAllowedDevice(mobile) || localStorage.getItem('uniqueEquipment') || '';
|
|
if (pinnedClientId) {
|
|
sessionStorage.setItem('clientId', pinnedClientId);
|
|
localStorage.setItem('clientId', pinnedClientId);
|
|
localStorage.setItem(appConfig.clientIdStorageKey, pinnedClientId);
|
|
this.loginClientId = pinnedClientId;
|
|
return pinnedClientId;
|
|
}
|
|
|
|
this.loginClientId = this.getClientId();
|
|
return this.loginClientId;
|
|
}
|
|
|
|
restoreClientId(clientId) {
|
|
if (!clientId) {
|
|
return;
|
|
}
|
|
sessionStorage.setItem('clientId', clientId);
|
|
localStorage.setItem('clientId', clientId);
|
|
localStorage.setItem(appConfig.clientIdStorageKey, clientId);
|
|
this.loginClientId = clientId;
|
|
}
|
|
|
|
async loginWithPassword(mobile, password) {
|
|
const deviceId = this.prepareClientIdForLogin(mobile);
|
|
await this.ensureSdk();
|
|
const url = `${appConfig.appServer}/login_pwd`;
|
|
const sdkClientId = this.getClientId();
|
|
if (sdkClientId !== deviceId) {
|
|
console.warn('[im] clientId mismatch before login', { deviceId, sdkClientId });
|
|
}
|
|
const response = await axios.post(url, {
|
|
mobile,
|
|
password,
|
|
platform: appConfig.platform,
|
|
clientId: deviceId,
|
|
uniqueEquipment: deviceId
|
|
}, { withCredentials: false });
|
|
|
|
this.persistAppToken(url, response);
|
|
if (response.data?.code !== 0) {
|
|
throw new Error(response.data?.message || '登录失败');
|
|
}
|
|
return response.data.result;
|
|
}
|
|
|
|
async requestAuthCode(mobile) {
|
|
const response = await axios.post(`${appConfig.appServer}/send_code`, { mobile }, { withCredentials: false });
|
|
if (response.data?.code !== 0) {
|
|
throw new Error(response.data?.message || '验证码发送失败');
|
|
}
|
|
return response.data.result;
|
|
}
|
|
|
|
async loginWithCode(mobile, code) {
|
|
const deviceId = this.prepareClientIdForLogin(mobile);
|
|
await this.ensureSdk();
|
|
const url = `${appConfig.appServer}/login`;
|
|
const sdkClientId = this.getClientId();
|
|
if (sdkClientId !== deviceId) {
|
|
console.warn('[im] clientId mismatch before login', { deviceId, sdkClientId });
|
|
}
|
|
const response = await axios.post(url, {
|
|
mobile,
|
|
code,
|
|
platform: appConfig.platform,
|
|
clientId: deviceId,
|
|
uniqueEquipment: deviceId
|
|
}, { withCredentials: false });
|
|
|
|
this.persistAppToken(url, response);
|
|
if (response.data?.code !== 0) {
|
|
throw new Error(response.data?.message || '登录失败');
|
|
}
|
|
return response.data.result;
|
|
}
|
|
|
|
async connect(userId, token) {
|
|
this.currentUser = { userId, token };
|
|
await this.ensureSdk();
|
|
console.info('[im] connect', {
|
|
userId,
|
|
clientId: this.getClientId(),
|
|
configuredClientId: this.loginClientId || localStorage.getItem(appConfig.clientIdStorageKey) || ''
|
|
});
|
|
this.sdk.connect(userId, token);
|
|
this.emit('connectionStatusChanged', { connected: false, statusText: '连接中' });
|
|
}
|
|
|
|
disconnect() {
|
|
if (this.sdkReady && this.sdk) {
|
|
this.sdk.disconnect();
|
|
}
|
|
this.connected = false;
|
|
this.currentUser = null;
|
|
this.emit('connectionStatusChanged', { connected: false });
|
|
}
|
|
|
|
sendTextMessage(conversation, text, initialMessage = null) {
|
|
const target = resolveConversationTarget(conversation);
|
|
const rawConversation = conversation.raw || this.createRawSingleConversation(target);
|
|
if (this.sdkReady && this.sdk && rawConversation) {
|
|
const { TextMessageContent } = this.sdkModules;
|
|
const content = new TextMessageContent(text);
|
|
console.info('[im] send text', {
|
|
conversationId: conversation.id,
|
|
target: rawConversation.target,
|
|
type: rawConversation.type,
|
|
line: rawConversation.line,
|
|
connected: this.connected
|
|
});
|
|
this.sdk.sendConversationMessage(
|
|
rawConversation,
|
|
content,
|
|
[],
|
|
(messageId, timestamp) => {
|
|
if (initialMessage) {
|
|
this.pendingOutgoingMessages.set(String(messageId), {
|
|
...initialMessage,
|
|
sdkMessageId: String(messageId),
|
|
sdkTimestamp: Number(timestamp || Date.now())
|
|
});
|
|
}
|
|
console.info('[im] send prepared', {
|
|
conversationId: conversation.id,
|
|
target: rawConversation.target,
|
|
messageId,
|
|
timestamp
|
|
});
|
|
if (!initialMessage) {
|
|
this.emit('messageSent', this.mapOutgoingMessage(conversation.id, messageId, timestamp, text, 'sending'));
|
|
}
|
|
},
|
|
null,
|
|
(messageUid, timestamp) => {
|
|
console.info('[im] send success', {
|
|
conversationId: conversation.id,
|
|
target: rawConversation.target,
|
|
messageUid,
|
|
timestamp
|
|
});
|
|
this.emit('messageStatusChanged', {
|
|
...(initialMessage || {}),
|
|
conversationId: conversation.id,
|
|
id: initialMessage?.id || String(messageUid || randomId()),
|
|
messageUid,
|
|
timestamp: initialMessage?.timestamp || Number(timestamp || Date.now()),
|
|
displayTimestamp: initialMessage?.displayTimestamp || initialMessage?.timestamp || Number(timestamp || Date.now()),
|
|
status: 'sent'
|
|
});
|
|
},
|
|
errorCode => {
|
|
const failedMessage = {
|
|
...(initialMessage || {}),
|
|
conversationId: conversation.id,
|
|
id: initialMessage?.id || randomId(),
|
|
text,
|
|
direction: 'out',
|
|
type: 'text',
|
|
status: 'failed',
|
|
errorCode,
|
|
error: sendErrorText(errorCode)
|
|
};
|
|
this.updatePendingOutgoingMessage(failedMessage);
|
|
console.error('[im] send failed', {
|
|
conversationId: conversation.id,
|
|
target: rawConversation.target,
|
|
connected: this.connected,
|
|
errorCode,
|
|
error: sendErrorText(errorCode)
|
|
});
|
|
this.emit('messageStatusChanged', failedMessage);
|
|
}
|
|
);
|
|
return null;
|
|
}
|
|
|
|
const message = {
|
|
id: randomId(),
|
|
conversationId: conversation.id,
|
|
from: this.currentUser?.userId || 'me',
|
|
direction: 'out',
|
|
type: 'text',
|
|
text,
|
|
status: 'failed',
|
|
timestamp: Date.now(),
|
|
error: rawConversation ? 'SDK未就绪' : `会话目标无效:${target || '空'}`
|
|
};
|
|
this.emit('messageSent', message);
|
|
return message;
|
|
}
|
|
|
|
getConversationList() {
|
|
if (!this.sdkReady || !this.sdk) {
|
|
return [];
|
|
}
|
|
const { ConversationType } = this.sdkModules;
|
|
return this.sdk.getConversationList(
|
|
[ConversationType.Single, ConversationType.Group, ConversationType.Channel],
|
|
[0]
|
|
).map(item => this.mapConversationInfo(item));
|
|
}
|
|
|
|
refreshConversationList() {
|
|
const conversations = this.getConversationList();
|
|
this.emit('conversationsChanged', conversations);
|
|
return conversations;
|
|
}
|
|
|
|
getMessages(conversation, count = 30) {
|
|
const rawConversation = conversation.raw || this.createRawSingleConversation(resolveConversationTarget(conversation));
|
|
if (!this.sdkReady || !this.sdk || !rawConversation) {
|
|
return [];
|
|
}
|
|
return this.sdk.getMessages(rawConversation, 0, true, count).map(message => this.mapMessage(message));
|
|
}
|
|
|
|
async fetchRemoteMessages(conversation, limit = 50) {
|
|
if (!conversation?.id || !this.currentUser?.userId) {
|
|
return this.getMessages(conversation, limit);
|
|
}
|
|
const response = await axios.post(appConfig.messagesApi, {
|
|
userId: this.currentUser.userId,
|
|
target: resolveConversationTarget(conversation),
|
|
limit
|
|
}, { withCredentials: false });
|
|
|
|
if (response.data?.code !== 0) {
|
|
throw new Error(response.data?.message || '消息同步失败');
|
|
}
|
|
|
|
return (response.data?.result?.messages || []).map(message => ({
|
|
...message,
|
|
displayTimestamp: message.displayTimestamp || message.timestamp,
|
|
conversationId: conversation.id
|
|
}));
|
|
}
|
|
|
|
on(eventName, handler) {
|
|
if (!this.listeners.has(eventName)) {
|
|
this.listeners.set(eventName, new Set());
|
|
}
|
|
this.listeners.get(eventName).add(handler);
|
|
return () => this.off(eventName, handler);
|
|
}
|
|
|
|
off(eventName, handler) {
|
|
this.listeners.get(eventName)?.delete(handler);
|
|
}
|
|
|
|
emit(eventName, payload) {
|
|
this.listeners.get(eventName)?.forEach(handler => handler(payload));
|
|
}
|
|
|
|
updatePendingOutgoingMessage(message) {
|
|
if (!message?.id) {
|
|
return;
|
|
}
|
|
this.pendingOutgoingMessages.forEach((pendingMessage, sdkMessageId) => {
|
|
if (pendingMessage.id === message.id) {
|
|
this.pendingOutgoingMessages.set(sdkMessageId, {
|
|
...pendingMessage,
|
|
...message,
|
|
sdkMessageId
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
mapSdkStatusMessage(message) {
|
|
const mappedMessage = this.mapMessage(message);
|
|
if (message.direction !== 0 || !message.messageId) {
|
|
return mappedMessage;
|
|
}
|
|
const sdkMessageId = String(message.messageId);
|
|
const pendingMessage = this.pendingOutgoingMessages.get(sdkMessageId);
|
|
if (!pendingMessage) {
|
|
return mappedMessage;
|
|
}
|
|
const nextMessage = {
|
|
...pendingMessage,
|
|
...mappedMessage,
|
|
id: pendingMessage.id,
|
|
conversationId: pendingMessage.conversationId || mappedMessage.conversationId,
|
|
text: pendingMessage.text || mappedMessage.text,
|
|
timestamp: pendingMessage.timestamp || mappedMessage.timestamp,
|
|
displayTimestamp: pendingMessage.displayTimestamp || mappedMessage.displayTimestamp,
|
|
sdkMessageId,
|
|
errorCode: mappedMessage.errorCode || pendingMessage.errorCode,
|
|
error: mappedMessage.error || pendingMessage.error
|
|
};
|
|
this.pendingOutgoingMessages.set(sdkMessageId, nextMessage);
|
|
if (nextMessage.status === 'sent') {
|
|
window.setTimeout(() => this.pendingOutgoingMessages.delete(sdkMessageId), 60000);
|
|
}
|
|
return nextMessage;
|
|
}
|
|
|
|
async ensureSdk() {
|
|
if (this.sdkReady || appConfig.sdkMode !== 'wildfire') {
|
|
return;
|
|
}
|
|
|
|
const wfcModule = await import('legacy-wfc/client/wfc');
|
|
const configModule = await import('legacy-config');
|
|
const eventModule = await import('legacy-wfc/client/wfcEvent');
|
|
const connectionStatusModule = await import('legacy-wfc/client/connectionStatus');
|
|
const conversationTypeModule = await import('legacy-wfc/model/conversationType');
|
|
const conversationModule = await import('legacy-wfc/model/conversation');
|
|
const textMessageModule = await import('legacy-wfc/messages/textMessageContent');
|
|
|
|
const Config = configModule.default;
|
|
Config.APP_SERVER = appConfig.appServer;
|
|
Config.USE_WSS = appConfig.useWss;
|
|
Config.ROUTE_PORT = appConfig.imRoutePort;
|
|
Config.WS_PATH = appConfig.wsPath;
|
|
Config.HTTP_IM_PREFIX_PATH = '';
|
|
Config.HTTP_UPLOAD_PREFIX_PATH = '';
|
|
Config.CLIENT_ID_STRATEGY = 2;
|
|
|
|
this.sdk = wfcModule.default;
|
|
this.sdkModules = {
|
|
EventType: eventModule.default,
|
|
ConnectionStatus: connectionStatusModule.default,
|
|
ConversationType: conversationTypeModule.default,
|
|
Conversation: conversationModule.default,
|
|
TextMessageContent: textMessageModule.default
|
|
};
|
|
|
|
this.bindSdkEvents();
|
|
this.sdk.init();
|
|
this.sdkReady = true;
|
|
}
|
|
|
|
bindSdkEvents() {
|
|
if (this.sdkEventsBound) {
|
|
return;
|
|
}
|
|
this.sdkEventsBound = true;
|
|
const { EventType, ConnectionStatus } = this.sdkModules;
|
|
this.sdk.eventEmitter.on(EventType.ConnectionStatusChanged, status => {
|
|
const connected = status === ConnectionStatus.ConnectionStatusConnected;
|
|
this.connected = connected;
|
|
this.emit('connectionStatusChanged', {
|
|
connected,
|
|
status,
|
|
statusText: ConnectionStatus.desc(status) || '连接状态变化'
|
|
});
|
|
if (connected || status === ConnectionStatus.ConnectionStatusReceiveing) {
|
|
window.setTimeout(() => this.refreshConversationList(), 0);
|
|
}
|
|
});
|
|
this.sdk.eventEmitter.on(EventType.ConversationInfoUpdate, () => {
|
|
this.refreshConversationList();
|
|
});
|
|
this.sdk.eventEmitter.on(EventType.FriendListUpdate, () => {
|
|
this.emit('contactsChanged', this.getContactList(true));
|
|
});
|
|
this.sdk.eventEmitter.on(EventType.UserInfosUpdate, () => {
|
|
this.emit('contactsChanged', this.getContactList(false));
|
|
});
|
|
this.sdk.eventEmitter.on(EventType.MessageStatusUpdate, message => {
|
|
this.emit('messageStatusChanged', this.mapSdkStatusMessage(message));
|
|
});
|
|
this.sdk.eventEmitter.on(EventType.ReceiveMessage, message => {
|
|
this.emit('messageReceived', this.mapMessage(message));
|
|
this.refreshConversationList();
|
|
});
|
|
}
|
|
|
|
mapConversationInfo(info) {
|
|
const conversation = info.conversation;
|
|
const id = `${conversation.type}-${conversation.target}-${conversation.line}`;
|
|
const title = this.getConversationTitle(info);
|
|
return {
|
|
id,
|
|
type: conversation.type,
|
|
title,
|
|
subtitle: info.lastMessage ? this.messageDigest(info.lastMessage) : '',
|
|
unread: info.unreadCount?.unread || info.unreadCount || 0,
|
|
avatarText: title.slice(0, 1).toUpperCase(),
|
|
updatedAt: Number(info.timestamp || info.lastMessage?.timestamp || Date.now()),
|
|
raw: conversation,
|
|
rawInfo: info
|
|
};
|
|
}
|
|
|
|
getContactList(refresh = false) {
|
|
if (!this.sdkReady || !this.sdk) {
|
|
return [];
|
|
}
|
|
const friendIds = this.sdk.getMyFriendList(refresh) || [];
|
|
if (!friendIds.length) {
|
|
return [];
|
|
}
|
|
const userInfos = this.sdk.getUserInfos(friendIds, '') || [];
|
|
return userInfos.map(userInfo => {
|
|
return this.mapContact(userInfo.uid, null, userInfo);
|
|
}).sort((a, b) => a.title.localeCompare(b.title, 'zh-CN'));
|
|
}
|
|
|
|
async getServerContactList(userId) {
|
|
if (!userId) {
|
|
return [];
|
|
}
|
|
const response = await axios.post(appConfig.contactsApi, { userId }, { withCredentials: false });
|
|
if (response.data?.code !== 0) {
|
|
throw new Error(response.data?.message || '联系人加载失败');
|
|
}
|
|
return (response.data?.result?.contacts || []).map(item => {
|
|
return this.mapContact(item.uid, { alias: item.alias }, {
|
|
uid: item.uid,
|
|
displayName: item.displayName,
|
|
name: item.name,
|
|
mobile: item.mobile,
|
|
portrait: item.portrait,
|
|
friendAlias: item.alias
|
|
});
|
|
}).sort((a, b) => a.title.localeCompare(b.title, 'zh-CN'));
|
|
}
|
|
|
|
refreshContactList() {
|
|
const contacts = this.getContactList(true);
|
|
this.emit('contactsChanged', contacts);
|
|
return contacts;
|
|
}
|
|
|
|
createRawSingleConversation(userId) {
|
|
if (!userId || !this.sdkModules?.Conversation || !this.sdkModules?.ConversationType) {
|
|
return null;
|
|
}
|
|
const { Conversation, ConversationType } = this.sdkModules;
|
|
return new Conversation(ConversationType.Single, userId, 0);
|
|
}
|
|
|
|
createSingleConversation(userId) {
|
|
if (!this.sdkReady || !this.sdk) {
|
|
const title = userId;
|
|
return {
|
|
id: `single-${userId}`,
|
|
type: 'single',
|
|
target: userId,
|
|
title,
|
|
subtitle: '',
|
|
unread: 0,
|
|
avatarText: title.slice(0, 1).toUpperCase(),
|
|
updatedAt: Date.now(),
|
|
raw: null
|
|
};
|
|
}
|
|
const { ConversationType } = this.sdkModules;
|
|
const raw = this.createRawSingleConversation(userId);
|
|
const info = this.sdk.getConversationInfo(raw);
|
|
return info ? this.mapConversationInfo(info) : {
|
|
id: `${ConversationType.Single}-${userId}-0`,
|
|
type: ConversationType.Single,
|
|
target: userId,
|
|
title: this.sdk.getUserDisplayName(userId),
|
|
subtitle: '',
|
|
unread: 0,
|
|
avatarText: this.sdk.getUserDisplayName(userId).slice(0, 1).toUpperCase(),
|
|
updatedAt: Date.now(),
|
|
raw
|
|
};
|
|
}
|
|
|
|
mapContact(userId, friend, userInfo) {
|
|
const title = userInfo?.friendAlias || friend?.alias || userInfo?.displayName || userInfo?.name || userId;
|
|
return {
|
|
id: userId,
|
|
uid: userId,
|
|
title,
|
|
subtitle: userInfo?.mobile || userInfo?.name || userId,
|
|
portrait: userInfo?.portrait || '',
|
|
avatarText: title.slice(0, 1).toUpperCase(),
|
|
alias: friend?.alias || userInfo?.friendAlias || '',
|
|
rawFriend: friend,
|
|
rawUser: userInfo
|
|
};
|
|
}
|
|
|
|
getConversationTitle(info) {
|
|
const conversation = info.conversation;
|
|
if (conversation._target?._displayName) {
|
|
return conversation._target._displayName;
|
|
}
|
|
if (conversation.type === this.sdkModules.ConversationType.Single) {
|
|
return this.sdk.getUserDisplayName(conversation.target);
|
|
}
|
|
if (conversation.type === this.sdkModules.ConversationType.Group) {
|
|
return this.sdk.getGroupInfo(conversation.target)?.name || conversation.target;
|
|
}
|
|
return conversation.target;
|
|
}
|
|
|
|
mapMessage(message) {
|
|
return {
|
|
id: String(message.messageId || message.messageUid || randomId()),
|
|
messageUid: message.messageUid,
|
|
conversationId: message.conversation ? `${message.conversation.type}-${message.conversation.target}-${message.conversation.line}` : '',
|
|
from: message.from,
|
|
direction: message.direction === 0 ? 'out' : 'in',
|
|
type: 'text',
|
|
text: this.messageDigest(message),
|
|
status: normalizeStatus(message),
|
|
timestamp: Number(message.timestamp || Date.now()),
|
|
displayTimestamp: Number(message.timestamp || Date.now()),
|
|
raw: message
|
|
};
|
|
}
|
|
|
|
mapOutgoingMessage(conversationId, messageId, timestamp, text, status) {
|
|
return {
|
|
id: String(messageId || randomId()),
|
|
conversationId,
|
|
from: this.currentUser?.userId || 'me',
|
|
direction: 'out',
|
|
type: 'text',
|
|
text,
|
|
status,
|
|
timestamp: Number(timestamp || Date.now())
|
|
};
|
|
}
|
|
|
|
messageDigest(message) {
|
|
if (!message?.messageContent) {
|
|
return '';
|
|
}
|
|
if (message.messageContent.content) {
|
|
return message.messageContent.content;
|
|
}
|
|
if (typeof message.messageContent.digest === 'function') {
|
|
return message.messageContent.digest(message);
|
|
}
|
|
return '[暂不支持的消息]';
|
|
}
|
|
|
|
persistAppToken(url, response) {
|
|
const appToken = response.headers?.authtoken || response.headers?.authToken;
|
|
if (appToken) {
|
|
localStorage.setItem(appConfig.authTokenStoragePrefix + new URL(url).host, appToken);
|
|
}
|
|
}
|
|
}
|
|
|
|
export const imClient = new ImClient();
|