Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions apps/desktop/src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ serde_json = { workspace = true }
strum = { workspace = true, features = ["derive"] }
tracing = { workspace = true }

ractor = { workspace = true }
ractor-supervisor = { workspace = true }

aspasia = "0.2.1"
tokio = { workspace = true, features = ["rt-multi-thread", "macros"] }

Expand Down
19 changes: 17 additions & 2 deletions apps/desktop/src-tauri/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ mod commands;
mod ext;
mod store;
mod subtitle;
mod supervisor;

use ext::*;
use store::*;
Expand All @@ -13,6 +14,12 @@ use tauri_plugin_windows::{AppWindow, WindowsPluginExt};
pub async fn main() {
tauri::async_runtime::set(tokio::runtime::Handle::current());

let (root_supervisor, _root_supervisor_handle) = match supervisor::spawn_root_supervisor().await
{
Some((supervisor, handle)) => (Some(supervisor), Some(handle)),
None => (None, None),
};

let sentry_client = {
let dsn = option_env!("SENTRY_DSN");

Expand Down Expand Up @@ -57,9 +64,7 @@ pub async fn main() {
.plugin(tauri_plugin_db2::init())
.plugin(tauri_plugin_tracing::init())
.plugin(tauri_plugin_hooks::init())
.plugin(tauri_plugin_listener::init())
.plugin(tauri_plugin_shell::init())
.plugin(tauri_plugin_local_stt::init())
.plugin(tauri_plugin_permissions::init())
.plugin(tauri_plugin_updater::Builder::new().build())
.plugin(tauri_plugin_deep_link::init())
Expand All @@ -77,6 +82,16 @@ pub async fn main() {
.plugin(tauri_plugin_store::Builder::default().build())
.plugin(tauri_plugin_store2::init())
.plugin(tauri_plugin_windows::init())
.plugin(tauri_plugin_listener::init(
tauri_plugin_listener::InitOptions {
parent_supervisor: root_supervisor.as_ref().map(|s| s.get_cell()),
},
))
.plugin(tauri_plugin_local_stt::init(
tauri_plugin_local_stt::InitOptions {
parent_supervisor: root_supervisor.as_ref().map(|s| s.get_cell()),
},
))
.plugin(tauri_plugin_autostart::init(
tauri_plugin_autostart::MacosLauncher::LaunchAgent,
Some(vec!["--background"]),
Expand Down
30 changes: 30 additions & 0 deletions apps/desktop/src-tauri/src/supervisor.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
use ractor::concurrency::Duration;
use ractor::ActorRef;
use ractor_supervisor::dynamic::{
DynamicSupervisor, DynamicSupervisorMsg, DynamicSupervisorOptions,
};

pub type SupervisorRef = ActorRef<DynamicSupervisorMsg>;
pub type SupervisorHandle = tokio::task::JoinHandle<()>;

const ROOT_SUPERVISOR_NAME: &str = "root_supervisor";

pub async fn spawn_root_supervisor() -> Option<(SupervisorRef, SupervisorHandle)> {
let options = DynamicSupervisorOptions {
max_children: Some(10),
max_restarts: 50,
max_window: Duration::from_secs(60),
reset_after: Some(Duration::from_secs(30)),
};

match DynamicSupervisor::spawn(ROOT_SUPERVISOR_NAME.to_string(), options).await {
Ok((supervisor_ref, handle)) => {
tracing::info!("root_supervisor_spawned");
Some((supervisor_ref, handle))
}
Err(e) => {
tracing::error!("failed_to_spawn_root_supervisor: {:?}", e);
None
}
}
}
41 changes: 36 additions & 5 deletions plugins/listener/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use ractor::ActorCell;
use ractor_supervisor::dynamic::DynamicSupervisorMsg;
use tauri::Manager;
use tokio::sync::Mutex;

Expand All @@ -7,17 +9,26 @@ mod error;
mod events;
mod ext;
pub mod fsm;
mod supervisor;

pub use error::*;
pub use events::*;
pub use ext::*;
pub use supervisor::{SupervisorHandle, SupervisorRef, SUPERVISOR_NAME};

const PLUGIN_NAME: &str = "listener";

pub type SharedState = Mutex<State>;
pub type SharedState = std::sync::Arc<Mutex<State>>;

pub struct State {
app: tauri::AppHandle,
pub app: tauri::AppHandle,
pub listener_supervisor: Option<ractor::ActorRef<DynamicSupervisorMsg>>,
pub supervisor_handle: Option<SupervisorHandle>,
}

#[derive(Default)]
pub struct InitOptions {
pub parent_supervisor: Option<ActorCell>,
}

impl State {
Expand Down Expand Up @@ -48,7 +59,7 @@ fn make_specta_builder<R: tauri::Runtime>() -> tauri_specta::Builder<R> {
.error_handling(tauri_specta::ErrorHandlingMode::Result)
}

pub fn init() -> tauri::plugin::TauriPlugin<tauri::Wry> {
pub fn init(options: InitOptions) -> tauri::plugin::TauriPlugin<tauri::Wry> {
let specta_builder = make_specta_builder();

tauri::plugin::Builder::new(PLUGIN_NAME)
Expand All @@ -58,9 +69,29 @@ pub fn init() -> tauri::plugin::TauriPlugin<tauri::Wry> {

let app_handle = app.app_handle().clone();

let state: SharedState = Mutex::new(State { app: app_handle });
let state: SharedState = std::sync::Arc::new(Mutex::new(State {
app: app_handle,
listener_supervisor: None,
supervisor_handle: None,
}));

app.manage(state.clone());

let parent = options.parent_supervisor.clone();
tauri::async_runtime::spawn(async move {
match supervisor::spawn_listener_supervisor(parent).await {
Ok((supervisor, handle)) => {
let mut guard = state.lock().await;
guard.listener_supervisor = Some(supervisor);
guard.supervisor_handle = Some(handle);
tracing::info!("listener_supervisor_spawned");
}
Err(e) => {
tracing::error!("failed_to_spawn_listener_supervisor: {:?}", e);
}
}
});

app.manage(state);
Ok(())
})
.build()
Expand Down
33 changes: 33 additions & 0 deletions plugins/listener/src/supervisor.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
use ractor::{ActorCell, ActorProcessingErr, ActorRef};
use ractor_supervisor::dynamic::{
DynamicSupervisor, DynamicSupervisorMsg, DynamicSupervisorOptions,
};

pub type SupervisorRef = ActorRef<DynamicSupervisorMsg>;
pub type SupervisorHandle = tokio::task::JoinHandle<()>;

pub const SUPERVISOR_NAME: &str = "listener_supervisor";

fn make_supervisor_options() -> DynamicSupervisorOptions {
DynamicSupervisorOptions {
max_children: Some(10),
max_restarts: 50,
max_window: ractor::concurrency::Duration::from_secs(60),
reset_after: Some(ractor::concurrency::Duration::from_secs(30)),
}
}

pub async fn spawn_listener_supervisor(
parent: Option<ActorCell>,
) -> Result<(SupervisorRef, SupervisorHandle), ActorProcessingErr> {
let options = make_supervisor_options();

let (supervisor_ref, handle) =
DynamicSupervisor::spawn(SUPERVISOR_NAME.to_string(), options).await?;

if let Some(parent_cell) = parent {
supervisor_ref.get_cell().link(parent_cell);
}

Ok((supervisor_ref, handle))
}
13 changes: 10 additions & 3 deletions plugins/local-stt/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use ractor::ActorRef;
use ractor::{ActorCell, ActorRef};
use ractor_supervisor::dynamic::DynamicSupervisorMsg;
use std::collections::HashMap;
use tauri::{Manager, Wry};
Expand All @@ -14,6 +14,7 @@ mod types;
pub use error::*;
pub use ext::*;
pub use model::*;
pub use server::supervisor::{SupervisorRef, SUPERVISOR_NAME};
pub use server::*;
pub use types::*;

Expand All @@ -27,6 +28,11 @@ pub struct State {
pub supervisor_handle: Option<SupervisorHandle>,
}

#[derive(Default)]
pub struct InitOptions {
pub parent_supervisor: Option<ActorCell>,
}

const PLUGIN_NAME: &str = "local-stt";

fn make_specta_builder<R: tauri::Runtime>() -> tauri_specta::Builder<R> {
Expand All @@ -48,7 +54,7 @@ fn make_specta_builder<R: tauri::Runtime>() -> tauri_specta::Builder<R> {
.error_handling(tauri_specta::ErrorHandlingMode::Result)
}

pub fn init<R: tauri::Runtime>() -> tauri::plugin::TauriPlugin<R> {
pub fn init<R: tauri::Runtime>(options: InitOptions) -> tauri::plugin::TauriPlugin<R> {
let specta_builder = make_specta_builder();

tauri::plugin::Builder::new(PLUGIN_NAME)
Expand All @@ -67,8 +73,9 @@ pub fn init<R: tauri::Runtime>() -> tauri::plugin::TauriPlugin<R> {

app.manage(state.clone());

let parent = options.parent_supervisor.clone();
tauri::async_runtime::spawn(async move {
match server::supervisor::spawn_stt_supervisor().await {
match server::supervisor::spawn_stt_supervisor(parent).await {
Ok((supervisor, handle)) => {
let mut guard = state.lock().await;
guard.stt_supervisor = Some(supervisor);
Expand Down
17 changes: 13 additions & 4 deletions plugins/local-stt/src/server/supervisor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,27 @@ pub const INTERNAL_STT_ACTOR_NAME: &str = "internal_stt";
pub const EXTERNAL_STT_ACTOR_NAME: &str = "external_stt";
pub const SUPERVISOR_NAME: &str = "stt_supervisor";

pub async fn spawn_stt_supervisor(
) -> Result<(ActorRef<DynamicSupervisorMsg>, crate::SupervisorHandle), ActorProcessingErr> {
let options = DynamicSupervisorOptions {
fn make_supervisor_options() -> DynamicSupervisorOptions {
DynamicSupervisorOptions {
max_children: Some(1),
max_restarts: 100,
max_window: Duration::from_secs(60 * 3),
reset_after: Some(Duration::from_secs(30)),
};
}
}

pub async fn spawn_stt_supervisor(
parent: Option<ActorCell>,
) -> Result<(ActorRef<DynamicSupervisorMsg>, crate::SupervisorHandle), ActorProcessingErr> {
let options = make_supervisor_options();

let (supervisor_ref, handle) =
DynamicSupervisor::spawn(SUPERVISOR_NAME.to_string(), options).await?;

if let Some(parent_cell) = parent {
supervisor_ref.get_cell().link(parent_cell);
}

Ok((supervisor_ref, handle))
}

Expand Down
Loading