spacegate_kernel/utils/
x_request_id.rs1use std::{
2 hash::Hasher,
3 sync::{atomic::AtomicU64, OnceLock},
4};
5
6use hyper::{http::HeaderValue, Request, Response};
7
8use crate::{helper_layers::function::Inner, SgBody};
9
10pub trait XRequestIdAlgo {
12 fn generate() -> HeaderValue;
13}
14pub const X_REQUEST_ID_HEADER_NAME: &str = "x-request-id";
16pub async fn x_request_id<A: XRequestIdAlgo>(mut request: Request<SgBody>, inner: Inner) -> Response<SgBody> {
20 let id = if let Some(id) = request.headers().get(X_REQUEST_ID_HEADER_NAME) {
21 id.clone()
22 } else {
23 let id = A::generate();
24 request.headers_mut().insert(X_REQUEST_ID_HEADER_NAME, id.clone());
25 id
26 };
27 let mut resp = inner.call(request).await;
28 resp.headers_mut().insert(X_REQUEST_ID_HEADER_NAME, id);
29 resp
30}
31#[derive(Debug, Default, Clone)]
39pub struct Snowflake;
40
41impl XRequestIdAlgo for Snowflake {
42 fn generate() -> HeaderValue {
43 static INC: AtomicU64 = AtomicU64::new(0);
44 let ts_id = unsafe { std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap_unchecked().as_millis() as u64 } << 22;
45 let mach_id = machine_id() << 12;
46 let inc = INC.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
47 let id = ts_id | mach_id | inc;
48 unsafe { HeaderValue::from_str(&format!("{:016x}", id)).unwrap_unchecked() }
49 }
50}
51
52fn machine_id() -> u64 {
53 static MACHINE_ID: OnceLock<u64> = OnceLock::new();
54 *MACHINE_ID.get_or_init(|| {
55 let mid = std::env::var("MACHINE_ID");
56 let mut hasher = std::hash::DefaultHasher::new();
57 if let Ok(mid) = mid {
58 if let Ok(mid) = mid.parse::<u64>() {
59 mid
60 } else {
61 hasher.write(mid.as_bytes());
62 hasher.finish()
63 }
64 } else {
65 #[cfg(target_os = "linux")]
66 {
67 let mid = std::fs::read_to_string("/var/lib/dbus/machine-id").unwrap_or(rand::random::<u64>().to_string());
69 hasher.write(mid.as_bytes());
70 hasher.finish()
71 }
72 #[cfg(not(target_os = "linux"))]
73 {
74 rand::random::<u64>()
76 }
77 }
78 })
79}