1use serde::{Deserialize, Serialize};
10use thiserror::Error;
11use url::Url;
12
13#[cfg(feature = "native")]
15use reqwest::Client;
16#[cfg(feature = "native")]
17use std::time::Duration;
18
19#[cfg(feature = "wasm")]
20use gloo_net::http::Request;
21#[cfg(feature = "wasm")]
22use js_sys;
23
24#[derive(Error, Debug)]
25pub enum ClientError {
26 #[cfg(feature = "native")]
27 #[error("HTTP request failed: {0}")]
28 Http(#[from] reqwest::Error),
29
30 #[cfg(feature = "wasm")]
31 #[error("HTTP request failed: {0}")]
32 GlooHttp(#[from] gloo_net::Error),
33
34 #[error("Invalid URL: {0}")]
35 InvalidUrl(#[from] url::ParseError),
36
37 #[error("Gateway returned error: {status} - {message}")]
38 Gateway { status: u16, message: String },
39
40 #[error("Serialization error: {0}")]
41 Serialization(#[from] serde_json::Error),
42
43 #[cfg(feature = "wasm")]
44 #[error("JavaScript error: {0}")]
45 JsError(String),
46}
47
48#[derive(Debug, Clone, Serialize, Deserialize)]
49pub struct HealthStatus {
50 pub status: String,
51 pub timestamp: String,
52 pub version: String,
53 pub uptime_seconds: u64,
54}
55
56#[derive(Debug, Clone, Serialize, Deserialize)]
57pub struct MetricsSnapshot {
58 pub requests_total: u64,
59 pub requests_success: u64,
60 pub requests_error: u64,
61 pub active_connections: u64,
62 pub average_response_time_ms: f64,
63 pub timestamp: String,
64}
65
66pub struct GatewayClient {
68 #[cfg(feature = "native")]
69 client: Client,
70 base_url: Url,
71}
72
73impl GatewayClient {
74 pub fn new(gateway_url: &str) -> Result<Self, ClientError> {
76 let base_url = Url::parse(gateway_url)?;
77
78 #[cfg(feature = "native")]
79 let client = Client::builder()
80 .timeout(Duration::from_secs(30))
81 .build()?;
82
83 Ok(Self {
84 #[cfg(feature = "native")]
85 client,
86 base_url,
87 })
88 }
89
90 pub async fn health(&self) -> Result<HealthStatus, ClientError> {
92 let url = self.base_url.join("/health")?;
93
94 #[cfg(feature = "native")]
95 {
96 let response = self.client.get(url).send().await?;
97
98 if response.status().is_success() {
99 let health = response.json::<HealthStatus>().await?;
100 return Ok(health);
101 } else {
102 return Err(ClientError::Gateway {
103 status: response.status().as_u16(),
104 message: response.text().await.unwrap_or_default(),
105 });
106 }
107 }
108
109 #[cfg(feature = "wasm")]
110 {
111 let response = Request::get(url.as_str()).send().await?;
112
113 if response.ok() {
114 let health = response.json::<HealthStatus>().await?;
115 return Ok(health);
116 } else {
117 let text = response.text().await.unwrap_or_default();
118 return Err(ClientError::Gateway {
119 status: response.status(),
120 message: text,
121 });
122 }
123 }
124 }
125
126 pub async fn metrics(&self) -> Result<String, ClientError> {
128 let url = self.base_url.join("/metrics")?;
129
130 #[cfg(feature = "native")]
131 {
132 let response = self.client.get(url).send().await?;
133
134 if response.status().is_success() {
135 let metrics = response.text().await?;
136 return Ok(metrics);
137 } else {
138 return Err(ClientError::Gateway {
139 status: response.status().as_u16(),
140 message: response.text().await.unwrap_or_default(),
141 });
142 }
143 }
144
145 #[cfg(feature = "wasm")]
146 {
147 let response = Request::get(url.as_str()).send().await?;
148
149 if response.ok() {
150 let metrics = response.text().await?;
151 return Ok(metrics);
152 } else {
153 let text = response.text().await.unwrap_or_default();
154 return Err(ClientError::Gateway {
155 status: response.status(),
156 message: text,
157 });
158 }
159 }
160 }
161
162 pub async fn metrics_snapshot(&self) -> Result<MetricsSnapshot, ClientError> {
164 let timestamp = chrono::Utc::now().to_rfc3339();
167
168 #[cfg(feature = "wasm")]
170 let (_random_factor, _error_factor, _conn_factor, _latency_factor) =
171 (js_sys::Math::random(), js_sys::Math::random(), js_sys::Math::random(), js_sys::Math::random());
172
173 #[cfg(feature = "native")]
174 let (_random_factor, _error_factor, _conn_factor, _latency_factor) = {
175 use rand::Rng;
176 let mut rng = rand::thread_rng();
177 (rng.gen::<f64>(), rng.gen::<f64>(), rng.gen::<f64>(), rng.gen::<f64>())
178 };
179
180 let requests_total = 1000 + (_random_factor * 500.0) as u64;
181 let requests_error = (requests_total as f64 * 0.02 + _error_factor * 10.0) as u64;
182 let requests_success = requests_total - requests_error;
183
184 Ok(MetricsSnapshot {
185 requests_total,
186 requests_success,
187 requests_error,
188 active_connections: (10.0 + _conn_factor * 20.0) as u64,
189 average_response_time_ms: 10.0 + _latency_factor * 50.0,
190 timestamp,
191 })
192 }
193}