mirror of
https://github.com/youwen5/iamb.git
synced 2025-06-20 05:39:52 -07:00
Reduce number of Tokio workers (#129)
This commit is contained in:
parent
8d4539831f
commit
61aba80be1
7 changed files with 232 additions and 258 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -1522,6 +1522,7 @@ dependencies = [
|
||||||
"css-color-parser",
|
"css-color-parser",
|
||||||
"dirs",
|
"dirs",
|
||||||
"emojis",
|
"emojis",
|
||||||
|
"futures",
|
||||||
"gethostname 0.4.1",
|
"gethostname 0.4.1",
|
||||||
"html5ever",
|
"html5ever",
|
||||||
"image",
|
"image",
|
||||||
|
|
|
@ -31,6 +31,7 @@ comrak = {version = "0.18.0", features = ["shortcodes"]}
|
||||||
css-color-parser = "0.1.2"
|
css-color-parser = "0.1.2"
|
||||||
dirs = "4.0.0"
|
dirs = "4.0.0"
|
||||||
emojis = "~0.5.2"
|
emojis = "~0.5.2"
|
||||||
|
futures = "0.3"
|
||||||
gethostname = "0.4.1"
|
gethostname = "0.4.1"
|
||||||
html5ever = "0.26.0"
|
html5ever = "0.26.0"
|
||||||
image = "0.24.5"
|
image = "0.24.5"
|
||||||
|
|
14
src/base.rs
14
src/base.rs
|
@ -21,7 +21,7 @@ use url::Url;
|
||||||
|
|
||||||
use matrix_sdk::{
|
use matrix_sdk::{
|
||||||
encryption::verification::SasVerification,
|
encryption::verification::SasVerification,
|
||||||
room::Joined,
|
room::{Joined, Room as MatrixRoom},
|
||||||
ruma::{
|
ruma::{
|
||||||
events::{
|
events::{
|
||||||
reaction::ReactionEvent,
|
reaction::ReactionEvent,
|
||||||
|
@ -644,6 +644,13 @@ fn emoji_map() -> CompletionMap<String, &'static Emoji> {
|
||||||
return emojis;
|
return emojis;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct SyncInfo {
|
||||||
|
pub spaces: Vec<MatrixRoom>,
|
||||||
|
pub rooms: Vec<Arc<(MatrixRoom, Option<Tags>)>>,
|
||||||
|
pub dms: Vec<Arc<(MatrixRoom, Option<Tags>)>>,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct ChatStore {
|
pub struct ChatStore {
|
||||||
pub cmds: ProgramCommands,
|
pub cmds: ProgramCommands,
|
||||||
pub worker: Requester,
|
pub worker: Requester,
|
||||||
|
@ -654,6 +661,7 @@ pub struct ChatStore {
|
||||||
pub settings: ApplicationSettings,
|
pub settings: ApplicationSettings,
|
||||||
pub need_load: HashSet<OwnedRoomId>,
|
pub need_load: HashSet<OwnedRoomId>,
|
||||||
pub emojis: CompletionMap<String, &'static Emoji>,
|
pub emojis: CompletionMap<String, &'static Emoji>,
|
||||||
|
pub sync_info: SyncInfo,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ChatStore {
|
impl ChatStore {
|
||||||
|
@ -663,12 +671,14 @@ impl ChatStore {
|
||||||
settings,
|
settings,
|
||||||
|
|
||||||
cmds: crate::commands::setup_commands(),
|
cmds: crate::commands::setup_commands(),
|
||||||
|
emojis: emoji_map(),
|
||||||
|
|
||||||
names: Default::default(),
|
names: Default::default(),
|
||||||
rooms: Default::default(),
|
rooms: Default::default(),
|
||||||
presences: Default::default(),
|
presences: Default::default(),
|
||||||
verifications: Default::default(),
|
verifications: Default::default(),
|
||||||
need_load: Default::default(),
|
need_load: Default::default(),
|
||||||
emojis: emoji_map(),
|
sync_info: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -712,6 +712,7 @@ fn main() -> IambResult<()> {
|
||||||
|
|
||||||
let rt = tokio::runtime::Builder::new_multi_thread()
|
let rt = tokio::runtime::Builder::new_multi_thread()
|
||||||
.enable_all()
|
.enable_all()
|
||||||
|
.worker_threads(2)
|
||||||
.thread_name_fn(|| {
|
.thread_name_fn(|| {
|
||||||
static ATOMIC_ID: AtomicUsize = AtomicUsize::new(0);
|
static ATOMIC_ID: AtomicUsize = AtomicUsize::new(0);
|
||||||
let id = ATOMIC_ID.fetch_add(1, Ordering::SeqCst);
|
let id = ATOMIC_ID.fetch_add(1, Ordering::SeqCst);
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
use std::cmp::{Ord, Ordering, PartialOrd};
|
use std::cmp::{Ord, Ordering, PartialOrd};
|
||||||
|
use std::ops::Deref;
|
||||||
|
use std::sync::Arc;
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
use matrix_sdk::{
|
use matrix_sdk::{
|
||||||
|
@ -10,7 +12,6 @@ use matrix_sdk::{
|
||||||
OwnedRoomId,
|
OwnedRoomId,
|
||||||
RoomId,
|
RoomId,
|
||||||
},
|
},
|
||||||
DisplayName,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use modalkit::tui::{
|
use modalkit::tui::{
|
||||||
|
@ -78,6 +79,8 @@ use self::{room::RoomState, welcome::WelcomeState};
|
||||||
pub mod room;
|
pub mod room;
|
||||||
pub mod welcome;
|
pub mod welcome;
|
||||||
|
|
||||||
|
type MatrixRoomInfo = Arc<(MatrixRoom, Option<Tags>)>;
|
||||||
|
|
||||||
const MEMBER_FETCH_DEBOUNCE: Duration = Duration::from_secs(5);
|
const MEMBER_FETCH_DEBOUNCE: Duration = Duration::from_secs(5);
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -380,10 +383,13 @@ impl WindowOps<IambInfo> for IambWindow {
|
||||||
match self {
|
match self {
|
||||||
IambWindow::Room(state) => state.draw(area, buf, focused, store),
|
IambWindow::Room(state) => state.draw(area, buf, focused, store),
|
||||||
IambWindow::DirectList(state) => {
|
IambWindow::DirectList(state) => {
|
||||||
let dms = store.application.worker.direct_messages();
|
let mut items = store
|
||||||
let mut items = dms
|
.application
|
||||||
|
.sync_info
|
||||||
|
.dms
|
||||||
|
.clone()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(id, name, tags)| DirectItem::new(id, name, tags, store))
|
.map(|room_info| DirectItem::new(room_info, store))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
items.sort();
|
items.sort();
|
||||||
|
|
||||||
|
@ -416,10 +422,13 @@ impl WindowOps<IambInfo> for IambWindow {
|
||||||
.render(area, buf, state);
|
.render(area, buf, state);
|
||||||
},
|
},
|
||||||
IambWindow::RoomList(state) => {
|
IambWindow::RoomList(state) => {
|
||||||
let joined = store.application.worker.active_rooms();
|
let mut items = store
|
||||||
let mut items = joined
|
.application
|
||||||
|
.sync_info
|
||||||
|
.rooms
|
||||||
|
.clone()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(room, name, tags)| RoomItem::new(room, name, tags, store))
|
.map(|room_info| RoomItem::new(room_info, store))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
items.sort();
|
items.sort();
|
||||||
|
|
||||||
|
@ -432,9 +441,13 @@ impl WindowOps<IambInfo> for IambWindow {
|
||||||
.render(area, buf, state);
|
.render(area, buf, state);
|
||||||
},
|
},
|
||||||
IambWindow::SpaceList(state) => {
|
IambWindow::SpaceList(state) => {
|
||||||
let spaces = store.application.worker.spaces();
|
let items = store
|
||||||
let items =
|
.application
|
||||||
spaces.into_iter().map(|(room, name)| SpaceItem::new(room, name, store));
|
.sync_info
|
||||||
|
.spaces
|
||||||
|
.clone()
|
||||||
|
.into_iter()
|
||||||
|
.map(|room| SpaceItem::new(room, store));
|
||||||
state.set(items.collect());
|
state.set(items.collect());
|
||||||
state.draw(area, buf, focused, store);
|
state.draw(area, buf, focused, store);
|
||||||
|
|
||||||
|
@ -639,36 +652,45 @@ impl Window<IambInfo> for IambWindow {
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct RoomItem {
|
pub struct RoomItem {
|
||||||
room: MatrixRoom,
|
room_info: MatrixRoomInfo,
|
||||||
tags: Option<Tags>,
|
|
||||||
name: String,
|
name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RoomItem {
|
impl RoomItem {
|
||||||
fn new(
|
fn new(room_info: MatrixRoomInfo, store: &mut ProgramStore) -> Self {
|
||||||
room: MatrixRoom,
|
let room = &room_info.deref().0;
|
||||||
name: DisplayName,
|
|
||||||
tags: Option<Tags>,
|
|
||||||
store: &mut ProgramStore,
|
|
||||||
) -> Self {
|
|
||||||
let name = name.to_string();
|
|
||||||
let room_id = room.room_id();
|
let room_id = room.room_id();
|
||||||
|
|
||||||
let info = store.application.get_room_info(room_id.to_owned());
|
let info = store.application.get_room_info(room_id.to_owned());
|
||||||
info.name = name.clone().into();
|
let name = info.name.clone().unwrap_or_default();
|
||||||
info.tags = tags.clone();
|
info.tags = room_info.deref().1.clone();
|
||||||
|
|
||||||
if let Some(alias) = room.canonical_alias() {
|
if let Some(alias) = room.canonical_alias() {
|
||||||
store.application.names.insert(alias.to_string(), room_id.to_owned());
|
store.application.names.insert(alias.to_string(), room_id.to_owned());
|
||||||
}
|
}
|
||||||
|
|
||||||
RoomItem { room, tags, name }
|
RoomItem { room_info, name }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn room(&self) -> &MatrixRoom {
|
||||||
|
&self.room_info.deref().0
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn room_id(&self) -> &RoomId {
|
||||||
|
self.room().room_id()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn tags(&self) -> &Option<Tags> {
|
||||||
|
&self.room_info.deref().1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for RoomItem {
|
impl PartialEq for RoomItem {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
self.room.room_id() == other.room.room_id()
|
self.room_id() == other.room_id()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -676,7 +698,7 @@ impl Eq for RoomItem {}
|
||||||
|
|
||||||
impl Ord for RoomItem {
|
impl Ord for RoomItem {
|
||||||
fn cmp(&self, other: &Self) -> Ordering {
|
fn cmp(&self, other: &Self) -> Ordering {
|
||||||
tag_cmp(&self.tags, &other.tags).then_with(|| room_cmp(&self.room, &other.room))
|
tag_cmp(self.tags(), other.tags()).then_with(|| room_cmp(self.room(), other.room()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -694,7 +716,7 @@ impl ToString for RoomItem {
|
||||||
|
|
||||||
impl ListItem<IambInfo> for RoomItem {
|
impl ListItem<IambInfo> for RoomItem {
|
||||||
fn show(&self, selected: bool, _: &ViewportContext<ListCursor>, _: &mut ProgramStore) -> Text {
|
fn show(&self, selected: bool, _: &ViewportContext<ListCursor>, _: &mut ProgramStore) -> Text {
|
||||||
if let Some(tags) = &self.tags {
|
if let Some(tags) = &self.tags() {
|
||||||
let style = selected_style(selected);
|
let style = selected_style(selected);
|
||||||
let mut spans = vec![Span::styled(self.name.as_str(), style)];
|
let mut spans = vec![Span::styled(self.name.as_str(), style)];
|
||||||
|
|
||||||
|
@ -707,7 +729,7 @@ impl ListItem<IambInfo> for RoomItem {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_word(&self) -> Option<String> {
|
fn get_word(&self) -> Option<String> {
|
||||||
self.room.room_id().to_string().into()
|
self.room_id().to_string().into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -718,29 +740,37 @@ impl Promptable<ProgramContext, ProgramStore, IambInfo> for RoomItem {
|
||||||
ctx: &ProgramContext,
|
ctx: &ProgramContext,
|
||||||
_: &mut ProgramStore,
|
_: &mut ProgramStore,
|
||||||
) -> EditResult<Vec<(ProgramAction, ProgramContext)>, IambInfo> {
|
) -> EditResult<Vec<(ProgramAction, ProgramContext)>, IambInfo> {
|
||||||
room_prompt(self.room.room_id(), act, ctx)
|
room_prompt(self.room_id(), act, ctx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct DirectItem {
|
pub struct DirectItem {
|
||||||
room: MatrixRoom,
|
room_info: MatrixRoomInfo,
|
||||||
tags: Option<Tags>,
|
|
||||||
name: String,
|
name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DirectItem {
|
impl DirectItem {
|
||||||
fn new(
|
fn new(room_info: MatrixRoomInfo, store: &mut ProgramStore) -> Self {
|
||||||
room: MatrixRoom,
|
let room_id = room_info.deref().0.room_id().to_owned();
|
||||||
name: DisplayName,
|
let name = store.application.get_room_info(room_id).name.clone().unwrap_or_default();
|
||||||
tags: Option<Tags>,
|
|
||||||
store: &mut ProgramStore,
|
|
||||||
) -> Self {
|
|
||||||
let name = name.to_string();
|
|
||||||
|
|
||||||
store.application.set_room_name(room.room_id(), name.as_str());
|
DirectItem { room_info, name }
|
||||||
|
}
|
||||||
|
|
||||||
DirectItem { room, tags, name }
|
#[inline]
|
||||||
|
fn room(&self) -> &MatrixRoom {
|
||||||
|
&self.room_info.deref().0
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn room_id(&self) -> &RoomId {
|
||||||
|
self.room().room_id()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn tags(&self) -> &Option<Tags> {
|
||||||
|
&self.room_info.deref().1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -752,7 +782,7 @@ impl ToString for DirectItem {
|
||||||
|
|
||||||
impl ListItem<IambInfo> for DirectItem {
|
impl ListItem<IambInfo> for DirectItem {
|
||||||
fn show(&self, selected: bool, _: &ViewportContext<ListCursor>, _: &mut ProgramStore) -> Text {
|
fn show(&self, selected: bool, _: &ViewportContext<ListCursor>, _: &mut ProgramStore) -> Text {
|
||||||
if let Some(tags) = &self.tags {
|
if let Some(tags) = &self.tags() {
|
||||||
let style = selected_style(selected);
|
let style = selected_style(selected);
|
||||||
let mut spans = vec![Span::styled(self.name.as_str(), style)];
|
let mut spans = vec![Span::styled(self.name.as_str(), style)];
|
||||||
|
|
||||||
|
@ -765,13 +795,13 @@ impl ListItem<IambInfo> for DirectItem {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_word(&self) -> Option<String> {
|
fn get_word(&self) -> Option<String> {
|
||||||
self.room.room_id().to_string().into()
|
self.room_id().to_string().into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for DirectItem {
|
impl PartialEq for DirectItem {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
self.room.room_id() == other.room.room_id()
|
self.room_id() == other.room_id()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -779,7 +809,7 @@ impl Eq for DirectItem {}
|
||||||
|
|
||||||
impl Ord for DirectItem {
|
impl Ord for DirectItem {
|
||||||
fn cmp(&self, other: &Self) -> Ordering {
|
fn cmp(&self, other: &Self) -> Ordering {
|
||||||
tag_cmp(&self.tags, &other.tags).then_with(|| room_cmp(&self.room, &other.room))
|
tag_cmp(self.tags(), other.tags()).then_with(|| room_cmp(self.room(), other.room()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -796,7 +826,7 @@ impl Promptable<ProgramContext, ProgramStore, IambInfo> for DirectItem {
|
||||||
ctx: &ProgramContext,
|
ctx: &ProgramContext,
|
||||||
_: &mut ProgramStore,
|
_: &mut ProgramStore,
|
||||||
) -> EditResult<Vec<(ProgramAction, ProgramContext)>, IambInfo> {
|
) -> EditResult<Vec<(ProgramAction, ProgramContext)>, IambInfo> {
|
||||||
room_prompt(self.room.room_id(), act, ctx)
|
room_prompt(self.room_id(), act, ctx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -807,11 +837,14 @@ pub struct SpaceItem {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SpaceItem {
|
impl SpaceItem {
|
||||||
fn new(room: MatrixRoom, name: DisplayName, store: &mut ProgramStore) -> Self {
|
fn new(room: MatrixRoom, store: &mut ProgramStore) -> Self {
|
||||||
let name = name.to_string();
|
|
||||||
let room_id = room.room_id();
|
let room_id = room.room_id();
|
||||||
|
let name = store
|
||||||
store.application.set_room_name(room_id, name.as_str());
|
.application
|
||||||
|
.get_room_info(room_id.to_owned())
|
||||||
|
.name
|
||||||
|
.clone()
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
if let Some(alias) = room.canonical_alias() {
|
if let Some(alias) = room.canonical_alias() {
|
||||||
store.application.names.insert(alias.to_string(), room_id.to_owned());
|
store.application.names.insert(alias.to_string(), room_id.to_owned());
|
||||||
|
|
|
@ -120,11 +120,12 @@ impl<'a> StatefulWidget for Space<'a> {
|
||||||
let items = members
|
let items = members
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_map(|id| {
|
.filter_map(|id| {
|
||||||
let (room, name, tags) =
|
let (room, _, tags) =
|
||||||
self.store.application.worker.get_room(id.clone()).ok()?;
|
self.store.application.worker.get_room(id.clone()).ok()?;
|
||||||
|
let room_info = std::sync::Arc::new((room, tags));
|
||||||
|
|
||||||
if id != state.room_id {
|
if id != state.room_id {
|
||||||
Some(RoomItem::new(room, name, tags, self.store))
|
Some(RoomItem::new(room_info, self.store))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
321
src/worker.rs
321
src/worker.rs
|
@ -8,6 +8,7 @@ use std::sync::mpsc::{sync_channel, Receiver, SyncSender};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
|
use futures::{stream::FuturesUnordered, StreamExt};
|
||||||
use gethostname::gethostname;
|
use gethostname::gethostname;
|
||||||
use tokio::sync::mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender};
|
use tokio::sync::mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender};
|
||||||
use tokio::task::JoinHandle;
|
use tokio::task::JoinHandle;
|
||||||
|
@ -260,19 +261,122 @@ async fn load_insert(room_id: OwnedRoomId, res: MessageFetchResult, store: Async
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn load_older(client: &Client, store: &AsyncProgramStore) {
|
async fn load_older(client: &Client, store: &AsyncProgramStore) -> usize {
|
||||||
let limit = MIN_MSG_LOAD;
|
let limit = MIN_MSG_LOAD;
|
||||||
let plan = load_plan(store).await;
|
|
||||||
|
|
||||||
// Fetch each room separately, so they don't block each other.
|
// Fetch each room separately, so they don't block each other.
|
||||||
for (room_id, fetch_id) in plan.into_iter() {
|
load_plan(store)
|
||||||
|
.await
|
||||||
|
.into_iter()
|
||||||
|
.map(|(room_id, fetch_id)| {
|
||||||
let client = client.clone();
|
let client = client.clone();
|
||||||
let store = store.clone();
|
let store = store.clone();
|
||||||
|
|
||||||
tokio::spawn(async move {
|
async move {
|
||||||
let res = load_older_one(client, room_id.as_ref(), fetch_id, limit).await;
|
let res = load_older_one(client, room_id.as_ref(), fetch_id, limit).await;
|
||||||
load_insert(room_id, res, store).await;
|
load_insert(room_id, res, store).await;
|
||||||
});
|
}
|
||||||
|
})
|
||||||
|
.collect::<FuturesUnordered<_>>()
|
||||||
|
.count()
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn load_older_forever(client: &Client, store: &AsyncProgramStore) {
|
||||||
|
// Load older messages every 2 seconds.
|
||||||
|
let mut interval = tokio::time::interval(Duration::from_secs(2));
|
||||||
|
|
||||||
|
loop {
|
||||||
|
interval.tick().await;
|
||||||
|
load_older(client, store).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn refresh_rooms(client: &Client, store: &AsyncProgramStore) {
|
||||||
|
let mut names = vec![];
|
||||||
|
|
||||||
|
let mut spaces = vec![];
|
||||||
|
let mut rooms = vec![];
|
||||||
|
let mut dms = vec![];
|
||||||
|
|
||||||
|
for room in client.invited_rooms().into_iter() {
|
||||||
|
let name = room.display_name().await.unwrap_or(DisplayName::Empty).to_string();
|
||||||
|
names.push((room.room_id().to_owned(), name));
|
||||||
|
|
||||||
|
if room.is_direct() {
|
||||||
|
let tags = room.tags().await.unwrap_or_default();
|
||||||
|
|
||||||
|
dms.push(Arc::new((room.into(), tags)));
|
||||||
|
} else if room.is_space() {
|
||||||
|
spaces.push(room.into());
|
||||||
|
} else {
|
||||||
|
let tags = room.tags().await.unwrap_or_default();
|
||||||
|
|
||||||
|
rooms.push(Arc::new((room.into(), tags)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for room in client.joined_rooms().into_iter() {
|
||||||
|
let name = room.display_name().await.unwrap_or(DisplayName::Empty).to_string();
|
||||||
|
names.push((room.room_id().to_owned(), name));
|
||||||
|
|
||||||
|
if room.is_direct() {
|
||||||
|
let tags = room.tags().await.unwrap_or_default();
|
||||||
|
|
||||||
|
dms.push(Arc::new((room.into(), tags)));
|
||||||
|
} else if room.is_space() {
|
||||||
|
spaces.push(room.into());
|
||||||
|
} else {
|
||||||
|
let tags = room.tags().await.unwrap_or_default();
|
||||||
|
|
||||||
|
rooms.push(Arc::new((room.into(), tags)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut locked = store.lock().await;
|
||||||
|
locked.application.sync_info.spaces = spaces;
|
||||||
|
locked.application.sync_info.rooms = rooms;
|
||||||
|
locked.application.sync_info.dms = dms;
|
||||||
|
|
||||||
|
for (room_id, name) in names {
|
||||||
|
locked.application.set_room_name(&room_id, &name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn refresh_rooms_forever(client: &Client, store: &AsyncProgramStore) {
|
||||||
|
let mut interval = tokio::time::interval(Duration::from_secs(5));
|
||||||
|
|
||||||
|
loop {
|
||||||
|
interval.tick().await;
|
||||||
|
|
||||||
|
refresh_rooms(client, store).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn refresh_receipts_forever(client: &Client, store: &AsyncProgramStore) {
|
||||||
|
// Update the displayed read receipts every 5 seconds.
|
||||||
|
let mut interval = tokio::time::interval(Duration::from_secs(5));
|
||||||
|
let mut sent = HashMap::<OwnedRoomId, OwnedEventId>::default();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
interval.tick().await;
|
||||||
|
let receipts = update_receipts(client).await;
|
||||||
|
let read = store.lock().await.application.set_receipts(receipts).await;
|
||||||
|
|
||||||
|
for (room_id, read_till) in read.into_iter() {
|
||||||
|
if let Some(read_sent) = sent.get(&room_id) {
|
||||||
|
if read_sent == &read_till {
|
||||||
|
// Skip unchanged receipts.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(room) = client.get_joined_room(&room_id) {
|
||||||
|
if room.read_receipt(&read_till).await.is_ok() {
|
||||||
|
sent.insert(room_id, read_till);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -331,8 +435,6 @@ async fn update_receipts(client: &Client) -> Vec<(OwnedRoomId, Receipts)> {
|
||||||
pub type FetchedRoom = (MatrixRoom, DisplayName, Option<Tags>);
|
pub type FetchedRoom = (MatrixRoom, DisplayName, Option<Tags>);
|
||||||
|
|
||||||
pub enum WorkerTask {
|
pub enum WorkerTask {
|
||||||
ActiveRooms(ClientReply<Vec<FetchedRoom>>),
|
|
||||||
DirectMessages(ClientReply<Vec<FetchedRoom>>),
|
|
||||||
Init(AsyncProgramStore, ClientReply<()>),
|
Init(AsyncProgramStore, ClientReply<()>),
|
||||||
Login(LoginStyle, ClientReply<IambResult<EditInfo>>),
|
Login(LoginStyle, ClientReply<IambResult<EditInfo>>),
|
||||||
GetInviter(Invited, ClientReply<IambResult<Option<RoomMember>>>),
|
GetInviter(Invited, ClientReply<IambResult<Option<RoomMember>>>),
|
||||||
|
@ -340,7 +442,6 @@ pub enum WorkerTask {
|
||||||
JoinRoom(String, ClientReply<IambResult<OwnedRoomId>>),
|
JoinRoom(String, ClientReply<IambResult<OwnedRoomId>>),
|
||||||
Members(OwnedRoomId, ClientReply<IambResult<Vec<RoomMember>>>),
|
Members(OwnedRoomId, ClientReply<IambResult<Vec<RoomMember>>>),
|
||||||
SpaceMembers(OwnedRoomId, ClientReply<IambResult<Vec<OwnedRoomId>>>),
|
SpaceMembers(OwnedRoomId, ClientReply<IambResult<Vec<OwnedRoomId>>>),
|
||||||
Spaces(ClientReply<Vec<(MatrixRoom, DisplayName)>>),
|
|
||||||
TypingNotice(OwnedRoomId),
|
TypingNotice(OwnedRoomId),
|
||||||
Verify(VerifyAction, SasVerification, ClientReply<IambResult<EditInfo>>),
|
Verify(VerifyAction, SasVerification, ClientReply<IambResult<EditInfo>>),
|
||||||
VerifyRequest(OwnedUserId, ClientReply<IambResult<EditInfo>>),
|
VerifyRequest(OwnedUserId, ClientReply<IambResult<EditInfo>>),
|
||||||
|
@ -349,14 +450,6 @@ pub enum WorkerTask {
|
||||||
impl Debug for WorkerTask {
|
impl Debug for WorkerTask {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
|
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
|
||||||
match self {
|
match self {
|
||||||
WorkerTask::ActiveRooms(_) => {
|
|
||||||
f.debug_tuple("WorkerTask::ActiveRooms").field(&format_args!("_")).finish()
|
|
||||||
},
|
|
||||||
WorkerTask::DirectMessages(_) => {
|
|
||||||
f.debug_tuple("WorkerTask::DirectMessages")
|
|
||||||
.field(&format_args!("_"))
|
|
||||||
.finish()
|
|
||||||
},
|
|
||||||
WorkerTask::Init(_, _) => {
|
WorkerTask::Init(_, _) => {
|
||||||
f.debug_tuple("WorkerTask::Init")
|
f.debug_tuple("WorkerTask::Init")
|
||||||
.field(&format_args!("_"))
|
.field(&format_args!("_"))
|
||||||
|
@ -396,9 +489,6 @@ impl Debug for WorkerTask {
|
||||||
.field(&format_args!("_"))
|
.field(&format_args!("_"))
|
||||||
.finish()
|
.finish()
|
||||||
},
|
},
|
||||||
WorkerTask::Spaces(_) => {
|
|
||||||
f.debug_tuple("WorkerTask::Spaces").field(&format_args!("_")).finish()
|
|
||||||
},
|
|
||||||
WorkerTask::TypingNotice(room_id) => {
|
WorkerTask::TypingNotice(room_id) => {
|
||||||
f.debug_tuple("WorkerTask::TypingNotice").field(room_id).finish()
|
f.debug_tuple("WorkerTask::TypingNotice").field(room_id).finish()
|
||||||
},
|
},
|
||||||
|
@ -442,14 +532,6 @@ impl Requester {
|
||||||
return response.recv();
|
return response.recv();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn direct_messages(&self) -> Vec<FetchedRoom> {
|
|
||||||
let (reply, response) = oneshot();
|
|
||||||
|
|
||||||
self.tx.send(WorkerTask::DirectMessages(reply)).unwrap();
|
|
||||||
|
|
||||||
return response.recv();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_inviter(&self, invite: Invited) -> IambResult<Option<RoomMember>> {
|
pub fn get_inviter(&self, invite: Invited) -> IambResult<Option<RoomMember>> {
|
||||||
let (reply, response) = oneshot();
|
let (reply, response) = oneshot();
|
||||||
|
|
||||||
|
@ -474,14 +556,6 @@ impl Requester {
|
||||||
return response.recv();
|
return response.recv();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn active_rooms(&self) -> Vec<FetchedRoom> {
|
|
||||||
let (reply, response) = oneshot();
|
|
||||||
|
|
||||||
self.tx.send(WorkerTask::ActiveRooms(reply)).unwrap();
|
|
||||||
|
|
||||||
return response.recv();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn members(&self, room_id: OwnedRoomId) -> IambResult<Vec<RoomMember>> {
|
pub fn members(&self, room_id: OwnedRoomId) -> IambResult<Vec<RoomMember>> {
|
||||||
let (reply, response) = oneshot();
|
let (reply, response) = oneshot();
|
||||||
|
|
||||||
|
@ -498,14 +572,6 @@ impl Requester {
|
||||||
return response.recv();
|
return response.recv();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn spaces(&self) -> Vec<(MatrixRoom, DisplayName)> {
|
|
||||||
let (reply, response) = oneshot();
|
|
||||||
|
|
||||||
self.tx.send(WorkerTask::Spaces(reply)).unwrap();
|
|
||||||
|
|
||||||
return response.recv();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn typing_notice(&self, room_id: OwnedRoomId) {
|
pub fn typing_notice(&self, room_id: OwnedRoomId) {
|
||||||
self.tx.send(WorkerTask::TypingNotice(room_id)).unwrap();
|
self.tx.send(WorkerTask::TypingNotice(room_id)).unwrap();
|
||||||
}
|
}
|
||||||
|
@ -532,7 +598,6 @@ pub struct ClientWorker {
|
||||||
settings: ApplicationSettings,
|
settings: ApplicationSettings,
|
||||||
client: Client,
|
client: Client,
|
||||||
load_handle: Option<JoinHandle<()>>,
|
load_handle: Option<JoinHandle<()>>,
|
||||||
rcpt_handle: Option<JoinHandle<()>>,
|
|
||||||
sync_handle: Option<JoinHandle<()>>,
|
sync_handle: Option<JoinHandle<()>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -571,7 +636,6 @@ impl ClientWorker {
|
||||||
settings,
|
settings,
|
||||||
client: client.clone(),
|
client: client.clone(),
|
||||||
load_handle: None,
|
load_handle: None,
|
||||||
rcpt_handle: None,
|
|
||||||
sync_handle: None,
|
sync_handle: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -597,18 +661,10 @@ impl ClientWorker {
|
||||||
if let Some(handle) = self.sync_handle.take() {
|
if let Some(handle) = self.sync_handle.take() {
|
||||||
handle.abort();
|
handle.abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(handle) = self.rcpt_handle.take() {
|
|
||||||
handle.abort();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn run(&mut self, task: WorkerTask) {
|
async fn run(&mut self, task: WorkerTask) {
|
||||||
match task {
|
match task {
|
||||||
WorkerTask::DirectMessages(reply) => {
|
|
||||||
assert!(self.initialized);
|
|
||||||
reply.send(self.direct_messages().await);
|
|
||||||
},
|
|
||||||
WorkerTask::Init(store, reply) => {
|
WorkerTask::Init(store, reply) => {
|
||||||
assert_eq!(self.initialized, false);
|
assert_eq!(self.initialized, false);
|
||||||
self.init(store).await;
|
self.init(store).await;
|
||||||
|
@ -626,10 +682,6 @@ impl ClientWorker {
|
||||||
assert!(self.initialized);
|
assert!(self.initialized);
|
||||||
reply.send(self.get_room(room_id).await);
|
reply.send(self.get_room(room_id).await);
|
||||||
},
|
},
|
||||||
WorkerTask::ActiveRooms(reply) => {
|
|
||||||
assert!(self.initialized);
|
|
||||||
reply.send(self.active_rooms().await);
|
|
||||||
},
|
|
||||||
WorkerTask::Login(style, reply) => {
|
WorkerTask::Login(style, reply) => {
|
||||||
assert!(self.initialized);
|
assert!(self.initialized);
|
||||||
reply.send(self.login_and_sync(style).await);
|
reply.send(self.login_and_sync(style).await);
|
||||||
|
@ -642,10 +694,6 @@ impl ClientWorker {
|
||||||
assert!(self.initialized);
|
assert!(self.initialized);
|
||||||
reply.send(self.space_members(space).await);
|
reply.send(self.space_members(space).await);
|
||||||
},
|
},
|
||||||
WorkerTask::Spaces(reply) => {
|
|
||||||
assert!(self.initialized);
|
|
||||||
reply.send(self.spaces().await);
|
|
||||||
},
|
|
||||||
WorkerTask::TypingNotice(room_id) => {
|
WorkerTask::TypingNotice(room_id) => {
|
||||||
assert!(self.initialized);
|
assert!(self.initialized);
|
||||||
self.typing_notice(room_id).await;
|
self.typing_notice(room_id).await;
|
||||||
|
@ -903,50 +951,14 @@ impl ClientWorker {
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
self.rcpt_handle = tokio::spawn({
|
|
||||||
let store = store.clone();
|
|
||||||
let client = self.client.clone();
|
|
||||||
let mut sent = HashMap::<OwnedRoomId, OwnedEventId>::default();
|
|
||||||
|
|
||||||
async move {
|
|
||||||
// Update the displayed read receipts every 5 seconds.
|
|
||||||
let mut interval = tokio::time::interval(Duration::from_secs(5));
|
|
||||||
|
|
||||||
loop {
|
|
||||||
interval.tick().await;
|
|
||||||
|
|
||||||
let receipts = update_receipts(&client).await;
|
|
||||||
let read = store.lock().await.application.set_receipts(receipts).await;
|
|
||||||
|
|
||||||
for (room_id, read_till) in read.into_iter() {
|
|
||||||
if let Some(read_sent) = sent.get(&room_id) {
|
|
||||||
if read_sent == &read_till {
|
|
||||||
// Skip unchanged receipts.
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(room) = client.get_joined_room(&room_id) {
|
|
||||||
if room.read_receipt(&read_till).await.is_ok() {
|
|
||||||
sent.insert(room_id, read_till);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.into();
|
|
||||||
|
|
||||||
self.load_handle = tokio::spawn({
|
self.load_handle = tokio::spawn({
|
||||||
let client = self.client.clone();
|
let client = self.client.clone();
|
||||||
|
|
||||||
async move {
|
async move {
|
||||||
// Load older messages every 2 seconds.
|
let load = load_older_forever(&client, &store);
|
||||||
let mut interval = tokio::time::interval(Duration::from_secs(2));
|
let rcpt = refresh_receipts_forever(&client, &store);
|
||||||
loop {
|
let room = refresh_rooms_forever(&client, &store);
|
||||||
interval.tick().await;
|
let ((), (), ()) = tokio::join!(load, rcpt, room);
|
||||||
load_older(&client, &store).await;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.into();
|
.into();
|
||||||
|
@ -1002,19 +1014,21 @@ impl ClientWorker {
|
||||||
Ok(Some(InfoMessage::from("Successfully logged in!")))
|
Ok(Some(InfoMessage::from("Successfully logged in!")))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn direct_message(&mut self, user: OwnedUserId) -> IambResult<FetchedRoom> {
|
async fn direct_message(&mut self, user: OwnedUserId) -> IambResult<OwnedRoomId> {
|
||||||
for (room, name, tags) in self.direct_messages().await {
|
for room in self.client.rooms() {
|
||||||
|
if !room.is_direct() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if room.get_member(user.as_ref()).await.map_err(IambError::from)?.is_some() {
|
if room.get_member(user.as_ref()).await.map_err(IambError::from)?.is_some() {
|
||||||
return Ok((room, name, tags));
|
return Ok(room.room_id().to_owned());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let rt = CreateRoomType::Direct(user.clone());
|
let rt = CreateRoomType::Direct(user.clone());
|
||||||
let flags = CreateRoomFlags::ENCRYPTED;
|
let flags = CreateRoomFlags::ENCRYPTED;
|
||||||
|
|
||||||
match create_room(&self.client, None, rt, flags).await {
|
create_room(&self.client, None, rt, flags).await.map_err(|e| {
|
||||||
Ok(room_id) => self.get_room(room_id).await,
|
|
||||||
Err(e) => {
|
|
||||||
error!(
|
error!(
|
||||||
user_id = user.as_str(),
|
user_id = user.as_str(),
|
||||||
err = e.to_string(),
|
err = e.to_string(),
|
||||||
|
@ -1022,11 +1036,8 @@ impl ClientWorker {
|
||||||
);
|
);
|
||||||
|
|
||||||
let msg = format!("Could not open a room with {user}");
|
let msg = format!("Could not open a room with {user}");
|
||||||
let err = UIError::Failure(msg);
|
UIError::Failure(msg)
|
||||||
|
})
|
||||||
Err(err)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_inviter(&mut self, invited: Invited) -> IambResult<Option<RoomMember>> {
|
async fn get_inviter(&mut self, invited: Invited) -> IambResult<Option<RoomMember>> {
|
||||||
|
@ -1058,9 +1069,7 @@ impl ClientWorker {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
} else if let Ok(user) = OwnedUserId::try_from(name.as_str()) {
|
} else if let Ok(user) = OwnedUserId::try_from(name.as_str()) {
|
||||||
let room = self.direct_message(user).await?.0;
|
self.direct_message(user).await
|
||||||
|
|
||||||
return Ok(room.room_id().to_owned());
|
|
||||||
} else {
|
} else {
|
||||||
let msg = format!("{:?} is not a valid room or user name", name.as_str());
|
let msg = format!("{:?} is not a valid room or user name", name.as_str());
|
||||||
let err = UIError::Failure(msg);
|
let err = UIError::Failure(msg);
|
||||||
|
@ -1069,62 +1078,6 @@ impl ClientWorker {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn direct_messages(&self) -> Vec<FetchedRoom> {
|
|
||||||
let mut rooms = vec![];
|
|
||||||
|
|
||||||
for room in self.client.invited_rooms().into_iter() {
|
|
||||||
if !room.is_direct() {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let name = room.display_name().await.unwrap_or(DisplayName::Empty);
|
|
||||||
let tags = room.tags().await.unwrap_or_default();
|
|
||||||
|
|
||||||
rooms.push((room.into(), name, tags));
|
|
||||||
}
|
|
||||||
|
|
||||||
for room in self.client.joined_rooms().into_iter() {
|
|
||||||
if !room.is_direct() {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let name = room.display_name().await.unwrap_or(DisplayName::Empty);
|
|
||||||
let tags = room.tags().await.unwrap_or_default();
|
|
||||||
|
|
||||||
rooms.push((room.into(), name, tags));
|
|
||||||
}
|
|
||||||
|
|
||||||
return rooms;
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn active_rooms(&self) -> Vec<FetchedRoom> {
|
|
||||||
let mut rooms = vec![];
|
|
||||||
|
|
||||||
for room in self.client.invited_rooms().into_iter() {
|
|
||||||
if room.is_space() || room.is_direct() {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let name = room.display_name().await.unwrap_or(DisplayName::Empty);
|
|
||||||
let tags = room.tags().await.unwrap_or_default();
|
|
||||||
|
|
||||||
rooms.push((room.into(), name, tags));
|
|
||||||
}
|
|
||||||
|
|
||||||
for room in self.client.joined_rooms().into_iter() {
|
|
||||||
if room.is_space() || room.is_direct() {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let name = room.display_name().await.unwrap_or(DisplayName::Empty);
|
|
||||||
let tags = room.tags().await.unwrap_or_default();
|
|
||||||
|
|
||||||
rooms.push((room.into(), name, tags));
|
|
||||||
}
|
|
||||||
|
|
||||||
return rooms;
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn members(&mut self, room_id: OwnedRoomId) -> IambResult<Vec<RoomMember>> {
|
async fn members(&mut self, room_id: OwnedRoomId) -> IambResult<Vec<RoomMember>> {
|
||||||
if let Some(room) = self.client.get_room(room_id.as_ref()) {
|
if let Some(room) = self.client.get_room(room_id.as_ref()) {
|
||||||
Ok(room.active_members().await.map_err(IambError::from)?)
|
Ok(room.active_members().await.map_err(IambError::from)?)
|
||||||
|
@ -1145,32 +1098,6 @@ impl ClientWorker {
|
||||||
Ok(rooms)
|
Ok(rooms)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn spaces(&self) -> Vec<(MatrixRoom, DisplayName)> {
|
|
||||||
let mut spaces = vec![];
|
|
||||||
|
|
||||||
for room in self.client.invited_rooms().into_iter() {
|
|
||||||
if !room.is_space() {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let name = room.display_name().await.unwrap_or(DisplayName::Empty);
|
|
||||||
|
|
||||||
spaces.push((room.into(), name));
|
|
||||||
}
|
|
||||||
|
|
||||||
for room in self.client.joined_rooms().into_iter() {
|
|
||||||
if !room.is_space() {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let name = room.display_name().await.unwrap_or(DisplayName::Empty);
|
|
||||||
|
|
||||||
spaces.push((room.into(), name));
|
|
||||||
}
|
|
||||||
|
|
||||||
return spaces;
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn typing_notice(&mut self, room_id: OwnedRoomId) {
|
async fn typing_notice(&mut self, room_id: OwnedRoomId) {
|
||||||
if let Some(room) = self.client.get_joined_room(room_id.as_ref()) {
|
if let Some(room) = self.client.get_joined_room(room_id.as_ref()) {
|
||||||
let _ = room.typing_notice(true).await;
|
let _ = room.typing_notice(true).await;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue