tauri-store 1.2.2

Persistent stores for Tauri
Documentation
use crate::manager::ManagerExt;
use futures::future::BoxFuture;
use std::sync::Arc;
use std::time::Duration;
use tauri::async_runtime::spawn_blocking;
use tauri::{AppHandle, Runtime};
use tauri_store_utils::set_interval;
use tokio::sync::Semaphore;
use tokio::task::AbortHandle;

use super::CollectionMarker;

type AutosaveFn<R> = Box<dyn Fn(AppHandle<R>) -> BoxFuture<'static, ()> + Send + 'static>;

pub(crate) struct Autosave {
  duration: Option<Duration>,
  abort_handle: Option<AbortHandle>,
  semaphore: Arc<Semaphore>,
}

impl Autosave {
  pub fn new(duration: Option<Duration>) -> Self {
    Self {
      duration,
      abort_handle: None,
      semaphore: Arc::new(Semaphore::new(1)),
    }
  }

  pub fn start<R, C>(&mut self, app: &AppHandle<R>)
  where
    R: Runtime,
    C: CollectionMarker,
  {
    self.stop();
    if let Some(duration) = self.duration {
      let semaphore = Arc::clone(&self.semaphore);
      let abort_handle = set_interval(app, duration, save::<R, C>(semaphore));
      self.abort_handle = Some(abort_handle);
    }
  }

  pub fn stop(&mut self) {
    if let Some(handle) = self.abort_handle.take() {
      handle.abort();
    }
  }

  pub fn set_duration(&mut self, duration: Duration) {
    self.duration.replace(duration);
  }
}

fn save<R, C>(semaphore: Arc<Semaphore>) -> AutosaveFn<R>
where
  R: Runtime,
  C: CollectionMarker,
{
  Box::new(move |app| {
    let semaphore = Arc::clone(&semaphore);
    Box::pin(async move {
      let _permit = semaphore
        .acquire()
        .await
        .expect("semaphore will not be closed");

      let _ = spawn_blocking(move || app.store_collection_with_marker::<C>().save_all()).await;
    })
  })
}

impl Drop for Autosave {
  fn drop(&mut self) {
    self.stop();
  }
}