File size: 3,697 Bytes
cdf301a
 
 
 
 
 
 
 
 
 
 
b2a31fd
cdf301a
 
 
 
 
 
 
 
 
 
 
b2a31fd
cdf301a
b2a31fd
cdf301a
 
 
 
 
 
 
 
 
b2a31fd
cdf301a
 
 
 
 
 
 
 
 
 
 
 
 
b2a31fd
cdf301a
 
b2a31fd
cdf301a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b2a31fd
cdf301a
 
 
 
 
 
 
 
 
 
b2a31fd
cdf301a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
02f98b1
 
 
 
 
cdf301a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
// RelayAPI.js - Next.js Wrapper for the WebSocket Server

import { useEffect, useState, useCallback, useRef } from "react";

const useWebSocket = (userId) => {
  const [socket, setSocket] = useState(null);
  const [messages, setMessages] = useState([]);
  const [connectedChannels, setConnectedChannels] = useState(new Set());
  const reconnectInterval = useRef(null);

  const connect = useCallback(() => {
    const ws = new WebSocket(`${process.env.NEXT_PUBLIC_RELAY_URL}/ws?user_id=${userId}`);

    ws.onopen = () => {
      console.debug("WebSocket connected.");
      clearInterval(reconnectInterval.current);
    };

    ws.onmessage = (event) => {
      try {
        const data = JSON.parse(event.data);
        console.debug("Received message:", data);
        setMessages((prev) => [...prev, data]);
        console.debug(messages);
      } catch (error) {
        console.debug("Failed to parse WebSocket message:", event.data);
      }
    };

    ws.onclose = () => {
      console.warn("WebSocket closed. Reconnecting...");
      reconnectInterval.current = setInterval(() => connect(), 5000);
    };

    ws.onerror = (error) => {
      console.debug("WebSocket error:", error);
      ws.close();
    };

    setSocket(ws);
  }, [userId]);

  useEffect(() => {
    if (!userId) return;

    connect();

    return () => {
      clearInterval(reconnectInterval.current);
      setConnectedChannels(new Set());
      if (socket) socket.close();
    };
  }, [connect, userId]);

  const sendMessage = useCallback(
    (action, channel, message, targetUserId = null) => {
      if (!socket || socket.readyState !== WebSocket.OPEN) {
        console.warn("WebSocket is not connected.");
        return;
      }

      const payload = { action, channel, message, sender: userId };
      if (targetUserId) payload.target_user_id = targetUserId;

      try {
        socket.send(JSON.stringify(payload));
        console.debug("Sent message:", payload);
      } catch (error) {
        console.debug("Failed to send WebSocket message:", error);
      }
    },
    [socket, userId]
  );

  const joinChannel = useCallback(
    (channel) => {
      if (connectedChannels.has(channel)) return;

      sendMessage("join", channel);
      setConnectedChannels((prev) => new Set([...prev, channel]));
    },
    [sendMessage, connectedChannels]
  );

  const leaveChannel = useCallback(
    (channel) => {
      if (!connectedChannels.has(channel)) return;

      sendMessage("leave", channel);
      setConnectedChannels((prev) => {
        const updated = new Set(prev);
        updated.delete(channel);
        return updated;
      });
    },
    [sendMessage, connectedChannels]
  );

  const broadcast = useCallback(
    (channel, message) => {
      sendMessage("broadcast", channel, message);
    },
    [sendMessage]
  );

  const sendToUser = useCallback(
    (targetUserId, message) => {
      sendMessage("send_to_user", null, message, targetUserId);
    },
    [sendMessage]
  );

  return { messages, joinChannel, leaveChannel, broadcast, sendToUser };
};

export const RelayAPIProvider = ({ userId=null, children }) => {
  if (userId === null) {
    userId = localStorage.getItem("u_id");
    console.log("inside context")
  }
  const contextValue = useWebSocket(userId);

  return (
    <RelayAPIContext.Provider value={contextValue}>{children}</RelayAPIContext.Provider>
  );
};

import React, { useContext } from "react";

const RelayAPIContext = React.createContext(null);

export const useRelayAPI = () => {
  const context = useContext(RelayAPIContext);
  if (!context) {
    throw new Error("useRelayAPI must be used within a RelayAPIProvider");
  }
  return context;
};