import{typeHoneypotEvent}from"src/types";import{URL}from"utils/utils";import{onBeforeUnmount,ref}from"vue";exporttypeConnectionStatus="disconnected"|"connecting"|"open";// Global state for shared WebSocket connection
constconnectionStatus=ref<ConnectionStatus>("disconnected");letsocket: WebSocket|null=null;letreconnectTimeout: ReturnType<typeofsetTimeout>|null=null;letmanualDisconnect=false;constlisteners=newSet<(events: HoneypotEvent[])=>void>();functionbuildWebSocketUrl():string{consturl=URL().replace("http","ws");return`${url}/ws`;}functionconnectInternal() {if(socket?.readyState===WebSocket.OPEN||connectionStatus.value==="connecting"){return;}connectionStatus.value="connecting";consturl=buildWebSocketUrl();constws=newWebSocket(url);socket=ws;ws.onopen=()=>{connectionStatus.value="open";if(reconnectTimeout){clearTimeout(reconnectTimeout);reconnectTimeout=null;}};ws.onclose=()=>{connectionStatus.value="disconnected";// Try to reconnect after a short delay.
if(!manualDisconnect){reconnectTimeout=setTimeout(()=>connectInternal(),2000);}};ws.onerror=()=>{// Errors are followed by onclose; we just mark closed here.
connectionStatus.value="disconnected";};ws.onmessage=(ev: MessageEvent)=>{try{constparsed=JSON.parse(ev.data);// Handle both single events and arrays of events
consteventArray: HoneypotEvent[]=Array.isArray(parsed)?(parsedasHoneypotEvent[]):[parsedasHoneypotEvent];// Filter fields for all events
for(constdataofeventArray){deletedata.fields?.body;deletedata.fields?.port;deletedata.fields?.remote_addr;}// Call all listeners with the entire batch
listeners.forEach((listener)=>listener(eventArray));}catch{// Ignore malformed messages.
}};}functiondisconnectInternal() {manualDisconnect=true;if(reconnectTimeout){clearTimeout(reconnectTimeout);reconnectTimeout=null;}if(socket){socket.close();socket=null;}}exportfunctionuseWebSocket(onMessage?:(events: HoneypotEvent[])=>void,maxEvents=1000,){constevents=ref<HoneypotEvent[]>([]);// Wrap the onMessage to also update local events ref
constinternalListener=(eventArray: HoneypotEvent[])=>{events.value.unshift(...eventArray);if(events.value.length>maxEvents){events.value.length=maxEvents;}if(onMessage){onMessage(eventArray);}};listeners.add(internalListener);onBeforeUnmount(()=>{listeners.delete(internalListener);if(listeners.size===0){disconnectInternal();}});return{connectionStatus,events,connect:()=>{manualDisconnect=false;connectInternal();},disconnect: disconnectInternal,};}