Files
MultiRoombaRover/webui/src/context/SessionContext.jsx
T
2025-11-15 04:05:01 -05:00

97 lines
2.7 KiB
React

import { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react';
import { useSocket } from './SocketContext.jsx';
const SessionContext = createContext({
connected: false,
session: null,
logs: [],
login: async () => {},
setRole: async () => {},
requestControl: async () => {},
releaseControl: async () => {},
subscribeAll: async () => {},
});
function useAckEmitter(socket) {
return useCallback(
(event, payload = {}) =>
new Promise((resolve, reject) => {
socket.emit(event, payload, (resp = {}) => {
if (resp.error) {
reject(new Error(resp.error));
} else {
resolve(resp);
}
});
}),
[socket],
);
}
export function SessionProvider({ children }) {
const socket = useSocket();
const emitWithAck = useAckEmitter(socket);
const [session, setSession] = useState(null);
const [logs, setLogs] = useState([]);
const [connected, setConnected] = useState(socket.connected);
useEffect(() => {
const onConnect = () => setConnected(true);
const onDisconnect = () => setConnected(false);
socket.on('connect', onConnect);
socket.on('disconnect', onDisconnect);
return () => {
socket.off('connect', onConnect);
socket.off('disconnect', onDisconnect);
};
}, [socket]);
useEffect(() => {
function handleSession(payload) {
setSession(payload);
}
function handleLogInit(entries = []) {
setLogs(entries);
}
function handleLogEntry(entry) {
setLogs((prev) => [...prev.slice(-199), entry]);
}
socket.on('session:sync', handleSession);
socket.on('log:init', handleLogInit);
socket.on('log:entry', handleLogEntry);
return () => {
socket.off('session:sync', handleSession);
socket.off('log:init', handleLogInit);
socket.off('log:entry', handleLogEntry);
};
}, [socket]);
const actions = useMemo(
() => ({
login: (username, password) => emitWithAck('auth:login', { username, password }),
setRole: (role) => emitWithAck('session:setRole', { role }),
requestControl: (roverId, options = {}) =>
emitWithAck('session:requestControl', { roverId, ...options }),
releaseControl: (roverId) => emitWithAck('session:releaseControl', { roverId }),
subscribeAll: () => emitWithAck('session:subscribeAll'),
}),
[emitWithAck],
);
const value = useMemo(
() => ({
connected,
session,
logs,
...actions,
}),
[actions, connected, logs, session],
);
return <SessionContext.Provider value={value}>{children}</SessionContext.Provider>;
}
export function useSession() {
return useContext(SessionContext);
}