初始化项目

This commit is contained in:
2026-02-08 22:38:13 +08:00
commit 334d2c6312
201 changed files with 32724 additions and 0 deletions

View File

@@ -0,0 +1,257 @@
/**
* WebSocket Client Helper
*
* Provides a simple interface for WebSocket connections
*/
class WebSocketClient {
constructor(url, options = {}) {
this.url = url
this.ws = null
this.reconnectAttempts = 0
this.maxReconnectAttempts = options.maxReconnectAttempts || 5
this.reconnectInterval = options.reconnectInterval || 3000
this.reconnectDelay = options.reconnectDelay || 1000
this.heartbeatInterval = options.heartbeatInterval || 30000
this.heartbeatTimer = null
this.isManualClose = false
this.isConnecting = false
// Event handlers
this.onOpen = options.onOpen || null
this.onMessage = options.onMessage || null
this.onError = options.onError || null
this.onClose = options.onClose || null
// Message handlers
this.messageHandlers = new Map()
}
/**
* Connect to WebSocket server
*/
connect() {
if (this.isConnecting || (this.ws && this.ws.readyState === WebSocket.OPEN)) {
return
}
this.isConnecting = true
this.isManualClose = false
try {
this.ws = new WebSocket(this.url)
this.ws.onopen = (event) => {
console.log('WebSocket connected', event)
this.isConnecting = false
this.reconnectAttempts = 0
// Start heartbeat
this.startHeartbeat()
// Call onOpen handler
if (this.onOpen) {
this.onOpen(event)
}
}
this.ws.onmessage = (event) => {
try {
const message = JSON.parse(event.data)
console.log('WebSocket message received', message)
// Handle different message types
this.handleMessage(message)
// Call onMessage handler
if (this.onMessage) {
this.onMessage(message, event)
}
} catch (error) {
console.error('Failed to parse WebSocket message', error)
}
}
this.ws.onerror = (error) => {
console.error('WebSocket error', error)
this.isConnecting = false
// Stop heartbeat
this.stopHeartbeat()
// Call onError handler
if (this.onError) {
this.onError(error)
}
}
this.ws.onclose = (event) => {
console.log('WebSocket closed', event)
this.isConnecting = false
// Stop heartbeat
this.stopHeartbeat()
// Call onClose handler
if (this.onClose) {
this.onClose(event)
}
// Attempt to reconnect if not manually closed
if (!this.isManualClose && this.reconnectAttempts < this.maxReconnectAttempts) {
this.reconnect()
}
}
} catch (error) {
console.error('Failed to create WebSocket connection', error)
this.isConnecting = false
// Call onError handler
if (this.onError) {
this.onError(error)
}
}
}
/**
* Reconnect to WebSocket server
*/
reconnect() {
if (this.isConnecting || this.reconnectAttempts >= this.maxReconnectAttempts) {
console.log('Max reconnection attempts reached')
return
}
this.reconnectAttempts++
const delay = this.reconnectDelay * Math.pow(2, this.reconnectAttempts - 1)
console.log(`Reconnecting attempt ${this.reconnectAttempts}/${this.maxReconnectAttempts} in ${delay}ms`)
setTimeout(() => {
this.connect()
}, delay)
}
/**
* Disconnect from WebSocket server
*/
disconnect() {
this.isManualClose = true
this.stopHeartbeat()
if (this.ws) {
this.ws.close()
this.ws = null
}
}
/**
* Send message to server
*/
send(type, data = {}) {
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
const message = JSON.stringify({
type,
data
})
this.ws.send(message)
console.log('WebSocket message sent', { type, data })
} else {
console.warn('WebSocket is not connected')
}
}
/**
* Handle incoming messages
*/
handleMessage(message) {
const { type, data } = message
// Get handler for this message type
const handler = this.messageHandlers.get(type)
if (handler) {
handler(data)
}
}
/**
* Register message handler
*/
on(messageType, handler) {
this.messageHandlers.set(messageType, handler)
}
/**
* Unregister message handler
*/
off(messageType) {
this.messageHandlers.delete(messageType)
}
/**
* Start heartbeat
*/
startHeartbeat() {
this.stopHeartbeat()
this.heartbeatTimer = setInterval(() => {
this.send('heartbeat', { timestamp: Date.now() })
}, this.heartbeatInterval)
}
/**
* Stop heartbeat
*/
stopHeartbeat() {
if (this.heartbeatTimer) {
clearInterval(this.heartbeatTimer)
this.heartbeatTimer = null
}
}
/**
* Get connection state
*/
get readyState() {
if (!this.ws) return WebSocket.CLOSED
return this.ws.readyState
}
/**
* Check if connected
*/
get isConnected() {
return this.ws && this.ws.readyState === WebSocket.OPEN
}
}
/**
* Create WebSocket connection
*/
export function createWebSocket(userId, token, options = {}) {
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'
const host = window.location.host
const url = `${protocol}//${host}/ws?user_id=${userId}&token=${token}`
return new WebSocketClient(url, options)
}
/**
* WebSocket singleton instance
*/
let wsClient = null
export function getWebSocket(userId, token, options = {}) {
if (!wsClient || !wsClient.isConnected) {
wsClient = createWebSocket(userId, token, options)
}
return wsClient
}
export function closeWebSocket() {
if (wsClient) {
wsClient.disconnect()
wsClient = null
}
}
export default WebSocketClient