Skip to content

Commit 93b1187

Browse files
feat: finish axum migration
Signed-off-by: Henry Gressmann <mail@henrygressmann.de>
1 parent 3575069 commit 93b1187

8 files changed

Lines changed: 142 additions & 115 deletions

File tree

Cargo.lock

Lines changed: 52 additions & 53 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ path="src/main.rs"
1717
[dependencies]
1818
# async/concurrency
1919
arc-swap="1.8"
20-
tokio={version="1.48", default-features=false, features=["macros", "rt-multi-thread", "signal"]}
20+
tokio={version="1.49", default-features=false, features=["macros", "rt-multi-thread", "signal"]}
2121
tokio-util={version="0.7", features=["io"]}
2222
futures-lite={version="2.6", default-features=false, features=["alloc"]}
2323
quick_cache={version="0.6", features=["ahash"]}

data/licenses-cargo.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

data/licenses-npm.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

src/web/routes/event.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use crate::utils::hash::{hash_ip, visitor_id};
33
use crate::utils::referrer::{Referrer, process_referer};
44
use crate::utils::useragent;
55
use crate::web::RouterState;
6-
use crate::web::webext::{ApiResult, AxumErrExt, empty_response};
6+
use crate::web::webext::{ApiResult, AxumErrExt, ClientIp, empty_response};
77

88
use aide::axum::routing::post;
99
use aide::axum::{ApiRouter, IntoApiResponse};
@@ -46,16 +46,14 @@ static EXISTING_ENTITIES: LazyLock<quick_cache::sync::Cache<String, ()>> =
4646

4747
async fn event_handler(
4848
state: State<RouterState>,
49-
// RealIp(ip): RealIp, TODO
49+
ClientIp(ip): ClientIp,
5050
TypedHeader(user_agent): TypedHeader<headers::UserAgent>,
5151
Json(event): Json<EventRequest>,
5252
) -> ApiResult<impl IntoApiResponse> {
5353
let url = Uri::from_str(&event.url).context("invalid url").http_err("invalid url", StatusCode::BAD_REQUEST)?;
5454
let app = state.app.clone();
5555
let events = state.events.clone();
5656

57-
let ip = None; // TODO: RealIp
58-
5957
// run the event processing in the background
6058
tokio::task::spawn_blocking(move || {
6159
if let Err(e) = process_event(app, events, event, url, ip, user_agent) {

src/web/webext.rs

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,15 @@
33
use std::convert::Infallible;
44
use std::fmt::Display;
55
use std::marker::PhantomData;
6+
use std::net::{IpAddr, SocketAddr};
67
use std::pin::Pin;
78
use std::task::{Context, Poll};
89

9-
use aide::OperationOutput;
10+
use crate::web::Files;
1011
use aide::axum::IntoApiResponse;
12+
use aide::{OperationIo, OperationOutput};
1113
use axum::body::Body;
12-
use axum::extract::Request;
14+
use axum::extract::{ConnectInfo, FromRequestParts, Request};
1315
use axum::response::IntoResponse;
1416
use axum::{Json, extract};
1517
use http::{Response, StatusCode, header};
@@ -205,7 +207,47 @@ macro_rules! http_bail {
205207
})
206208
};
207209
}
208-
209210
pub(crate) use http_bail;
210211

211-
use crate::web::Files;
212+
#[derive(Debug, Copy, Clone, OperationIo)]
213+
pub struct ClientIp(pub Option<IpAddr>);
214+
215+
impl<S: Send + Sync> FromRequestParts<S> for ClientIp {
216+
type Rejection = Infallible;
217+
218+
async fn from_request_parts(parts: &mut http::request::Parts, state: &S) -> Result<Self, Self::Rejection> {
219+
if let Some(ip) = [
220+
"cf-connecting-ip",
221+
"fly-client-ip",
222+
"true-client-ip",
223+
"x-real-ip",
224+
"cloudfront-viewer-address",
225+
"x-forwarded-for",
226+
"forwarded",
227+
]
228+
.iter()
229+
.find_map(|&name| {
230+
let v = parts.headers.get(name)?.to_str().ok()?.trim();
231+
match name {
232+
"cloudfront-viewer-address" => v.rsplit_once(':')?.0.parse().ok(),
233+
"x-forwarded-for" => v.split(',').next_back()?.trim().parse().ok(),
234+
"forwarded" => v
235+
.split(',')
236+
.next_back()?
237+
.split(';')
238+
.find_map(|p| p.trim().strip_prefix("for="))
239+
.map(|p| p.trim_matches('"'))
240+
.and_then(|p| p.parse().ok()),
241+
_ => v.parse().ok(),
242+
}
243+
}) {
244+
return Ok(ClientIp(Some(ip)));
245+
}
246+
247+
if let Ok(ConnectInfo(addr)) = ConnectInfo::<SocketAddr>::from_request_parts(parts, state).await {
248+
return Ok(ClientIp(Some(addr.ip())));
249+
}
250+
251+
Ok(ClientIp(None))
252+
}
253+
}

web/bun.lock

Lines changed: 37 additions & 49 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

web/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,11 @@
5151
"@types/d3-shape": "^3.1.7",
5252
"@types/d3-transition": "^3.0.9",
5353
"@types/d3-zoom": "^3.0.8",
54-
"@types/react": "^19.2.7",
54+
"@types/react": "^19.2.8",
5555
"@types/react-dom": "^19.2.3",
5656
"@types/topojson-client": "^3.1.5",
5757
"@types/topojson-specification": "^1.0.5",
58-
"astro": "5.16.6",
58+
"astro": "5.16.8",
5959
"rollup-plugin-license": "^3.6.0",
6060
"typescript": "^5.9.3"
6161
},

0 commit comments

Comments
 (0)