tauri_plugin_matrix_svelte/
lib.rs1use matrix::{
2 requests::MatrixRequest,
3 room::rooms_list::{enqueue_rooms_list_update, RoomsListUpdate},
4 singletons::{CLIENT, LOGIN_STORE_READY, REQUEST_SENDER},
5 stores::login_store::{update_login_state, LoginState},
6 try_restore_session_to_state,
7 workers::{async_main_loop, async_worker},
8};
9use serde::Deserialize;
10use stronghold::init_stronghold_client;
11use tauri::{
12 plugin::{Builder, TauriPlugin},
13 Manager, Runtime,
14};
15
16pub use models::*;
17
18#[cfg(desktop)]
19mod desktop;
20#[cfg(mobile)]
21mod mobile;
22
23mod commands;
24mod error;
25
26pub mod matrix;
27pub mod models;
28pub mod stronghold;
29pub mod utils;
30
31pub use error::{Error, Result};
32
33#[cfg(desktop)]
34use desktop::MatrixSvelte;
35#[cfg(mobile)]
36use mobile::MatrixSvelte;
37
38use crate::matrix::room::rooms_list::RoomsCollectionStatus;
39
40#[derive(Deserialize)]
42pub struct PluginConfig {
43 stronghold_password: String,
44}
45
46pub trait MatrixSvelteExt<R: Runtime> {
48 fn matrix_svelte(&self) -> &MatrixSvelte<R>;
49}
50
51impl<R: Runtime, T: Manager<R>> crate::MatrixSvelteExt<R> for T {
52 fn matrix_svelte(&self) -> &MatrixSvelte<R> {
53 self.state::<MatrixSvelte<R>>().inner()
54 }
55}
56
57pub fn init<R: Runtime>() -> TauriPlugin<R, PluginConfig> {
59 Builder::<R, PluginConfig>::new("matrix-svelte")
60 .invoke_handler(tauri::generate_handler![
61 commands::ping,
62 commands::login_and_create_new_session,
63 commands::submit_async_request
64 ])
65 .setup(|app, api| {
66 crate::matrix::singletons::init_broadcaster(16)
68 .expect("Couldn't init the UI broadcaster"); let (sender, receiver) = tokio::sync::mpsc::unbounded_channel::<MatrixRequest>();
71 REQUEST_SENDER
72 .set(sender)
73 .expect("BUG: REQUEST_SENDER already set!");
74
75 let init_app_handle = app.app_handle().clone();
76 let stronghold_app_handle = app.app_handle().clone();
77 let main_loop_app_handle = app.app_handle().clone();
78
79 let stronghold_handle = tauri::async_runtime::spawn(async move {
80 init_stronghold_client(&stronghold_app_handle)
81 .expect("Couldn't init stronghold client")
82 });
83
84 let _monitor = tauri::async_runtime::spawn(async move {
85 stronghold_handle
86 .await
87 .expect("Couldn't init stronghold client");
88 let client = try_restore_session_to_state(&init_app_handle)
89 .await
90 .expect("Couldn't try to restore session");
91
92 LOGIN_STORE_READY.wait();
93 let client = match client {
94 Some(new_login) => {
95 update_login_state(&init_app_handle, LoginState::Restored)
97 .expect("Couldn't update login state");
98 new_login
99 }
100 None => {
101 println!("Waiting for login request...");
102 update_login_state(&init_app_handle, LoginState::AwaitingForLogin)
103 .expect("Couldn't update login state");
104 CLIENT.wait();
107 update_login_state(&init_app_handle, LoginState::LoggedIn)
108 .expect("Couldn't update login state");
109 CLIENT.get().unwrap().clone()
110 }
111 };
112
113 let mut ui_event_receiver = crate::matrix::singletons::subscribe_to_events()
114 .expect("Couldn't get UI event receiver"); let mut worker_join_handle = tauri::async_runtime::spawn(async_worker(receiver));
118
119 let mut main_loop_join_handle =
121 tauri::async_runtime::spawn(async_main_loop(main_loop_app_handle, client));
122
123 #[allow(clippy::never_loop)] loop {
125 tokio::select! {
126 result = &mut main_loop_join_handle => {
127 match result {
128 Ok(Ok(())) => {
129 eprintln!("BUG: main async loop task ended unexpectedly!");
130 }
131 Ok(Err(e)) => {
132 eprintln!("Error: main async loop task ended:\n\t{e:?}");
133 enqueue_rooms_list_update(RoomsListUpdate::Status {
134 status: RoomsCollectionStatus::Error(e.to_string()),
135 });
136 },
138 Err(e) => {
139 eprintln!("BUG: failed to join main async loop task: {e:?}");
140 }
141 }
142 break;
143 }
144 result = &mut worker_join_handle => {
145 match result {
146 Ok(Ok(())) => {
147 eprintln!("BUG: async worker task ended unexpectedly!");
148 }
149 Ok(Err(e)) => {
150 eprintln!("Error: async worker task ended:\n\t{e:?}");
151 enqueue_rooms_list_update(RoomsListUpdate::Status {
152 status: RoomsCollectionStatus::Error(e.to_string()),
153 });
154 },
156 Err(e) => {
157 eprintln!("BUG: failed to join async worker task: {e:?}");
158 }
159 }
160 break;
161 }
162 _ = ui_event_receiver.recv() => {
163 #[cfg(debug_assertions)]
164 println!("Received UI update event");
165 }
166 }
167 }
168 });
169 #[cfg(mobile)]
170 let matrix_svelte = mobile::init(app, api)?;
171 #[cfg(desktop)]
172 let matrix_svelte = desktop::init(app, api)?;
173 app.manage(matrix_svelte);
174 Ok(())
175 })
176 .build()
177}