feat: Implement initial backend structure with API, WebSocket, core models, services, and documentation, alongside dependency and gitignore updates.
This commit is contained in:
1 parent
f82191dd83
commit
7710be86a6
29 files changed
+3927
-1301
No files matched your search
@@ -0,0 +1,145 @@
|
||||
use actix_web::{
|
||||
dev::{forward_ready, Service, ServiceRequest, ServiceResponse, Transform},
|
||||
Error,
|
||||
};
|
||||
use std::{
|
||||
future::{ready, Ready},
|
||||
pin::Pin,
|
||||
rc::Rc,
|
||||
time::Instant,
|
||||
};
|
||||
use crate::utils::log;
|
||||
|
||||
pub struct LoggingMiddleware;
|
||||
|
||||
impl<S, B> Transform<S, ServiceRequest> for LoggingMiddleware
|
||||
where
|
||||
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error> + 'static,
|
||||
S::Future: 'static,
|
||||
B: 'static,
|
||||
{
|
||||
type Response = ServiceResponse<B>;
|
||||
type Error = Error;
|
||||
type InitError = ();
|
||||
type Transform = LoggingMiddlewareService<S>;
|
||||
type Future = Ready<Result<Self::Transform, Self::InitError>>;
|
||||
|
||||
fn new_transform(&self, service: S) -> Self::Future {
|
||||
ready(Ok(LoggingMiddlewareService {
|
||||
service: Rc::new(service),
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct LoggingMiddlewareService<S> {
|
||||
service: Rc<S>,
|
||||
}
|
||||
|
||||
impl<S, B> Service<ServiceRequest> for LoggingMiddlewareService<S>
|
||||
where
|
||||
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error> + 'static,
|
||||
S::Future: 'static,
|
||||
B: 'static,
|
||||
{
|
||||
type Response = ServiceResponse<B>;
|
||||
type Error = Error;
|
||||
type Future = Pin<Box<dyn std::future::Future<Output = Result<Self::Response, Self::Error>>>>;
|
||||
|
||||
forward_ready!(service);
|
||||
|
||||
fn call(&self, req: ServiceRequest) -> Self::Future {
|
||||
let start = Instant::now();
|
||||
let method = req.method().clone();
|
||||
let path = req.path().to_string();
|
||||
let query_string = req.query_string();
|
||||
let full_path = if query_string.is_empty() {
|
||||
path.clone()
|
||||
} else {
|
||||
format!("{}?{}", path, query_string)
|
||||
};
|
||||
|
||||
// Obter IP do cliente
|
||||
let peer_addr = req.peer_addr()
|
||||
.map(|addr| addr.ip().to_string())
|
||||
.unwrap_or_else(|| "unknown".to_string());
|
||||
|
||||
// Obter User-Agent
|
||||
let user_agent = req.headers()
|
||||
.get("user-agent")
|
||||
.and_then(|h| h.to_str().ok())
|
||||
.unwrap_or("unknown")
|
||||
.to_string();
|
||||
|
||||
// Obter Content-Type
|
||||
let content_type = req.headers()
|
||||
.get("content-type")
|
||||
.and_then(|h| h.to_str().ok())
|
||||
.unwrap_or("unknown")
|
||||
.to_string();
|
||||
|
||||
// Obter Content-Length
|
||||
let content_length = req.headers()
|
||||
.get("content-length")
|
||||
.and_then(|h| h.to_str().ok())
|
||||
.unwrap_or("0")
|
||||
.to_string();
|
||||
|
||||
// Obter Authorization header (mascarado)
|
||||
let auth_header = req.headers()
|
||||
.get("authorization")
|
||||
.and_then(|h| h.to_str().ok())
|
||||
.map(|h| {
|
||||
if h.starts_with("Bearer ") {
|
||||
let token = &h[7..];
|
||||
if token.len() > 10 {
|
||||
format!("Bearer {}...", &token[..10])
|
||||
} else {
|
||||
"Bearer [token]".to_string()
|
||||
}
|
||||
} else {
|
||||
"[present]".to_string()
|
||||
}
|
||||
})
|
||||
.unwrap_or_else(|| "none".to_string());
|
||||
|
||||
let service = self.service.clone();
|
||||
Box::pin(async move {
|
||||
let res = service.call(req).await?;
|
||||
let elapsed_ms = start.elapsed().as_millis();
|
||||
let status = res.status();
|
||||
let status_code = status.as_u16();
|
||||
|
||||
// Obter tamanho da resposta (se disponível)
|
||||
let response_size = res.response().headers()
|
||||
.get("content-length")
|
||||
.and_then(|h| h.to_str().ok())
|
||||
.unwrap_or("unknown")
|
||||
.to_string();
|
||||
|
||||
// Log formatado completo
|
||||
let log_message = format!(
|
||||
"API ACCESS | {} {} | Status: {} | IP: {} | Time: {}ms | UA: {} | CT: {} | CL: {} | Auth: {} | RespSize: {}",
|
||||
method,
|
||||
full_path,
|
||||
status_code,
|
||||
peer_addr,
|
||||
elapsed_ms,
|
||||
user_agent,
|
||||
content_type,
|
||||
content_length,
|
||||
auth_header,
|
||||
response_size
|
||||
);
|
||||
|
||||
// Log de erro para status >= 400
|
||||
if status_code >= 400 {
|
||||
log::error(&log_message);
|
||||
} else {
|
||||
log::info(&log_message);
|
||||
}
|
||||
|
||||
Ok(res)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user