tauri-plugin-bare-kit 0.2.1

Effortless JavaScript backends for Tauri apps - Android 🤖 iOS 📱Linux 🐧 Macos 🖥️ Windows 💩
use std::collections::HashMap;

use serde::de::DeserializeOwned;
use tauri::{plugin::PluginApi, AppHandle, Runtime, WebviewWindow};

use crate::runtime::{plugin::worklet::BareKitWorklet, Result};

#[cfg(target_os = "android")]
use crate::runtime::bare_kit::ffi::ALooper_forThread;
#[cfg(target_os = "android")]
use crate::runtime::plugin::worklet::Looper;

pub(crate) mod commands;
pub(crate) mod models;
mod worklet;

pub struct BareKit<R: Runtime> {
    id: u8,
    #[cfg(target_os = "android")]
    looper: Looper,
    worklets: HashMap<u8, BareKitWorklet<R>>,
}

impl<R: Runtime> BareKit<R> {
    pub(crate) fn new<C: DeserializeOwned>(
        _app: &AppHandle<R>,
        _api: PluginApi<R, C>,
    ) -> Result<Self> {
        Ok(Self {
            id: 0,
            #[cfg(target_os = "android")]
            looper: Looper(ALooper_forThread()),
            worklets: HashMap::new(),
        })
    }

    pub(crate) fn optimize_for_memory(&mut self, enabled: bool) -> Result<()> {
        if self.id > 0 {
            Err("`optimize_for_memory` must be called before any worklets are created.".into())
        } else {
            BareKitWorklet::<R>::optimize_for_memory(enabled);

            Ok(())
        }
    }

    pub(crate) fn invalidate(&mut self) -> Result<()> {
        for worklet in self.worklets.values_mut() {
            worklet.terminate();
        }

        self.worklets.clear();

        Ok(())
    }

    pub(crate) fn new_worklet(
        &mut self,
        app: AppHandle<R>,
        window: WebviewWindow<R>,
        memory_limit: usize,
        assets: Option<String>,
        on_poll: u32,
        on_suspend: u32,
        on_wakeup: u32,
        on_idle: u32,
        on_resume: u32,
    ) -> Result<u8> {
        self.id += 1;

        let worklet = BareKitWorklet::new(
            self.id,
            app,
            window,
            memory_limit,
            assets,
            on_poll,
            on_suspend,
            on_wakeup,
            on_idle,
            on_resume,
        );

        self.worklets.insert(self.id, worklet);

        Ok(self.id)
    }

    pub(crate) fn start_file(&mut self, id: u8, filename: String, args: Vec<String>) -> Result<()> {
        if let Some(worklet) = self.worklets.get_mut(&id) {
            worklet.start(filename, None, args);

            #[cfg(target_os = "android")]
            worklet.set_looper(self.looper);

            Ok(())
        } else {
            Err(format!("No worklet found for ID {id}").into())
        }
    }

    pub(crate) fn start_utf8(
        &mut self,
        id: u8,
        filename: String,
        source: String,
        args: Vec<String>,
    ) -> Result<()> {
        if let Some(worklet) = self.worklets.get_mut(&id) {
            let source = Vec::from(source);

            worklet.start(filename, Some(source), args);

            #[cfg(target_os = "android")]
            worklet.set_looper(self.looper);

            Ok(())
        } else {
            Err(format!("No worklet found for ID {id}").into())
        }
    }

    pub(crate) fn start_bytes(
        &mut self,
        id: u8,
        filename: String,
        source: Vec<u8>,
        args: Vec<String>,
    ) -> Result<()> {
        if let Some(worklet) = self.worklets.get_mut(&id) {
            worklet.start(filename, Some(source), args);

            #[cfg(target_os = "android")]
            worklet.set_looper(self.looper);

            Ok(())
        } else {
            Err(format!("No worklet found for ID {id}").into())
        }
    }

    pub(crate) fn read(&mut self, id: u8) -> Result<Option<Vec<u8>>> {
        if let Some(worklet) = self.worklets.get_mut(&id) {
            Ok(worklet.read())
        } else {
            Err(format!("No worklet found for ID {id}").into())
        }
    }

    pub(crate) fn write(&mut self, id: u8, data: Option<Vec<u8>>) -> Result<i32> {
        if let Some(worklet) = self.worklets.get_mut(&id) {
            Ok(worklet.write(data))
        } else {
            Err(format!("No worklet found for ID {id}").into())
        }
    }

    pub(crate) fn update(&mut self, id: u8, readable: bool, writable: bool) -> Result<()> {
        if let Some(worklet) = self.worklets.get_mut(&id) {
            worklet.update(readable, writable);

            Ok(())
        } else {
            Err(format!("No worklet found for ID {id}").into())
        }
    }

    pub(crate) fn suspend(&mut self, id: u8, linger: i32) -> Result<()> {
        if let Some(worklet) = self.worklets.get_mut(&id) {
            worklet.suspend(linger);

            Ok(())
        } else {
            Err(format!("No worklet found for ID {id}").into())
        }
    }

    pub(crate) fn resume(&mut self, id: u8) -> Result<()> {
        if let Some(worklet) = self.worklets.get_mut(&id) {
            worklet.resume();

            Ok(())
        } else {
            Err(format!("No worklet found for ID {id}").into())
        }
    }

    pub(crate) fn wakeup(&mut self, id: u8, deadline: i32) -> Result<()> {
        if let Some(worklet) = self.worklets.get_mut(&id) {
            worklet.wakeup(deadline);

            Ok(())
        } else {
            Err(format!("No worklet found for ID {id}").into())
        }
    }

    pub(crate) fn terminate(&mut self, id: u8) -> Result<()> {
        if let Some(worklet) = self.worklets.get_mut(&id) {
            worklet.terminate();

            Ok(())
        } else {
            Err(format!("No worklet found for ID {id}").into())
        }
    }
}