Skip to content

Commit b94108d

Browse files
committed
Refactoring
1 parent 8b52f99 commit b94108d

File tree

5 files changed

+581
-20
lines changed

5 files changed

+581
-20
lines changed

Cargo.toml

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[package]
22
name = "tauri-plugin-iap"
33
version = "0.2.1"
4-
authors = [ "You" ]
4+
authors = ["You"]
55
description = "A Tauri v2 plugin that enables In-App Purchases (IAP)"
66
edition = "2021"
77
rust-version = "1.77.2"
@@ -12,20 +12,37 @@ repository = "https://github.com/Choochmeque/tauri-plugin-iap"
1212

1313
[features]
1414
default = ["unstable"]
15-
unstable = ["dep:swift-bridge", "dep:serde_json", "dep:objc2", "dep:objc2-core-foundation", "dep:objc2-security"]
15+
unstable = [
16+
"dep:swift-bridge",
17+
"dep:serde_json",
18+
"dep:objc2",
19+
"dep:objc2-core-foundation",
20+
"dep:objc2-security",
21+
]
1622

1723
[dependencies]
1824
tauri = { version = "2.7.0" }
1925
serde = "1.0"
2026
thiserror = "2"
2127

2228
[target.'cfg(target_os = "macos")'.dependencies]
23-
swift-bridge = { version = "0.1", features = ["async"], optional = true}
29+
swift-bridge = { version = "0.1", features = ["async"], optional = true }
2430
serde_json = { version = "1.0", optional = true }
2531
objc2 = { version = "0.6", optional = true }
2632
objc2-core-foundation = { version = "0.3", optional = true }
2733
objc2-security = { version = "0.3", optional = true }
2834

35+
[target.'cfg(target_os = "windows")'.dependencies]
36+
windows = { version = "0.61", features = [
37+
"Foundation",
38+
"Foundation_Collections",
39+
"Services_Store",
40+
"System",
41+
] }
42+
windows-result = "0.3"
43+
windows-collections = "0.2"
44+
serde_json = "1.0"
45+
2946
[build-dependencies]
3047
tauri-plugin = { version = "2.3.0", features = ["build"] }
3148

src/error.rs

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,63 @@ use serde::{ser::Serializer, Serialize};
22

33
pub type Result<T> = std::result::Result<T, Error>;
44

5+
/// Replica of the tauri::plugin::mobile::ErrorResponse for desktop platforms.
6+
#[cfg(desktop)]
7+
#[derive(Debug, thiserror::Error, Clone, serde::Deserialize)]
8+
pub struct ErrorResponse<T = ()> {
9+
/// Error code.
10+
pub code: Option<String>,
11+
/// Error message.
12+
pub message: Option<String>,
13+
/// Optional error data.
14+
#[serde(flatten)]
15+
pub data: T,
16+
}
17+
18+
#[cfg(desktop)]
19+
impl<T> std::fmt::Display for ErrorResponse<T> {
20+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
21+
if let Some(code) = &self.code {
22+
write!(f, "[{code}]")?;
23+
if self.message.is_some() {
24+
write!(f, " - ")?;
25+
}
26+
}
27+
if let Some(message) = &self.message {
28+
write!(f, "{message}")?;
29+
}
30+
Ok(())
31+
}
32+
}
33+
34+
/// Replica of the tauri::plugin::mobile::PluginInvokeError for desktop platforms.
35+
#[cfg(desktop)]
36+
#[derive(Debug, thiserror::Error)]
37+
pub enum PluginInvokeError {
38+
/// Error returned from direct desktop plugin.
39+
#[error(transparent)]
40+
InvokeRejected(#[from] ErrorResponse),
41+
/// Failed to deserialize response.
42+
#[error("failed to deserialize response: {0}")]
43+
CannotDeserializeResponse(serde_json::Error),
44+
/// Failed to serialize request payload.
45+
#[error("failed to serialize payload: {0}")]
46+
CannotSerializePayload(serde_json::Error),
47+
}
48+
549
#[derive(Debug, thiserror::Error)]
650
pub enum Error {
751
#[error(transparent)]
852
Io(#[from] std::io::Error),
953
#[cfg(mobile)]
1054
#[error(transparent)]
1155
PluginInvoke(#[from] tauri::plugin::mobile::PluginInvokeError),
12-
#[cfg(all(target_os = "macos", feature = "unstable"))]
56+
#[cfg(desktop)]
57+
#[error(transparent)]
58+
PluginInvoke(#[from] crate::error::PluginInvokeError),
59+
#[cfg(target_os = "windows")]
1360
#[error(transparent)]
14-
PluginInvoke(#[from] serde_json::Error),
61+
WindowsApi(#[from] windows_result::Error),
1562
}
1663

1764
impl Serialize for Error {

src/lib.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ use tauri::{
66
pub use models::*;
77

88
#[cfg(any(
9-
target_os = "windows",
109
target_os = "linux",
1110
all(target_os = "macos", not(feature = "unstable"))
1211
))]
@@ -15,6 +14,8 @@ mod desktop;
1514
mod macos;
1615
#[cfg(mobile)]
1716
mod mobile;
17+
#[cfg(target_os = "windows")]
18+
mod windows;
1819

1920
mod commands;
2021
mod error;
@@ -23,7 +24,6 @@ mod models;
2324
pub use error::{Error, Result};
2425

2526
#[cfg(any(
26-
target_os = "windows",
2727
target_os = "linux",
2828
all(target_os = "macos", not(feature = "unstable"))
2929
))]
@@ -32,6 +32,8 @@ use desktop::Iap;
3232
use macos::Iap;
3333
#[cfg(mobile)]
3434
use mobile::Iap;
35+
#[cfg(target_os = "windows")]
36+
use windows::Iap;
3537

3638
/// Extensions to [`tauri::App`], [`tauri::AppHandle`] and [`tauri::Window`] to access the iap APIs.
3739
pub trait IapExt<R: Runtime> {
@@ -60,8 +62,9 @@ pub fn init<R: Runtime>() -> TauriPlugin<R> {
6062
let iap = macos::init(app, api)?;
6163
#[cfg(mobile)]
6264
let iap = mobile::init(app, api)?;
65+
#[cfg(target_os = "windows")]
66+
let iap = windows::init(app, api)?;
6367
#[cfg(any(
64-
target_os = "windows",
6568
target_os = "linux",
6669
all(target_os = "macos", not(feature = "unstable"))
6770
))]

src/macos.rs

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,12 @@ mod codesign {
1818
let self_code_ptr = NonNull::<*mut SecCode>::new_unchecked(&mut self_code);
1919
let status = SecCode::copy_self(SecCSFlags::empty(), self_code_ptr);
2020
if status != 0 {
21-
return Err(std::io::Error::new(
22-
std::io::ErrorKind::Other,
23-
format!("Failed to get code reference: OSStatus {}", status),
24-
)
25-
.into());
21+
let error_response = crate::error::ErrorResponse {
22+
code: Some(status.to_string()),
23+
message: Some(format!("Failed to get code reference: OSStatus {status}")),
24+
data: (),
25+
};
26+
return Err(crate::error::PluginInvokeError::InvokeRejected(error_response).into());
2627
}
2728

2829
// 2) Validate the dynamic code - this checks if the signature is valid
@@ -32,11 +33,14 @@ mod codesign {
3233
let self_code_ref = self_code_ptr.as_ref().as_ref().unwrap();
3334
let status = SecCode::check_validity(self_code_ref, validity_flags, None);
3435
if status != 0 {
35-
return Err(std::io::Error::new(
36-
std::io::ErrorKind::Other,
37-
format!("Code signature validation failed: OSStatus {}", status),
38-
)
39-
.into());
36+
let error_response = crate::error::ErrorResponse {
37+
code: Some(status.to_string()),
38+
message: Some(format!(
39+
"Code signature validation failed: OSStatus {status}"
40+
)),
41+
data: (),
42+
};
43+
return Err(crate::error::PluginInvokeError::InvokeRejected(error_response).into());
4044
}
4145

4246
Ok(())
@@ -80,10 +84,18 @@ impl<R: Runtime> Iap<R> {
8084
fn to_result<T: serde::de::DeserializeOwned>(bridged: ffi::FFIResult) -> crate::Result<T> {
8185
match bridged {
8286
ffi::FFIResult::Ok(response) => {
83-
let parsed: T = serde_json::from_str(&response)?;
87+
let parsed: T = serde_json::from_str(&response)
88+
.map_err(crate::error::PluginInvokeError::CannotDeserializeResponse)?;
8489
Ok(parsed)
8590
}
86-
ffi::FFIResult::Err(err) => Err(std::io::Error::other(err).into()),
91+
ffi::FFIResult::Err(err) => {
92+
let error_response = crate::error::ErrorResponse {
93+
code: None,
94+
message: Some(err),
95+
data: (),
96+
};
97+
Err(crate::error::PluginInvokeError::InvokeRejected(error_response).into())
98+
}
8799
}
88100
}
89101

0 commit comments

Comments
 (0)