From 704f372c3e1402f9cde6409f056ddef6bbc9a697 Mon Sep 17 00:00:00 2001 From: shockrah Date: Wed, 7 Apr 2021 20:38:06 -0700 Subject: [PATCH] + Adding list_channel handler More agressive channel caching may be required here but it works as an MVP for now * Switch to hashmap for container of channel caches instead of vector This should help with cache accesses as we don't have to iterate anymore Also it makes data fetches much cleaner/shorthanded * net::list_channels has its own private structure for collecting channels vector This is basically required and is in the scope of the func itsefl to not pollute any other namespaces --- tui/src/cache.rs | 55 ++++++++++++++++++++++++++++-------------------- tui/src/main.rs | 2 +- tui/src/net.rs | 33 +++++++++++++++++++++++------ 3 files changed, 59 insertions(+), 31 deletions(-) diff --git a/tui/src/cache.rs b/tui/src/cache.rs index 6a1d86d..2632eee 100644 --- a/tui/src/cache.rs +++ b/tui/src/cache.rs @@ -30,7 +30,7 @@ struct ServerCache { // container for the relevant user/serer meta data // We use both parts in order to to maintain jwt's within the cache meta: ServerConfig, - channels: Vec + channels: HashMap // channel_id -> cache } pub struct Cache { @@ -41,7 +41,7 @@ pub struct Cache { } impl ServerCache { - pub fn from(meta: ServerConfig, channels: Vec) -> Self { + pub fn from(meta: ServerConfig, channels: HashMap) -> Self { ServerCache { meta, channels } } } @@ -50,7 +50,7 @@ impl Cache { pub fn from(config: &ConfigFile) -> Cache { let mut servers = HashMap::new(); for servercfg in &config.servers { - let i_server_cache = ServerCache::from(servercfg.clone(), Vec::new()); + let i_server_cache = ServerCache::from(servercfg.clone(), HashMap::new()); let url = i_server_cache.meta.server.url.clone(); servers.insert(url, i_server_cache); } @@ -83,14 +83,18 @@ impl Cache { let secret = &meta.meta.user.secret; found = match net::login(url, id, secret).await { Ok(jwt) => { + let twt = jwt.clone(); meta.meta.user.jwt = Some(jwt); self.active_server = Some(meta.meta.clone()); - // Setup websocket to server or something idk + // TODO: Setup websocket to server or something idk self.active_text = None; true }, - Err(e) => { // TODO: some kind of logging here - err_msg = format!("{}", e); + Err(e) => { + err_msg = match e.is_status() { + true => format!("{:?}", e.status().unwrap()), + false => format!("Issue connecting to server") + }; meta.meta.user.jwt = None; false } @@ -123,25 +127,30 @@ impl Cache { Command::Text(hosts) } - pub fn list_channels(&self) -> Command { - use crate::api_types; - if let Some(serv) = &self.active_server { - // Find the server we're whose channels we want - let (_, cache) = self.servers.iter() - .find(|(url, _)| url == &&serv.server.url).unwrap(); - - let mut buffer = String::from("! Channels "); - for (i, chan) in cache.channels.iter().enumerate() { - // NOTE only list out text channels for now - // another command will be provided for voice channels later - if chan.meta.r#type == api_types::TEXT_CHANNEL { - buffer.push_str(&format!("[{}] {}, ", i, chan.meta.r#type)); + pub async fn list_channels(&mut self) -> Command { + if let None = self.active_server { + return Command::Failure("No active server".into()) + } + // we have to own our own reference here to avoid mutating after immutable borrows + let config = self.active_server.clone().unwrap(); + let id = config.user.id; + let jwt = config.user.jwt.unwrap(); + let url = config.server.url.as_str(); + let mut buf = String::new(); + match net::list_channels(url, id, jwt.as_str()).await { + Ok(mut channels) => { + for chan in channels.iter_mut() { + let id = chan.id; + let chan_cache = ChannelCache { meta: chan.clone(), messages: Vec::new() }; + self.servers.get_mut(url).unwrap().channels.insert(id, chan_cache); + let chan = format!("{}: {},", id, chan.name); + buf.push_str(chan.as_str()); } + Command::Text(buf) + }, + Err(e) => { + Command::Failure(format!("Couldn't fetch channels: {:?}", e.status())) } - - Command::Text(buffer) - } else { - Command::Failure(format!("No active server")) } } } diff --git a/tui/src/main.rs b/tui/src/main.rs index 5231523..a542e42 100644 --- a/tui/src/main.rs +++ b/tui/src/main.rs @@ -226,7 +226,7 @@ async fn main() -> Result<(), Box> { Command::Server(host) => app.cache.switch_server(&host).await, Command::Message(msg) => app.cache.send_message(&msg).await, Command::ListHost => app.cache.list_hosts(), - Command::ListChannel => app.cache.list_channels(), + Command::ListChannel => app.cache.list_channels().await, _ => cmd }); } diff --git a/tui/src/net.rs b/tui/src/net.rs index fd275e2..0981b20 100644 --- a/tui/src/net.rs +++ b/tui/src/net.rs @@ -1,19 +1,38 @@ -use crate::api_types::Channel; -use crate::api_types::Jwt; +use serde::Deserialize; +use crate::api_types::{Jwt, Channel, TEXT_CHANNEL}; use reqwest::{Client, Url}; use reqwest::Result as HttpResult; +// TODO: Url generation is kinda gross looking but i'm not 100% +// convinced it needs to be pretty if its just going to add overhead + pub async fn login(url: &str, id: u64, secret: &str) -> HttpResult { let client = Client::new(); - let mut url = Url::parse(&format!("{}/login", url)).unwrap(); - url.query_pairs_mut().append_pair("id", &format!("{}", id)); - url.query_pairs_mut().append_pair("secret", secret); + let url = Url::parse_with_params( + &format!("{}/login", url), + &[("id", format!("{}", id).as_str()), ("secret", secret)] + ).unwrap(); let response: Jwt = client.get(url).send().await?.json().await?; Ok(response.jwt) } -fn list_channels(url: &str, id: u64, secret: &str) -> Vec { - todo!() +pub async fn list_channels(url: &str, id: u64, jwt: &str) -> HttpResult> { + let client = Client::new(); + let url = Url::parse_with_params( + &format!("{}/channels/list", url), + &[ + ("id", format!("{}", id).as_str()), + ("jwt", jwt), + ("kind", format!("{}", TEXT_CHANNEL).as_str()) + ] + ).unwrap(); + + #[derive(Deserialize)] + struct ChannelResponse { + pub channels: Vec + } + let response: ChannelResponse = client.get(url).send().await?.json().await?; + Ok(response.channels) }