Compare commits
No commits in common. "a8170fd5c6938ad0e48f3fcfdd13ebcf7ce15f5d" and "69ef3c3892220bdc599bb8305f81ac9d21e94e88" have entirely different histories.
a8170fd5c6
...
69ef3c3892
|
@ -522,7 +522,7 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
name = "changeset"
|
name = "changeset"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"uuid 0.8.2",
|
"uuid 1.10.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -2357,7 +2357,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4"
|
checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"windows-targets 0.52.6",
|
"windows-targets 0.48.5",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -4815,9 +4815,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uuid"
|
name = "uuid"
|
||||||
version = "1.11.0"
|
version = "1.10.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a"
|
checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom",
|
"getrandom",
|
||||||
]
|
]
|
||||||
|
@ -4857,15 +4857,12 @@ name = "visions"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"authdb",
|
"authdb",
|
||||||
"futures",
|
|
||||||
"http 1.1.0",
|
"http 1.1.0",
|
||||||
"mime 0.3.17",
|
"mime 0.3.17",
|
||||||
"mime_guess 2.0.5",
|
"mime_guess 2.0.5",
|
||||||
"serde 1.0.210",
|
"serde 1.0.210",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-stream",
|
|
||||||
"uuid 1.11.0",
|
|
||||||
"warp",
|
"warp",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,3 @@ tokio = { version = "1", features = [ "full" ] }
|
||||||
warp = { version = "0.3" }
|
warp = { version = "0.3" }
|
||||||
mime_guess = "2.0.5"
|
mime_guess = "2.0.5"
|
||||||
mime = "0.3.17"
|
mime = "0.3.17"
|
||||||
uuid = { version = "1.11.0", features = ["v4"] }
|
|
||||||
futures = "0.3.31"
|
|
||||||
tokio-stream = "0.1.16"
|
|
||||||
|
|
|
@ -1,25 +1,17 @@
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
|
||||||
io::Read,
|
io::Read,
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
sync::{Arc, RwLock},
|
sync::{Arc, RwLock},
|
||||||
};
|
};
|
||||||
|
|
||||||
use tokio::sync::mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender};
|
|
||||||
use uuid::Uuid;
|
|
||||||
|
|
||||||
use crate::types::Message;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct WebsocketClient {
|
pub enum AppError {
|
||||||
sender: Option<UnboundedSender<Message>>,
|
JsonError(serde_json::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct AppState {
|
pub struct AppState {
|
||||||
pub image_base: PathBuf,
|
pub image_base: PathBuf,
|
||||||
|
|
||||||
pub clients: HashMap<String, WebsocketClient>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
@ -29,40 +21,9 @@ impl Core {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self(Arc::new(RwLock::new(AppState {
|
Self(Arc::new(RwLock::new(AppState {
|
||||||
image_base: PathBuf::from("/home/savanni/Pictures"),
|
image_base: PathBuf::from("/home/savanni/Pictures"),
|
||||||
clients: HashMap::new(),
|
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn register_client(&self) -> String {
|
|
||||||
let mut state = self.0.write().unwrap();
|
|
||||||
let uuid = Uuid::new_v4().simple().to_string();
|
|
||||||
|
|
||||||
let client = WebsocketClient { sender: None };
|
|
||||||
|
|
||||||
state.clients.insert(uuid.clone(), client);
|
|
||||||
uuid
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn unregister_client(&self, client_id: String) {
|
|
||||||
let mut state = self.0.write().unwrap();
|
|
||||||
let _ = state.clients.remove(&client_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn connect_client(&self, client_id: String) -> UnboundedReceiver<Message> {
|
|
||||||
let mut state = self.0.write().unwrap();
|
|
||||||
|
|
||||||
match state.clients.get_mut(&client_id) {
|
|
||||||
Some(client) => {
|
|
||||||
let (tx, rx) = unbounded_channel();
|
|
||||||
client.sender = Some(tx);
|
|
||||||
rx
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
unimplemented!();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_file(&self, file_name: String) -> Vec<u8> {
|
pub fn get_file(&self, file_name: String) -> Vec<u8> {
|
||||||
let mut full_path = self.0.read().unwrap().image_base.clone();
|
let mut full_path = self.0.read().unwrap().image_base.clone();
|
||||||
full_path.push(&file_name);
|
full_path.push(&file_name);
|
||||||
|
@ -94,14 +55,4 @@ impl Core {
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn publish(&self, message: Message) {
|
|
||||||
let state = self.0.read().unwrap();
|
|
||||||
|
|
||||||
state.clients.values().for_each(|client| {
|
|
||||||
if let Some(ref sender) = client.sender {
|
|
||||||
let _ = sender.send(message.clone());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,11 @@
|
||||||
use std::{pin::Pin, time::Duration};
|
use std::{io::Read, path::PathBuf};
|
||||||
|
|
||||||
use futures::{SinkExt, StreamExt};
|
use authdb::{AuthDB, AuthToken};
|
||||||
|
use http::{response::Response, status::StatusCode, Error};
|
||||||
use serde::{Deserialize, Serialize};
|
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(
|
pub async fn handle_auth(
|
||||||
auth_ctx: &AuthDB,
|
auth_ctx: &AuthDB,
|
||||||
auth_token: AuthToken,
|
auth_token: AuthToken,
|
||||||
|
@ -29,91 +27,18 @@ pub async fn handle_auth(
|
||||||
.body("".to_owned()),
|
.body("".to_owned()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
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);
|
|
||||||
Response::builder()
|
|
||||||
.header("application-type", mimetype.to_string())
|
|
||||||
.body(bytes)
|
|
||||||
.unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn handle_available_images(core: Core) -> impl Reply {
|
|
||||||
Response::builder()
|
|
||||||
.header("Access-Control-Allow-Origin", "*")
|
|
||||||
.header("Content-Type", "application/json")
|
|
||||||
.body(serde_json::to_string(&core.available_images()).unwrap())
|
|
||||||
.unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize)]
|
#[derive(Deserialize, Serialize)]
|
||||||
pub struct RegisterRequest {}
|
pub struct PlayArea {
|
||||||
|
pub background_image: PathBuf,
|
||||||
#[derive(Deserialize, Serialize)]
|
|
||||||
pub struct RegisterResponse {
|
|
||||||
url: String,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn handle_register_client(core: Core, request: RegisterRequest) -> impl Reply {
|
pub fn handle_playing_field() -> PlayArea {
|
||||||
let client_id = core.register_client();
|
PlayArea {
|
||||||
|
background_image: PathBuf::from("tower-in-mist.jpg"),
|
||||||
Response::builder()
|
|
||||||
.header("Access-Control-Allow-Origin", "*")
|
|
||||||
.header("Content-Type", "application/json")
|
|
||||||
.body(
|
|
||||||
serde_json::to_string(&RegisterResponse {
|
|
||||||
url: format!("ws://127.0.0.1:8001/ws/{}", client_id),
|
|
||||||
})
|
|
||||||
.unwrap(),
|
|
||||||
)
|
|
||||||
.unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn handle_unregister_client(core: Core, client_id: String) -> impl Reply {
|
|
||||||
core.unregister_client(client_id);
|
|
||||||
|
|
||||||
warp::reply::reply()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn handle_connect_websocket(
|
|
||||||
core: Core,
|
|
||||||
ws: warp::ws::Ws,
|
|
||||||
client_id: String,
|
|
||||||
) -> impl Reply {
|
|
||||||
println!("handle_connect_websocket: {}", client_id);
|
|
||||||
ws.on_upgrade(move |socket| {
|
|
||||||
let core = core.clone();
|
|
||||||
async move {
|
|
||||||
let (mut ws_sender, mut ws_recv) = socket.split();
|
|
||||||
let mut receiver = core.connect_client(client_id);
|
|
||||||
|
|
||||||
tokio::task::spawn(async move {
|
|
||||||
let _ = ws_sender
|
|
||||||
.send(Message::text(
|
|
||||||
serde_json::to_string(&crate::types::Message::Count(0)).unwrap(),
|
|
||||||
))
|
|
||||||
.await;
|
|
||||||
while let Some(msg) = receiver.recv().await {
|
|
||||||
println!("Relaying message: {:?}", msg);
|
|
||||||
let _ = ws_sender
|
|
||||||
.send(Message::text(serde_json::to_string(&msg).unwrap()))
|
|
||||||
.await;
|
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
}
|
|
||||||
})
|
pub fn handle_file(core: Core, file_name: String) -> Vec<u8> {
|
||||||
|
core.get_file(file_name)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,5 @@
|
||||||
use authdb::AuthError;
|
use authdb::AuthError;
|
||||||
use handlers::{
|
use handlers::{handle_file, handle_playing_field};
|
||||||
handle_available_images, handle_connect_websocket, handle_file, handle_playing_field,
|
|
||||||
handle_register_client, handle_unregister_client, RegisterRequest,
|
|
||||||
};
|
|
||||||
use std::{
|
use std::{
|
||||||
convert::Infallible,
|
convert::Infallible,
|
||||||
net::{IpAddr, Ipv4Addr, SocketAddr},
|
net::{IpAddr, Ipv4Addr, SocketAddr},
|
||||||
|
@ -19,7 +16,7 @@ mod core;
|
||||||
mod handlers;
|
mod handlers;
|
||||||
// use handlers::handle_auth;
|
// use handlers::handle_auth;
|
||||||
|
|
||||||
mod types;
|
mod routes;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct Unauthorized;
|
struct Unauthorized;
|
||||||
|
@ -98,61 +95,37 @@ async fn handle_rejection(err: warp::Rejection) -> Result<impl Reply, Infallible
|
||||||
pub async fn main() {
|
pub async fn main() {
|
||||||
let core = core::Core::new();
|
let core = core::Core::new();
|
||||||
|
|
||||||
let route_playing_field = warp::path!("api" / "v1" / "field").then(|| handle_playing_field());
|
let route_playing_field =
|
||||||
|
warp::path!("api" / "v1" / "field").map(move || warp::reply::json(&handle_playing_field()));
|
||||||
|
|
||||||
let route_image = warp::path!("api" / "v1" / "image" / String)
|
let route_image = warp::path!("api" / "v1" / "image" / String)
|
||||||
.and(warp::get())
|
.and(warp::get())
|
||||||
.then({
|
|
||||||
let core = core.clone();
|
|
||||||
move |file_name| handle_file(core.clone(), file_name)
|
|
||||||
});
|
|
||||||
|
|
||||||
let route_available_images = warp::path!("api" / "v1" / "image").and(warp::get()).then({
|
|
||||||
let core = core.clone();
|
|
||||||
move || handle_available_images(core.clone())
|
|
||||||
});
|
|
||||||
|
|
||||||
let route_register_client = warp::path!("api" / "v1" / "client")
|
|
||||||
.and(warp::post())
|
|
||||||
.then({
|
|
||||||
let core = core.clone();
|
|
||||||
move || handle_register_client(core.clone(), RegisterRequest {})
|
|
||||||
});
|
|
||||||
|
|
||||||
let route_unregister_client = warp::path!("api" / "v1" / "client" / String)
|
|
||||||
.and(warp::delete())
|
|
||||||
.then({
|
|
||||||
let core = core.clone();
|
|
||||||
move |client_id| handle_unregister_client(core.clone(), client_id)
|
|
||||||
});
|
|
||||||
|
|
||||||
let route_websocket = warp::path("ws")
|
|
||||||
.and(warp::ws())
|
|
||||||
.and(warp::path::param())
|
|
||||||
.then({
|
|
||||||
let core = core.clone();
|
|
||||||
move |ws, client_id| handle_connect_websocket(core.clone(), ws, client_id)
|
|
||||||
});
|
|
||||||
|
|
||||||
let route_publish = warp::path!("api" / "v1" / "message")
|
|
||||||
.and(warp::post())
|
|
||||||
.and(warp::body::json())
|
|
||||||
.map({
|
.map({
|
||||||
let core = core.clone();
|
let core = core.clone();
|
||||||
move |body| {
|
move |file_name| {
|
||||||
println!("route_publish: {:?}", body);
|
let core = core.clone();
|
||||||
core.publish(body);
|
let mimetype = mime_guess::from_path(&file_name).first().unwrap();
|
||||||
warp::reply()
|
let bytes = handle_file(core, file_name);
|
||||||
|
Response::builder()
|
||||||
|
.header("application-type", mimetype.to_string())
|
||||||
|
.body(bytes)
|
||||||
|
.unwrap()
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let filter = route_register_client
|
let route_available_images = warp::path!("api" / "v1" / "image").and(warp::get()).map({
|
||||||
.or(route_unregister_client)
|
let core = core.clone();
|
||||||
.or(route_websocket)
|
move || {
|
||||||
.or(route_playing_field)
|
let core = core.clone();
|
||||||
|
Response::builder()
|
||||||
|
.header("Access-Control-Allow-Origin", "*")
|
||||||
|
.body(serde_json::to_string(&core.available_images()).unwrap())
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let filter = route_playing_field
|
||||||
.or(route_image)
|
.or(route_image)
|
||||||
.or(route_available_images)
|
.or(route_available_images)
|
||||||
.or(route_publish)
|
|
||||||
.recover(handle_rejection);
|
.recover(handle_rejection);
|
||||||
|
|
||||||
let server = warp::serve(filter);
|
let server = warp::serve(filter);
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
use crate::{core::Core, handlers::handle_playing_field};
|
||||||
|
|
||||||
|
use warp::{reply::Json, Filter};
|
||||||
|
|
||||||
|
pub fn route_playing_field(
|
||||||
|
_app: Core,
|
||||||
|
) -> impl Filter<Extract = (Json,), Error = warp::Rejection> + Clone {
|
||||||
|
warp::path!("api" / "v1" / "field").map(move || warp::reply::json(&handle_playing_field()))
|
||||||
|
}
|
|
@ -1,20 +0,0 @@
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
|
||||||
pub struct PlayArea {
|
|
||||||
pub background_image: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum AppError {
|
|
||||||
JsonError(serde_json::Error),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
|
||||||
pub enum Message {
|
|
||||||
Count(u32),
|
|
||||||
// PlayArea(PlayArea),
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -10,14 +10,9 @@
|
||||||
"@types/node": "^16.18.119",
|
"@types/node": "^16.18.119",
|
||||||
"@types/react": "^18.3.12",
|
"@types/react": "^18.3.12",
|
||||||
"@types/react-dom": "^18.3.1",
|
"@types/react-dom": "^18.3.1",
|
||||||
"@types/react-router": "^5.1.20",
|
|
||||||
"@types/react-router-dom": "^5.3.3",
|
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-dom": "^18.3.1",
|
"react-dom": "^18.3.1",
|
||||||
"react-router": "^6.28.0",
|
|
||||||
"react-router-dom": "^6.28.0",
|
|
||||||
"react-scripts": "5.0.1",
|
"react-scripts": "5.0.1",
|
||||||
"react-use-websocket": "^4.11.1",
|
|
||||||
"typescript": "^4.9.5",
|
"typescript": "^4.9.5",
|
||||||
"web-vitals": "^2.1.4"
|
"web-vitals": "^2.1.4"
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,34 +1,14 @@
|
||||||
import React, { useEffect, useState } from 'react';
|
import React from 'react';
|
||||||
import logo from './logo.svg';
|
import logo from './logo.svg';
|
||||||
import './App.css';
|
import './App.css';
|
||||||
import { WebsocketPlayingFieldComponent } from './components/PlayingField/PlayingField';
|
import { PlayingFieldComponent } from './components/PlayingField/PlayingField';
|
||||||
import { Client } from './client';
|
import { Client } from './client';
|
||||||
import { createBrowserRouter, RouterProvider } from 'react-router-dom';
|
|
||||||
import { GmPlayingFieldComponent } from './components/GmPlayingField/GmPlayingField';
|
|
||||||
|
|
||||||
const App = () => {
|
const App = () => {
|
||||||
console.log("rendering app");
|
let client = new Client();
|
||||||
const client = new Client();
|
|
||||||
const [websocketUrl, setWebsocketUrl] = useState<string | undefined>(undefined);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
client.registerWebsocket().then((url) => setWebsocketUrl(url));
|
|
||||||
}, [client]);
|
|
||||||
|
|
||||||
let router =
|
|
||||||
createBrowserRouter([
|
|
||||||
{
|
|
||||||
path: "/gm",
|
|
||||||
element: <GmPlayingFieldComponent client={client} />
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: "/",
|
|
||||||
element: websocketUrl ? <WebsocketPlayingFieldComponent websocketUrl={websocketUrl} /> : <div> </div>
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
return (
|
return (
|
||||||
<div className="App">
|
<div className="App">
|
||||||
<RouterProvider router={router} />
|
<PlayingFieldComponent client={client} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,20 +9,6 @@ export class Client {
|
||||||
this.base = new URL("http://localhost:8001");
|
this.base = new URL("http://localhost:8001");
|
||||||
}
|
}
|
||||||
|
|
||||||
registerWebsocket() {
|
|
||||||
const url = new URL(this.base);
|
|
||||||
url.pathname = `api/v1/client`;
|
|
||||||
return fetch(url, { method: 'POST' }).then((response) => response.json()).then((ws) => ws.url);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
unregisterWebsocket() {
|
|
||||||
const url = new URL(this.base);
|
|
||||||
url.pathname = `api/v1/client`;
|
|
||||||
return fetch(url, { method: 'POST' }).then((response => response.json()));
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
imageUrl(imageId: string) {
|
imageUrl(imageId: string) {
|
||||||
const url = new URL(this.base);
|
const url = new URL(this.base);
|
||||||
url.pathname = `/api/v1/image/${imageId}`;
|
url.pathname = `/api/v1/image/${imageId}`;
|
||||||
|
|
|
@ -1,29 +0,0 @@
|
||||||
import React, { useEffect, useState } from 'react';
|
|
||||||
import { Client, PlayingField } from '../../client';
|
|
||||||
import { ThumbnailComponent } from '../Thumbnail/Thumbnail';
|
|
||||||
import './GmPlayingField.css';
|
|
||||||
|
|
||||||
interface GmPlayingFieldProps {
|
|
||||||
client: Client
|
|
||||||
}
|
|
||||||
|
|
||||||
export const GmPlayingFieldComponent = ({ client }: GmPlayingFieldProps) => {
|
|
||||||
const [field, setField] = useState<PlayingField | undefined>(undefined);
|
|
||||||
useEffect(() => {
|
|
||||||
client.playingField().then((field) => setField(field));
|
|
||||||
}, [client]);
|
|
||||||
|
|
||||||
const [images, setImages] = useState<string[]>([]);
|
|
||||||
useEffect(() => {
|
|
||||||
client.availableImages().then((images) => setImages(images));
|
|
||||||
}, [client]);
|
|
||||||
|
|
||||||
const backgroundUrl = field && client.imageUrl(field.backgroundImage);
|
|
||||||
return (<div className="playing-field">
|
|
||||||
<div>
|
|
||||||
{images.map((imageName) => <ThumbnailComponent client={client} imageId={imageName} />)}
|
|
||||||
</div>
|
|
||||||
<div className="playing-field__background"> {backgroundUrl && <img src={backgroundUrl.toString()} alt="playing field" />} </div>
|
|
||||||
</div>)
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,13 +1,17 @@
|
||||||
import React, { useEffect, useState, useCallback } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { Client, PlayingField } from '../../client';
|
import { Client, PlayingField } from '../../client';
|
||||||
import { ThumbnailComponent } from '../Thumbnail/Thumbnail';
|
import { ThumbnailComponent } from '../Thumbnail';
|
||||||
import './PlayingField.css';
|
import './PlayingField.css';
|
||||||
import useWebSocket, { ReadyState } from 'react-use-websocket';
|
|
||||||
|
|
||||||
/*
|
interface PlayingFieldProps {
|
||||||
|
client: Client
|
||||||
|
}
|
||||||
|
|
||||||
export const PlayingFieldComponent = ({ client }: PlayingFieldProps) => {
|
export const PlayingFieldComponent = ({ client }: PlayingFieldProps) => {
|
||||||
const [socketUrl, setSocketUrl] = useState<string | undefined>(undefined);
|
|
||||||
const [field, setField] = useState<PlayingField | undefined>(undefined);
|
const [field, setField] = useState<PlayingField | undefined>(undefined);
|
||||||
|
useEffect(() => {
|
||||||
|
client.playingField().then((field) => setField(field));
|
||||||
|
}, [client]);
|
||||||
|
|
||||||
const [images, setImages] = useState<string[]>([]);
|
const [images, setImages] = useState<string[]>([]);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -23,48 +27,3 @@ export const PlayingFieldComponent = ({ client }: PlayingFieldProps) => {
|
||||||
<div> Right Panel </div>
|
<div> Right Panel </div>
|
||||||
</div>)
|
</div>)
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
interface WebsocketPlayingFieldProps {
|
|
||||||
websocketUrl: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const WebsocketPlayingFieldComponent = ({ websocketUrl }: WebsocketPlayingFieldProps) => {
|
|
||||||
const { lastMessage, readyState } = useWebSocket(websocketUrl);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (lastMessage !== null) {
|
|
||||||
console.log("last message: ", lastMessage);
|
|
||||||
}
|
|
||||||
}, [lastMessage]);
|
|
||||||
|
|
||||||
const connectionStatus = {
|
|
||||||
[ReadyState.CONNECTING]: 'Connecting',
|
|
||||||
[ReadyState.OPEN]: 'Open',
|
|
||||||
[ReadyState.CLOSING]: 'Closing',
|
|
||||||
[ReadyState.CLOSED]: 'Closed',
|
|
||||||
[ReadyState.UNINSTANTIATED]: 'Uninstantiated',
|
|
||||||
}[readyState];
|
|
||||||
|
|
||||||
return <PlayingFieldComponent backgroundUrl={undefined} connectionStatus={connectionStatus} />;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface PlayingFieldProps {
|
|
||||||
backgroundUrl: string | undefined;
|
|
||||||
connectionStatus: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const PlayingFieldComponent = ({ backgroundUrl, connectionStatus }: PlayingFieldProps) => {
|
|
||||||
if (backgroundUrl) {
|
|
||||||
return (<div className="playing-field">
|
|
||||||
<div className="playing-field__background"> {backgroundUrl && <img src={backgroundUrl.toString()} alt="playing field" />} </div>
|
|
||||||
<div> {connectionStatus} </div>
|
|
||||||
</div>)
|
|
||||||
} else {
|
|
||||||
return (<div className="playing-field">
|
|
||||||
<div> </div>
|
|
||||||
<div> {connectionStatus} </div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { Client } from '../../client';
|
import { Client } from '../client';
|
||||||
import './Thumbnail.css';
|
import './Thumbnail.css';
|
||||||
|
|
||||||
interface ThumbnailProps {
|
interface ThumbnailProps {
|
Loading…
Reference in New Issue