1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
//! # modo::geolocation
//!
//! IP-to-location lookup using a MaxMind GeoLite2/GeoIP2 `.mmdb` database.
//!
//! ## Provides
//!
//! - [`GeolocationConfig`] — YAML-deserializable config with `mmdb_path`
//! - [`GeoLocator`] — MaxMind database reader; cheaply cloneable via `Arc`
//! - [`GeoLayer`] — Tower layer that resolves location per request; also
//! re-exported as [`modo::middlewares::Geo`](crate::middlewares::Geo)
//! - [`Location`] — resolved geolocation data; doubles as an axum extractor
//!
//! ## Quick start
//!
//! 1. Configure `mmdb_path` in the `geolocation` section of your YAML config.
//! 2. Build a [`GeoLocator`] at startup with [`GeoLocator::from_config`].
//! 3. Add [`ClientIpLayer`](crate::ip::ClientIpLayer) **before** [`GeoLayer`]
//! in your middleware stack so client IP resolution happens first.
//! 4. Use [`Location`] as an axum extractor in handlers to read the resolved
//! geolocation for each request.
//!
//! ```rust,ignore
//! let config = GeolocationConfig { mmdb_path: "data/GeoLite2-City.mmdb".into() };
//! let locator = GeoLocator::from_config(&config)?;
//!
//! let app = Router::new()
//! .route("/", get(handler))
//! .layer(GeoLayer::new(locator))
//! .layer(ClientIpLayer::new());
//!
//! async fn handler(location: Location) -> String {
//! format!("country: {:?}", location.country_code)
//! }
//! ```
pub use GeolocationConfig;
pub use Location;
pub use GeoLocator;
pub use GeoLayer;