use std::sync::Arc;
use tauri::plugin::{Builder as PluginBuilder, TauriPlugin};
use tauri::{Manager, Runtime};
mod assets;
mod commands;
mod config;
mod download;
mod error;
mod extract;
mod machine;
mod manifest;
mod runtime;
#[cfg(any(feature = "cli", test))]
pub mod sign;
mod store;
#[cfg(test)]
mod testutil;
mod update;
pub use assets::HotUpdateAssets;
pub use commands::{DownloadProgress, PROGRESS_EVENT};
pub use config::Config;
pub use error::{Error, Result};
pub use extract::ExtractError;
pub use machine::{AckOutcome, StageError};
pub use manifest::{ArchiveInfo, Manifest};
pub use runtime::{BundleSource, CurrentBundle, HotUpdate};
pub use update::{UpdateConfig, UpdateOutcome};
use runtime::Shared;
pub struct HotUpdateHandle {
shared: Arc<Shared>,
}
pub fn install<R: Runtime>(context: &mut tauri::Context<R>) -> HotUpdateHandle {
let shared = Arc::new(Shared::default());
let embedded = context.set_assets(Box::new(assets::PlaceholderAssets));
context.set_assets(Box::new(HotUpdateAssets::new(
embedded,
Arc::clone(&shared),
)));
HotUpdateHandle { shared }
}
pub fn init<R: Runtime>(handle: HotUpdateHandle) -> TauriPlugin<R, Option<Config>> {
init_with_root(handle, None)
}
#[cfg(test)]
pub(crate) fn init_for_test<R: Runtime>(
handle: HotUpdateHandle,
root: std::path::PathBuf,
) -> TauriPlugin<R, Option<Config>> {
init_with_root(handle, Some(root))
}
fn init_with_root<R: Runtime>(
handle: HotUpdateHandle,
root_override: Option<std::path::PathBuf>,
) -> TauriPlugin<R, Option<Config>> {
PluginBuilder::<R, Option<Config>>::new("hot-update")
.invoke_handler(tauri::generate_handler![
commands::check,
commands::download,
commands::notify_app_ready,
commands::current_bundle,
commands::reset,
])
.setup(move |app, api| {
let config = api.config().as_ref().ok_or_else(|| {
Error::Config(
"missing `plugins.hot-update` in tauri.conf.json; \
set { \"enabled\": false } to ship the plugin dark"
.into(),
)
})?;
let update = config.validate()?;
if update.is_some() {
let root = match &root_override {
Some(root) => Some(root.clone()),
None => match app.path().app_data_dir() {
Ok(base) => Some(base.join("hot-update")),
Err(e) => {
log::error!(
"hot-update: app_data_dir() failed ({e}); \
serving embedded assets only"
);
None
}
},
};
if let Some(root) = root {
let embedded_version = app.package_info().version.clone();
runtime::initialize(&handle.shared, root, embedded_version);
}
} else {
log::info!("hot-update: disabled by config; serving embedded assets");
}
app.manage(HotUpdate {
shared: Arc::clone(&handle.shared),
});
app.manage(commands::CommandConfig { update });
Ok(())
})
.build()
}
pub trait HotUpdateExt<R: Runtime> {
fn hot_update(&self) -> &HotUpdate;
}
impl<R: Runtime, T: Manager<R>> HotUpdateExt<R> for T {
fn hot_update(&self) -> &HotUpdate {
self.state::<HotUpdate>().inner()
}
}