chat
This commit is contained in:
parent
50a75bbc70
commit
0021c0be79
3 changed files with 166 additions and 63 deletions
|
@ -1,9 +1,37 @@
|
|||
use html::Textarea;
|
||||
use std::rc::Rc;
|
||||
|
||||
use html::{Input, Textarea};
|
||||
use leptos::*;
|
||||
use leptos_use::{core::ConnectionReadyState, use_websocket, UseWebsocketReturn};
|
||||
use lib::models::*;
|
||||
use serde_json::to_string;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct WebSocketContext {
|
||||
pub ready_state: Signal<ConnectionReadyState>,
|
||||
pub message: Signal<Option<String>>,
|
||||
send: Rc<dyn Fn(&str)>,
|
||||
}
|
||||
|
||||
impl WebSocketContext {
|
||||
pub fn new(
|
||||
ready_state: Signal<ConnectionReadyState>,
|
||||
message: Signal<Option<String>>,
|
||||
send: Rc<dyn Fn(&str)>,
|
||||
) -> Self {
|
||||
Self {
|
||||
ready_state,
|
||||
message,
|
||||
send,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn send(&self, message: &str) {
|
||||
(self.send)(message)
|
||||
}
|
||||
}
|
||||
|
||||
#[component]
|
||||
pub fn Websocket() -> impl IntoView {
|
||||
let UseWebsocketReturn {
|
||||
|
@ -15,10 +43,15 @@ pub fn Websocket() -> impl IntoView {
|
|||
..
|
||||
} = use_websocket("ws://0.0.0.0:3030/websocket");
|
||||
|
||||
provide_context(WebSocketContext::new(
|
||||
ready_state,
|
||||
message,
|
||||
Rc::new(send.clone()),
|
||||
));
|
||||
|
||||
// Signals
|
||||
let (online_users, set_online_users) = create_signal(0);
|
||||
let (active_games, set_active_games) = create_signal(0);
|
||||
let (chat_history, set_chat_history) = create_signal::<Vec<String>>(vec![]);
|
||||
|
||||
// Websocket stuff
|
||||
let status = move || ready_state.get().to_string();
|
||||
|
@ -37,23 +70,16 @@ pub fn Websocket() -> impl IntoView {
|
|||
packs: vec![0],
|
||||
};
|
||||
|
||||
// Game stuff
|
||||
let new_game_test = move |_| {
|
||||
send(&to_string(&fake_new_game_request).unwrap());
|
||||
};
|
||||
|
||||
let close_connection = move |_| {
|
||||
close();
|
||||
set_online_users(0);
|
||||
set_active_games(0);
|
||||
update_chat_history(&set_chat_history, format!("Disconnected.\n"));
|
||||
};
|
||||
// Chat stuff
|
||||
let chat_history_ref = create_node_ref::<Textarea>();
|
||||
|
||||
fn update_chat_history(&history: &WriteSignal<Vec<String>>, message: String) {
|
||||
let _ = &history.update(|history: &mut Vec<_>| history.push(message));
|
||||
}
|
||||
// Game stuff
|
||||
let new_game_test = move |_| {
|
||||
send(&to_string(&fake_new_game_request).unwrap());
|
||||
};
|
||||
|
||||
// handle incoming messages
|
||||
|
||||
|
@ -75,29 +101,17 @@ pub fn Websocket() -> impl IntoView {
|
|||
set_online_users(state_summary.online_users);
|
||||
set_active_games(state_summary.active_games);
|
||||
} else {
|
||||
update_chat_history(&set_chat_history, format!("{}\n", message));
|
||||
logging::log!("Send {} to Chat component", message);
|
||||
// update_chat_history(&set_chat_history, format!("{}\n", message));
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
create_effect(move |_| {
|
||||
chat_history.with(move |_| {
|
||||
// Scroll chat textarea to bottom
|
||||
if let Some(hist) = chat_history_ref.get() {
|
||||
hist.set_scroll_top(hist.scroll_height());
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
// Login stuff
|
||||
let (username, _set_username) = create_signal("ligma");
|
||||
|
||||
view! {
|
||||
<div class="w-auto bg-slate-500">
|
||||
<hr/>
|
||||
<h2 class="text-2xl">Connection</h2>
|
||||
|
||||
<h2 class="p-1 text-2xl">Server Info:</h2>
|
||||
<p class="p-1">"Users Online: " {online_users}</p>
|
||||
<p class="p-1">"Active Games: " {active_games}</p>
|
||||
<p class="p-1">"Connection Status: " {status}</p>
|
||||
|
@ -110,40 +124,129 @@ pub fn Websocket() -> impl IntoView {
|
|||
</button>
|
||||
</div>
|
||||
<hr/>
|
||||
<div class="p-1">
|
||||
<h2 class="text-2xl">Sign in</h2>
|
||||
<p>Username:</p>
|
||||
<input
|
||||
class="w-96 font-mono rounded-sm bg-slate-900 text-slate-200"
|
||||
placeholder={move || username.get()}
|
||||
/>
|
||||
</div>
|
||||
<hr />
|
||||
<div class="p-1">
|
||||
<h2 class="text-2xl">Chat</h2>
|
||||
<textarea
|
||||
node_ref=chat_history_ref
|
||||
class="w-96 h-60 font-mono rounded-sm resize-none bg-slate-900 text-slate-200"
|
||||
readonly=true
|
||||
wrap="soft"
|
||||
>
|
||||
{move || chat_history.get()}
|
||||
</textarea>
|
||||
<br/>
|
||||
<input
|
||||
class="w-96 font-mono rounded-sm bg-slate-900 text-slate-200"
|
||||
placeholder="talk shit..."
|
||||
/>
|
||||
<br/>
|
||||
// <button on:click=send_message disabled=move || !connected()>
|
||||
// "Send"
|
||||
// </button>
|
||||
<br />
|
||||
<button on:click=new_game_test disabled=move || !connected()>
|
||||
"Test New Game"
|
||||
</button>
|
||||
</div>
|
||||
<Auth/>
|
||||
<hr/>
|
||||
<Chat/>
|
||||
<hr/>
|
||||
<button on:click=new_game_test disabled=move || !connected()>
|
||||
"Test New Game"
|
||||
</button>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
#[component]
|
||||
pub fn Chat() -> impl IntoView {
|
||||
let websocket = expect_context::<WebSocketContext>();
|
||||
|
||||
// Chat stuff
|
||||
let (chat_history, set_chat_history) = create_signal::<Vec<String>>(vec![]);
|
||||
let chat_history_ref = create_node_ref::<Textarea>();
|
||||
let chat_input_ref = create_node_ref::<Input>();
|
||||
|
||||
fn update_chat_history(&history: &WriteSignal<Vec<String>>, message: String) {
|
||||
let _ = &history.update(|history: &mut Vec<_>| history.push(message));
|
||||
}
|
||||
|
||||
// Connection status updates in chat window
|
||||
create_effect(move |_| {
|
||||
websocket.ready_state.with(move |state| match *state {
|
||||
ConnectionReadyState::Connecting => {
|
||||
update_chat_history(&set_chat_history, format!("Connecting to game server...\n"));
|
||||
}
|
||||
ConnectionReadyState::Open => {
|
||||
update_chat_history(&set_chat_history, format!("Connected!\n"));
|
||||
}
|
||||
ConnectionReadyState::Closing => {
|
||||
update_chat_history(&set_chat_history, format!("Disconnecting...\n"));
|
||||
}
|
||||
ConnectionReadyState::Closed => {
|
||||
update_chat_history(&set_chat_history, format!("Disconnected.\n"));
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
// let chat = move || {
|
||||
// if let Some(ye) = chat_input_ref.get() {
|
||||
// &websocket.send(&ye.value());
|
||||
// };
|
||||
// };
|
||||
|
||||
// This should be done elsewhere
|
||||
create_effect(move |_| {
|
||||
websocket.message.with(move |message_raw| {
|
||||
// Send all messages as strings into chat box
|
||||
if let Some(message) = message_raw {
|
||||
if let Ok(_game) = serde_json::from_str::<Game>(message) {
|
||||
logging::log!("Game object received at chat component");
|
||||
} else if let Ok(_) = serde_json::from_str::<ServerStateSummary>(message) {
|
||||
logging::log!("State Summary received at chat component");
|
||||
} else {
|
||||
update_chat_history(&set_chat_history, format!("{}\n", message));
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
let send_message = move |_| {
|
||||
websocket.send(&chat_input_ref.get().unwrap().value());
|
||||
chat_input_ref.get().unwrap().set_value("");
|
||||
logging::log!("Send Message");
|
||||
};
|
||||
|
||||
// Keep chat scrolled to the bottom
|
||||
create_effect(move |_| {
|
||||
chat_history.with(move |_| {
|
||||
// Scroll chat textarea to bottom
|
||||
if let Some(hist) = chat_history_ref.get() {
|
||||
hist.set_scroll_top(hist.scroll_height());
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
view! {
|
||||
<div class="p-1">
|
||||
<h2 class="text-2xl">Chat:</h2>
|
||||
<textarea
|
||||
node_ref=chat_history_ref
|
||||
class="w-96 h-60 font-mono rounded-sm resize-none bg-slate-900 text-slate-200"
|
||||
readonly=true
|
||||
wrap="soft"
|
||||
>
|
||||
{move || chat_history.get()}
|
||||
</textarea>
|
||||
<br/>
|
||||
<span>
|
||||
<input
|
||||
class="w-80 h-11 font-mono rounded-sm bg-slate-900 text-slate-200"
|
||||
placeholder="talk shit..."
|
||||
node_ref=chat_input_ref
|
||||
on:change=send_message.clone()
|
||||
/>
|
||||
<input
|
||||
class="py-2 px-4 pl-4 font-bold text-white rounded border-b-4 bg-slate-600 border-slate-800 hover:bg-slate-700 hover:border-slate-500"
|
||||
type="submit"
|
||||
value="Send"
|
||||
on:change=send_message.clone()
|
||||
/>
|
||||
</span>
|
||||
<br/>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
#[component]
|
||||
pub fn Auth() -> impl IntoView {
|
||||
let (username, _set_username) = create_signal("Anonymous");
|
||||
|
||||
view! {
|
||||
<div class="p-1">
|
||||
<h2 class="text-2xl">Sign in:</h2>
|
||||
<p>Username:</p>
|
||||
<input
|
||||
class="w-96 font-mono rounded-sm bg-slate-900 text-slate-200"
|
||||
placeholder=move || username.get()
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ pub fn Home() -> impl IntoView {
|
|||
<div class="container m-auto">
|
||||
<h1 class="text-6xl text-slate-300">"Cards For Humanity"</h1>
|
||||
<Websocket/>
|
||||
<a href="https://git.doordesk.net/adam/cards/">git</a>
|
||||
<a href="https://git.doordesk.net/adam/cards/">git</a>
|
||||
</div>
|
||||
</ErrorBoundary>
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ use crate::message_handler::*;
|
|||
|
||||
fn motd() -> String {
|
||||
format!(
|
||||
"Welcome!"
|
||||
"Greetings from the game server!"
|
||||
)
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue