You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
hexmap/client/src/ui/WebsocketReactAdapter.tsx

72 lines
3.1 KiB

import {ReactElement, useContext, useEffect, useRef, useState} from "react";
import {
CLIENT_ACT,
CLIENT_REFRESH,
ClientActCommand,
ClientGoodbyeAction,
ClientHelloCommand,
ClientRefreshCommand, isClientGoodbyeCommand,
isClientHelloCommand,
isClientRefreshCommand,
SendableAction,
SentAction
} from "../../../common/src/actions/ClientAction";
import {DispatchContext} from "./context/DispatchContext";
import {DOMWebsocketTranslator} from "./DOMWebsocketTranslator";
import {ServerConnectionState} from "../state/NetworkState";
import {SERVER_SOCKET_STARTUP, SocketState} from "../../../common/src/actions/ServerAction";
export function WebsocketReactAdapter({url, protocols = ["v1.hexmap.deliciousreya.net"], state, specialMessage, pendingMessages, nextID}: {
url: string,
protocols?: readonly string[],
state: ServerConnectionState,
specialMessage: ClientHelloCommand | ClientRefreshCommand | ClientGoodbyeAction | null,
pendingMessages: readonly SendableAction[],
nextID: number
}): ReactElement {
const dispatch = useContext(DispatchContext)
if (dispatch === null) {
throw Error("What the heck?! No dispatch?! I quit!")
}
const connector = useRef(new DOMWebsocketTranslator({
url,
protocols,
onStartup: dispatch,
onMessage: dispatch,
onError: dispatch,
onGoodbye: dispatch,
}))
useEffect(() => {
connector.current.connect();
dispatch({
type: SERVER_SOCKET_STARTUP,
state: SocketState.CONNECTING,
});
}, [dispatch])
const [lastSpecialMessage, setLastSpecialMessage] = useState<ClientHelloCommand | ClientRefreshCommand | ClientGoodbyeAction | null>(null)
useEffect(() => {
if (state === ServerConnectionState.CONNECTED && pendingMessages.length > 0) {
const sentMessages: SentAction[] = pendingMessages.map((action, index) => {
return {id: index + nextID, action}
});
const sentMessage: ClientActCommand = {
type: CLIENT_ACT,
actions: sentMessages,
};
connector.current.send(sentMessage)
dispatch(sentMessage)
}
}, [nextID, dispatch, pendingMessages, state])
useEffect(() => {
if (specialMessage !== null && specialMessage !== lastSpecialMessage) {
if ((state === ServerConnectionState.AWAITING_HELLO && isClientHelloCommand(specialMessage))
|| (state === ServerConnectionState.AWAITING_REFRESH && isClientRefreshCommand(specialMessage))) {
connector.current.send(specialMessage);
} else if (state === ServerConnectionState.AWAITING_GOODBYE && isClientGoodbyeCommand(specialMessage)) {
connector.current.close(specialMessage.code, specialMessage.reason)
}
setLastSpecialMessage(specialMessage);
}
}, [specialMessage, lastSpecialMessage, setLastSpecialMessage, state])
return <div className="connectionState" onClick={() => dispatch ? dispatch({type: CLIENT_REFRESH}) : null}>{state}</div>
}