// WatchRoom 全局状态管理 Provider 'use client'; import React, { createContext, useContext, useEffect, useState, useCallback } from 'react'; import { useWatchRoom } from '@/hooks/useWatchRoom'; import type { Room, Member, ChatMessage, WatchRoomConfig } from '@/types/watch-room'; import Toast, { ToastProps } from '@/components/Toast'; // Import type from watch-room-socket type WatchRoomSocket = import('@/lib/watch-room-socket').WatchRoomSocket; interface WatchRoomContextType { socket: WatchRoomSocket | null; isConnected: boolean; reconnectFailed: boolean; currentRoom: Room | null; members: Member[]; chatMessages: ChatMessage[]; isOwner: boolean; isEnabled: boolean; config: WatchRoomConfig | null; // 房间操作 createRoom: (data: { name: string; description: string; password?: string; isPublic: boolean; userName: string; }) => Promise; joinRoom: (data: { roomId: string; password?: string; userName: string; }) => Promise<{ room: Room; members: Member[] }>; leaveRoom: () => void; getRoomList: () => Promise; // 聊天 sendChatMessage: (content: string, type?: 'text' | 'emoji') => void; // 播放控制(供 play/live 页面使用) updatePlayState: (state: any) => void; seekPlayback: (currentTime: number) => void; play: () => void; pause: () => void; changeVideo: (state: any) => void; changeLiveChannel: (state: any) => void; clearRoomState: () => void; // 重连 manualReconnect: () => Promise; } const WatchRoomContext = createContext(null); export const useWatchRoomContext = () => { const context = useContext(WatchRoomContext); if (!context) { throw new Error('useWatchRoomContext must be used within WatchRoomProvider'); } return context; }; // 安全版本,可以在非 Provider 内使用 export const useWatchRoomContextSafe = () => { return useContext(WatchRoomContext); }; interface WatchRoomProviderProps { children: React.ReactNode; } export function WatchRoomProvider({ children }: WatchRoomProviderProps) { const [config, setConfig] = useState(null); const [isEnabled, setIsEnabled] = useState(false); const [toast, setToast] = useState(null); const [reconnectFailed, setReconnectFailed] = useState(false); // 处理房间删除的回调 const handleRoomDeleted = useCallback((data?: { reason?: string }) => { console.log('[WatchRoomProvider] Room deleted:', data); // 显示Toast提示 if (data?.reason === 'owner_left') { setToast({ message: '房主已解散房间', type: 'error', duration: 4000, onClose: () => setToast(null), }); } else { setToast({ message: '房间已被删除', type: 'info', duration: 3000, onClose: () => setToast(null), }); } }, []); // 处理房间状态清除的回调(房主离开超过30秒) const handleStateCleared = useCallback(() => { console.log('[WatchRoomProvider] Room state cleared'); setToast({ message: '房主已离开,播放状态已清除', type: 'info', duration: 4000, onClose: () => setToast(null), }); }, []); const watchRoom = useWatchRoom(handleRoomDeleted, handleStateCleared); // 手动重连 const manualReconnect = useCallback(async () => { console.log('[WatchRoomProvider] Manual reconnect initiated'); setReconnectFailed(false); const { watchRoomSocketManager } = await import('@/lib/watch-room-socket'); const success = await watchRoomSocketManager.reconnect(); if (success) { console.log('[WatchRoomProvider] Manual reconnect succeeded'); // 尝试重新加入房间 const storedInfo = localStorage.getItem('watch_room_info'); if (storedInfo && watchRoom.socket) { try { const info = JSON.parse(storedInfo); console.log('[WatchRoomProvider] Attempting to rejoin room after reconnect'); await watchRoom.joinRoom({ roomId: info.roomId, password: info.password, userName: info.userName, }); } catch (error) { console.error('[WatchRoomProvider] Failed to rejoin room after reconnect:', error); } } } else { console.error('[WatchRoomProvider] Manual reconnect failed'); setReconnectFailed(true); } }, [watchRoom]); // 加载配置 useEffect(() => { const loadConfig = async () => { try { // 使用公共 API 获取观影室配置(不需要管理员权限) const response = await fetch('/api/server-config'); if (response.ok) { const data = await response.json(); // API 返回格式: { SiteName, StorageType, Version, WatchRoom } const watchRoomConfig: WatchRoomConfig = { enabled: data.WatchRoom?.enabled ?? false, // 默认不启用 serverType: data.WatchRoom?.serverType ?? 'internal', externalServerUrl: data.WatchRoom?.externalServerUrl, }; // 如果使用外部服务器,需要获取认证信息(需要登录) if (watchRoomConfig.serverType === 'external' && watchRoomConfig.enabled) { try { const authResponse = await fetch('/api/watch-room-auth'); if (authResponse.ok) { const authData = await authResponse.json(); watchRoomConfig.externalServerAuth = authData.externalServerAuth; } else { console.error('[WatchRoom] Failed to load auth info:', authResponse.status); // 如果无法获取认证信息,禁用观影室 watchRoomConfig.enabled = false; } } catch (error) { console.error('[WatchRoom] Error loading auth info:', error); // 如果无法获取认证信息,禁用观影室 watchRoomConfig.enabled = false; } } setConfig(watchRoomConfig); setIsEnabled(watchRoomConfig.enabled); // 只在启用了观影室时才连接 if (watchRoomConfig.enabled) { console.log('[WatchRoom] Connecting with config:', watchRoomConfig); // 设置重连回调 const { watchRoomSocketManager } = await import('@/lib/watch-room-socket'); watchRoomSocketManager.setReconnectFailedCallback(() => { console.log('[WatchRoomProvider] Reconnect failed callback triggered'); setReconnectFailed(true); }); watchRoomSocketManager.setReconnectSuccessCallback(() => { console.log('[WatchRoomProvider] Reconnect success callback triggered'); setReconnectFailed(false); }); await watchRoom.connect(watchRoomConfig); } else { console.log('[WatchRoom] Watch room is disabled, skipping connection'); } } else { console.error('[WatchRoom] Failed to load config:', response.status); // 加载配置失败时,不连接,保持禁用状态 const defaultConfig: WatchRoomConfig = { enabled: false, serverType: 'internal', }; setConfig(defaultConfig); setIsEnabled(false); } } catch (error) { console.error('[WatchRoom] Error loading config:', error); // 加载配置失败时,不连接,保持禁用状态 const defaultConfig: WatchRoomConfig = { enabled: false, serverType: 'internal', }; setConfig(defaultConfig); setIsEnabled(false); } }; loadConfig(); // 清理 return () => { watchRoom.disconnect(); }; }, []); const contextValue: WatchRoomContextType = { socket: watchRoom.socket, isConnected: watchRoom.isConnected, reconnectFailed, currentRoom: watchRoom.currentRoom, members: watchRoom.members, chatMessages: watchRoom.chatMessages, isOwner: watchRoom.isOwner, isEnabled, config, createRoom: watchRoom.createRoom, joinRoom: watchRoom.joinRoom, leaveRoom: watchRoom.leaveRoom, getRoomList: watchRoom.getRoomList, sendChatMessage: watchRoom.sendChatMessage, updatePlayState: watchRoom.updatePlayState, seekPlayback: watchRoom.seekPlayback, play: watchRoom.play, pause: watchRoom.pause, changeVideo: watchRoom.changeVideo, changeLiveChannel: watchRoom.changeLiveChannel, clearRoomState: watchRoom.clearRoomState, manualReconnect, }; return ( {children} {toast && } ); }