Chat can now send and recieve messages perfectly. Needs UI help.
This commit is contained in:
parent
6861a3d8c2
commit
ea8807faf6
|
@ -1,7 +1,8 @@
|
|||
use std::sync::{Arc};
|
||||
|
||||
use chat_types::{dto::server_in::ServerMessageIn, domain::chat_message::{ChatMessageSender, ChatMessageContent}};
|
||||
use dev_dtos::dtos::user::user_dtos::UserForAuthenticationDto;
|
||||
use tokio::runtime::Runtime;
|
||||
use tokio::{runtime::Runtime, sync::RwLock};
|
||||
|
||||
|
||||
use crate::{utils::storage, ForeignError, client::chat::init_client_connection};
|
||||
|
@ -23,7 +24,9 @@ pub trait WebsocketFfi: Send + Sync + std::fmt::Debug {
|
|||
//fn attempt(&self, string_from_rust: String) -> Result<Option<String>, ForeignError>;
|
||||
}
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct WebsocketCaller;
|
||||
pub struct WebsocketCaller {
|
||||
message_queue: Arc<RwLock<Vec<ServerMessageIn>>>,
|
||||
}
|
||||
|
||||
impl<'a> WebsocketCaller {
|
||||
pub fn new() -> Self {
|
||||
|
@ -36,14 +39,22 @@ impl<'a> WebsocketCaller {
|
|||
let ws_ffi_rwlock = Arc::new(websocket_ffi);
|
||||
|
||||
let user: UserForAuthenticationDto = storage::read("user".into()).unwrap(); //TODO: Remove unwrap
|
||||
//websocket_ffi.message_recieved(ChatMessage { id: 20, from_id: 2, to_id: 1, message: "What the fuck nigga".as_bytes().to_vec(), message_content: MessageContentType::Text, time_sent: 1, time_delivered: vec![], time_seen: vec![] }).unwrap();
|
||||
|
||||
let rt = Runtime::new().unwrap();
|
||||
let _ = rt.block_on(
|
||||
init_client_connection(user, ws_ffi_rwlock)
|
||||
init_client_connection(user, ws_ffi_rwlock, self.message_queue.clone())
|
||||
);
|
||||
}
|
||||
pub fn send_message(&self, ) {
|
||||
pub fn send_text_message(&self, message: String, to: u32) {
|
||||
let rt = Runtime::new().unwrap();
|
||||
let _ = rt.block_on(
|
||||
add_message_to_queue(&self.message_queue, ServerMessageIn::SendMessage(ChatMessageSender { message: ChatMessageContent::Text(message), to }))
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn add_message_to_queue(queue: &Arc<RwLock<Vec<ServerMessageIn>>>, message: ServerMessageIn) {
|
||||
let mut lock = queue.write().await;
|
||||
lock.push(message);
|
||||
}
|
|
@ -1,10 +1,10 @@
|
|||
pub mod utils; pub mod handler;
|
||||
|
||||
use std::{sync::{RwLock, Arc}};
|
||||
use std::{sync::{Arc}, time::Duration};
|
||||
|
||||
use chat_types::{dto::server_in::ServerMessageIn, domain::error::SocketError};
|
||||
use chat_types::{dto::server_in::ServerMessageIn, domain::{error::SocketError}};
|
||||
use dev_dtos::dtos::user::user_dtos::UserForAuthenticationDto;
|
||||
use tokio::sync::Mutex;
|
||||
use tokio::{sync::{Mutex, RwLock}, time::{interval}};
|
||||
use tokio_tungstenite::{connect_async};
|
||||
use futures_util::{StreamExt};
|
||||
|
||||
|
@ -12,10 +12,10 @@ use crate::{WebsocketFfi};
|
|||
|
||||
use self::{utils::send_message, handler::handle_message};
|
||||
|
||||
// TODO: Message queue for sending
|
||||
static _MESSAGE_QUEUE: RwLock<Vec<ServerMessageIn>> = RwLock::new(Vec::new());
|
||||
const MESSAGE_QUEUE_POLLING_INTERVAL: u64 = 300;
|
||||
//const RWLOCK_READ_LOCK_ERROR: &str = "Failed to lock an RwLock for reading purposes. This should never happen.";
|
||||
|
||||
pub async fn init_client_connection(user: UserForAuthenticationDto, ws_caller: Arc<Box<dyn WebsocketFfi>>) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||
pub async fn init_client_connection(user: UserForAuthenticationDto, ws_caller: Arc<Box<dyn WebsocketFfi>>, message_queue: Arc<RwLock<Vec<ServerMessageIn>>>,) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||
let ws_stream = match connect_async("ws://0.0.0.0:3000/websocket").await {
|
||||
Ok((stream, _response)) => {
|
||||
stream
|
||||
|
@ -32,65 +32,68 @@ pub async fn init_client_connection(user: UserForAuthenticationDto, ws_caller: A
|
|||
//
|
||||
|
||||
//spawn an async sender to push some more messages into the server
|
||||
let caller = ws_caller.clone();
|
||||
let recv_caller = ws_caller.clone();
|
||||
//receiver just prints whatever it gets
|
||||
let mut recv_task = tokio::spawn(async move {
|
||||
while let Some(Ok(msg)) = receiver.next().await {
|
||||
// Never break this loop?
|
||||
let a = handle_message(msg, &caller).await;
|
||||
let a = handle_message(msg, &recv_caller).await;
|
||||
println!("Something happened {:?}", a);
|
||||
}
|
||||
});
|
||||
let sender_arc = Arc::new(Mutex::new(sender));
|
||||
send_message(sender_arc.clone(), ServerMessageIn::Login(user)).await?;
|
||||
|
||||
|
||||
// Right here I'm creating the send task. Which should every X amount of ms check the MessageQueue.
|
||||
// If there's anything in it then send it to the backend and remove it from the queue.
|
||||
let sender_arc_cloned = sender_arc.clone();
|
||||
let send_caller = ws_caller.clone();
|
||||
let message_queue_cloned = message_queue.clone();
|
||||
let mut send_task = tokio::spawn(async move {
|
||||
let mut interval = interval(Duration::from_millis(MESSAGE_QUEUE_POLLING_INTERVAL));
|
||||
loop { // Infinite loop to check for messages sent from the frontend
|
||||
interval.tick().await; // Wait 200 ms
|
||||
handle_user_messages(&send_caller, sender_arc_cloned.clone(), message_queue_cloned.clone()).await;
|
||||
}
|
||||
});
|
||||
//wait for either task to finish and kill the other task
|
||||
tokio::select! {
|
||||
/*_ = (&mut send_task) => {
|
||||
_ = (&mut send_task) => {
|
||||
recv_task.abort();
|
||||
},*/
|
||||
},
|
||||
_ = (&mut recv_task) => {
|
||||
send_task.abort();
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
/*
|
||||
/// Function to handle messages we get (with a slight twist that Frame variant is visible
|
||||
/// since we are working with the underlying tungstenite library directly without axum here).
|
||||
fn process_message(msg: Message) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||
match msg {
|
||||
Message::Text(t) => {
|
||||
println!(">>> got str: {:?}", t);
|
||||
|
||||
/// Function to handle messages sent from the user to the backend via the MessageQueue
|
||||
/// If no messages exist then this function will just return
|
||||
pub async fn handle_user_messages<S>(ws_caller: &Arc<Box<dyn WebsocketFfi>>, sender: Arc<Mutex<S>>, message_queue: Arc<RwLock<Vec<ServerMessageIn>>>)
|
||||
where S: futures_util::Sink<tokio_tungstenite::tungstenite::Message> + Unpin {
|
||||
let queue = message_queue.read().await;
|
||||
let mut messages_to_remove_from_queue = Vec::new();
|
||||
if queue.len() > 0 {
|
||||
// Send message
|
||||
for (index, message) in queue.iter().enumerate() {
|
||||
match send_message(sender.clone(), message.clone()).await {
|
||||
Ok(_) => { // if message send was successful then remove the message from the queue
|
||||
messages_to_remove_from_queue.push(index);
|
||||
},
|
||||
Err(error) => { // if message wasn't successful send the error back to the client
|
||||
let _ = ws_caller.error(error.to_string()); // Nothing we can do here tbh
|
||||
},
|
||||
};
|
||||
|
||||
}
|
||||
Message::Binary(d) => {
|
||||
println!(">>> got {} bytes: {:?}", d.len(), d);
|
||||
}
|
||||
Message::Close(c) => {
|
||||
if let Some(cf) = c {
|
||||
println!(
|
||||
">>> got close with code {} and reason `{}`",
|
||||
cf.code, cf.reason
|
||||
);
|
||||
} else {
|
||||
println!(">>> somehow got close message without CloseFrame");
|
||||
drop(queue); // This is to make sure the RwLock doesn't get posioned
|
||||
let mut write_lock_for_queue = message_queue.write().await;
|
||||
if messages_to_remove_from_queue.len() > 0 {
|
||||
for i in messages_to_remove_from_queue {
|
||||
write_lock_for_queue.remove(i);
|
||||
}
|
||||
return ControlFlow::Break(());
|
||||
}
|
||||
|
||||
Message::Pong(v) => {
|
||||
println!(">>> got pong with {:?}", v);
|
||||
}
|
||||
// Just as with axum server, the underlying tungstenite websocket library
|
||||
// will handle Ping for you automagically by replying with Pong and copying the
|
||||
// v according to spec. But if you need the contents of the pings you can see them here.
|
||||
Message::Ping(v) => {
|
||||
println!(">>> got ping with {:?}", v);
|
||||
}
|
||||
|
||||
Message::Frame(_) => {
|
||||
unreachable!("This is never supposed to happen")
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}*/
|
||||
|
||||
// Do nothing
|
||||
}
|
|
@ -7,8 +7,6 @@ use tokio_tungstenite::{tungstenite::{Message}};
|
|||
|
||||
|
||||
/// Este es el metodo para enviar mensajes a un cliente a traves de un websocket
|
||||
/// Si le pasas un None en el payload tienes que darle un tipo al metodo, ya que
|
||||
/// El compilador no permite especificarle un metodo default.
|
||||
pub async fn send_message<S>(
|
||||
sender: Arc<Mutex<S>>,
|
||||
message: ServerMessageIn,
|
||||
|
|
|
@ -23,6 +23,7 @@ pub fn get_all_sports() -> Result<Vec<Sport>, RustError> {
|
|||
pub fn get_me() -> Result<UserForAuthenticationDto, RustError> {
|
||||
storage::read("user".into())
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! unwrap_rust_error {
|
||||
($e:expr) => {
|
||||
|
|
|
@ -53,7 +53,6 @@ dictionary ChatRoom {
|
|||
i64 last_updated;
|
||||
u64 session_messages;
|
||||
};
|
||||
|
||||
enum ClientError {
|
||||
"One",
|
||||
"Two",
|
||||
|
@ -79,6 +78,7 @@ callback interface WebsocketFfi {
|
|||
interface WebsocketCaller {
|
||||
constructor();
|
||||
void init_ws_connection(WebsocketFfi websocket_ffi);
|
||||
void send_text_message(string message, u32 to);
|
||||
};
|
||||
namespace network {
|
||||
[Throws=RustError]
|
||||
|
|
Loading…
Reference in New Issue