socket接入

im
dylanmay 2024-11-12 09:11:08 +08:00
parent 755bf1bb08
commit 5feb3e6815
2 changed files with 222 additions and 0 deletions

View File

@ -0,0 +1,199 @@
import { defineStore } from 'pinia'
import { ref, onUnmounted } from 'vue'
import { getRefreshToken } from '@/utils/auth'
import { useChatStore } from './chatstore'
import {
ContentType,
ImMessageContent,
ImMessageReceiveResponse,
WEBSOCKET_MESSAGE_TYPE_ENUM
} from '../types/types'
import TextMessage from '../model/TextMessage'
import { debug } from 'console'
import { useUserStore } from '@/store/modules/user'
interface Message {
type: string
data: any
}
enum ImConversationTypeEnum {
SINGLE = 1,
GROUP = 2
// Add other conversation types if needed
}
export function generateConversationNo(
fromUserId: number,
receiverId: number,
conversationType: number
): string | null {
if (conversationType === ImConversationTypeEnum.SINGLE) {
return `s_${fromUserId}_${receiverId}`
} else if (conversationType === ImConversationTypeEnum.GROUP) {
return `g_${receiverId}`
}
return null
}
export const useWebSocketStore = defineStore('webSocket', () => {
const socket = ref<WebSocket | null>(null)
const messages = ref<Message[]>([])
const isConnected = ref(false)
let reconnectTimer: ReturnType<typeof setTimeout> | null = null
let heartbeatTimer: ReturnType<typeof setInterval> | null = null
// 初始化 WebSocket 连接
function connect() {
const refreshToken = getRefreshToken()
// 设置 WebSocket URL
if (refreshToken) {
console.log('refreshToken null')
}
const url = `ws://localhost:48080/infra/ws?token=${refreshToken}`
socket.value = new WebSocket(url)
socket.value.onopen = () => {
isConnected.value = true
console.log('WebSocket connected')
startHeartbeat()
}
// {"type":"im-message-receive",
// "content":
// "{\
// "id\":239,\
// "conversationType\":1,\
// "senderId\":144,\
// "senderNickname\":\"dylan\",\
// "senderAvatar\":\"http://192.168.0.208:48083/admin-api/infra/file/4/get/c34f9521ce6a2e21148f16b73ab652e578b5bb572dbc259a5043f754c19c8a3f.png\",\
// "receiverId\":1,\
// "contentType\":101,\
// "content\":\"111\",\
// "sendTime\":1731139168438,\
// "sequence\":2}"
// }
socket.value.onmessage = (event) => {
if (event.data === 'pong') {
return
}
try {
const websoketMessage = JSON.parse(event.data) as ImMessageReceiveResponse
if (websoketMessage.type === WEBSOCKET_MESSAGE_TYPE_ENUM.IM_MESSAGE_RECEIVE.toString()) {
const socketChatMessage = JSON.parse(websoketMessage.content) as ImMessageContent
// 暂不处理自己发送的消息
if (socketChatMessage.senderId === useUserStore().user.id) {
return
}
if (socketChatMessage.contentType === ContentType.TEXT) {
const chatStore = useChatStore()
const localTextMessage = TextMessage.fromWebsocket(socketChatMessage)
chatStore.addMessageToConversation(localTextMessage)
} else if (socketChatMessage.contentType === ContentType.IMAGE) {
} else if (socketChatMessage.contentType === ContentType.AUDIO) {
}
} else {
// TODO:[dylan]
}
console.log('Received message:', websoketMessage)
} catch (error) {
console.info(error)
}
// messages.value.push(message)
}
socket.value.onclose = () => {
isConnected.value = false
console.log('WebSocket disconnected')
reconnect()
}
socket.value.onerror = (error) => {
console.error('WebSocket error:', error)
isConnected.value = false
reconnect()
}
}
// 发送消息
function sendMessage(message: Message) {
if (socket.value && isConnected.value) {
socket.value.send(JSON.stringify(message))
}
}
/**
*
*/
function sendHeartBeat() {
if (socket.value && isConnected.value) {
socket.value.send('ping')
}
}
// 断开 WebSocket 连接
function disconnect() {
if (socket.value) {
socket.value.close()
socket.value = null
}
stopHeartbeat()
clearTimeout(reconnectTimer!)
}
// 自动重连逻辑
function reconnect() {
stopHeartbeat()
if (reconnectTimer) clearTimeout(reconnectTimer)
reconnectTimer = setTimeout(() => {
console.log('Reconnecting WebSocket...')
connect()
}, 3000) // 3秒后重连
}
// 启动心跳
function startHeartbeat() {
if (heartbeatTimer) clearInterval(heartbeatTimer)
heartbeatTimer = setInterval(() => {
if (socket.value && isConnected.value) {
sendHeartBeat()
console.log('Heartbeat sent')
}
}, 5000) // 每5秒发送一次心跳
}
// 停止心跳
function stopHeartbeat() {
if (heartbeatTimer) {
clearInterval(heartbeatTimer)
heartbeatTimer = null
}
}
// 自动断开连接,清理资源
onUnmounted(() => {
disconnect()
})
return {
connect,
disconnect,
sendMessage,
messages,
isConnected,
generateConversationNo
}
})

View File

@ -34,6 +34,29 @@ export const enum CONVERSATION_TYPE {
NOTIFICATION = 4 NOTIFICATION = 4
} }
export enum WEBSOCKET_MESSAGE_TYPE_ENUM {
IM_MESSAGE_RECEIVE = 'im-message-receive'
}
export type MessageModelType = BaseMessage | TextMessage | ImageMessage export type MessageModelType = BaseMessage | TextMessage | ImageMessage
export type ConversationModelType = BaseConversation | ChatConversation export type ConversationModelType = BaseConversation | ChatConversation
export type ConversationType = CONVERSATION_TYPE export type ConversationType = CONVERSATION_TYPE
export type ImMessageReceiveResponse = {
type: WEBSOCKET_MESSAGE_TYPE_ENUM
content: string
};
export type ImMessageContent = {
id: number;
conversationType: number;
senderId: number;
senderNickname: string;
senderAvatar: string;
receiverId: number;
contentType: number;
content: string;
sendTime: number; // Use `Date` if you'd prefer the time to be a `Date` object
sequence: number;
}