reinhardt_deeplink/
router.rs1use hyper::Method;
7use reinhardt_urls::routers::{ServerRouter, UnifiedRouter};
8
9use crate::config::DeeplinkConfig;
10use crate::endpoints::{AasaHandler, AssetLinksHandler};
11use crate::error::DeeplinkError;
12
13pub struct DeeplinkRouter {
45 config: DeeplinkConfig,
47
48 server: ServerRouter,
50}
51
52impl std::fmt::Debug for DeeplinkRouter {
53 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
54 f.debug_struct("DeeplinkRouter")
55 .field("config", &self.config)
56 .field("server", &"ServerRouter { ... }")
57 .finish()
58 }
59}
60
61impl DeeplinkRouter {
62 pub fn new(config: DeeplinkConfig) -> Result<Self, DeeplinkError> {
70 let mut server = ServerRouter::new().with_namespace("wellknown");
71
72 if let Some(ios_config) = &config.ios {
74 let aasa_handler = AasaHandler::new(ios_config.clone())?;
75
76 server = server
78 .handler_with_method(
79 "/apple-app-site-association",
80 Method::GET,
81 aasa_handler.clone(),
82 )
83 .handler_with_method(
84 "/apple-app-site-association.json",
85 Method::GET,
86 aasa_handler,
87 );
88 }
89
90 if let Some(android_config) = &config.android {
92 let assetlinks_handler = AssetLinksHandler::new(android_config.clone())?;
93 server =
94 server.handler_with_method("/assetlinks.json", Method::GET, assetlinks_handler);
95 }
96
97 Ok(Self { config, server })
98 }
99
100 pub fn into_server(self) -> ServerRouter {
105 self.server
106 }
107
108 pub fn server(&self) -> &ServerRouter {
110 &self.server
111 }
112
113 pub fn config(&self) -> &DeeplinkConfig {
115 &self.config
116 }
117}
118
119pub trait DeeplinkRouterExt {
144 type Output;
146
147 fn with_deeplinks(self, config: DeeplinkConfig) -> Result<Self::Output, DeeplinkError>;
155}
156
157impl DeeplinkRouterExt for UnifiedRouter {
158 type Output = Self;
159
160 fn with_deeplinks(self, config: DeeplinkConfig) -> Result<Self, DeeplinkError> {
161 let deeplink_router = DeeplinkRouter::new(config)?;
162 Ok(self.mount("/.well-known/", deeplink_router.into_server()))
163 }
164}
165
166impl DeeplinkRouterExt for ServerRouter {
167 type Output = Self;
168
169 fn with_deeplinks(self, config: DeeplinkConfig) -> Result<Self, DeeplinkError> {
170 let deeplink_router = DeeplinkRouter::new(config)?;
171 Ok(self.mount("/.well-known/", deeplink_router.into_server()))
172 }
173}
174
175#[cfg(test)]
176mod tests {
177 use rstest::rstest;
178
179 use super::*;
180 use crate::config::{AndroidConfig, IosConfig};
181
182 const VALID_FINGERPRINT: &str = "FA:C6:17:45:DC:09:03:78:6F:B9:ED:E6:2A:96:2B:39:9F:73:48:F0:BB:6F:89:9B:83:32:66:75:91:03:3B:9C";
183
184 fn create_ios_config() -> IosConfig {
185 IosConfig::builder()
186 .app_id("TEAM123456.com.example.app")
187 .paths(&["/products/*"])
188 .build()
189 }
190
191 fn create_android_config() -> AndroidConfig {
192 AndroidConfig::builder()
193 .package_name("com.example.app")
194 .sha256_fingerprint(VALID_FINGERPRINT)
195 .build()
196 .unwrap()
197 }
198
199 #[rstest]
200 fn test_router_creation_ios_only() {
201 let config = DeeplinkConfig::builder().ios(create_ios_config()).build();
202
203 let router = DeeplinkRouter::new(config).unwrap();
204 assert!(router.config().has_ios());
205 assert!(!router.config().has_android());
206 }
207
208 #[rstest]
209 fn test_router_creation_android_only() {
210 let config = DeeplinkConfig::builder()
211 .android(create_android_config())
212 .build();
213
214 let router = DeeplinkRouter::new(config).unwrap();
215 assert!(!router.config().has_ios());
216 assert!(router.config().has_android());
217 }
218
219 #[rstest]
220 fn test_router_creation_both() {
221 let config = DeeplinkConfig::builder()
222 .ios(create_ios_config())
223 .android(create_android_config())
224 .build();
225
226 let router = DeeplinkRouter::new(config).unwrap();
227 assert!(router.config().has_ios());
228 assert!(router.config().has_android());
229 }
230
231 #[rstest]
232 fn test_into_server() {
233 let config = DeeplinkConfig::builder().ios(create_ios_config()).build();
234
235 let router = DeeplinkRouter::new(config).unwrap();
236 let _server = router.into_server();
237 }
238
239 #[rstest]
240 fn test_extension_trait_unified() {
241 let config = DeeplinkConfig::builder().ios(create_ios_config()).build();
242
243 let router = UnifiedRouter::new().with_deeplinks(config).unwrap();
244
245 let _ = router;
247 }
248
249 #[rstest]
250 fn test_extension_trait_server() {
251 let config = DeeplinkConfig::builder().ios(create_ios_config()).build();
252
253 let router = ServerRouter::new().with_deeplinks(config).unwrap();
254
255 let _ = router;
257 }
258
259 #[rstest]
260 fn test_empty_config() {
261 let config = DeeplinkConfig::default();
262 let router = DeeplinkRouter::new(config).unwrap();
263
264 assert!(!router.config().is_configured());
266 }
267}