Skip to main content
Glama
useSocket.tsx3.44 kB
import { useEffect, useRef, useState } from "react"; export type Events = { Loaded: (data: { rootContents: any }) => void; fetchDirResponse: (data: any) => void; fetchContentResponse: (data: any) => void; updateContentResponse: (data: any) => void; terminalResponse: (data: any) => void; terminalClosed: (data: any) => void; terminalConnected: (data: any) => void; terminalError: (data: any) => void; copyResponse: (data: any) => void; renameResponse: (data: any) => void; deleteResponse: (data: any) => void; createFolderResponse: (data: any) => void; createFileResponse: (data: any) => void; cutResponse: (data: any) => void; pasteResponse: (data: any) => void; error: (data: any) => void; }; type EventHandler = (...args: any[]) => void; interface Socket extends WebSocket { emit?: (event: string, data?: any) => void; on?: (event: keyof Events, handler: EventHandler) => void; off?: (event: keyof Events) => void; } const RUNNER_DOMAIN_NAME = process.env.NEXT_PUBLIC_RUNNER_DOMAIN_NAME || "localhost:8000"; export function useRunnerSocket(replId: string) { const socketRef = useRef<Socket | null>(null); const [isConnected, setIsConnected] = useState(false); const listenersRef = useRef<Record<string, EventHandler[]>>({}); useEffect(() => { const protocol = window.location.protocol === "https:" ? "wss" : "ws"; const url = `${protocol}://${process.env.NEXT_PUBLIC_RUNNER_DOMAIN_NAME}/${replId}/api/v1/repl/ws`; const testingUrl = "ws://localhost:8081/api/v1/repl/ws"; const socket: Socket = new WebSocket(url); // Extend native WebSocket with .emit/.on/.off socket.emit = (event: string, data: any) => { socket.send(JSON.stringify({ event, data })); }; socket.on = (event: keyof Events, handler: EventHandler) => { if (!listenersRef.current[event]) { listenersRef.current[event] = []; } listenersRef.current[event].push(handler); }; socket.off = (event) => { delete listenersRef.current[event]; }; socket.addEventListener("open", () => { setIsConnected(true); console.log("✅ Connected to runner WebSocket"); }); socket.addEventListener("close", () => { setIsConnected(false); console.warn("⚠️ Disconnected from runner WebSocket"); }); socket.addEventListener("error", (err) => { console.error("❌ WebSocket error:", err); }); socket.addEventListener("message", (msg) => { try { const parsed = JSON.parse(msg.data); const { event, data } = parsed; const handlers = listenersRef.current[event]; if (handlers) { handlers.forEach((fn) => fn(data)); } } catch (err) { console.error("❌ Failed to parse WebSocket message:", err); } }); socketRef.current = socket; return () => { socket.close(); socketRef.current = null; listenersRef.current = {}; }; }, [replId]); // Proxy functions (typed) const emit = (event: string, payload?: any) => { socketRef.current?.emit?.(event, payload); }; const on = <K extends keyof Events>(event: K, handler: Events[K]) => { socketRef.current?.on?.(event, handler as EventHandler); }; const off = (event: keyof Events) => { socketRef.current?.off?.(event); }; return { socket: socketRef.current, isConnected, emit, on, off, }; }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/ParthKapoor-dev/devex'

If you have feedback or need assistance with the MCP directory API, please join our Discord server