refactor(core): use anyhow for endpoint errors, ref #3457 (#3467)

This commit is contained in:
Lucas Fernandes Nogueira 2022-02-16 10:12:10 -03:00 committed by GitHub
parent 76b8c214df
commit d6918efdaf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 204 additions and 156 deletions

View File

@ -91,7 +91,7 @@ pub fn generate_run_fn(input: DeriveInput) -> TokenStream {
let expanded = quote! {
impl #impl_generics #name #ty_generics #where_clause {
pub #maybe_async fn run<R: crate::Runtime>(self, context: crate::endpoints::InvokeContext<R>) -> crate::Result<crate::endpoints::InvokeResponse> {
pub #maybe_async fn run<R: crate::Runtime>(self, context: crate::endpoints::InvokeContext<R>) -> super::Result<crate::endpoints::InvokeResponse> {
match self {
#matcher
}
@ -160,9 +160,7 @@ pub fn command_handler(attributes: HandlerAttributes, function: ItemFn) -> Token
#[allow(unused_variables)]
#[allow(unused_mut)]
#signature {
Err(crate::Error::ApiNotAllowlisted(
#error_message.to_string(),
))
Err(anyhow::anyhow!(crate::Error::ApiNotAllowlisted(#error_message.to_string()).to_string()))
}
)
}
@ -198,8 +196,8 @@ pub fn command_test(attributes: HandlerTestAttributes, function: ItemFn) -> Toke
#[cfg(not(#allowlist))]
#[quickcheck_macros::quickcheck]
#signature {
if let Err(crate::Error::ApiNotAllowlisted(e)) = #response {
assert_eq!(e, #error_message);
if let Err(e) = #response {
assert!(e.to_string().contains(#error_message));
} else {
panic!("unexpected response");
}

View File

@ -50,6 +50,7 @@ tokio = { version = "1.16", features = [ "rt", "rt-multi-thread", "sync", "fs",
futures = "0.3"
uuid = { version = "0.8", features = [ "v4" ] }
url = { version = "2.2" }
anyhow = "1.0"
thiserror = "1.0"
once_cell = "1.9"
tauri-runtime = { version = "0.3.1", path = "../tauri-runtime" }

View File

@ -7,6 +7,7 @@ use crate::{
runtime::Runtime,
Config, Invoke, PackageInfo, Window,
};
pub use anyhow::Result;
use serde::{Deserialize, Serialize};
use serde_json::Value as JsonValue;
@ -48,7 +49,7 @@ impl<R: Runtime> Clone for InvokeContext<R> {
/// The response for a JS `invoke` call.
pub struct InvokeResponse {
json: crate::Result<JsonValue>,
json: Result<JsonValue>,
}
impl<T: Serialize> From<T> for InvokeResponse {
@ -96,87 +97,87 @@ impl Module {
cmd
.run(context)
.and_then(|r| r.json)
.map_err(InvokeError::from)
.map_err(InvokeError::from_anyhow)
}),
Self::Process(cmd) => resolver.respond_async(async move {
cmd
.run(context)
.and_then(|r| r.json)
.map_err(InvokeError::from)
.map_err(InvokeError::from_anyhow)
}),
Self::Fs(cmd) => resolver.respond_async(async move {
cmd
.run(context)
.and_then(|r| r.json)
.map_err(InvokeError::from)
.map_err(InvokeError::from_anyhow)
}),
Self::Path(cmd) => resolver.respond_async(async move {
cmd
.run(context)
.and_then(|r| r.json)
.map_err(InvokeError::from)
.map_err(InvokeError::from_anyhow)
}),
Self::Os(cmd) => resolver.respond_async(async move {
cmd
.run(context)
.and_then(|r| r.json)
.map_err(InvokeError::from)
.map_err(InvokeError::from_anyhow)
}),
Self::Window(cmd) => resolver.respond_async(async move {
cmd
.run(context)
.await
.and_then(|r| r.json)
.map_err(InvokeError::from)
.map_err(InvokeError::from_anyhow)
}),
Self::Shell(cmd) => resolver.respond_async(async move {
cmd
.run(context)
.and_then(|r| r.json)
.map_err(InvokeError::from)
.map_err(InvokeError::from_anyhow)
}),
Self::Event(cmd) => resolver.respond_async(async move {
cmd
.run(context)
.and_then(|r| r.json)
.map_err(InvokeError::from)
.map_err(InvokeError::from_anyhow)
}),
Self::Dialog(cmd) => resolver.respond_async(async move {
cmd
.run(context)
.and_then(|r| r.json)
.map_err(InvokeError::from)
.map_err(InvokeError::from_anyhow)
}),
Self::Cli(cmd) => resolver.respond_async(async move {
cmd
.run(context)
.and_then(|r| r.json)
.map_err(InvokeError::from)
.map_err(InvokeError::from_anyhow)
}),
Self::Notification(cmd) => resolver.respond_async(async move {
cmd
.run(context)
.and_then(|r| r.json)
.map_err(InvokeError::from)
.map_err(InvokeError::from_anyhow)
}),
Self::Http(cmd) => resolver.respond_async(async move {
cmd
.run(context)
.await
.and_then(|r| r.json)
.map_err(InvokeError::from)
.map_err(InvokeError::from_anyhow)
}),
Self::GlobalShortcut(cmd) => resolver.respond_async(async move {
cmd
.run(context)
.and_then(|r| r.json)
.map_err(InvokeError::from)
.map_err(InvokeError::from_anyhow)
}),
Self::Clipboard(cmd) => resolver.respond_async(async move {
cmd
.run(context)
.and_then(|r| r.json)
.map_err(InvokeError::from)
.map_err(InvokeError::from_anyhow)
}),
}
}

View File

@ -21,15 +21,15 @@ pub enum Cmd {
}
impl Cmd {
fn get_app_version<R: Runtime>(context: InvokeContext<R>) -> crate::Result<String> {
fn get_app_version<R: Runtime>(context: InvokeContext<R>) -> super::Result<String> {
Ok(context.package_info.version)
}
fn get_app_name<R: Runtime>(context: InvokeContext<R>) -> crate::Result<String> {
fn get_app_name<R: Runtime>(context: InvokeContext<R>) -> super::Result<String> {
Ok(context.package_info.name)
}
fn get_tauri_version<R: Runtime>(_context: InvokeContext<R>) -> crate::Result<&'static str> {
fn get_tauri_version<R: Runtime>(_context: InvokeContext<R>) -> super::Result<&'static str> {
Ok(env!("CARGO_PKG_VERSION"))
}
}

View File

@ -17,13 +17,13 @@ pub enum Cmd {
impl Cmd {
#[module_command_handler(cli, "CLI definition not set under tauri.conf.json > tauri > cli (https://tauri.studio/docs/api/config#tauri.cli)")]
fn cli_matches<R: Runtime>(context: InvokeContext<R>) -> crate::Result<InvokeResponse> {
fn cli_matches<R: Runtime>(context: InvokeContext<R>) -> super::Result<InvokeResponse> {
if let Some(cli) = &context.config.tauri.cli {
crate::api::cli::get_matches(cli, &context.package_info)
.map(Into::into)
.map_err(Into::into)
} else {
Err(crate::Error::ApiNotAllowlisted("CLI definition not set under tauri.conf.json > tauri > cli (https://tauri.studio/docs/api/config#tauri.cli)".into()))
Err(crate::Error::ApiNotAllowlisted("CLI definition not set under tauri.conf.json > tauri > cli (https://tauri.studio/docs/api/config#tauri.cli)".into()).into_anyhow())
}
}
}
@ -34,6 +34,6 @@ mod tests {
#[quickcheck_macros::quickcheck]
fn cli_matches() {
let res = super::Cmd::cli_matches(crate::test::mock_invoke_context());
assert!(!matches!(res, Err(crate::Error::ApiNotAllowlisted(_))));
crate::test_utils::assert_not_allowlist_error(res);
}
}

View File

@ -21,19 +21,23 @@ pub enum Cmd {
impl Cmd {
#[module_command_handler(clipboard_write_text, "clipboard > writeText")]
fn write_text<R: Runtime>(context: InvokeContext<R>, text: String) -> crate::Result<()> {
Ok(
context
.window
.app_handle
.clipboard_manager()
.write_text(text)?,
)
fn write_text<R: Runtime>(context: InvokeContext<R>, text: String) -> super::Result<()> {
context
.window
.app_handle
.clipboard_manager()
.write_text(text)
.map_err(crate::error::into_anyhow)
}
#[module_command_handler(clipboard_read_text, "clipboard > readText")]
fn read_text<R: Runtime>(context: InvokeContext<R>) -> crate::Result<Option<String>> {
Ok(context.window.app_handle.clipboard_manager().read_text()?)
fn read_text<R: Runtime>(context: InvokeContext<R>) -> super::Result<Option<String>> {
context
.window
.app_handle
.clipboard_manager()
.read_text()
.map_err(crate::error::into_anyhow)
}
}

View File

@ -83,7 +83,7 @@ impl Cmd {
fn open_dialog<R: Runtime>(
context: InvokeContext<R>,
options: OpenDialogOptions,
) -> crate::Result<InvokeResponse> {
) -> super::Result<InvokeResponse> {
let mut dialog_builder = FileDialogBuilder::new();
#[cfg(any(windows, target_os = "macos"))]
{
@ -113,7 +113,7 @@ impl Cmd {
fn save_dialog<R: Runtime>(
context: InvokeContext<R>,
options: SaveDialogOptions,
) -> crate::Result<Option<PathBuf>> {
) -> super::Result<Option<PathBuf>> {
let mut dialog_builder = FileDialogBuilder::new();
#[cfg(any(windows, target_os = "macos"))]
{
@ -131,7 +131,7 @@ impl Cmd {
}
#[module_command_handler(dialog_message, "dialog > message")]
fn message_dialog<R: Runtime>(context: InvokeContext<R>, message: String) -> crate::Result<()> {
fn message_dialog<R: Runtime>(context: InvokeContext<R>, message: String) -> super::Result<()> {
crate::api::dialog::blocking::message(
Some(&context.window),
&context.window.app_handle.package_info().name,
@ -145,7 +145,7 @@ impl Cmd {
context: InvokeContext<R>,
title: Option<String>,
message: String,
) -> crate::Result<bool> {
) -> super::Result<bool> {
Ok(crate::api::dialog::blocking::ask(
Some(&context.window),
title.unwrap_or_else(|| context.window.app_handle.package_info().name.clone()),
@ -158,7 +158,7 @@ impl Cmd {
context: InvokeContext<R>,
title: Option<String>,
message: String,
) -> crate::Result<bool> {
) -> super::Result<bool> {
Ok(crate::api::dialog::blocking::confirm(
Some(&context.window),
title.unwrap_or_else(|| context.window.app_handle.package_info().name.clone()),

View File

@ -80,18 +80,21 @@ impl Cmd {
event: EventId,
window_label: Option<WindowLabel>,
handler: CallbackFn,
) -> crate::Result<u64> {
) -> super::Result<u64> {
let event_id = rand::random();
let window_label = window_label.map(|l| l.0);
context.window.eval(&listen_js(
context.window.manager().event_listeners_object_name(),
format!("'{}'", event.0),
event_id,
window_label.clone(),
format!("window['_{}']", handler.0),
))?;
context
.window
.eval(&listen_js(
context.window.manager().event_listeners_object_name(),
format!("'{}'", event.0),
event_id,
window_label.clone(),
format!("window['_{}']", handler.0),
))
.map_err(crate::error::into_anyhow)?;
context
.window
@ -100,11 +103,14 @@ impl Cmd {
Ok(event_id)
}
fn unlisten<R: Runtime>(context: InvokeContext<R>, event_id: u64) -> crate::Result<()> {
context.window.eval(&unlisten_js(
context.window.manager().event_listeners_object_name(),
event_id,
))?;
fn unlisten<R: Runtime>(context: InvokeContext<R>, event_id: u64) -> super::Result<()> {
context
.window
.eval(&unlisten_js(
context.window.manager().event_listeners_object_name(),
event_id,
))
.map_err(crate::error::into_anyhow)?;
context.window.unregister_js_listener(event_id);
Ok(())
}
@ -114,14 +120,20 @@ impl Cmd {
event: EventId,
window_label: Option<WindowLabel>,
payload: Option<String>,
) -> crate::Result<()> {
) -> super::Result<()> {
// dispatch the event to Rust listeners
context.window.trigger(&event.0, payload.clone());
if let Some(target) = window_label {
context.window.emit_to(&target.0, &event.0, payload)?;
context
.window
.emit_to(&target.0, &event.0, payload)
.map_err(crate::error::into_anyhow)?;
} else {
context.window.emit_all(&event.0, payload)?;
context
.window
.emit_all(&event.0, payload)
.map_err(crate::error::into_anyhow)?;
}
Ok(())
}

View File

@ -127,7 +127,7 @@ impl Cmd {
context: InvokeContext<R>,
path: SafePathBuf,
options: Option<FileOperationOptions>,
) -> crate::Result<Vec<u8>> {
) -> super::Result<Vec<u8>> {
file::read_binary(resolve_path(
&context.config,
&context.package_info,
@ -135,7 +135,7 @@ impl Cmd {
path,
options.and_then(|o| o.dir),
)?)
.map_err(crate::Error::FailedToExecuteApi)
.map_err(Into::into)
}
#[module_command_handler(fs_write_file, "fs > writeFile")]
@ -144,7 +144,7 @@ impl Cmd {
path: SafePathBuf,
contents: Vec<u8>,
options: Option<FileOperationOptions>,
) -> crate::Result<()> {
) -> super::Result<()> {
File::create(resolve_path(
&context.config,
&context.package_info,
@ -161,7 +161,7 @@ impl Cmd {
context: InvokeContext<R>,
path: SafePathBuf,
options: Option<DirOperationOptions>,
) -> crate::Result<Vec<dir::DiskEntry>> {
) -> super::Result<Vec<dir::DiskEntry>> {
let (recursive, dir) = if let Some(options_value) = options {
(options_value.recursive, options_value.dir)
} else {
@ -177,7 +177,7 @@ impl Cmd {
)?,
recursive,
)
.map_err(crate::Error::FailedToExecuteApi)
.map_err(Into::into)
}
#[module_command_handler(fs_copy_file, "fs > copyFile")]
@ -186,7 +186,7 @@ impl Cmd {
source: SafePathBuf,
destination: SafePathBuf,
options: Option<FileOperationOptions>,
) -> crate::Result<()> {
) -> super::Result<()> {
let (src, dest) = match options.and_then(|o| o.dir) {
Some(dir) => (
resolve_path(
@ -215,7 +215,7 @@ impl Cmd {
context: InvokeContext<R>,
path: SafePathBuf,
options: Option<DirOperationOptions>,
) -> crate::Result<()> {
) -> super::Result<()> {
let (recursive, dir) = if let Some(options_value) = options {
(options_value.recursive, options_value.dir)
} else {
@ -242,7 +242,7 @@ impl Cmd {
context: InvokeContext<R>,
path: SafePathBuf,
options: Option<DirOperationOptions>,
) -> crate::Result<()> {
) -> super::Result<()> {
let (recursive, dir) = if let Some(options_value) = options {
(options_value.recursive, options_value.dir)
} else {
@ -269,7 +269,7 @@ impl Cmd {
context: InvokeContext<R>,
path: SafePathBuf,
options: Option<FileOperationOptions>,
) -> crate::Result<()> {
) -> super::Result<()> {
let resolved_path = resolve_path(
&context.config,
&context.package_info,
@ -287,7 +287,7 @@ impl Cmd {
old_path: SafePathBuf,
new_path: SafePathBuf,
options: Option<FileOperationOptions>,
) -> crate::Result<()> {
) -> super::Result<()> {
let (old, new) = match options.and_then(|o| o.dir) {
Some(dir) => (
resolve_path(
@ -307,7 +307,7 @@ impl Cmd {
),
None => (old_path, new_path),
};
fs::rename(old, new).map_err(crate::Error::Io)
fs::rename(old, new).map_err(Into::into)
}
}
@ -318,14 +318,16 @@ fn resolve_path<R: Runtime>(
window: &Window<R>,
path: SafePathBuf,
dir: Option<BaseDirectory>,
) -> crate::Result<SafePathBuf> {
) -> super::Result<SafePathBuf> {
let env = window.state::<Env>().inner();
match crate::api::path::resolve_path(config, package_info, env, path, dir) {
Ok(path) => {
if window.state::<Scopes>().fs.is_allowed(&path) {
Ok(SafePathBuf(path))
} else {
Err(crate::Error::PathNotAllowed(path))
Err(anyhow::anyhow!(
crate::Error::PathNotAllowed(path).to_string()
))
}
}
Err(e) => Err(e.into()),
@ -381,21 +383,21 @@ mod tests {
#[quickcheck_macros::quickcheck]
fn read_file(path: SafePathBuf, options: Option<FileOperationOptions>) {
let res = super::Cmd::read_file(crate::test::mock_invoke_context(), path, options);
assert!(!matches!(res, Err(crate::Error::ApiNotAllowlisted(_))));
crate::test_utils::assert_not_allowlist_error(res);
}
#[tauri_macros::module_command_test(fs_write_file, "fs > writeFile")]
#[quickcheck_macros::quickcheck]
fn write_file(path: SafePathBuf, contents: Vec<u8>, options: Option<FileOperationOptions>) {
let res = super::Cmd::write_file(crate::test::mock_invoke_context(), path, contents, options);
assert!(!matches!(res, Err(crate::Error::ApiNotAllowlisted(_))));
crate::test_utils::assert_not_allowlist_error(res);
}
#[tauri_macros::module_command_test(fs_read_dir, "fs > readDir")]
#[quickcheck_macros::quickcheck]
fn read_dir(path: SafePathBuf, options: Option<DirOperationOptions>) {
let res = super::Cmd::read_dir(crate::test::mock_invoke_context(), path, options);
assert!(!matches!(res, Err(crate::Error::ApiNotAllowlisted(_))));
crate::test_utils::assert_not_allowlist_error(res);
}
#[tauri_macros::module_command_test(fs_copy_file, "fs > copyFile")]
@ -411,28 +413,28 @@ mod tests {
destination,
options,
);
assert!(!matches!(res, Err(crate::Error::ApiNotAllowlisted(_))));
crate::test_utils::assert_not_allowlist_error(res);
}
#[tauri_macros::module_command_test(fs_create_dir, "fs > createDir")]
#[quickcheck_macros::quickcheck]
fn create_dir(path: SafePathBuf, options: Option<DirOperationOptions>) {
let res = super::Cmd::create_dir(crate::test::mock_invoke_context(), path, options);
assert!(!matches!(res, Err(crate::Error::ApiNotAllowlisted(_))));
crate::test_utils::assert_not_allowlist_error(res);
}
#[tauri_macros::module_command_test(fs_remove_dir, "fs > removeDir")]
#[quickcheck_macros::quickcheck]
fn remove_dir(path: SafePathBuf, options: Option<DirOperationOptions>) {
let res = super::Cmd::remove_dir(crate::test::mock_invoke_context(), path, options);
assert!(!matches!(res, Err(crate::Error::ApiNotAllowlisted(_))));
crate::test_utils::assert_not_allowlist_error(res);
}
#[tauri_macros::module_command_test(fs_remove_file, "fs > removeFile")]
#[quickcheck_macros::quickcheck]
fn remove_file(path: SafePathBuf, options: Option<FileOperationOptions>) {
let res = super::Cmd::remove_file(crate::test::mock_invoke_context(), path, options);
assert!(!matches!(res, Err(crate::Error::ApiNotAllowlisted(_))));
crate::test_utils::assert_not_allowlist_error(res);
}
#[tauri_macros::module_command_test(fs_rename_file, "fs > renameFile")]
@ -448,6 +450,6 @@ mod tests {
new_path,
options,
);
assert!(!matches!(res, Err(crate::Error::ApiNotAllowlisted(_))));
crate::test_utils::assert_not_allowlist_error(res);
}
}

View File

@ -38,7 +38,7 @@ impl Cmd {
context: InvokeContext<R>,
shortcut: String,
handler: CallbackFn,
) -> crate::Result<()> {
) -> super::Result<()> {
let mut manager = context.window.app_handle.global_shortcut_manager();
register_shortcut(context.window, &mut manager, shortcut, handler)?;
Ok(())
@ -49,7 +49,7 @@ impl Cmd {
context: InvokeContext<R>,
shortcuts: Vec<String>,
handler: CallbackFn,
) -> crate::Result<()> {
) -> super::Result<()> {
let mut manager = context.window.app_handle.global_shortcut_manager();
for shortcut in shortcuts {
register_shortcut(context.window.clone(), &mut manager, shortcut, handler)?;
@ -58,34 +58,35 @@ impl Cmd {
}
#[module_command_handler(global_shortcut_all, "globalShortcut > all")]
fn unregister<R: Runtime>(context: InvokeContext<R>, shortcut: String) -> crate::Result<()> {
fn unregister<R: Runtime>(context: InvokeContext<R>, shortcut: String) -> super::Result<()> {
context
.window
.app_handle
.global_shortcut_manager()
.unregister(&shortcut)?;
.unregister(&shortcut)
.map_err(crate::error::into_anyhow)?;
Ok(())
}
#[module_command_handler(global_shortcut_all, "globalShortcut > all")]
fn unregister_all<R: Runtime>(context: InvokeContext<R>) -> crate::Result<()> {
fn unregister_all<R: Runtime>(context: InvokeContext<R>) -> super::Result<()> {
context
.window
.app_handle
.global_shortcut_manager()
.unregister_all()?;
.unregister_all()
.map_err(crate::error::into_anyhow)?;
Ok(())
}
#[module_command_handler(global_shortcut_all, "globalShortcut > all")]
fn is_registered<R: Runtime>(context: InvokeContext<R>, shortcut: String) -> crate::Result<bool> {
Ok(
context
.window
.app_handle
.global_shortcut_manager()
.is_registered(&shortcut)?,
)
fn is_registered<R: Runtime>(context: InvokeContext<R>, shortcut: String) -> super::Result<bool> {
context
.window
.app_handle
.global_shortcut_manager()
.is_registered(&shortcut)
.map_err(crate::error::into_anyhow)
}
}
@ -95,13 +96,15 @@ fn register_shortcut<R: Runtime>(
manager: &mut R::GlobalShortcutManager,
shortcut: String,
handler: CallbackFn,
) -> crate::Result<()> {
) -> super::Result<()> {
let accelerator = shortcut.clone();
manager.register(&shortcut, move || {
let callback_string = crate::api::ipc::format_callback(handler, &accelerator)
.expect("unable to serialize shortcut string to json");
let _ = window.eval(callback_string.as_str());
})?;
manager
.register(&shortcut, move || {
let callback_string = crate::api::ipc::format_callback(handler, &accelerator)
.expect("unable to serialize shortcut string to json");
let _ = window.eval(callback_string.as_str());
})
.map_err(crate::error::into_anyhow)?;
Ok(())
}

View File

@ -54,7 +54,7 @@ impl Cmd {
async fn create_client<R: Runtime>(
_context: InvokeContext<R>,
options: Option<ClientBuilder>,
) -> crate::Result<ClientId> {
) -> super::Result<ClientId> {
let client = options.unwrap_or_default().build()?;
let mut store = clients().lock().unwrap();
let id = rand::random::<ClientId>();
@ -66,7 +66,7 @@ impl Cmd {
async fn drop_client<R: Runtime>(
_context: InvokeContext<R>,
client: ClientId,
) -> crate::Result<()> {
) -> super::Result<()> {
let mut store = clients().lock().unwrap();
store.remove(&client);
Ok(())
@ -77,7 +77,7 @@ impl Cmd {
context: InvokeContext<R>,
client_id: ClientId,
options: Box<HttpRequestBuilder>,
) -> crate::Result<ResponseData> {
) -> super::Result<ResponseData> {
use crate::Manager;
if context
.window
@ -89,12 +89,12 @@ impl Cmd {
.lock()
.unwrap()
.get(&client_id)
.ok_or(crate::Error::HttpClientNotInitialized)?
.ok_or_else(|| crate::Error::HttpClientNotInitialized.into_anyhow())?
.clone();
let response = client.send(*options).await?;
Ok(response.read().await?)
} else {
Err(crate::Error::UrlNotAllowed(options.url))
Err(crate::Error::UrlNotAllowed(options.url).into_anyhow())
}
}
}

View File

@ -44,13 +44,13 @@ impl Cmd {
fn notification<R: Runtime>(
context: InvokeContext<R>,
options: NotificationOptions,
) -> crate::Result<()> {
) -> super::Result<()> {
let allowed = match is_permission_granted(&context) {
Some(p) => p,
None => request_permission(&context),
};
if !allowed {
return Err(crate::Error::NotificationNotAllowed);
return Err(crate::Error::NotificationNotAllowed.into_anyhow());
}
let mut notification =
Notification::new(context.config.tauri.bundle.identifier.clone()).title(options.title);
@ -67,7 +67,7 @@ impl Cmd {
#[cfg(notification_all)]
fn request_notification_permission<R: Runtime>(
context: InvokeContext<R>,
) -> crate::Result<&'static str> {
) -> super::Result<&'static str> {
if request_permission(&context) {
Ok(PERMISSION_GRANTED)
} else {
@ -78,14 +78,14 @@ impl Cmd {
#[cfg(not(notification_all))]
fn request_notification_permission<R: Runtime>(
_context: InvokeContext<R>,
) -> crate::Result<&'static str> {
) -> super::Result<&'static str> {
Ok(PERMISSION_DENIED)
}
#[cfg(notification_all)]
fn is_notification_permission_granted<R: Runtime>(
context: InvokeContext<R>,
) -> crate::Result<Option<bool>> {
) -> super::Result<Option<bool>> {
if let Some(allow_notification) = is_permission_granted(&context) {
Ok(Some(allow_notification))
} else {
@ -96,7 +96,7 @@ impl Cmd {
#[cfg(not(notification_all))]
fn is_notification_permission_granted<R: Runtime>(
_context: InvokeContext<R>,
) -> crate::Result<Option<bool>> {
) -> super::Result<Option<bool>> {
Ok(Some(false))
}
}

View File

@ -21,27 +21,27 @@ pub enum Cmd {
impl Cmd {
#[module_command_handler(os_all, "os > all")]
fn platform<R: Runtime>(_context: InvokeContext<R>) -> crate::Result<&'static str> {
fn platform<R: Runtime>(_context: InvokeContext<R>) -> super::Result<&'static str> {
Ok(os_platform())
}
#[module_command_handler(os_all, "os > all")]
fn version<R: Runtime>(_context: InvokeContext<R>) -> crate::Result<String> {
fn version<R: Runtime>(_context: InvokeContext<R>) -> super::Result<String> {
Ok(os_info::get().version().to_string())
}
#[module_command_handler(os_all, "os > all")]
fn os_type<R: Runtime>(_context: InvokeContext<R>) -> crate::Result<&'static str> {
fn os_type<R: Runtime>(_context: InvokeContext<R>) -> super::Result<&'static str> {
Ok(os_type())
}
#[module_command_handler(os_all, "os > all")]
fn arch<R: Runtime>(_context: InvokeContext<R>) -> crate::Result<&'static str> {
fn arch<R: Runtime>(_context: InvokeContext<R>) -> super::Result<&'static str> {
Ok(std::env::consts::ARCH)
}
#[module_command_handler(os_all, "os > all")]
fn tempdir<R: Runtime>(_context: InvokeContext<R>) -> crate::Result<PathBuf> {
fn tempdir<R: Runtime>(_context: InvokeContext<R>) -> super::Result<PathBuf> {
Ok(std::env::temp_dir())
}
}

View File

@ -51,7 +51,7 @@ impl Cmd {
context: InvokeContext<R>,
path: String,
directory: Option<BaseDirectory>,
) -> crate::Result<PathBuf> {
) -> super::Result<PathBuf> {
crate::api::path::resolve_path(
&context.config,
&context.package_info,
@ -63,7 +63,7 @@ impl Cmd {
}
#[module_command_handler(path_all, "path > all")]
fn resolve<R: Runtime>(_context: InvokeContext<R>, paths: Vec<String>) -> crate::Result<PathBuf> {
fn resolve<R: Runtime>(_context: InvokeContext<R>, paths: Vec<String>) -> super::Result<PathBuf> {
// Start with current directory then start adding paths from the vector one by one using `PathBuf.push()` which
// will ensure that if an absolute path is encountered in the iteration, it will be used as the current full path.
//
@ -78,7 +78,7 @@ impl Cmd {
}
#[module_command_handler(path_all, "path > all")]
fn normalize<R: Runtime>(_context: InvokeContext<R>, path: String) -> crate::Result<String> {
fn normalize<R: Runtime>(_context: InvokeContext<R>, path: String) -> super::Result<String> {
let mut p = normalize_path_no_absolute(Path::new(&path))
.to_string_lossy()
.to_string();
@ -102,7 +102,7 @@ impl Cmd {
}
#[module_command_handler(path_all, "path > all")]
fn join<R: Runtime>(_context: InvokeContext<R>, mut paths: Vec<String>) -> crate::Result<String> {
fn join<R: Runtime>(_context: InvokeContext<R>, mut paths: Vec<String>) -> super::Result<String> {
let path = PathBuf::from(
paths
.iter_mut()
@ -126,23 +126,23 @@ impl Cmd {
}
#[module_command_handler(path_all, "path > all")]
fn dirname<R: Runtime>(_context: InvokeContext<R>, path: String) -> crate::Result<PathBuf> {
fn dirname<R: Runtime>(_context: InvokeContext<R>, path: String) -> super::Result<PathBuf> {
match Path::new(&path).parent() {
Some(p) => Ok(p.to_path_buf()),
None => Err(crate::Error::FailedToExecuteApi(crate::api::Error::Path(
None => Err(crate::error::into_anyhow(crate::api::Error::Path(
"Couldn't get the parent directory".into(),
))),
}
}
#[module_command_handler(path_all, "path > all")]
fn extname<R: Runtime>(_context: InvokeContext<R>, path: String) -> crate::Result<String> {
fn extname<R: Runtime>(_context: InvokeContext<R>, path: String) -> super::Result<String> {
match Path::new(&path)
.extension()
.and_then(std::ffi::OsStr::to_str)
{
Some(p) => Ok(p.to_string()),
None => Err(crate::Error::FailedToExecuteApi(crate::api::Error::Path(
None => Err(crate::error::into_anyhow(crate::api::Error::Path(
"Couldn't get the extension of the file".into(),
))),
}
@ -153,7 +153,7 @@ impl Cmd {
_context: InvokeContext<R>,
path: String,
ext: Option<String>,
) -> crate::Result<String> {
) -> super::Result<String> {
match Path::new(&path)
.file_name()
.and_then(std::ffi::OsStr::to_str)
@ -163,14 +163,14 @@ impl Cmd {
} else {
p.to_string()
}),
None => Err(crate::Error::FailedToExecuteApi(crate::api::Error::Path(
None => Err(crate::error::into_anyhow(crate::api::Error::Path(
"Couldn't get the basename".into(),
))),
}
}
#[module_command_handler(path_all, "path > all")]
fn is_absolute<R: Runtime>(_context: InvokeContext<R>, path: String) -> crate::Result<bool> {
fn is_absolute<R: Runtime>(_context: InvokeContext<R>, path: String) -> super::Result<bool> {
Ok(Path::new(&path).is_absolute())
}
}

View File

@ -22,13 +22,13 @@ pub enum Cmd {
impl Cmd {
#[module_command_handler(process_relaunch, "process > relaunch")]
fn relaunch<R: Runtime>(context: InvokeContext<R>) -> crate::Result<()> {
fn relaunch<R: Runtime>(context: InvokeContext<R>) -> super::Result<()> {
crate::api::process::restart(&context.window.state());
Ok(())
}
#[module_command_handler(process_exit, "process > exit")]
fn exit<R: Runtime>(_context: InvokeContext<R>, exit_code: i32) -> crate::Result<()> {
fn exit<R: Runtime>(_context: InvokeContext<R>, exit_code: i32) -> super::Result<()> {
// would be great if we can have a handler inside tauri
// who close all window and emit an event that user can catch
// if they want to process something before closing the app

View File

@ -88,12 +88,10 @@ impl Cmd {
args: ExecuteArgs,
on_event_fn: CallbackFn,
options: CommandOptions,
) -> crate::Result<ChildId> {
) -> super::Result<ChildId> {
let mut command = if options.sidecar {
#[cfg(not(shell_sidecar))]
return Err(crate::Error::ApiNotAllowlisted(
"shell > sidecar".to_string(),
));
return Err(crate::Error::ApiNotAllowlisted("shell > sidecar".to_string()).into_anyhow());
#[cfg(shell_sidecar)]
{
let program = PathBuf::from(program);
@ -117,16 +115,14 @@ impl Cmd {
.state::<Scopes>()
.shell
.prepare(&program.to_string_lossy(), args, true)
.map_err(Box::new)?
.map_err(crate::error::into_anyhow)?
} else {
return Err(crate::Error::SidecarNotAllowed(program));
return Err(crate::Error::SidecarNotAllowed(program).into_anyhow());
}
}
} else {
#[cfg(not(shell_execute))]
return Err(crate::Error::ApiNotAllowlisted(
"shell > execute".to_string(),
));
return Err(crate::Error::ApiNotAllowlisted("shell > execute".to_string()).into_anyhow());
#[cfg(shell_execute)]
match context
.window
@ -138,7 +134,7 @@ impl Cmd {
Err(e) => {
#[cfg(debug_assertions)]
eprintln!("{}", e);
return Err(crate::Error::ProgramNotAllowed(PathBuf::from(program)));
return Err(crate::Error::ProgramNotAllowed(PathBuf::from(program)).into_anyhow());
}
}
};
@ -178,7 +174,7 @@ impl Cmd {
_context: InvokeContext<R>,
pid: ChildId,
buffer: Buffer,
) -> crate::Result<()> {
) -> super::Result<()> {
if let Some(child) = command_childs().lock().unwrap().get_mut(&pid) {
match buffer {
Buffer::Text(t) => child.write(t.as_bytes())?,
@ -193,14 +189,12 @@ impl Cmd {
_context: InvokeContext<R>,
_pid: ChildId,
_buffer: Buffer,
) -> crate::Result<()> {
Err(crate::Error::ApiNotAllowlisted(
"shell > execute or shell > sidecar".into(),
))
) -> super::Result<()> {
Err(crate::Error::ApiNotAllowlisted("shell > execute or shell > sidecar".into()).into_anyhow())
}
#[cfg(any(shell_execute, shell_sidecar))]
fn kill_child<R: Runtime>(_context: InvokeContext<R>, pid: ChildId) -> crate::Result<()> {
fn kill_child<R: Runtime>(_context: InvokeContext<R>, pid: ChildId) -> super::Result<()> {
if let Some(child) = command_childs().lock().unwrap().remove(&pid) {
child.kill()?;
}
@ -208,10 +202,8 @@ impl Cmd {
}
#[cfg(not(any(shell_execute, shell_sidecar)))]
fn kill_child<R: Runtime>(_context: InvokeContext<R>, _pid: ChildId) -> crate::Result<()> {
Err(crate::Error::ApiNotAllowlisted(
"shell > execute or shell > sidecar".into(),
))
fn kill_child<R: Runtime>(_context: InvokeContext<R>, _pid: ChildId) -> super::Result<()> {
Err(crate::Error::ApiNotAllowlisted("shell > execute or shell > sidecar".into()).into_anyhow())
}
/// Open a (url) path with a default or specific browser opening program.
@ -222,7 +214,7 @@ impl Cmd {
context: InvokeContext<R>,
path: String,
with: Option<String>,
) -> crate::Result<()> {
) -> super::Result<()> {
use std::str::FromStr;
with

View File

@ -151,17 +151,19 @@ impl Cmd {
async fn create_webview<R: Runtime>(
context: InvokeContext<R>,
options: Box<WindowConfig>,
) -> crate::Result<()> {
) -> super::Result<()> {
let mut window = context.window;
let label = options.label.clone();
let url = options.url.clone();
window.create_window(label, url, |_, webview_attributes| {
(
<<R::Dispatcher as Dispatch>::WindowBuilder>::with_config(*options),
webview_attributes,
)
})?;
window
.create_window(label, url, |_, webview_attributes| {
(
<<R::Dispatcher as Dispatch>::WindowBuilder>::with_config(*options),
webview_attributes,
)
})
.map_err(crate::error::into_anyhow)?;
Ok(())
}
@ -170,6 +172,16 @@ impl Cmd {
context: InvokeContext<R>,
label: Option<String>,
cmd: WindowManagerCmd,
) -> super::Result<InvokeResponse> {
Self::_manage(context, label, cmd)
.await
.map_err(crate::error::into_anyhow)
}
async fn _manage<R: Runtime>(
context: InvokeContext<R>,
label: Option<String>,
cmd: WindowManagerCmd,
) -> crate::Result<InvokeResponse> {
let window = match label {
Some(l) if !l.is_empty() => context

View File

@ -109,6 +109,16 @@ pub enum Error {
InvalidWindowUrl(&'static str),
}
pub(crate) fn into_anyhow<T: std::fmt::Display>(err: T) -> anyhow::Error {
anyhow::anyhow!(err.to_string())
}
impl Error {
pub(crate) fn into_anyhow(self) -> anyhow::Error {
anyhow::anyhow!(self.to_string())
}
}
impl From<serde_json::Error> for Error {
fn from(error: serde_json::Error) -> Self {
if error.to_string().contains("unknown variant") {

View File

@ -95,6 +95,12 @@ impl InvokeError {
pub fn from_serde_json(error: serde_json::Error) -> Self {
Self(JsonValue::String(error.to_string()))
}
/// Create an [`InvokeError`] as a string of the [`anyhow::Error`] message.
#[inline(always)]
pub fn from_anyhow(error: anyhow::Error) -> Self {
Self(JsonValue::String(error.to_string()))
}
}
impl<T: Serialize> From<T> for InvokeError {

View File

@ -577,6 +577,13 @@ mod test_utils {
pub fn assert_send<T: Send>() {}
pub fn assert_sync<T: Sync>() {}
#[allow(dead_code)]
pub fn assert_not_allowlist_error<T>(res: anyhow::Result<T>) {
if let Err(e) = res {
assert!(!e.to_string().contains("not on the allowlist"));
}
}
proptest! {
#![proptest_config(ProptestConfig::with_cases(10000))]
#[test]