- Migrated from HIVE branding to WHOOSH across all components - Enhanced backend API with new services: AI models, BZZZ integration, templates, members - Added comprehensive testing suite with security, performance, and integration tests - Improved frontend with new components for project setup, AI models, and team management - Updated MCP server implementation with WHOOSH-specific tools and resources - Enhanced deployment configurations with production-ready Docker setups - Added comprehensive documentation and setup guides - Implemented age encryption service and UCXL integration 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
147 lines
4.3 KiB
TypeScript
147 lines
4.3 KiB
TypeScript
import React, { createContext, useContext, useEffect, useState } from 'react';
|
|
import { useWebSocket, WebSocketMessage } from '../hooks/useWebSocket';
|
|
|
|
interface WebSocketContextType {
|
|
isConnected: boolean;
|
|
connectionState: 'connecting' | 'connected' | 'disconnected' | 'error';
|
|
sendMessage: (type: string, data: any) => void;
|
|
lastMessage: WebSocketMessage | null;
|
|
subscribe: (messageType: string, handler: (data: any) => void) => () => void;
|
|
reconnect: () => void;
|
|
}
|
|
|
|
const WebSocketContext = createContext<WebSocketContextType | null>(null);
|
|
|
|
interface WebSocketProviderProps {
|
|
children: React.ReactNode;
|
|
url?: string;
|
|
}
|
|
|
|
export const WebSocketProvider: React.FC<WebSocketProviderProps> = ({
|
|
children,
|
|
url = import.meta.env.VITE_WS_BASE_URL || 'wss://whoosh.home.deepblack.cloud'
|
|
}) => {
|
|
const [subscriptions, setSubscriptions] = useState<Map<string, Set<(data: any) => void>>>(new Map());
|
|
|
|
const {
|
|
isConnected,
|
|
connectionState,
|
|
sendMessage,
|
|
lastMessage,
|
|
reconnect
|
|
} = useWebSocket({
|
|
url,
|
|
reconnectAttempts: 5,
|
|
reconnectDelay: 3000,
|
|
onMessage: (message) => {
|
|
// Handle incoming messages and notify subscribers
|
|
const handlers = subscriptions.get(message.type);
|
|
if (handlers) {
|
|
handlers.forEach(handler => {
|
|
try {
|
|
handler(message.data);
|
|
} catch (error) {
|
|
console.error('Error in WebSocket message handler:', error);
|
|
}
|
|
});
|
|
}
|
|
},
|
|
onConnect: () => {
|
|
console.log('WebSocket connected to WHOOSH backend');
|
|
// Subscribe to general system events
|
|
sendMessage('subscribe', {
|
|
events: ['agent_status_changed', 'execution_started', 'execution_completed', 'metrics_updated']
|
|
});
|
|
},
|
|
onDisconnect: () => {
|
|
console.log('WebSocket disconnected from WHOOSH backend');
|
|
},
|
|
onError: (error) => {
|
|
console.error('WebSocket error:', error);
|
|
}
|
|
});
|
|
|
|
const subscribe = (messageType: string, handler: (data: any) => void) => {
|
|
setSubscriptions(prev => {
|
|
const newSubscriptions = new Map(prev);
|
|
if (!newSubscriptions.has(messageType)) {
|
|
newSubscriptions.set(messageType, new Set());
|
|
}
|
|
newSubscriptions.get(messageType)!.add(handler);
|
|
return newSubscriptions;
|
|
});
|
|
|
|
// Return unsubscribe function
|
|
return () => {
|
|
setSubscriptions(prev => {
|
|
const newSubscriptions = new Map(prev);
|
|
const handlers = newSubscriptions.get(messageType);
|
|
if (handlers) {
|
|
handlers.delete(handler);
|
|
if (handlers.size === 0) {
|
|
newSubscriptions.delete(messageType);
|
|
}
|
|
}
|
|
return newSubscriptions;
|
|
});
|
|
};
|
|
};
|
|
|
|
const contextValue: WebSocketContextType = {
|
|
isConnected,
|
|
connectionState,
|
|
sendMessage,
|
|
lastMessage,
|
|
subscribe,
|
|
reconnect
|
|
};
|
|
|
|
return (
|
|
<WebSocketContext.Provider value={contextValue}>
|
|
{children}
|
|
</WebSocketContext.Provider>
|
|
);
|
|
};
|
|
|
|
export const useWebSocketContext = (): WebSocketContextType => {
|
|
const context = useContext(WebSocketContext);
|
|
if (!context) {
|
|
throw new Error('useWebSocketContext must be used within a WebSocketProvider');
|
|
}
|
|
return context;
|
|
};
|
|
|
|
// Convenience hooks for common real-time updates
|
|
export const useAgentUpdates = (onAgentUpdate: (agentData: any) => void) => {
|
|
const { subscribe } = useWebSocketContext();
|
|
|
|
useEffect(() => {
|
|
const unsubscribe = subscribe('agent_status_changed', onAgentUpdate);
|
|
return unsubscribe;
|
|
}, [subscribe, onAgentUpdate]);
|
|
};
|
|
|
|
export const useExecutionUpdates = (onExecutionUpdate: (executionData: any) => void) => {
|
|
const { subscribe } = useWebSocketContext();
|
|
|
|
useEffect(() => {
|
|
const unsubscribeStart = subscribe('execution_started', onExecutionUpdate);
|
|
const unsubscribeComplete = subscribe('execution_completed', onExecutionUpdate);
|
|
const unsubscribeFailed = subscribe('execution_failed', onExecutionUpdate);
|
|
|
|
return () => {
|
|
unsubscribeStart();
|
|
unsubscribeComplete();
|
|
unsubscribeFailed();
|
|
};
|
|
}, [subscribe, onExecutionUpdate]);
|
|
};
|
|
|
|
export const useMetricsUpdates = (onMetricsUpdate: (metricsData: any) => void) => {
|
|
const { subscribe } = useWebSocketContext();
|
|
|
|
useEffect(() => {
|
|
const unsubscribe = subscribe('metrics_updated', onMetricsUpdate);
|
|
return unsubscribe;
|
|
}, [subscribe, onMetricsUpdate]);
|
|
}; |