diff --git a/Cargo.lock b/Cargo.lock index 7ed4186..a99ead4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -522,7 +522,7 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" name = "changeset" version = "0.1.0" dependencies = [ - "uuid 0.8.2", + "uuid 1.11.0", ] [[package]] @@ -4637,9 +4637,9 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "typeshare" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04f17399b76c2e743d58eac0635d7686e9c00f48cd4776f00695d9882a7d3187" +checksum = "19be0f411120091e76e13e5a0186d8e2bcc3e7e244afdb70152197f1a8486ceb" dependencies = [ "chrono", "serde 1.0.210", @@ -4865,6 +4865,7 @@ dependencies = [ "serde_json", "tokio", "tokio-stream", + "typeshare", "uuid 1.11.0", "warp", ] diff --git a/flake.lock b/flake.lock index 48c239e..7fc0bd8 100644 --- a/flake.lock +++ b/flake.lock @@ -5,11 +5,11 @@ "systems": "systems" }, "locked": { - "lastModified": 1681202837, - "narHash": "sha256-H+Rh19JDwRtpVPAWp64F+rlEtxUWBAQW28eAi3SRSzg=", + "lastModified": 1710146030, + "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=", "owner": "numtide", "repo": "flake-utils", - "rev": "cfacdce06f30d2b68473a46042957675eebb3401", + "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a", "type": "github" }, "original": { @@ -35,11 +35,11 @@ }, "nixpkgs_2": { "locked": { - "lastModified": 1681303793, - "narHash": "sha256-JEdQHsYuCfRL2PICHlOiH/2ue3DwoxUX7DJ6zZxZXFk=", + "lastModified": 1714906307, + "narHash": "sha256-UlRZtrCnhPFSJlDQE7M0eyhgvuuHBTe1eJ9N9AQlJQ0=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "fe2ecaf706a5907b5e54d979fbde4924d84b65fc", + "rev": "25865a40d14b3f9cf19f19b924e2ab4069b09588", "type": "github" }, "original": { @@ -76,11 +76,11 @@ "nixpkgs": "nixpkgs_2" }, "locked": { - "lastModified": 1698205128, - "narHash": "sha256-jP+81TkldLtda8bzmsBWahETGsyFkoDOCT244YkA+S4=", + "lastModified": 1731966246, + "narHash": "sha256-e/V7Ffm5wPd9DVzCThnPZ7lFxd43bb64tSk8/oGP4Ag=", "owner": "1Password", "repo": "typeshare", - "rev": "c3ee2ad8f27774c45db7af4f2ba746c4ae11de21", + "rev": "e0e5f27ee34d7d4da76a9dc96a11552e98be56da", "type": "github" }, "original": { diff --git a/visions/server/Cargo.toml b/visions/server/Cargo.toml index 94f0ccb..f00e67c 100644 --- a/visions/server/Cargo.toml +++ b/visions/server/Cargo.toml @@ -17,3 +17,4 @@ mime = "0.3.17" uuid = { version = "1.11.0", features = ["v4"] } futures = "0.3.31" tokio-stream = "0.1.16" +typeshare = "1.0.4" diff --git a/visions/server/src/core.rs b/visions/server/src/core.rs index bf6780a..d566f9b 100644 --- a/visions/server/src/core.rs +++ b/visions/server/src/core.rs @@ -8,7 +8,7 @@ use std::{ use tokio::sync::mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender}; use uuid::Uuid; -use crate::types::{AppError, Message, PlayArea}; +use crate::types::{AppError, Message, Tabletop, RGB}; #[derive(Debug)] struct WebsocketClient { @@ -18,9 +18,7 @@ struct WebsocketClient { #[derive(Debug)] pub struct AppState { pub image_base: PathBuf, - - pub playfield_background: String, - + pub tabletop: Tabletop, pub clients: HashMap, } @@ -31,7 +29,10 @@ impl Core { pub fn new() -> Self { Self(Arc::new(RwLock::new(AppState { image_base: PathBuf::from("/home/savanni/Pictures"), - playfield_background: "moon.jpg".to_owned(), + tabletop: Tabletop { + background_color: RGB{ red: 15, green: 0, blue: 0 }, + background_image: None, + }, clients: HashMap::new(), }))) } @@ -53,7 +54,7 @@ impl Core { pub fn connect_client(&self, client_id: String) -> UnboundedReceiver { let mut state = self.0.write().unwrap(); - + match state.clients.get_mut(&client_id) { Some(client) => { let (tx, rx) = unbounded_channel(); @@ -98,12 +99,13 @@ impl Core { .collect() } - pub fn set_playfield_background(&self, path: String) -> Result<(), AppError> { - { + pub fn set_background_image(&self, path: String) -> Result<(), AppError> { + let tabletop = { let mut state = self.0.write().unwrap(); - state.playfield_background = path.clone(); - } - self.publish(Message::PlayArea(PlayArea{ background_image: path })); + state.tabletop.background_image = Some(path.clone()); + state.tabletop.clone() + }; + self.publish(Message::UpdateTabletop(tabletop)); Ok(()) } diff --git a/visions/server/src/handlers.rs b/visions/server/src/handlers.rs index eb35e10..83a1386 100644 --- a/visions/server/src/handlers.rs +++ b/visions/server/src/handlers.rs @@ -5,7 +5,7 @@ use serde::{Deserialize, Serialize}; use tokio_stream::wrappers::UnboundedReceiverStream; use warp::{http::Response, reply::Reply, ws::Message}; -use crate::{core::Core, types::PlayArea}; +use crate::{core::Core}; /* pub async fn handle_auth( @@ -31,18 +31,6 @@ pub async fn handle_auth( } */ -pub async fn handle_playing_field() -> impl Reply { - Response::builder() - .header("application-type", "application/json") - .body( - serde_json::to_string(&PlayArea { - background_image: "tower-in-mist.jpg".to_owned(), - }) - .unwrap(), - ) - .unwrap() -} - pub async fn handle_file(core: Core, file_name: String) -> impl Reply { let mimetype = mime_guess::from_path(&file_name).first().unwrap(); let bytes = core.get_file(file_name); @@ -102,11 +90,11 @@ pub async fn handle_connect_websocket( let mut receiver = core.connect_client(client_id.clone()); tokio::task::spawn(async move { - let background_image = core.0.read().unwrap().playfield_background.clone(); + let tabletop = core.0.read().unwrap().tabletop.clone(); let _ = ws_sender - .send(Message::text( - serde_json::to_string(&crate::types::Message::PlayArea(PlayArea{ background_image })).unwrap(), - )) + .send(Message::text(serde_json::to_string( + &crate::types::Message::UpdateTabletop(tabletop), + ).unwrap())) .await; while let Some(msg) = receiver.recv().await { println!("Relaying message: {:?}", msg); diff --git a/visions/server/src/main.rs b/visions/server/src/main.rs index ff680af..c93d8e1 100644 --- a/visions/server/src/main.rs +++ b/visions/server/src/main.rs @@ -1,6 +1,6 @@ use authdb::AuthError; use handlers::{ - handle_available_images, handle_connect_websocket, handle_file, handle_playing_field, + handle_available_images, handle_connect_websocket, handle_file, handle_register_client, handle_unregister_client, RegisterRequest, }; use std::{ @@ -98,8 +98,6 @@ async fn handle_rejection(err: warp::Rejection) -> Result, +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(tag = "type", content = "content")] +#[typeshare] pub enum Message { - PlayArea(PlayArea), + UpdateTabletop(Tabletop), } diff --git a/visions/ui/src/App.tsx b/visions/ui/src/App.tsx index 9148424..b3ad3af 100644 --- a/visions/ui/src/App.tsx +++ b/visions/ui/src/App.tsx @@ -1,6 +1,6 @@ import React, { useEffect, useState } from 'react'; import './App.css'; -import { PlayingFieldComponent} from './components/PlayingField/PlayingField'; +import { TabletopElement } from './components/Tabletop/Tabletop'; import { Client } from './client'; import { createBrowserRouter, RouterProvider } from 'react-router-dom'; import { GmPlayingFieldComponent } from './components/GmPlayingField/GmPlayingField'; @@ -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 deleted file mode 100644 index 9cbf15d..0000000 --- a/visions/ui/src/components/PlayingField/PlayingField.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import React, { useContext } from 'react'; -import './PlayingField.css'; -import { WebsocketContext } from '../WebsocketProvider'; -import { Client } from '../../client'; - -interface PlayingFieldComponentProps { - client: Client; -} - -export const PlayingFieldComponent = ({ client }: PlayingFieldComponentProps) => { - const { backgroundImage } = useContext(WebsocketContext); - console.log("backgroundImage", backgroundImage); - if (backgroundImage) { - return (
-
{backgroundImage && playing field}
-
) - } else { - return (
-
-
- ); - } -} diff --git a/visions/ui/src/components/PlayingField/PlayingField.css b/visions/ui/src/components/Tabletop/Tabletop.css similarity index 100% rename from visions/ui/src/components/PlayingField/PlayingField.css rename to visions/ui/src/components/Tabletop/Tabletop.css diff --git a/visions/ui/src/components/Tabletop/Tabletop.tsx b/visions/ui/src/components/Tabletop/Tabletop.tsx new file mode 100644 index 0000000..50c7375 --- /dev/null +++ b/visions/ui/src/components/Tabletop/Tabletop.tsx @@ -0,0 +1,23 @@ +import React, { useContext } from 'react'; +import './Tabletop.css'; +import { WebsocketContext } from '../WebsocketProvider'; +import { Client } from '../../client'; + +interface TabletopElementProps { + client: Client; +} + +export const TabletopElement = ({ client }: TabletopElementProps) => { + const { tabletop } = useContext(WebsocketContext); + console.log("backgroundImage", tabletop.backgroundImage); + if (tabletop.backgroundImage) { + return (
+
{tabletop.backgroundImage && playing field}
+
) + } else { + return (
+
+
+ ); + } +} diff --git a/visions/ui/src/components/WebsocketProvider.tsx b/visions/ui/src/components/WebsocketProvider.tsx index 4737170..42cdf48 100644 --- a/visions/ui/src/components/WebsocketProvider.tsx +++ b/visions/ui/src/components/WebsocketProvider.tsx @@ -1,17 +1,12 @@ import React, { createContext, PropsWithChildren, useEffect, useReducer } from "react"; import useWebSocket from "react-use-websocket"; - -type Message = | -{ - type: "PlayArea"; - background_image: string; -} +import { Message, Tabletop } from "visions"; type TabletopState = { - backgroundImage: string | undefined; + tabletop: Tabletop; } -const initialState = () => ({ backgroundImage: undefined }); +const initialState = (): TabletopState => ({ tabletop: { backgroundColor: { red: 0, green: 0, blue: 0 }, backgroundImage: undefined } }); export const WebsocketContext = createContext(initialState()); @@ -37,11 +32,12 @@ export const WebsocketProvider = ({ websocketUrl, children }: PropsWithChildren< } const handleMessage = (state: TabletopState, message: Message): TabletopState => { + console.log(message); switch (message.type) { - case "PlayArea": { + case "UpdateTabletop": { return { ...state, - backgroundImage: message.background_image, + tabletop: message.content, } } } diff --git a/visions/ui/tsconfig.json b/visions/ui/tsconfig.json index a273b0c..2ccd292 100644 --- a/visions/ui/tsconfig.json +++ b/visions/ui/tsconfig.json @@ -21,6 +21,7 @@ "jsx": "react-jsx" }, "include": [ - "src" + "src", + "gen" ] }