initial commit

This commit is contained in:
Jonas Kruckenberg 2022-11-01 15:19:25 +01:00
commit c3e5b84282
54 changed files with 2009 additions and 0 deletions

83
src/app.rs Normal file
View file

@ -0,0 +1,83 @@
use semver::Version;
/// Gets the application name.
///
/// # Example
///
/// ```typescript
/// import { getName } from '@tauri-apps/api/app';
/// const appName = await getName();
/// ```
#[inline(always)]
pub async fn get_name() -> String {
inner::getName().await.as_string().unwrap()
}
/// Gets the application version.
///
/// # Example
///
/// ```rust,no_run
/// use tauri_api::app::get_version;
///
/// let version = get_version().await;
/// ```
#[inline(always)]
pub async fn get_version() -> Version {
Version::parse(&inner::getVersion().await.as_string().unwrap()).unwrap()
}
/// Gets the Tauri version.
///
/// # Example
///
/// ```rust,no_run
/// use tauri_app::app:get_tauri_version;
///
/// let version = get_tauri_version().await;
/// ```
#[inline(always)]
pub async fn get_tauri_version() -> Version {
Version::parse(&inner::getTauriVersion().await.as_string().unwrap()).unwrap()
}
/// Shows the application on macOS. This function does not automatically focuses any app window.
///
/// # Example
///
/// ```rust,no_run
/// use tauri_api::app::show;
///
/// show().await;
/// ```
#[inline(always)]
pub async fn show() {
inner::show().await;
}
/// Hides the application on macOS.
///
/// # Example
///
/// ```rust,no_run
/// use tauri_api::app::hide;
///
/// hide().await;
/// ```
#[inline(always)]
pub async fn hide() {
inner::hide().await;
}
mod inner {
use wasm_bindgen::{prelude::wasm_bindgen, JsValue};
#[wasm_bindgen(module = "/dist/app.js")]
extern "C" {
pub async fn getName() -> JsValue;
pub async fn getTauriVersion() -> JsValue;
pub async fn getVersion() -> JsValue;
pub async fn hide();
pub async fn show();
}
}

40
src/clipboard.rs Normal file
View file

@ -0,0 +1,40 @@
/// Gets the clipboard content as plain text.
///
/// # Example
///
/// ```rust,no_run
/// use tauri_api::clipboard::read_text;
///
/// let clipboard_text = read_text().await;
/// ```
#[inline(always)]
pub async fn read_text() -> Option<String> {
inner::readText().await.as_string()
}
/// Writes plain text to the clipboard.
///
/// # Example
///
/// ```rust,no_run
/// use tauri_api::clipboard::{write_text, read_text};
///
/// write_text("Tauri is awesome!").await;
/// assert_eq!(read_text().await, "Tauri is awesome!");
/// ```
///
/// @returns A promise indicating the success or failure of the operation.
#[inline(always)]
pub async fn write_text(text: &str) {
inner::writeText(text).await
}
mod inner {
use wasm_bindgen::{prelude::wasm_bindgen, JsValue};
#[wasm_bindgen(module = "/dist/clipboard.js")]
extern "C" {
pub async fn readText() -> JsValue;
pub async fn writeText(text: &str);
}
}

134
src/event.rs Normal file
View file

@ -0,0 +1,134 @@
use std::fmt::Debug;
use serde::{de::DeserializeOwned, Deserialize, Serialize};
#[derive(Deserialize)]
pub struct Event<T> {
/// Event name
pub event: String,
/// Event identifier used to unlisten
pub id: u32,
/// Event payload
pub payload: T,
/// The label of the window that emitted this event
pub window_label: String,
}
impl<T: Debug> Debug for Event<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Event")
.field("event", &self.event)
.field("id", &self.id)
.field("payload", &self.payload)
.field("window_label", &self.window_label)
.finish()
}
}
/// Emits an event to the backend.
///
/// # Example
///
/// ```rust,no_run
/// use tauri_api::event::emit;
/// use serde::Serialize;
///
/// #[derive(Serialize)]
/// struct Payload {
/// logged_in: bool,
/// token: String
/// }
///
/// emit("frontend-loaded", &Payload { logged_in: true, token: "authToken" }).await;
/// ```
///
/// @param event Event name. Must include only alphanumeric characters, `-`, `/`, `:` and `_`.
#[inline(always)]
pub async fn emit<T: Serialize>(event: &str, payload: &T) {
inner::emit(event, serde_wasm_bindgen::to_value(payload).unwrap()).await
}
/// Listen to an event from the backend.
///
/// # Example
///
/// ```rust,no_run
/// use tauri_api::event::{emit, listen};
///
/// const unlisten = listen::<String>("error", |event| {
/// println!("Got error in window {}, payload: {}", event.window_label, event.payload);
/// }).await;
///
/// // you need to call unlisten if your handler goes out of scope e.g. the component is unmounted
/// unlisten();
/// ```
///
/// @param event Event name. Must include only alphanumeric characters, `-`, `/`, `:` and `_`.
/// @param handler Event handler callback.
/// @returns A promise resolving to a function to unlisten to the event.
///
/// Note that removing the listener is required if your listener goes out of scope e.g. the component is unmounted.
#[inline(always)]
pub async fn listen<T: DeserializeOwned>(event: &str, handler: &dyn Fn(Event<T>)) -> impl FnOnce() {
let unlisten = inner::listen(event, &|raw| {
handler(serde_wasm_bindgen::from_value(raw).unwrap())
})
.await;
let unlisten = js_sys::Function::from(unlisten);
move || {
unlisten.call0(&wasm_bindgen::JsValue::NULL).unwrap();
}
}
/// Listen to an one-off event from the backend.
///
/// # Example
///
/// ```rust,no_run
/// use tauri_api::event::once;
/// use serde::Deserialize;
///
/// #[derive(Deserialize)]
/// interface LoadedPayload {
/// logged_in: bool,
/// token: String
/// }
/// const unlisten = once::<LoadedPayload>("loaded", |event| {
/// println!("App is loaded, loggedIn: {}, token: {}", event.payload.logged_in, event.payload.token);
/// }).await;
///
/// // you need to call unlisten if your handler goes out of scope e.g. the component is unmounted
/// unlisten();
/// ```
///
/// @param event Event name. Must include only alphanumeric characters, `-`, `/`, `:` and `_`.
/// @returns A promise resolving to a function to unlisten to the event.
///
/// Note that removing the listener is required if your listener goes out of scope e.g. the component is unmounted.
#[inline(always)]
pub async fn once<T: DeserializeOwned>(
event: &str,
handler: &mut dyn FnMut(Event<T>),
) -> impl FnOnce() {
let unlisten = inner::once(event, &mut |raw| {
handler(serde_wasm_bindgen::from_value(raw).unwrap())
})
.await;
let unlisten = js_sys::Function::from(unlisten);
move || {
unlisten.call0(&wasm_bindgen::JsValue::NULL).unwrap();
}
}
mod inner {
use wasm_bindgen::{prelude::wasm_bindgen, JsValue};
#[wasm_bindgen(module = "/dist/event.js")]
extern "C" {
pub async fn emit(event: &str, payload: JsValue);
pub async fn listen(event: &str, handler: &dyn Fn(JsValue)) -> JsValue;
pub async fn once(event: &str, handler: &mut dyn FnMut(JsValue)) -> JsValue;
}
}

22
src/lib.rs Normal file
View file

@ -0,0 +1,22 @@
use wasm_bindgen::JsValue;
#[cfg(feature = "app")]
pub mod app;
#[cfg(feature = "clipboard")]
pub mod clipboard;
#[cfg(feature = "event")]
pub mod event;
#[cfg(feature = "mocks")]
pub mod mocks;
#[cfg(feature = "tauri")]
pub mod tauri;
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error(transparent)]
Serde(#[from] serde_wasm_bindgen::Error),
#[error("{0:?}")]
Other(JsValue)
}
pub(crate) type Result<T> = std::result::Result<T, Error>;

54
src/mocks.rs Normal file
View file

@ -0,0 +1,54 @@
use js_sys::Array;
use wasm_bindgen::JsValue;
/// Mocks the current window label
/// In non-tauri context it is required to call this function///before* using the `@tauri-apps/api/window` module.
///
/// This function only mocks the *presence* of a window,
/// window properties (e.g. width and height) can be mocked like regular IPC calls using the `mockIPC` function.
pub fn mock_window(current: &str) {
inner::mockWindows(
current,
JsValue::UNDEFINED,
)
}
/// Mocks many window labels.
/// In non-tauri context it is required to call this function///before* using the `@tauri-apps/api/window` module.
///
/// This function only mocks the *presence* of windows,
/// window properties (e.g. width and height) can be mocked like regular IPC calls using the `mockIPC` function.
///
/// @param current Label of window this JavaScript context is running in.
/// @param additionalWindows Label of additional windows the app has.
pub fn mock_windows(current: &str, additional_windows: &[&str]) {
inner::mockWindows(
current,
Array::from_iter(additional_windows.iter().map(|str| JsValue::from_str(str))).into(),
)
}
/// Intercepts all IPC requests with the given mock handler.
///
/// This function can be used when testing tauri frontend applications or when running the frontend in a Node.js context during static site generation.
pub fn mock_ipc(handler: &dyn Fn(JsValue)) {
inner::mockIPC(handler);
}
/// Clears mocked functions/data injected by the other functions in this module.
/// When using a test runner that doesn't provide a fresh window object for each test, calling this function will reset tauri specific properties.
pub fn clear_mocks() {
inner::clearMocks()
}
mod inner {
use wasm_bindgen::{prelude::wasm_bindgen, JsValue};
#[wasm_bindgen(module = "/dist/mocks.js")]
extern "C" {
#[wasm_bindgen(variadic)]
pub fn mockWindows(current: &str, rest: JsValue);
pub fn mockIPC(handler: &dyn Fn(JsValue));
pub fn clearMocks();
}
}

100
src/tauri.rs Normal file
View file

@ -0,0 +1,100 @@
use serde::{de::DeserializeOwned, Serialize};
use url::Url;
/// Convert a device file path to an URL that can be loaded by the webview.
/// Note that `asset:` and `https://asset.localhost` must be added to [`tauri.security.csp`](https://tauri.app/v1/api/config/#securityconfig.csp) in `tauri.conf.json`.
/// Example CSP value: `"csp": "default-src 'self'; img-src 'self' asset: https://asset.localhost"` to use the asset protocol on image sources.
///
/// Additionally, `asset` must be added to [`tauri.allowlist.protocol`](https://tauri.app/v1/api/config/#allowlistconfig.protocol)
/// in `tauri.conf.json` and its access scope must be defined on the `assetScope` array on the same `protocol` object.
///
/// @param filePath The file path.
/// @param protocol The protocol to use. Defaults to `asset`. You only need to set this when using a custom protocol.
///
/// # Example
///
/// ```rust,no_run
/// use tauri_api::path::{app_data_dir, join};
/// use tauri_api::tauri::convert_file_src;
///
/// const app_data_dir_path = app_data_dir().await;
/// const file_path = join(app_data_dir_path, "assets/video.mp4").await;
/// const asset_url = convert_file_src(file_path);
///
/// let window = web_sys::window().expect("no global `window` exists");
/// let document = window.document().expect("should have a document on window");
///
/// // Manufacture the element we're gonna append
/// let video = document.get_element_by_id("my-video")?;
/// let source = document.create_element("source")?;
///
/// source.set_attribute("type", "video/mp4")?;
/// source.set_attribute("src", asset_url.as_str())?;
///
/// video.append_child(&val)?;
/// ```
///
/// @return the URL that can be used as source on the webview.
#[inline(always)]
pub async fn convert_file_src(file_path: &str, protocol: Option<&str>) -> Url {
Url::parse(
&inner::convertFileSrc(file_path, protocol)
.await
.as_string()
.unwrap(),
)
.unwrap()
}
/// Sends a message to the backend.
///
/// # Example
///
/// ```rust,no_run
/// use tauri_api::tauri::invoke;
///
/// struct User<'a> {
/// user: &'a str,
/// password: &'a str
/// }
///
/// invoke("login", &User { user: "tauri", password: "poiwe3h4r5ip3yrhtew9ty" }).await;
/// ```
///
/// @param cmd The command name.
/// @param args The optional arguments to pass to the command.
/// @return A promise resolving or rejecting to the backend response.
#[inline(always)]
pub async fn invoke<A: Serialize, R: DeserializeOwned>(cmd: &str, args: &A) -> crate::Result<R> {
let res = inner::invoke(cmd, serde_wasm_bindgen::to_value(args).unwrap()).await;
let raw = res.map_err(crate::Error::Other)?;
serde_wasm_bindgen::from_value(raw).map_err(Into::into)
}
/// Transforms a callback function to a string identifier that can be passed to the backend.
/// The backend uses the identifier to `eval()` the callback.
///
/// @return A unique identifier associated with the callback function.
#[inline(always)]
pub async fn transform_callback<T: DeserializeOwned>(callback: &dyn Fn(T), once: bool) -> f64 {
inner::transformCallback(
&|raw| callback(serde_wasm_bindgen::from_value(raw).unwrap()),
once,
)
.await
.as_f64()
.unwrap()
}
mod inner {
use wasm_bindgen::{prelude::wasm_bindgen, JsValue};
#[wasm_bindgen(module = "/dist/tauri.js")]
extern "C" {
pub async fn convertFileSrc(filePath: &str, protocol: Option<&str>) -> JsValue;
#[wasm_bindgen(catch)]
pub async fn invoke(cmd: &str, args: JsValue) -> Result<JsValue, JsValue>;
pub async fn transformCallback(callback: &dyn Fn(JsValue), once: bool) -> JsValue;
}
}