use actix_web::{HttpRequest, HttpResponse, web}; use channel::http::{WsHandler, WsInMessage, WsOutEvent}; use channel::{ChannelBus, ChannelError}; use session::SessionExt; use uuid::Uuid; use crate::error::ApiError; pub(crate) fn extract_user(req: &HttpRequest) -> Result { req.get_session() .user() .ok_or_else(|| ApiError(service::error::AppError::Unauthorized)) } pub(crate) fn channel_err(e: ChannelError) -> ApiError { ApiError(match e { ChannelError::Unauthorized | ChannelError::TokenInvalidOrExpired => { service::error::AppError::Unauthorized } ChannelError::AccessDenied => { service::error::AppError::PermissionDenied } ChannelError::Validation(msg) => { service::error::AppError::BadRequest(msg) } ChannelError::RateLimitExceeded => { service::error::AppError::BadRequest("rate limit exceeded".into()) } ChannelError::RenewalLimitExceeded => { service::error::AppError::BadRequest( "renewal limit exceeded".into(), ) } ChannelError::RoomNotFound => { service::error::AppError::NotFound("room not found".into()) } ChannelError::UserNotFound => { service::error::AppError::NotFound("user not found".into()) } ChannelError::Internal(msg) => { service::error::AppError::InternalServerError(msg) } ChannelError::Database(e) => { service::error::AppError::InternalServerError(e.to_string()) } ChannelError::Cache(e) => { service::error::AppError::InternalServerError(e.to_string()) } ChannelError::SocketIo(e) => { service::error::AppError::InternalServerError(e.to_string()) } ChannelError::Serialization(e) => { service::error::AppError::InternalServerError(e.to_string()) } ChannelError::Redis(e) => { service::error::AppError::InternalServerError(e.to_string()) } ChannelError::Storage(e) => { service::error::AppError::InternalServerError(e.to_string()) } }) } pub(crate) fn ok_json(event: Option) -> HttpResponse { match event { Some(e) => HttpResponse::Ok().json(e), None => HttpResponse::NoContent().finish(), } } pub(crate) fn created_json(event: Option) -> HttpResponse { match event { Some(e) => HttpResponse::Created().json(e), None => HttpResponse::NoContent().finish(), } } #[utoipa::path( get, path = "/api/v1/ws/ping", responses((status = 200, description = "Pong with protocol version")), tag = "channel", )] pub async fn ping( req: HttpRequest, bus: web::Data, ) -> Result { let user_id = extract_user(&req)?; let result = WsHandler::handle(&bus, user_id, WsInMessage::Ping) .await .map_err(channel_err)?; Ok(ok_json(result)) } #[utoipa::path( get, path = "/api/v1/ws/csrf", responses((status = 200, description = "CSRF token")), tag = "channel", )] pub async fn csrf_token( req: HttpRequest, bus: web::Data, ) -> Result { let user_id = extract_user(&req)?; let result = WsHandler::handle(&bus, user_id, WsInMessage::CsrfToken) .await .map_err(channel_err)?; Ok(ok_json(result)) }