use actix_web::{HttpResponse, Result, web}; use serde::Serialize; use session::Session; use utoipa::ToSchema; use crate::ApiResponse; use crate::error::ApiError; use service::AppService; use service::error::AppError; use service::ws_token::WS_TOKEN_TTL_SECONDS; #[derive(Debug, Serialize, ToSchema)] pub struct WsTokenResponse { pub token: String, pub expires_in_seconds: i64, } /// Returns a short-lived token that can be used to authenticate WebSocket connections /// by passing it as a query parameter: `ws://host/ws?token=xxx` #[utoipa::path( post, path = "/api/ws/token", responses( (status = 200, description = "Token generated successfully", body = ApiResponse), (status = 401, description = "Unauthorized - not logged in", body = ApiResponse), ), tag = "WebSocket" )] pub async fn ws_token_generate( service: web::Data, session: Session, ) -> Result { let user_id = session .user() .ok_or_else(|| ApiError::from(AppError::Unauthorized))?; let device_id = session.get::("device_id").unwrap_or_default(); let client_id = session.get::("client_id").unwrap_or_default(); let token = service .ws_token .generate_token(user_id, device_id, client_id) .await .map_err(ApiError::from)?; let response = WsTokenResponse { token, expires_in_seconds: WS_TOKEN_TTL_SECONDS, }; Ok(ApiResponse::ok(response).to_response()) }