mod commands;
mod config;
mod error;
mod profiler;
pub use config::{ProfileResult, ProfilingConfig, StartOptions};
pub use error::{Error, Result};
use commands::ProfilingState;
use tauri::{
Manager, Runtime,
plugin::{Builder, TauriPlugin},
};
pub trait ProfilingExt<R: Runtime> {
fn start_cpu_profile(&self) -> Result<()>;
fn start_cpu_profile_with_options(&self, options: StartOptions) -> Result<()>;
fn stop_cpu_profile(&self) -> Result<ProfileResult>;
fn is_profiling(&self) -> Result<bool>;
}
impl<R: Runtime, T: Manager<R>> ProfilingExt<R> for T {
fn start_cpu_profile(&self) -> Result<()> {
self.start_cpu_profile_with_options(StartOptions::default())
}
fn start_cpu_profile_with_options(&self, options: StartOptions) -> Result<()> {
let state = self.state::<ProfilingState>();
let mut session_lock = state.session.lock().map_err(|_| Error::LockPoisoned)?;
if session_lock.is_some() {
return Err(Error::AlreadyRunning);
}
let frequency = options.frequency.unwrap_or(state.config.frequency);
let app = self.app_handle();
let output_dir = state
.config
.output_dir
.clone()
.or_else(|| app.path().app_data_dir().ok().map(|p| p.join("profiles")))
.ok_or_else(|| Error::PathResolution("Could not determine output directory".into()))?;
std::fs::create_dir_all(&output_dir)?;
let filename_prefix = options
.filename
.unwrap_or_else(|| state.config.filename_prefix.clone());
let output_path = profiler::generate_output_path(&output_dir, &filename_prefix);
let session = profiler::ProfileSession::start(frequency, output_path)?;
*session_lock = Some(session);
Ok(())
}
fn stop_cpu_profile(&self) -> Result<ProfileResult> {
let state = self.state::<ProfilingState>();
let mut session_lock = state.session.lock().map_err(|_| Error::LockPoisoned)?;
let session = session_lock.take().ok_or(Error::NotRunning)?;
session.stop()
}
fn is_profiling(&self) -> Result<bool> {
let state = self.state::<ProfilingState>();
let session_lock = state.session.lock().map_err(|_| Error::LockPoisoned)?;
Ok(session_lock.is_some())
}
}
pub fn init<R: Runtime>() -> TauriPlugin<R> {
Builder::new("profiling")
.setup(|app, _api| {
app.manage(ProfilingState::new(ProfilingConfig::default()));
Ok(())
})
.invoke_handler(tauri::generate_handler![
commands::start_cpu_profile,
commands::stop_cpu_profile,
commands::is_profiling,
commands::is_profiling_supported,
])
.build()
}
pub fn init_with_config<R: Runtime>(config: ProfilingConfig) -> TauriPlugin<R> {
Builder::new("profiling")
.setup(move |app, _api| {
app.manage(ProfilingState::new(config.clone()));
Ok(())
})
.invoke_handler(tauri::generate_handler![
commands::start_cpu_profile,
commands::stop_cpu_profile,
commands::is_profiling,
commands::is_profiling_supported,
])
.build()
}