Use locat for Geo-IP locating.
This commit is contained in:
parent
9dba835bcf
commit
9f681ff4ac
1
.envrc
1
.envrc
|
@ -1,3 +1,4 @@
|
||||||
watch_file flake.nix flake.lock
|
watch_file flake.nix flake.lock
|
||||||
dotenv_if_exists
|
dotenv_if_exists
|
||||||
|
export GEOLITE2_COUNTRY_DB="db/ip_country_sample.mmdb"
|
||||||
use flake
|
use flake
|
||||||
|
|
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -1,2 +1,3 @@
|
||||||
target
|
/db
|
||||||
|
/target
|
||||||
.env
|
.env
|
||||||
|
|
32
Cargo.lock
generated
32
Cargo.lock
generated
|
@ -334,6 +334,7 @@ dependencies = [
|
||||||
"axum",
|
"axum",
|
||||||
"color-eyre",
|
"color-eyre",
|
||||||
"image",
|
"image",
|
||||||
|
"locat",
|
||||||
"opentelemetry",
|
"opentelemetry",
|
||||||
"opentelemetry-honeycomb",
|
"opentelemetry-honeycomb",
|
||||||
"pretty-hex",
|
"pretty-hex",
|
||||||
|
@ -1122,6 +1123,15 @@ version = "2.7.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "12b6ee2129af8d4fb011108c73d99a1b83a85977f23b82460c0ae2e25bb4b57f"
|
checksum = "12b6ee2129af8d4fb011108c73d99a1b83a85977f23b82460c0ae2e25bb4b57f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ipnetwork"
|
||||||
|
version = "0.18.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4088d739b183546b239688ddbc79891831df421773df95e236daf7867866d355"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itoa"
|
name = "itoa"
|
||||||
version = "1.0.6"
|
version = "1.0.6"
|
||||||
|
@ -1197,6 +1207,16 @@ version = "0.3.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ece97ea872ece730aed82664c424eb4c8291e1ff2480247ccf7409044bc6479f"
|
checksum = "ece97ea872ece730aed82664c424eb4c8291e1ff2480247ccf7409044bc6479f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "locat"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+ssh://git@git.shipyard.rs/menteeth/crate-index.git"
|
||||||
|
checksum = "5710a18ee2dbe5aff9a408bc48e25a9c53116b2e3a0a334b23388437806c0884"
|
||||||
|
dependencies = [
|
||||||
|
"maxminddb",
|
||||||
|
"thiserror",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lock_api"
|
name = "lock_api"
|
||||||
version = "0.4.9"
|
version = "0.4.9"
|
||||||
|
@ -1223,6 +1243,18 @@ version = "0.7.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b87248edafb776e59e6ee64a79086f65890d3510f2c656c000bf2a7e8a0aea40"
|
checksum = "b87248edafb776e59e6ee64a79086f65890d3510f2c656c000bf2a7e8a0aea40"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "maxminddb"
|
||||||
|
version = "0.23.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fe2ba61113f9f7a9f0e87c519682d39c43a6f3f79c2cc42c3ba3dda83b1fa334"
|
||||||
|
dependencies = [
|
||||||
|
"ipnetwork",
|
||||||
|
"log",
|
||||||
|
"memchr",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memchr"
|
name = "memchr"
|
||||||
version = "2.5.0"
|
version = "2.5.0"
|
||||||
|
|
|
@ -9,6 +9,7 @@ artem = { version = "=1.1.5", default-features = false }
|
||||||
axum = "0.6"
|
axum = "0.6"
|
||||||
color-eyre = "0.6"
|
color-eyre = "0.6"
|
||||||
image = "0.24"
|
image = "0.24"
|
||||||
|
locat = { version = "0.3.1", registry = "menteeth" }
|
||||||
opentelemetry = { version = "0.18", features = ["rt-tokio"] }
|
opentelemetry = { version = "0.18", features = ["rt-tokio"] }
|
||||||
opentelemetry-honeycomb = { git = "https://github.com/fasterthanlime/opentelemetry-honeycomb-rs", branch = "simplified", version = "0.1.0" }
|
opentelemetry-honeycomb = { git = "https://github.com/fasterthanlime/opentelemetry-honeycomb-rs", branch = "simplified", version = "0.1.0" }
|
||||||
pretty-hex = "0.3"
|
pretty-hex = "0.3"
|
||||||
|
|
28
src/main.rs
28
src/main.rs
|
@ -1,4 +1,6 @@
|
||||||
|
use std::net::IpAddr;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
use axum::{
|
use axum::{
|
||||||
body::BoxBody,
|
body::BoxBody,
|
||||||
|
@ -15,12 +17,15 @@ use opentelemetry::{
|
||||||
};
|
};
|
||||||
use reqwest::StatusCode;
|
use reqwest::StatusCode;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use tracing::{info, Level};
|
use tracing::{info, warn, Level};
|
||||||
use tracing_subscriber::{filter::Targets, layer::SubscriberExt, util::SubscriberInitExt};
|
use tracing_subscriber::{filter::Targets, layer::SubscriberExt, util::SubscriberInitExt};
|
||||||
|
|
||||||
|
use locat::Locat;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
struct ServerState {
|
struct ServerState {
|
||||||
client: reqwest::Client,
|
client: reqwest::Client,
|
||||||
|
locat: Arc<Locat>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
|
@ -40,8 +45,12 @@ async fn main() {
|
||||||
.with(filter)
|
.with(filter)
|
||||||
.init();
|
.init();
|
||||||
|
|
||||||
|
let cdb_env_var = "GEOLITE2_COUNTRY_DB";
|
||||||
|
let cdb_path = std::env::var(cdb_env_var)
|
||||||
|
.unwrap_or_else(|_| panic!("${cdb_env_var} must be set"));
|
||||||
let state = ServerState {
|
let state = ServerState {
|
||||||
client: Default::default(),
|
client: Default::default(),
|
||||||
|
locat: Arc::new(Locat::new(&cdb_path, "todo.db").unwrap()),
|
||||||
};
|
};
|
||||||
|
|
||||||
let app = Router::new().route("/", get(root_get)).with_state(state);
|
let app = Router::new().route("/", get(root_get)).with_state(state);
|
||||||
|
@ -60,6 +69,13 @@ async fn main() {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_client_addr(headers: &HeaderMap) -> Option<IpAddr> {
|
||||||
|
let header = headers.get("x-remote-ip")?;
|
||||||
|
let header = header.to_str().ok()?;
|
||||||
|
let addr = header.parse::<IpAddr>().ok()?;
|
||||||
|
Some(addr)
|
||||||
|
}
|
||||||
|
|
||||||
async fn root_get(headers: HeaderMap, State(state): State<ServerState>) -> Response<BoxBody> {
|
async fn root_get(headers: HeaderMap, State(state): State<ServerState>) -> Response<BoxBody> {
|
||||||
let tracer = global::tracer("");
|
let tracer = global::tracer("");
|
||||||
let mut span = tracer.start("root_get");
|
let mut span = tracer.start("root_get");
|
||||||
|
@ -71,6 +87,16 @@ async fn root_get(headers: HeaderMap, State(state): State<ServerState>) -> Respo
|
||||||
.unwrap_or_default(),
|
.unwrap_or_default(),
|
||||||
));
|
));
|
||||||
|
|
||||||
|
if let Some(addr) = get_client_addr(&headers) {
|
||||||
|
match state.locat.ip_to_iso_code(addr).await {
|
||||||
|
Some(country) => {
|
||||||
|
info!("Got request from {country}");
|
||||||
|
span.set_attribute(KeyValue::new("country", country.to_string()));
|
||||||
|
}
|
||||||
|
None => warn!("Could not determine country for IP address"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
root_get_inner(state)
|
root_get_inner(state)
|
||||||
.with_context(Context::current_with_span(span))
|
.with_context(Context::current_with_span(span))
|
||||||
.await
|
.await
|
||||||
|
|
Loading…
Reference in a new issue