添加socketservice

This commit is contained in:
2025-10-21 15:13:11 +08:00
parent cfb00ba895
commit 74968d5bc8
4 changed files with 935 additions and 21 deletions

View File

@@ -0,0 +1,161 @@
// src/hooks/useEventNotifications.js
/**
* React Hook用于在组件中订阅事件推送通知
*
* 使用示例:
* ```jsx
* import { useEventNotifications } from 'hooks/useEventNotifications';
*
* function MyComponent() {
* const { newEvent, isConnected } = useEventNotifications({
* eventType: 'all',
* importance: 'all',
* onNewEvent: (event) => {
* console.log('收到新事件:', event);
* // 显示通知...
* }
* });
*
* return <div>...</div>;
* }
* ```
*/
import { useEffect, useState, useRef } from 'react';
import { socketService } from '../services/socketService';
export const useEventNotifications = (options = {}) => {
const {
eventType = 'all',
importance = 'all',
enabled = true,
onNewEvent,
} = options;
const [isConnected, setIsConnected] = useState(false);
const [newEvent, setNewEvent] = useState(null);
const [error, setError] = useState(null);
const unsubscribeRef = useRef(null);
useEffect(() => {
// 如果禁用,则不订阅
if (!enabled) {
return;
}
// 连接状态监听
const handleConnect = () => {
setIsConnected(true);
setError(null);
};
const handleDisconnect = () => {
setIsConnected(false);
};
const handleConnectError = (err) => {
setError(err);
setIsConnected(false);
};
// 连接 WebSocket
socketService.connect();
// 监听连接事件
socketService.on('connect', handleConnect);
socketService.on('disconnect', handleDisconnect);
socketService.on('connect_error', handleConnectError);
// 新事件处理函数
const handleNewEvent = (eventData) => {
setNewEvent(eventData);
// 调用外部回调
if (onNewEvent) {
onNewEvent(eventData);
}
};
// 订阅事件推送
socketService.subscribeToEvents({
eventType,
importance,
onNewEvent: handleNewEvent,
onSubscribed: (data) => {
console.log('订阅成功:', data);
},
});
// 保存取消订阅函数
unsubscribeRef.current = () => {
socketService.unsubscribeFromEvents({ eventType });
};
// 组件卸载时清理
return () => {
console.log('清理 WebSocket 订阅');
// 取消订阅
if (unsubscribeRef.current) {
unsubscribeRef.current();
}
// 移除监听器
socketService.off('connect', handleConnect);
socketService.off('disconnect', handleDisconnect);
socketService.off('connect_error', handleConnectError);
// 断开连接
socketService.disconnect();
};
}, [eventType, importance, enabled, onNewEvent]);
return {
newEvent, // 最新收到的事件
isConnected, // WebSocket 连接状态
error, // 错误信息
clearNewEvent: () => setNewEvent(null), // 清除新事件状态
};
};
/**
* 简化版 Hook只订阅所有事件
*/
export const useAllEventNotifications = (onNewEvent) => {
return useEventNotifications({
eventType: 'all',
importance: 'all',
onNewEvent,
});
};
/**
* Hook订阅重要事件S 和 A 级)
*/
export const useImportantEventNotifications = (onNewEvent) => {
const [importantEvents, setImportantEvents] = useState([]);
const handleEvent = (event) => {
// 只处理 S 和 A 级事件
if (event.importance === 'S' || event.importance === 'A') {
setImportantEvents(prev => [event, ...prev].slice(0, 10)); // 最多保留 10 个
if (onNewEvent) {
onNewEvent(event);
}
}
};
const result = useEventNotifications({
eventType: 'all',
importance: 'all',
onNewEvent: handleEvent,
});
return {
...result,
importantEvents,
clearImportantEvents: () => setImportantEvents([]),
};
};
export default useEventNotifications;

View File

@@ -186,6 +186,169 @@ class SocketService {
getSocketId() {
return this.socket?.id || null;
}
// ==================== 事件推送专用方法 ====================
/**
* 订阅事件推送
* @param {object} options - 订阅选项
* @param {string} options.eventType - 事件类型 ('all' | 'policy' | 'market' | 'tech' | ...)
* @param {string} options.importance - 重要性 ('all' | 'S' | 'A' | 'B' | 'C')
* @param {Function} options.onNewEvent - 收到新事件时的回调函数
* @param {Function} options.onSubscribed - 订阅成功的回调函数(可选)
*/
subscribeToEvents(options = {}) {
const {
eventType = 'all',
importance = 'all',
onNewEvent,
onSubscribed,
} = options;
if (!this.socket || !this.connected) {
logger.warn('socketService', 'Cannot subscribe: socket not connected');
// 自动连接
this.connect();
// 等待连接成功后再订阅
this.socket.once('connect', () => {
this._doSubscribe(eventType, importance, onNewEvent, onSubscribed);
});
return;
}
this._doSubscribe(eventType, importance, onNewEvent, onSubscribed);
}
/**
* 执行订阅操作(内部方法)
*/
_doSubscribe(eventType, importance, onNewEvent, onSubscribed) {
// 发送订阅请求
this.emit('subscribe_events', {
event_type: eventType,
importance: importance,
});
// 监听订阅确认
this.socket.once('subscription_confirmed', (data) => {
logger.info('socketService', 'Subscription confirmed', data);
if (onSubscribed) {
onSubscribed(data);
}
});
// 监听订阅错误
this.socket.once('subscription_error', (error) => {
logger.error('socketService', 'Subscription error', error);
});
// 监听新事件推送
if (onNewEvent) {
// 先移除之前的监听器(避免重复)
this.socket.off('new_event');
// 添加新的监听器
this.socket.on('new_event', (eventData) => {
logger.info('socketService', 'New event received', eventData);
onNewEvent(eventData);
});
}
}
/**
* 取消订阅事件推送
* @param {object} options - 取消订阅选项
* @param {string} options.eventType - 事件类型
* @param {Function} options.onUnsubscribed - 取消订阅成功的回调函数(可选)
*/
unsubscribeFromEvents(options = {}) {
const {
eventType = 'all',
onUnsubscribed,
} = options;
if (!this.socket || !this.connected) {
logger.warn('socketService', 'Cannot unsubscribe: socket not connected');
return;
}
// 发送取消订阅请求
this.emit('unsubscribe_events', {
event_type: eventType,
});
// 监听取消订阅确认
this.socket.once('unsubscription_confirmed', (data) => {
logger.info('socketService', 'Unsubscription confirmed', data);
// 移除新事件监听器
this.socket.off('new_event');
if (onUnsubscribed) {
onUnsubscribed(data);
}
});
// 监听取消订阅错误
this.socket.once('unsubscription_error', (error) => {
logger.error('socketService', 'Unsubscription error', error);
});
}
/**
* 快捷方法:订阅所有类型的事件
* @param {Function} onNewEvent - 收到新事件时的回调函数
* @returns {Function} 取消订阅的函数
*/
subscribeToAllEvents(onNewEvent) {
this.subscribeToEvents({
eventType: 'all',
importance: 'all',
onNewEvent,
});
// 返回取消订阅的清理函数
return () => {
this.unsubscribeFromEvents({ eventType: 'all' });
};
}
/**
* 快捷方法:订阅特定重要性的事件
* @param {string} importance - 重要性级别 ('S' | 'A' | 'B' | 'C')
* @param {Function} onNewEvent - 收到新事件时的回调函数
* @returns {Function} 取消订阅的函数
*/
subscribeToImportantEvents(importance, onNewEvent) {
this.subscribeToEvents({
eventType: 'all',
importance,
onNewEvent,
});
// 返回取消订阅的清理函数
return () => {
this.unsubscribeFromEvents({ eventType: 'all' });
};
}
/**
* 快捷方法:订阅特定类型的事件
* @param {string} eventType - 事件类型
* @param {Function} onNewEvent - 收到新事件时的回调函数
* @returns {Function} 取消订阅的函数
*/
subscribeToEventType(eventType, onNewEvent) {
this.subscribeToEvents({
eventType,
importance: 'all',
onNewEvent,
});
// 返回取消订阅的清理函数
return () => {
this.unsubscribeFromEvents({ eventType });
};
}
}
// 导出单例