@fishjam-cloud/react-client
Version:
React client library for Fishjam
88 lines (87 loc) • 2.99 kB
JavaScript
import { useCallback, useContext, useEffect, useState } from "react";
import { FishjamClientContext } from "../contexts/fishjamClient";
import { PeerStatusContext } from "../contexts/peerStatus";
import { useCurrentCallback } from "./internal/useCurrentCallback";
/**
* Hook for data channel operations - publish and subscribe to data.
*
* @category Connection
* @group Hooks
*/
export function useDataChannel() {
const fishjamClientRef = useContext(FishjamClientContext);
const peerStatus = useContext(PeerStatusContext);
if (!fishjamClientRef)
throw Error("useDataPublisher must be used within FishjamProvider");
const client = fishjamClientRef.current;
const [ready, setReady] = useState(false);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
useEffect(() => {
const publisherReady = client.getDataChannelsReadiness();
setReady(publisherReady);
const handleReady = () => {
setReady(true);
setError(null);
};
const handleDisconnect = () => {
setReady(false);
};
const handleError = (err) => {
setReady(false);
setLoading(false);
setError(err);
};
client.on("dataChannelsReady", handleReady);
client.on("dataChannelsError", handleError);
client.on("disconnected", handleDisconnect);
return () => {
client.removeListener("dataChannelsReady", handleReady);
client.removeListener("disconnected", handleDisconnect);
};
}, [client]);
// Stable identity with a live closure: peerStatus / loading / ready must be
// observed at call time so a captured reference doesn't reject with a stale
// "Peer is not connected" right after the connect promise settles.
const initialize = useCurrentCallback(async () => {
if (loading || ready)
return;
if (peerStatus !== "connected") {
setError(new Error("Peer is not connected"));
return;
}
try {
setLoading(true);
await client.createDataChannels();
}
catch (err) {
if (err instanceof Error) {
setError(err);
}
}
finally {
setLoading(false);
}
});
const publishData = useCallback((data, options) => {
try {
client.publishData(data, options);
}
catch (err) {
if (err instanceof Error) {
setError(err);
}
}
}, [client]);
const subscribeData = useCallback((callback, options) => {
return client.subscribeData(callback, options);
}, [client]);
return {
publishData,
subscribeData,
initializeDataChannel: initialize,
dataChannelReady: ready,
dataChannelLoading: loading,
dataChannelError: error,
};
}