Implement account config + login
This commit is contained in:
@ -1,4 +1,10 @@
|
||||
{
|
||||
"accounts": [
|
||||
{
|
||||
"user_id": "@alice:example.org",
|
||||
"password": "hunter2",
|
||||
},
|
||||
],
|
||||
"keybindings": {
|
||||
"Home": {
|
||||
"<q>": "/quit", // Quit the application
|
||||
|
@ -39,10 +39,12 @@ human-panic = "1.2.0"
|
||||
inventory = "0.3"
|
||||
lazy_static = "1.4.0"
|
||||
libc = "0.2.148"
|
||||
log = "0.4.20"
|
||||
nonempty = { version = "0.8.1", features = ["serialize"] }
|
||||
signal-hook = "0.3.17"
|
||||
|
||||
# Misc
|
||||
log = "0.4.20"
|
||||
# Matrix
|
||||
matrix-sdk = { version = "0.6.2", features = ["eyre", "markdown"] }
|
||||
|
||||
# UI
|
||||
crossterm = { version = "0.27.0", features = ["serde", "event-stream"] }
|
||||
|
31
src/app.rs
31
src/app.rs
@ -1,5 +1,6 @@
|
||||
use color_eyre::eyre::{Result, WrapErr};
|
||||
use crossterm::event::KeyEvent;
|
||||
use nonempty::NonEmpty;
|
||||
use ratatui::prelude::Rect;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tokio::sync::mpsc;
|
||||
@ -15,6 +16,7 @@ use crate::{
|
||||
|
||||
pub struct App {
|
||||
pub config: Config,
|
||||
pub clients: NonEmpty<matrix_sdk::Client>,
|
||||
pub commands: RataCommands,
|
||||
pub tick_rate: f64,
|
||||
pub frame_rate: f64,
|
||||
@ -26,17 +28,44 @@ pub struct App {
|
||||
}
|
||||
|
||||
impl App {
|
||||
pub fn new(tick_rate: f64, frame_rate: f64) -> Result<Self> {
|
||||
pub async fn new(tick_rate: f64, frame_rate: f64) -> Result<Self> {
|
||||
let home = Home::new();
|
||||
let fps = FpsCounter::default();
|
||||
let config = Config::new()?;
|
||||
let mode = Mode::Home;
|
||||
let future_clients = config.accounts.clone().map(|conf| {
|
||||
tokio::spawn(async move {
|
||||
let server_name = conf.user_id.server_name();
|
||||
let client = matrix_sdk::Client::builder()
|
||||
.server_name(server_name)
|
||||
.build()
|
||||
.await
|
||||
.with_context(|| format!("Could not initialize client for {}", server_name))?;
|
||||
client
|
||||
.login_username(&conf.user_id, &conf.password)
|
||||
.send()
|
||||
.await
|
||||
.with_context(|| format!("Could not login as {}", conf.user_id))?;
|
||||
Ok::<_, color_eyre::eyre::Report>(client)
|
||||
})
|
||||
});
|
||||
let mut clients = Vec::new();
|
||||
for client in futures::future::join_all(future_clients).await {
|
||||
clients.push(
|
||||
client
|
||||
.context("Could not join client init task")?
|
||||
.context("Could not connect to all accounts")?,
|
||||
);
|
||||
}
|
||||
let clients = NonEmpty::collect(clients).expect("map on NonEmpty returned empty vec");
|
||||
|
||||
let mut app = Self {
|
||||
tick_rate,
|
||||
frame_rate,
|
||||
components: vec![Box::new(home), Box::new(fps)],
|
||||
should_quit: false,
|
||||
should_suspend: false,
|
||||
clients,
|
||||
config,
|
||||
commands: RataCommands::new(),
|
||||
mode,
|
||||
|
@ -1,10 +1,11 @@
|
||||
use std::{collections::HashMap, time::Duration};
|
||||
|
||||
use color_eyre::eyre::Result;
|
||||
use color_eyre::eyre::{Result, WrapErr};
|
||||
use crossterm::event::{KeyCode, KeyEvent};
|
||||
use ratatui::{prelude::*, widgets::*};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tokio::sync::mpsc::UnboundedSender;
|
||||
use tokio::sync::OnceCell;
|
||||
|
||||
use super::{Component, Frame};
|
||||
use crate::{
|
||||
@ -15,7 +16,7 @@ use crate::{
|
||||
#[derive(Default)]
|
||||
pub struct Home {
|
||||
command_tx: Option<UnboundedSender<Action>>,
|
||||
config: Config,
|
||||
config: OnceCell<Config>,
|
||||
}
|
||||
|
||||
impl Home {
|
||||
@ -31,8 +32,10 @@ impl Component for Home {
|
||||
}
|
||||
|
||||
fn register_config_handler(&mut self, config: Config) -> Result<()> {
|
||||
self.config = config;
|
||||
Ok(())
|
||||
self
|
||||
.config
|
||||
.set(config)
|
||||
.context("Home config was already set")
|
||||
}
|
||||
|
||||
fn update(&mut self, action: Action) -> Result<Option<Action>> {
|
||||
|
@ -13,8 +13,6 @@ use serde_json::Value as JsonValue;
|
||||
|
||||
use crate::{action::Action, mode::Mode};
|
||||
|
||||
const CONFIG: &str = include_str!("../.config/config.json5");
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Default)]
|
||||
pub struct AppConfig {
|
||||
#[serde(default)]
|
||||
@ -23,10 +21,17 @@ pub struct AppConfig {
|
||||
pub _config_dir: PathBuf,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Deserialize)]
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
pub struct AccountConfig {
|
||||
pub user_id: Box<matrix_sdk::ruma::UserId>,
|
||||
pub password: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
pub struct Config {
|
||||
#[serde(default, flatten)]
|
||||
pub config: AppConfig,
|
||||
pub accounts: nonempty::NonEmpty<AccountConfig>,
|
||||
#[serde(default)]
|
||||
pub keybindings: KeyBindings,
|
||||
#[serde(default)]
|
||||
@ -35,7 +40,6 @@ pub struct Config {
|
||||
|
||||
impl Config {
|
||||
pub fn new() -> Result<Self, config::ConfigError> {
|
||||
let default_config: Config = json5::from_str(CONFIG).unwrap();
|
||||
let data_dir = crate::utils::get_data_dir();
|
||||
let config_dir = crate::utils::get_config_dir();
|
||||
let mut builder = config::Config::builder()
|
||||
@ -64,26 +68,7 @@ impl Config {
|
||||
log::error!("No configuration file found. Application may not behave as expected");
|
||||
}
|
||||
|
||||
let mut cfg: Self = builder.build()?.try_deserialize()?;
|
||||
|
||||
for (mode, default_bindings) in default_config.keybindings.iter() {
|
||||
let user_bindings = cfg.keybindings.entry(*mode).or_default();
|
||||
for (key, cmd) in default_bindings.iter() {
|
||||
user_bindings
|
||||
.entry(key.clone())
|
||||
.or_insert_with(|| cmd.clone());
|
||||
}
|
||||
}
|
||||
for (mode, default_styles) in default_config.styles.iter() {
|
||||
let user_styles = cfg.styles.entry(*mode).or_default();
|
||||
for (style_key, style) in default_styles.iter() {
|
||||
user_styles
|
||||
.entry(style_key.clone())
|
||||
.or_insert_with(|| style.clone());
|
||||
}
|
||||
}
|
||||
|
||||
Ok(cfg)
|
||||
Ok(builder.build()?.try_deserialize()?)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -28,7 +28,7 @@ async fn tokio_main() -> Result<()> {
|
||||
initialize_panic_handler()?;
|
||||
|
||||
let args = Cli::parse();
|
||||
let mut app = App::new(args.tick_rate, args.frame_rate)?;
|
||||
let mut app = App::new(args.tick_rate, args.frame_rate).await?;
|
||||
app.run().await?;
|
||||
|
||||
Ok(())
|
||||
|
Reference in New Issue
Block a user