- Removing network control from the cache

From this point forward the cache should basically just be a data container.
Methods on the cache object are there for convenience and should only ever
return very simple data [booleans, integers, () etc.].
The cache should also have very litter/no concept of commands to decouple it
from the renderer process.
! list_channels is still implemented in the cache however it remaains a vestige
and will be moved to the net module

Also the client is getting some new packages for websocket connections and
while they work some additional work has to be put in to figure out where fug to
actually place the websocket so that it can update the cache+DOM in a seomewhat sensible fashion
This commit is contained in:
shockrah 2021-04-11 17:39:54 -07:00
parent 3708d2cd08
commit 42d6a77050
6 changed files with 56 additions and 184 deletions

View File

@ -259,14 +259,6 @@
"integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
"dev": true
},
"bufferutil": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.3.tgz",
"integrity": "sha512-yEYTwGndELGvfXsImMBLop58eaGW+YdONi1fNjTINSY98tmMmFijBG6WXgdkfuLNt4imzQNtIE+eBp1PVpMCSw==",
"requires": {
"node-gyp-build": "^4.2.0"
}
},
"cacheable-lookup": {
"version": "5.0.4",
"resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz",
@ -330,19 +322,11 @@
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
"dev": true
},
"d": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz",
"integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==",
"requires": {
"es5-ext": "^0.10.50",
"type": "^1.0.1"
}
},
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"dev": true,
"requires": {
"ms": "2.0.0"
},
@ -350,7 +334,8 @@
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
"dev": true
}
}
},
@ -445,16 +430,6 @@
"integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==",
"dev": true
},
"es5-ext": {
"version": "0.10.53",
"resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.53.tgz",
"integrity": "sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==",
"requires": {
"es6-iterator": "~2.0.3",
"es6-symbol": "~3.1.3",
"next-tick": "~1.0.0"
}
},
"es6-error": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz",
@ -462,25 +437,6 @@
"dev": true,
"optional": true
},
"es6-iterator": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz",
"integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=",
"requires": {
"d": "1",
"es5-ext": "^0.10.35",
"es6-symbol": "^3.1.1"
}
},
"es6-symbol": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz",
"integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==",
"requires": {
"d": "^1.0.1",
"ext": "^1.1.2"
}
},
"escape-string-regexp": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
@ -488,21 +444,6 @@
"dev": true,
"optional": true
},
"ext": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/ext/-/ext-1.4.0.tgz",
"integrity": "sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A==",
"requires": {
"type": "^2.0.0"
},
"dependencies": {
"type": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/type/-/type-2.5.0.tgz",
"integrity": "sha512-180WMDQaIMm3+7hGXWf12GtdniDEy7nYcyFMKJn/eZz/6tSLXrUN9V0wKSbMjej0I1WHWbpREDEKHtqPQa9NNw=="
}
}
},
"extract-zip": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.7.0.tgz",
@ -645,11 +586,6 @@
"dev": true,
"optional": true
},
"is-typedarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
"integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo="
},
"isarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
@ -826,16 +762,6 @@
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
},
"next-tick": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz",
"integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw="
},
"node-gyp-build": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.2.3.tgz",
"integrity": "sha512-MN6ZpzmfNCRM+3t57PTJHgHyw/h4OWnZ6mR8P5j/uZtqQr46RRuDE/P+g3n0YR/AiYXeWixZZzaip77gdICfRg=="
},
"normalize-url": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.0.tgz",
@ -1070,11 +996,6 @@
"dev": true,
"optional": true
},
"type": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz",
"integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg=="
},
"type-fest": {
"version": "0.13.1",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz",
@ -1088,14 +1009,6 @@
"integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=",
"dev": true
},
"typedarray-to-buffer": {
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz",
"integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==",
"requires": {
"is-typedarray": "^1.0.0"
}
},
"typescript": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.3.tgz",
@ -1116,42 +1029,21 @@
"prepend-http": "^2.0.0"
}
},
"utf-8-validate": {
"version": "5.0.4",
"resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.4.tgz",
"integrity": "sha512-MEF05cPSq3AwJ2C7B7sHAA6i53vONoZbMGX8My5auEVm6W+dJ2Jd/TZPyGJ5CH42V2XtbI5FD28HeHeqlPzZ3Q==",
"requires": {
"node-gyp-build": "^4.2.0"
}
},
"util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
"dev": true
},
"websocket": {
"version": "1.0.33",
"resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.33.tgz",
"integrity": "sha512-XwNqM2rN5eh3G2CUQE3OHZj+0xfdH42+OFK6LdC2yqiC0YU8e5UK0nYre220T0IyyN031V/XOvtHvXozvJYFWA==",
"requires": {
"bufferutil": "^4.0.1",
"debug": "^2.2.0",
"es5-ext": "^0.10.50",
"typedarray-to-buffer": "^3.1.5",
"utf-8-validate": "^5.0.2",
"yaeti": "^0.0.6"
}
},
"wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
},
"yaeti": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz",
"integrity": "sha1-8m9ITXJoTPQr7ft2lwqhYI+/lXc="
"ws": {
"version": "7.4.4",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.4.4.tgz",
"integrity": "sha512-Qm8k8ojNQIMx7S+Zp8u/uHOx7Qazv3Yv4q68MiWWWOJhiwG5W3x7iqmRtJo8xxrciZUY4vRxUTJCKuRnF28ZZw=="
},
"yallist": {
"version": "4.0.0",

View File

@ -16,7 +16,7 @@
"jsonwebtoken": "^8.5.1",
"popper.js": "^1.16.1",
"typescript": "^4.2.3",
"websocket": "^1.0.33"
"ws": "^7.4.4"
},
"devDependencies": {
"electron": "^7.3.3"

View File

@ -16,16 +16,11 @@ use crate::api_types::Channel;
use crate::net;
use crate::command::Command;
use crate::config::{ConfigFile, ServerConfig};
use tokio_tungstenite::connect_async;
use futures::StreamExt;
use std::collections::HashMap;
use crate::api_types as api;
type ChannelMeta = Channel;
async fn nop() {
}
struct ChannelCache {
pub meta: ChannelMeta,
pub messages: Vec<api::Message>
@ -67,17 +62,6 @@ impl Cache {
}
}
pub fn find_serv(&self, portion: String) -> Option<(String, u64)> {
let item = self.servers.iter()
.find(|(url, _)| url.contains(portion.as_str()));
if let Some((url, cache)) = item {
Some((url.clone(), cache.meta.user.id))
} else {
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())
@ -99,48 +83,29 @@ impl Cache {
}
fn new_message(&mut self, msg: api::Message, url: String, chan_id: u64) {
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 async fn switch_server(&mut self, host: &str) -> (Command, Option<String>) {
// TODO: clean this func to be less ugly/easier to read
let mut found = false;
let mut err_msg = String::from("Nothing found");
let mut fresh_token: Option<String> = None;
for (url, meta) in self.servers.iter_mut() {
if url.contains(host) {
let id = meta.meta.user.id;
let secret = &meta.meta.user.secret;
found = match net::login(url, id, secret).await {
Ok(jwt) => {
fresh_token = Some(jwt.clone());
meta.meta.user.jwt = Some(jwt);
self.active_server = Some(meta.meta.clone());
self.active_text = None;
true
},
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
}
};
meta.meta.user.jwt = Some(String::from("asdf"));
break
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());
}
}
if found {
(Command::Text(format!("logged in - /lc to list to list channels")), fresh_token)
} else {
(Command::Failure(err_msg), None)
}
}
pub async fn send_message(&self, msg: &str) -> Command {
@ -156,7 +121,7 @@ impl Cache {
Err(_) => Command::Failure("Couldn't send text message".into())
}
}
Command::Text("yes".into())
Command::Text("No active channel".into())
}
pub fn list_hosts(&self) -> Command {

View File

@ -43,6 +43,16 @@ impl ConfigFile {
Ok(())
}
pub fn find_login_data(&self, url_portion: &str) -> Option<(u64, String, String)> {
let mut found: Option<(u64, String, String)> = None;
for serv in self.servers.iter() {
if serv.server.url.contains(url_portion) {
found = Some((serv.user.id, serv.user.secret.clone(), serv.server.url.clone()))
}
}
return found;
}
}

View File

@ -37,8 +37,7 @@ struct App {
/// Current input mode
input_mode: InputMode,
/// History of recorded messages
messages: Mutex<Vec<Command>>,
cache: Cache
messages: Vec<Command>,
}
impl App {
@ -54,8 +53,7 @@ impl App {
App {
input: String::new(),
input_mode: InputMode::Normal,
messages: Mutex::new(init_commands),
cache
messages: init_commands,
}
}
}
@ -113,6 +111,7 @@ async fn main() -> Result<(), Box<dyn Error>> {
// Create default app state
let mut app = App::new(&config);
let cache: Mutex<Cache> = Mutex::new(Cache::from(&config));
loop {
// Draw UI
@ -157,7 +156,7 @@ async fn main() -> Result<(), Box<dyn Error>> {
f.render_widget(input, chunks[1]);
let mut lines: Vec<Spans> = Vec::new();
let msgs = app.messages.lock().unwrap();
let msgs = &app.messages;
for cmd in msgs.iter().rev() {
&lines.push(cmd.styled());
}
@ -219,27 +218,32 @@ async fn main() -> Result<(), Box<dyn Error>> {
let raw: String = app.input.drain(..).collect();
let trimmed = raw.trim();
// ensure that we don't bother with empty input
// TODO: flattten me mommy
if trimmed.len() != 0 {
let cmd = Command::from(trimmed);
app.messages.lock().unwrap().push(match cmd {
app.messages.push(match cmd {
// only for networked commands do we need to touch cache
Command::Channel(id) => {
app.cache.switch_channel(id).await
cache.lock().unwrap().switch_channel(id).await
},
Command::Server(url_portion) => {
if let Some((url, id)) = app.cache.find_serv(url_portion) {
let (cmd, jwt) = app.cache.switch_server(url.as_str()).await;
let url = net::ws_url(url.as_str(), jwt);
// maybe hook some message passing listener here?
cmd
if let Some((id, secret, url)) = config.find_login_data(&url_portion) {
match net::login(&url, id, &secret).await {
Ok(jwt) => if cache.lock().unwrap().set_jwt(&url, &jwt) {
cache.lock().unwrap().set_active(&url);
Command::Text("[Tell shock to make this ux not suck btw] /lc to fetch/update channels".into())
} else {
Command::Failure("Token could not be set".into())
},
Err(_) => Command::Failure(format!("Unable to login to {}", url))
}
} else {
Command::Failure("No server found".into())
}
},
Command::Message(msg) => app.cache.send_message(&msg).await,
Command::ListHost => app.cache.list_hosts(),
Command::ListChannel => app.cache.list_channels().await,
Command::Message(msg) => cache.lock().unwrap().send_message(&msg).await,
Command::ListHost => cache.lock().unwrap().list_hosts(),
Command::ListChannel => cache.lock().unwrap().list_channels().await,
_ => cmd
});
}

View File

@ -61,3 +61,4 @@ pub fn ws_url(base: &str, jwt: Option<String>) -> String {
let _ = url.set_scheme("ws");
url.to_string()
}