From e5deaa51d9b7454cc170fd68cd762c2fa453f2aa Mon Sep 17 00:00:00 2001 From: Savanni D'Gerinel Date: Tue, 19 Nov 2024 00:09:48 -0500 Subject: [PATCH] Extract the websocket code into a wrapper component --- visions/server/src/handlers.rs | 3 +- visions/ui/src/App.tsx | 6 +- .../components/PlayingField/PlayingField.tsx | 76 +++---------------- .../ui/src/components/WebsocketProvider.tsx | 48 ++++++++++++ 4 files changed, 62 insertions(+), 71 deletions(-) create mode 100644 visions/ui/src/components/WebsocketProvider.tsx diff --git a/visions/server/src/handlers.rs b/visions/server/src/handlers.rs index c8861ca..eb35e10 100644 --- a/visions/server/src/handlers.rs +++ b/visions/server/src/handlers.rs @@ -99,7 +99,7 @@ pub async fn handle_connect_websocket( let core = core.clone(); async move { let (mut ws_sender, _) = socket.split(); - let mut receiver = core.connect_client(client_id); + let mut receiver = core.connect_client(client_id.clone()); tokio::task::spawn(async move { let background_image = core.0.read().unwrap().playfield_background.clone(); @@ -114,6 +114,7 @@ pub async fn handle_connect_websocket( .send(Message::text(serde_json::to_string(&msg).unwrap())) .await; } + println!("process ended for id {}", client_id); }); } }) diff --git a/visions/ui/src/App.tsx b/visions/ui/src/App.tsx index 1497180..9148424 100644 --- a/visions/ui/src/App.tsx +++ b/visions/ui/src/App.tsx @@ -1,10 +1,10 @@ import React, { useEffect, useState } from 'react'; -import logo from './logo.svg'; import './App.css'; -import { WebsocketPlayingFieldComponent } from './components/PlayingField/PlayingField'; +import { PlayingFieldComponent} from './components/PlayingField/PlayingField'; import { Client } from './client'; import { createBrowserRouter, RouterProvider } from 'react-router-dom'; import { GmPlayingFieldComponent } from './components/GmPlayingField/GmPlayingField'; +import { WebsocketProvider } from './components/WebsocketProvider'; interface AppProps { client: Client; @@ -26,7 +26,7 @@ const App = ({ client }: AppProps) => { }, { path: "/", - element: websocketUrl ? :
+ element: websocketUrl ? :
} ]); return ( diff --git a/visions/ui/src/components/PlayingField/PlayingField.tsx b/visions/ui/src/components/PlayingField/PlayingField.tsx index ec44de9..9cbf15d 100644 --- a/visions/ui/src/components/PlayingField/PlayingField.tsx +++ b/visions/ui/src/components/PlayingField/PlayingField.tsx @@ -1,80 +1,22 @@ -import React, { useEffect, useState, useCallback } from 'react'; -import { Client, PlayingField } from '../../client'; -import { ThumbnailComponent } from '../Thumbnail/Thumbnail'; +import React, { useContext } from 'react'; import './PlayingField.css'; -import useWebSocket, { ReadyState } from 'react-use-websocket'; +import { WebsocketContext } from '../WebsocketProvider'; +import { Client } from '../../client'; -/* -export const PlayingFieldComponent = ({ client }: PlayingFieldProps) => { - const [socketUrl, setSocketUrl] = useState(undefined); - const [field, setField] = useState(undefined); - - const [images, setImages] = useState([]); - useEffect(() => { - client.availableImages().then((images) => setImages(images)); - }, [client]); - - const backgroundUrl = field && client.imageUrl(field.backgroundImage); - return (
-
- {images.map((imageName) => )} -
-
{backgroundUrl && playing field}
-
Right Panel
-
) -} -*/ - -interface WebsocketPlayingFieldProps { +interface PlayingFieldComponentProps { client: Client; - websocketUrl: string; } -type Message = | -{ - type: "PlayArea"; - background_image: string; -} - -export const WebsocketPlayingFieldComponent = ({ client, websocketUrl }: WebsocketPlayingFieldProps) => { - const { lastMessage, readyState } = useWebSocket(websocketUrl); - const [backgroundUrl, setBackgroundUrl] = useState(undefined); - - useEffect(() => { - if (lastMessage !== null) { - const message: Message = JSON.parse(lastMessage.data); - console.log("playing area: ", message); - console.log("playing area: ", message.background_image); - setBackgroundUrl(client.imageUrl(message.background_image)); - } - }, [lastMessage]); - - const connectionStatus = { - [ReadyState.CONNECTING]: 'Connecting', - [ReadyState.OPEN]: 'Open', - [ReadyState.CLOSING]: 'Closing', - [ReadyState.CLOSED]: 'Closed', - [ReadyState.UNINSTANTIATED]: 'Uninstantiated', - }[readyState]; - - return ; -} - -interface PlayingFieldProps { - backgroundUrl: URL | undefined; - connectionStatus: string; -} - -export const PlayingFieldComponent = ({ backgroundUrl, connectionStatus }: PlayingFieldProps) => { - if (backgroundUrl) { +export const PlayingFieldComponent = ({ client }: PlayingFieldComponentProps) => { + const { backgroundImage } = useContext(WebsocketContext); + console.log("backgroundImage", backgroundImage); + if (backgroundImage) { return (
-
{backgroundUrl && playing field}
-
{connectionStatus}
+
{backgroundImage && playing field}
) } else { return (
-
{connectionStatus}
); } diff --git a/visions/ui/src/components/WebsocketProvider.tsx b/visions/ui/src/components/WebsocketProvider.tsx new file mode 100644 index 0000000..4737170 --- /dev/null +++ b/visions/ui/src/components/WebsocketProvider.tsx @@ -0,0 +1,48 @@ +import React, { createContext, PropsWithChildren, useEffect, useReducer } from "react"; +import useWebSocket from "react-use-websocket"; + +type Message = | +{ + type: "PlayArea"; + background_image: string; +} + +type TabletopState = { + backgroundImage: string | undefined; +} + +const initialState = () => ({ backgroundImage: undefined }); + +export const WebsocketContext = createContext(initialState()); + +interface WebsocketProviderProps { + websocketUrl: string; +} + +export const WebsocketProvider = ({ websocketUrl, children }: PropsWithChildren) => { + const { lastMessage } = useWebSocket(websocketUrl); + + const [state, dispatch] = useReducer(handleMessage, initialState()); + + useEffect(() => { + if (lastMessage !== null) { + const message: Message = JSON.parse(lastMessage.data); + dispatch(message); + } + }, [lastMessage]); + + return ( + {children} + ); +} + +const handleMessage = (state: TabletopState, message: Message): TabletopState => { + switch (message.type) { + case "PlayArea": { + return { + ...state, + backgroundImage: message.background_image, + } + } + } +}