Fix domain errors in UI

This commit is contained in:
Joscha 2024-01-01 01:38:41 +01:00
parent 708d66b256
commit 78bbfac2f3
2 changed files with 141 additions and 66 deletions

View file

@ -87,8 +87,12 @@ impl EuphRoom {
self.chat.store()
}
fn domain(&self) -> &str {
&self.vault().room().domain
}
fn name(&self) -> &str {
self.vault().room()
&self.vault().room().name
}
pub fn connect(&mut self, next_instance_id: &mut usize) {
@ -307,6 +311,8 @@ impl EuphRoom {
}
};
info = info.then(format!(" - {}", self.domain()), Style::new().grey());
let unseen = self.unseen_msgs_count().await;
if unseen > 0 {
info = info

View file

@ -1,3 +1,4 @@
use std::collections::hash_map::Entry;
use std::collections::{HashMap, HashSet};
use std::iter;
use std::sync::{Arc, Mutex};
@ -14,7 +15,7 @@ use toss::{Style, Styled, Widget, WidgetExt};
use crate::euph;
use crate::macros::logging_unwrap;
use crate::vault::Vault;
use crate::vault::{EuphVault, RoomIdentifier, Vault};
use super::euph::room::EuphRoom;
use super::widgets::{ListBuilder, ListState, Popup};
@ -22,9 +23,9 @@ use super::{key_bindings, util, UiError, UiEvent};
enum State {
ShowList,
ShowRoom(String),
ShowRoom(RoomIdentifier),
Connect(EditorState),
Delete(String, EditorState),
Delete(RoomIdentifier, EditorState),
}
#[derive(Clone, Copy)]
@ -42,6 +43,24 @@ impl Order {
}
}
struct EuphServer {
config: ServerConfig,
next_instance_id: usize,
}
impl EuphServer {
async fn new(vault: &EuphVault, domain: String) -> Self {
let cookies = logging_unwrap!(vault.cookies(domain.clone()).await);
let config = ServerConfig::default()
.domain(domain)
.cookies(Arc::new(Mutex::new(cookies)));
Self {
config,
next_instance_id: 0,
}
}
}
pub struct Rooms {
config: &'static Config,
@ -50,12 +69,11 @@ pub struct Rooms {
state: State,
list: ListState<String>,
list: ListState<RoomIdentifier>,
order: Order,
euph_server_config: ServerConfig,
euph_next_instance_id: usize,
euph_rooms: HashMap<String, EuphRoom>,
euph_servers: HashMap<String, EuphServer>,
euph_rooms: HashMap<RoomIdentifier, EuphRoom>,
}
impl Rooms {
@ -64,9 +82,6 @@ impl Rooms {
vault: Vault,
ui_event_tx: mpsc::UnboundedSender<UiEvent>,
) -> Self {
let cookies = logging_unwrap!(vault.euph().cookies().await);
let euph_server_config = ServerConfig::default().cookies(Arc::new(Mutex::new(cookies)));
let mut result = Self {
config,
vault,
@ -74,15 +89,20 @@ impl Rooms {
state: State::ShowList,
list: ListState::new(),
order: Order::from_rooms_sort_order(config.rooms_sort_order),
euph_server_config,
euph_next_instance_id: 0,
euph_servers: HashMap::new(),
euph_rooms: HashMap::new(),
};
if !config.offline {
for (name, config) in &config.euph.rooms {
if config.autojoin {
result.connect_to_room(name.clone());
result
.connect_to_room(RoomIdentifier {
// TODO Remove hardcoded domain
domain: "euphoria.leet.nu".to_string(),
name: name.clone(),
})
.await;
}
}
}
@ -90,39 +110,66 @@ impl Rooms {
result
}
fn get_or_insert_room(&mut self, name: String) -> &mut EuphRoom {
self.euph_rooms.entry(name.clone()).or_insert_with(|| {
async fn get_or_insert_server<'a>(
vault: &Vault,
euph_servers: &'a mut HashMap<String, EuphServer>,
domain: String,
) -> &'a mut EuphServer {
match euph_servers.entry(domain.clone()) {
Entry::Occupied(entry) => entry.into_mut(),
Entry::Vacant(entry) => {
let server = EuphServer::new(&vault.euph(), domain).await;
entry.insert(server)
}
}
}
async fn get_or_insert_room(&mut self, room: RoomIdentifier) -> &mut EuphRoom {
let server =
Self::get_or_insert_server(&self.vault, &mut self.euph_servers, room.domain.clone())
.await;
self.euph_rooms.entry(room.clone()).or_insert_with(|| {
EuphRoom::new(
self.config,
self.euph_server_config.clone(),
self.config.euph_room(&name),
self.vault.euph().room(name),
server.config.clone(),
self.config.euph_room(&room.name),
self.vault.euph().room(room),
self.ui_event_tx.clone(),
)
})
}
fn connect_to_room(&mut self, name: String) {
let room = self.euph_rooms.entry(name.clone()).or_insert_with(|| {
async fn connect_to_room(&mut self, room: RoomIdentifier) {
let server =
Self::get_or_insert_server(&self.vault, &mut self.euph_servers, room.domain.clone())
.await;
let room = self.euph_rooms.entry(room.clone()).or_insert_with(|| {
EuphRoom::new(
self.config,
self.euph_server_config.clone(),
self.config.euph_room(&name),
self.vault.euph().room(name),
server.config.clone(),
self.config.euph_room(&room.name),
self.vault.euph().room(room),
self.ui_event_tx.clone(),
)
});
room.connect(&mut self.euph_next_instance_id);
room.connect(&mut server.next_instance_id);
}
fn connect_to_all_rooms(&mut self) {
for room in self.euph_rooms.values_mut() {
room.connect(&mut self.euph_next_instance_id);
async fn connect_to_all_rooms(&mut self) {
for (id, room) in &mut self.euph_rooms {
let server =
Self::get_or_insert_server(&self.vault, &mut self.euph_servers, id.domain.clone())
.await;
room.connect(&mut server.next_instance_id);
}
}
fn disconnect_from_room(&mut self, name: &str) {
if let Some(room) = self.euph_rooms.get_mut(name) {
fn disconnect_from_room(&mut self, room: &RoomIdentifier) {
if let Some(room) = self.euph_rooms.get_mut(room) {
room.disconnect();
}
}
@ -145,7 +192,11 @@ impl Rooms {
let rooms = logging_unwrap!(self.vault.euph().rooms().await);
let mut rooms_set = rooms
.into_iter()
.chain(self.config.euph.rooms.keys().cloned())
.chain(self.config.euph.rooms.keys().map(|name| RoomIdentifier {
// TODO Remove hardcoded domain
domain: "euphoria.leet.nu".to_string(),
name: name.clone(),
}))
.collect::<HashSet<_>>();
// Prevent room that is currently being shown from being removed. This
@ -161,7 +212,7 @@ impl Rooms {
.retain(|n, r| !r.stopped() || rooms_set.contains(n));
for room in rooms_set {
self.get_or_insert_room(room).retain();
self.get_or_insert_room(room).await.retain();
}
}
@ -179,9 +230,9 @@ impl Rooms {
.boxed_async()
}
State::ShowRoom(name) => {
State::ShowRoom(id) => {
self.euph_rooms
.get_mut(name)
.get_mut(id)
.expect("room exists after stabilization")
.widget()
.await
@ -195,10 +246,11 @@ impl Rooms {
.boxed_async()
}
State::Delete(name, editor) => {
State::Delete(id, editor) => {
Self::rooms_widget(self.config, &mut self.list, self.order, &self.euph_rooms)
.await
.below(Self::delete_room_widget(name, editor))
// TODO Respect domain
.below(Self::delete_room_widget(&id.name, editor))
.desync()
.boxed_async()
}
@ -345,20 +397,20 @@ impl Rooms {
}
}
fn sort_rooms(rooms: &mut [(&String, Option<&euph::State>, usize)], order: Order) {
fn sort_rooms(rooms: &mut [(&RoomIdentifier, Option<&euph::State>, usize)], order: Order) {
match order {
Order::Alphabet => rooms.sort_unstable_by_key(|(name, _, _)| *name),
Order::Importance => rooms.sort_unstable_by_key(|(name, state, unseen)| {
(state.is_none(), *unseen == 0, *name)
Order::Alphabet => rooms.sort_unstable_by_key(|(id, _, _)| (&id.name, &id.domain)),
Order::Importance => rooms.sort_unstable_by_key(|(id, state, unseen)| {
(state.is_none(), *unseen == 0, &id.name, &id.domain)
}),
}
}
async fn render_rows(
config: &Config,
list_builder: &mut ListBuilder<'_, String, Text>,
list_builder: &mut ListBuilder<'_, RoomIdentifier, Text>,
order: Order,
euph_rooms: &HashMap<String, EuphRoom>,
euph_rooms: &HashMap<RoomIdentifier, EuphRoom>,
) {
if euph_rooms.is_empty() {
let style = Style::new().grey().italic();
@ -370,23 +422,25 @@ impl Rooms {
}
let mut rooms = vec![];
for (name, room) in euph_rooms {
for (id, room) in euph_rooms {
let state = room.room_state();
let unseen = room.unseen_msgs_count().await;
rooms.push((name, state, unseen));
rooms.push((id, state, unseen));
}
Self::sort_rooms(&mut rooms, order);
for (name, state, unseen) in rooms {
let name = name.clone();
for (id, state, unseen) in rooms {
let id = id.clone();
let info = Self::format_room_info(state, unseen);
list_builder.add_sel(name.clone(), move |selected| {
list_builder.add_sel(id.clone(), move |selected| {
let style = if selected {
Style::new().bold().black().on_white()
} else {
Style::new().bold().blue()
};
let text = Styled::new(format!("&{name}"), style).and_then(info);
let text = Styled::new(format!("&{}", id.name), style)
.and_then(info)
.then(format!(" - {}", id.domain), Style::new().grey());
Text::new(text)
});
@ -395,9 +449,9 @@ impl Rooms {
async fn rooms_widget<'a>(
config: &Config,
list: &'a mut ListState<String>,
list: &'a mut ListState<RoomIdentifier>,
order: Order,
euph_rooms: &HashMap<String, EuphRoom>,
euph_rooms: &HashMap<RoomIdentifier, EuphRoom>,
) -> impl Widget<UiError> + 'a {
let heading_style = Style::new().bold();
let heading_text =
@ -416,7 +470,11 @@ impl Rooms {
c.is_ascii_alphanumeric() || c == '_'
}
fn handle_showlist_input_event(&mut self, event: &mut InputEvent<'_>, keys: &Keys) -> bool {
async fn handle_showlist_input_event(
&mut self,
event: &mut InputEvent<'_>,
keys: &Keys,
) -> bool {
// Open room
if event.matches(&keys.general.confirm) {
if let Some(name) = self.list.selected() {
@ -433,17 +491,17 @@ impl Rooms {
// Room actions
if event.matches(&keys.rooms.action.connect) {
if let Some(name) = self.list.selected() {
self.connect_to_room(name.clone());
self.connect_to_room(name.clone()).await;
}
return true;
}
if event.matches(&keys.rooms.action.connect_all) {
self.connect_to_all_rooms();
self.connect_to_all_rooms().await;
return true;
}
if event.matches(&keys.rooms.action.disconnect) {
if let Some(name) = self.list.selected() {
self.disconnect_from_room(&name.clone());
if let Some(room) = self.list.selected() {
self.disconnect_from_room(&room.clone());
}
return true;
}
@ -454,18 +512,23 @@ impl Rooms {
if event.matches(&keys.rooms.action.connect_autojoin) {
for (name, options) in &self.config.euph.rooms {
if options.autojoin {
self.connect_to_room(name.clone());
let room = RoomIdentifier {
// TODO Remove hardcoded domain
domain: "euphoria.leet.nu".to_string(),
name: name.clone(),
};
self.connect_to_room(room).await;
}
}
return true;
}
if event.matches(&keys.rooms.action.disconnect_non_autojoin) {
for (name, room) in &mut self.euph_rooms {
for (id, room) in &mut self.euph_rooms {
let autojoin = self
.config
.euph
.rooms
.get(name)
.get(&id.name) // TODO Respect domain
.map(|r| r.autojoin)
.unwrap_or(false);
if !autojoin {
@ -479,8 +542,8 @@ impl Rooms {
return true;
}
if event.matches(&keys.rooms.action.delete) {
if let Some(name) = self.list.selected() {
self.state = State::Delete(name.clone(), EditorState::new());
if let Some(room) = self.list.selected() {
self.state = State::Delete(room.clone(), EditorState::new());
}
return true;
}
@ -500,7 +563,7 @@ impl Rooms {
match &mut self.state {
State::ShowList => {
if self.handle_showlist_input_event(event, keys) {
if self.handle_showlist_input_event(event, keys).await {
return true;
}
}
@ -523,8 +586,13 @@ impl Rooms {
if event.matches(&keys.general.confirm) {
let name = editor.text().to_string();
if !name.is_empty() {
self.connect_to_room(name.clone());
self.state = State::ShowRoom(name);
let room = RoomIdentifier {
// TODO Remove hardcoded domain
domain: "euphoria.leet.nu".to_string(),
name,
};
self.connect_to_room(room.clone()).await;
self.state = State::ShowRoom(room);
}
return true;
}
@ -553,15 +621,16 @@ impl Rooms {
}
pub async fn handle_euph_event(&mut self, event: Event) -> bool {
let room_name = event.config().room.clone();
let Some(room) = self.euph_rooms.get_mut(&room_name) else {
let config = event.config();
let room_id = RoomIdentifier::new(config.server.domain.clone(), config.room.clone());
let Some(room) = self.euph_rooms.get_mut(&room_id) else {
return false;
};
let handled = room.handle_event(event).await;
let room_visible = match &self.state {
State::ShowRoom(name) => *name == room_name,
State::ShowRoom(id) => *id == room_id,
_ => true,
};
handled && room_visible