tauri_plugin_profiling/
lib.rs1mod commands;
27mod config;
28mod error;
29mod profiler;
30
31pub use config::{ProfileResult, ProfilingConfig, StartOptions};
32pub use error::{Error, Result};
33
34use commands::ProfilingState;
35use tauri::{
36 Manager, Runtime,
37 plugin::{Builder, TauriPlugin},
38};
39
40pub trait ProfilingExt<R: Runtime> {
42 fn start_cpu_profile(&self) -> Result<()>;
44
45 fn start_cpu_profile_with_options(&self, options: StartOptions) -> Result<()>;
47
48 fn stop_cpu_profile(&self) -> Result<ProfileResult>;
50
51 fn is_profiling(&self) -> Result<bool>;
53}
54
55impl<R: Runtime, T: Manager<R>> ProfilingExt<R> for T {
56 fn start_cpu_profile(&self) -> Result<()> {
57 self.start_cpu_profile_with_options(StartOptions::default())
58 }
59
60 fn start_cpu_profile_with_options(&self, options: StartOptions) -> Result<()> {
61 let state = self.state::<ProfilingState>();
62 let mut session_lock = state.session.lock().map_err(|_| Error::LockPoisoned)?;
63
64 if session_lock.is_some() {
65 return Err(Error::AlreadyRunning);
66 }
67
68 let frequency = options.frequency.unwrap_or(state.config.frequency);
69
70 let app = self.app_handle();
72 let output_dir = state
73 .config
74 .output_dir
75 .clone()
76 .or_else(|| app.path().app_data_dir().ok().map(|p| p.join("profiles")))
77 .ok_or_else(|| Error::PathResolution("Could not determine output directory".into()))?;
78
79 std::fs::create_dir_all(&output_dir)?;
80
81 let filename_prefix = options
82 .filename
83 .unwrap_or_else(|| state.config.filename_prefix.clone());
84 let output_path = profiler::generate_output_path(&output_dir, &filename_prefix);
85
86 let session = profiler::ProfileSession::start(frequency, output_path)?;
87 *session_lock = Some(session);
88
89 Ok(())
90 }
91
92 fn stop_cpu_profile(&self) -> Result<ProfileResult> {
93 let state = self.state::<ProfilingState>();
94 let mut session_lock = state.session.lock().map_err(|_| Error::LockPoisoned)?;
95
96 let session = session_lock.take().ok_or(Error::NotRunning)?;
97 session.stop()
98 }
99
100 fn is_profiling(&self) -> Result<bool> {
101 let state = self.state::<ProfilingState>();
102 let session_lock = state.session.lock().map_err(|_| Error::LockPoisoned)?;
103 Ok(session_lock.is_some())
104 }
105}
106
107pub fn init<R: Runtime>() -> TauriPlugin<R> {
109 Builder::new("profiling")
110 .setup(|app, _api| {
111 app.manage(ProfilingState::new(ProfilingConfig::default()));
112 Ok(())
113 })
114 .invoke_handler(tauri::generate_handler![
115 commands::start_cpu_profile,
116 commands::stop_cpu_profile,
117 commands::is_profiling,
118 commands::is_profiling_supported,
119 ])
120 .build()
121}
122
123pub fn init_with_config<R: Runtime>(config: ProfilingConfig) -> TauriPlugin<R> {
125 Builder::new("profiling")
126 .setup(move |app, _api| {
127 app.manage(ProfilingState::new(config.clone()));
128 Ok(())
129 })
130 .invoke_handler(tauri::generate_handler![
131 commands::start_cpu_profile,
132 commands::stop_cpu_profile,
133 commands::is_profiling,
134 commands::is_profiling_supported,
135 ])
136 .build()
137}