1use core::fmt;
4
5use serde::{Deserialize, Serialize};
6
7use crate::ffi;
8use crate::private::parse_json_from_static;
9
10pub const WEATHERKIT_BRIDGE_ERROR_DOMAIN: &str = "WeatherKitBridge";
12
13#[derive(Debug, Clone, PartialEq, Eq)]
15pub struct WeatherKitError {
16 pub domain: String,
18 pub code: i64,
20 pub message: String,
22}
23
24#[derive(Debug, Clone, PartialEq, Eq)]
26#[non_exhaustive]
27pub enum WeatherError {
28 PermissionDenied,
30 Unknown(String),
32}
33
34#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
36#[serde(rename_all = "camelCase")]
37pub struct WeatherErrorDescriptor {
38 pub raw_value: String,
40 pub error_description: Option<String>,
42 pub failure_reason: Option<String>,
44 pub help_anchor: Option<String>,
46 pub recovery_suggestion: Option<String>,
48}
49
50#[derive(Debug, Clone, Serialize, Deserialize)]
51#[serde(rename_all = "camelCase")]
52pub(crate) struct ErrorPayload {
53 pub domain: String,
54 pub code: i64,
55 pub message: String,
56}
57
58impl WeatherError {
59 pub fn raw_value(&self) -> &str {
61 match self {
62 Self::PermissionDenied => "permissionDenied",
63 Self::Unknown(value) => value.as_str(),
64 }
65 }
66
67 pub fn descriptors() -> Result<Vec<WeatherErrorDescriptor>, WeatherKitError> {
69 parse_json_from_static(
70 ffi::error::wk_weather_error_copy_descriptors_json,
71 "weather error descriptors",
72 )
73 }
74}
75
76impl WeatherKitError {
77 pub(crate) fn from_payload(payload: ErrorPayload) -> Self {
78 Self {
79 domain: payload.domain,
80 code: payload.code,
81 message: payload.message,
82 }
83 }
84
85 pub(crate) fn bridge(code: i64, message: impl Into<String>) -> Self {
86 Self {
87 domain: WEATHERKIT_BRIDGE_ERROR_DOMAIN.into(),
88 code,
89 message: message.into(),
90 }
91 }
92
93 pub fn is_entitlement_issue(&self) -> bool {
95 let domain = self.domain.to_ascii_lowercase();
96 let message = self.message.to_ascii_lowercase();
97 message.contains("entitlement")
98 || message.contains("permission")
99 || message.contains("bundle")
100 || message.contains("not authorized")
101 || message.contains("denied")
102 || domain.contains("jwtauthenticator")
103 || domain.contains("weatherdaemon")
104 || domain.contains("auth")
105 }
106}
107
108impl fmt::Display for WeatherKitError {
109 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
110 write!(f, "{} ({}) [{}]", self.message, self.code, self.domain)
111 }
112}
113
114impl std::error::Error for WeatherKitError {}