add real-time infrastructure (#137)

* setup infra for pusher service

* setup client sdk for pusher service

* fix: ping parse failure

* fix: send pong back to client

avoid disconnections every 2.5 minutes

* increase replicas

* feat: show presence and compose indicator
This commit was merged in pull request #137.
This commit is contained in:
Arjun Patel
2026-04-09 12:08:18 -07:00
committed by GitHub
parent ce368c9e6e
commit 3d8fa79657
29 changed files with 2549 additions and 11 deletions
+76
View File
@@ -0,0 +1,76 @@
import {
createContext,
useContext,
useEffect,
useRef,
useState,
type ReactNode,
} from "react";
import { PusherClient, type ConnectionState } from "./pusher-client";
import { useSessionStore } from "@/stores/session-store";
const PusherContext = createContext<PusherClient | null>(null);
const PusherStateContext = createContext<ConnectionState>("disconnected");
// TODO: make this configurable per environment
const PUSHER_URL = "wss://pusher.dev.flowy.live/ws";
export function PusherProvider({ children }: { children: ReactNode }) {
const token = useSessionStore((s) => s.token);
const clientRef = useRef<PusherClient | null>(null);
const [connectionState, setConnectionState] =
useState<ConnectionState>("disconnected");
useEffect(() => {
if (!token) {
// Disconnect if token is cleared (logout)
if (clientRef.current) {
clientRef.current.disconnect();
clientRef.current = null;
setConnectionState("disconnected");
}
return;
}
const client = new PusherClient({
url: PUSHER_URL,
getToken: () => useSessionStore.getState().token,
});
clientRef.current = client;
const unsubscribeState = client.onStateChange((state) => {
setConnectionState(state);
});
client.connect();
return () => {
unsubscribeState();
client.disconnect();
clientRef.current = null;
};
}, [token]);
return (
<PusherContext.Provider value={clientRef.current}>
<PusherStateContext.Provider value={connectionState}>
{children}
</PusherStateContext.Provider>
</PusherContext.Provider>
);
}
/**
* Returns the PusherClient instance, or null if not connected.
*/
export function usePusherClient(): PusherClient | null {
return useContext(PusherContext);
}
/**
* Returns the current WebSocket connection state.
*/
export function usePusherConnectionState(): ConnectionState {
return useContext(PusherStateContext);
}