gitdataai/lib/api/src/channel/rest.rs
2026-05-30 01:38:40 +08:00

111 lines
3.4 KiB
Rust

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<Uuid, ApiError> {
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<WsOutEvent>) -> HttpResponse {
match event {
Some(e) => HttpResponse::Ok().json(e),
None => HttpResponse::NoContent().finish(),
}
}
pub(crate) fn created_json(event: Option<WsOutEvent>) -> 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<ChannelBus>,
) -> Result<HttpResponse, ApiError> {
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<ChannelBus>,
) -> Result<HttpResponse, ApiError> {
let user_id = extract_user(&req)?;
let result = WsHandler::handle(&bus, user_id, WsInMessage::CsrfToken)
.await
.map_err(channel_err)?;
Ok(ok_json(result))
}