freechat/tui/src/cache.rs
shockrah 894a5bae34 - Removing more behavior from the cache for complexity reduciton
+ Cache is no longer contained in app structure
This should let us later throw this into an Arc<Mutex<>> for better
async support.
! Also more cache access safety is being done on the front end because the cahe doesn't guarantee much on access
Perhaps some convenience wrappers would make this look nicer(with inline)

!!! Main needs a lot of flattening
It's technically not much of a problem since most of the code behind 1/2 match's
which really just bloat the hell out of indentation making it look bad when its not _that_ bad.
However it still bugs me so I should probably do something about that(also (inline))
2021-04-14 22:44:57 -07:00

158 lines
4.9 KiB
Rust

/**
* welcum to the cache zone
* Notes about data model here
* Basically none of the ever gets written to disk so its mutability is
*
* Memory Model things
* The cache should always own its own data and nothing else
* On calls where the cache system needs to take data it should actually
* make its own copy to not disturb the render side of things as it too requires
* ownership of its own data. For this reason all parts of this are basically
* going to be really selfish about its own data
*
*/
use crate::api_types::Channel;
use crate::net;
use crate::command::Command;
use crate::config::{ConfigFile, ServerConfig};
use std::collections::HashMap;
use crate::api_types as api;
type ChannelMeta = Channel;
struct ChannelCache {
pub meta: ChannelMeta,
pub messages: Vec<api::Message>
}
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: HashMap<u64, ChannelCache> // channel_id -> cache
}
pub struct Cache {
// url -> Cache
servers: HashMap<String, ServerCache>,
active_server: Option<ServerConfig>,
active_text: Option<ChannelMeta>,
}
impl ServerCache {
pub fn from(meta: ServerConfig, channels: HashMap<u64, ChannelCache>) -> Self {
ServerCache { meta, channels }
}
}
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(), HashMap::new());
let url = i_server_cache.meta.server.url.clone();
servers.insert(url, i_server_cache);
}
Cache {
servers,
active_server: None,
active_text: None,
}
}
pub async fn switch_channel(&mut self, id: u64) -> Command {
if let None = self.active_server {
return Command::Failure("No active server set!".into())
}
let mut msg = String::new();
for (_url, cache) in &self.servers {
if let Some(channel_cache) = cache.channels.get(&id) {
let meta = channel_cache.meta.clone();
msg = format!("Switched to channel: [{}]: {}", meta.id, meta.name);
self.active_text = Some(meta);
break;
}
}
if msg.len() == 0 {
Command::Failure(format!("Channel not found in cache try /lc to refresh cache"))
} else {
Command::Text(msg)
}
}
pub fn set_jwt(&mut self, url: &str, jwt: &str) -> bool {
let mut set = false;
for (surl, serv) in self.servers.iter_mut() {
if url == surl {
serv.meta.user.jwt = Some(jwt.into());
set = true;
}
};
return set;
}
fn _new_message(&mut self, msg: api::Message, url: String, chan_id: u64) {
self.servers.get_mut(&url).unwrap()
.channels.get_mut(&chan_id).unwrap()
.messages.push(msg);
}
pub fn set_active(&mut self, url: &str) {
for (surl, serv) in self.servers.iter() {
if url == surl {
self.active_server = Some(serv.meta.clone());
}
}
}
pub async fn send_message(&self, msg: &str) -> Command {
if let Some(channel) = &self.active_text {
let config = self.active_server.as_ref().unwrap();
let chan = channel.id;
let uid = config.user.id;
let jwt = config.user.jwt.as_ref().unwrap();
let url = config.server.url.as_str();
return match net::send_text(url, uid, jwt, chan, msg).await {
Ok(_) => Command::Message(msg.into()),
Err(_) => Command::Failure("Couldn't send text message".into())
}
}
Command::Text("No active channel".into())
}
pub fn list_hosts(&self) -> Command {
let mut hosts = String::from("Hosts: ");
for (host, _) in self.servers.iter() {
hosts.push_str(format!("{}, ", host).as_str());
}
Command::Text(hosts)
}
pub fn add_channels(&mut self, url: &str, channels: &[api::Channel]) {
// if the url isn't there we just silently fail?
let serv_ref = self.servers.get_mut(url).unwrap();
for chan in channels.iter() {
let cache = ChannelCache {
meta: chan.clone(),
messages: Vec::new()
};
serv_ref.channels.insert(chan.id, cache);
}
}
pub fn session(&self) -> Option<(String, u64, String)>{
if let Some(serv) = &self.active_server {
let id = serv.user.id;
let url = serv.server.url.clone();
let jwt = serv.user.jwt.clone().unwrap_or("".to_string());
Some((url, id, jwt))
} else {
None
}
}
}