diff --git a/src/requests/indicator.rs b/src/requests/indicator.rs new file mode 100644 index 0000000..770a239 --- /dev/null +++ b/src/requests/indicator.rs @@ -0,0 +1,30 @@ +use crate::{server::Server, types::message::ServerMessage, utils::client::Client}; +use anyhow::Context; +use serde::{Deserialize, Serialize}; +use std::sync::Arc; + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(tag = "type", content = "params", rename_all = "snake_case")] +pub enum Indicator { + Typing { user_id: String, channel_id: String }, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct IndicatorContext { + pub indicator: Indicator, + pub expires: u16, +} + +crate::logger!(LOGGER "Typing Indicator"); + +pub fn start_typing(server: &Arc, client: &Client, channel_id: &str) -> crate::Result<()> { + server.broadcast(ServerMessage::Indicator(IndicatorContext { + indicator: Indicator::Typing { + user_id: client.get_uuid().context("Failed to get uuid")?, + channel_id: channel_id.to_string(), + }, + expires: 5, // 5 secs + })); + + Ok(()) +} diff --git a/src/requests/mod.rs b/src/requests/mod.rs index 3e620bb..bda1c86 100644 --- a/src/requests/mod.rs +++ b/src/requests/mod.rs @@ -1,5 +1,6 @@ pub mod chunk; pub mod message; +pub mod indicator; use std::sync::Arc; @@ -36,8 +37,10 @@ impl Server { ClientMessage::LoadChunk { chunk_id, channel_id, - } => { - chunk::load_chunk(self, client, channel_id, *chunk_id)?; + } => chunk::load_chunk(self, client, channel_id, *chunk_id)?, + + ClientMessage::Typing { channel_id } => { + indicator::start_typing(self, client, channel_id)? } }, diff --git a/src/server.rs b/src/server.rs index f7378fb..0f35140 100644 --- a/src/server.rs +++ b/src/server.rs @@ -44,6 +44,7 @@ pub struct Server { pub plugins: Mutex>, pub db: utils::database::Database, pub shutting_down: AtomicBool, + pub indicators: Mutex>, } impl Default for ServerConfig { @@ -79,6 +80,7 @@ impl Server { clients: Mutex::new(HashSet::new()), plugins: Mutex::new(Vec::new()), shutting_down: AtomicBool::new(false), + indicators: Mutex::new(Vec::new()), }) } @@ -164,7 +166,10 @@ impl Server { let uuid = self.wrap_err(&client, auth_res)?; self.wrap_err( &client, - client.send(types::message::ServerMessage::Authenticated { uuid }), + client.send(types::message::ServerMessage::Authenticated { + uuid, + indicators: self.indicators.lock().unwrap().clone(), + }), )?; } Some(v) => { diff --git a/src/types.rs b/src/types.rs index 91d888f..0c86311 100644 --- a/src/types.rs +++ b/src/types.rs @@ -55,9 +55,12 @@ pub mod handshake { pub mod message { use serde::{Deserialize, Serialize}; - use crate::types::{ - Author, - data::{self, Message}, + use crate::{ + requests::indicator::IndicatorContext, + types::{ + Author, + data::{self, Message}, + }, }; /// Messages sent *from the client* (user’s app) to the server @@ -85,6 +88,10 @@ pub mod message { channel_id: String, chunk_id: usize, }, + + Typing { + channel_id: String, + }, } /// Messages sent *from the server* to the client @@ -94,6 +101,7 @@ pub mod message { /// Successful authentication Authenticated { uuid: Author, + indicators: Vec, }, TempMessage { @@ -120,11 +128,8 @@ pub mod message { status: String, }, - /// Typing indicator - Typing { - user_id: Author, - channel_id: String, - }, + /// Indicator + Indicator(IndicatorContext), Shutdown { message: String, diff --git a/src/utils/logger.rs b/src/utils/logger.rs index 6c6d52c..f33d1ff 100644 --- a/src/utils/logger.rs +++ b/src/utils/logger.rs @@ -33,13 +33,13 @@ impl Logger { } } - pub fn extract_panic(&self, v: Result, m: D) -> T { - match v { - Ok(a) => a, - Err(e) => { - self.error(format!("{m}: {e}")); - panic!() - } - } - } + // pub fn extract_panic(&self, v: Result, m: D) -> T { + // match v { + // Ok(a) => a, + // Err(e) => { + // self.error(format!("{m}: {e}")); + // panic!() + // } + // } + // } } diff --git a/src/utils/vfs.rs b/src/utils/vfs.rs index 0b62a96..2e7b2a0 100644 --- a/src/utils/vfs.rs +++ b/src/utils/vfs.rs @@ -16,29 +16,29 @@ pub fn dir(path: &Path) -> crate::Result<()> { Ok(()) } -pub fn read(path: &Path, default_content: &str) -> crate::Result { - if !path.exists() { - LOGGER.info(format!( - "File {path:?} does not exist, creating it with default contents" - )); - write(path, default_content)?; - return Ok(default_content.to_string()); - } +// pub fn read(path: &Path, default_content: &str) -> crate::Result { +// if !path.exists() { +// LOGGER.info(format!( +// "File {path:?} does not exist, creating it with default contents" +// )); +// write(path, default_content)?; +// return Ok(default_content.to_string()); +// } - Ok(fs::read_to_string(path)?) -} +// Ok(fs::read_to_string(path)?) +// } -pub fn read_bytes<'a>(path: &Path, default_content: Vec) -> crate::Result> { - if !path.exists() { - LOGGER.info(format!( - "File {path:?} does not exist, creating it with default contents" - )); - write_bytes(path, &default_content)?; - return Ok(default_content); - } +// pub fn read_bytes<'a>(path: &Path, default_content: Vec) -> crate::Result> { +// if !path.exists() { +// LOGGER.info(format!( +// "File {path:?} does not exist, creating it with default contents" +// )); +// write_bytes(path, &default_content)?; +// return Ok(default_content); +// } - Ok(fs::read(path)?) -} +// Ok(fs::read(path)?) +// } pub fn read_config Deserialize<'de>>( path: &Path, @@ -56,23 +56,23 @@ pub fn read_config Deserialize<'de>>( Ok(serde_json::from_str::(&read)?) } -pub fn write(path: &Path, content: &str) -> crate::Result<()> { - dir(path.parent().ok_or(std::io::Error::new( - std::io::ErrorKind::InvalidFilename, - "File doesn't have a parent assigned, example: `config/config.json`", - ))?)?; - fs::write(path, content)?; - Ok(()) -} +// pub fn write(path: &Path, content: &str) -> crate::Result<()> { +// dir(path.parent().ok_or(std::io::Error::new( +// std::io::ErrorKind::InvalidFilename, +// "File doesn't have a parent assigned, example: `config/config.json`", +// ))?)?; +// fs::write(path, content)?; +// Ok(()) +// } -pub fn write_bytes(path: &Path, content: &[u8]) -> crate::Result<()> { - dir(path.parent().ok_or(std::io::Error::new( - std::io::ErrorKind::InvalidFilename, - "File doesn't have a parent assigned, example: `config/config.json`", - ))?)?; - fs::write(path, content)?; - Ok(()) -} +// pub fn write_bytes(path: &Path, content: &[u8]) -> crate::Result<()> { +// dir(path.parent().ok_or(std::io::Error::new( +// std::io::ErrorKind::InvalidFilename, +// "File doesn't have a parent assigned, example: `config/config.json`", +// ))?)?; +// fs::write(path, content)?; +// Ok(()) +// } pub fn write_config(path: &Path, content: &T) -> crate::Result<()> { dir(path.parent().ok_or(std::io::Error::new(