use std::sync::Mutex;
use actix_web::{
delete,
error::{ErrorConflict, ErrorNotFound, ErrorServiceUnavailable},
get, patch, post,
web::{Data, Json, Path},
HttpResponse, Responder, Result,
};
use log::error;
use uuid::Uuid;
use crate::{models::Room, storage::Storage, worker::Worker};
#[utoipa::path(
request_body = Room,
responses(
(status = 200, description = "OK", body = Uuid),
(status = 409, description = "Conflict", body = String),
),
)]
#[post("/v1/rooms")]
async fn create(req: Json<Room>, storage: Data<Mutex<Storage>>) -> Result<impl Responder> {
let room = req.into_inner();
let mut data = storage.lock().unwrap();
if let Ok(id) = data.new_room(room) {
Ok(HttpResponse::Ok().json(id))
} else {
Err(ErrorConflict("Failed to create new room"))
}
}
#[utoipa::path(
responses(
(status = 204, description = "OK"),
(status = 404, description = "Not Found", body = String),
),
params(
("id", description = "Room ID")
)
)]
#[delete("/v1/room/{id}")]
async fn destroy(id: Path<Uuid>, storage: Data<Mutex<Storage>>) -> Result<impl Responder> {
let id = id.into_inner();
let mut data = storage.lock().unwrap();
if data.delete_room(&id).is_ok() {
Ok(HttpResponse::Ok())
} else {
Err(ErrorNotFound(format!("Not found: {}", id)))
}
}
#[utoipa::path(
responses(
(status = 200, description = "OK", body = Vec<Uuid>),
(status = 404, description = "Not Found", body = String),
),
)]
#[get("/v1/rooms")]
async fn list(storage: Data<Mutex<Storage>>) -> Result<impl Responder> {
let data = storage.lock().unwrap();
if let Ok(ids) = data.list() {
Ok(HttpResponse::Ok().json(ids))
} else {
Err(ErrorNotFound("Failed to list rooms"))
}
}
#[utoipa::path(
responses(
(status = 200, description = "OK", body = Room),
(status = 404, description = "Not Found", body = String),
),
params(
("id", description = "Room ID")
)
)]
#[get("/v1/room/{id}")]
async fn read(id: Path<Uuid>, storage: Data<Mutex<Storage>>) -> Result<impl Responder> {
let id = id.into_inner();
let data = storage.lock().unwrap();
if let Some(room) = data.read(&id) {
Ok(HttpResponse::Ok().json(room))
} else {
Err(ErrorNotFound(format!("No such room: {}", id)))
}
}
#[utoipa::path(
request_body = Room,
responses(
(status = 204, description = "OK"),
(status = 404, description = "Not Found", body = String),
),
params(
("id", description = "Room ID")
)
)]
#[patch("/v1/room/{id}")]
async fn update(
id: Path<Uuid>,
req: Json<Room>,
storage: Data<Mutex<Storage>>,
) -> Result<impl Responder> {
let id = id.into_inner();
let room = req.into_inner();
let mut data = storage.lock().unwrap();
if data.update_room(&id, &room).is_ok() {
Ok(HttpResponse::Ok())
} else {
Err(ErrorNotFound(format!("Not found: {}", id)))
}
}
#[utoipa::path(
responses(
(status = 200, description = "OK", body = Room),
(status = 404, description = "Not Found", body = String),
(status = 503, description = "Unavailable", body = String),
),
params(
("id", description = "Room ID")
)
)]
#[get("/v1/room/{id}/status")]
async fn status(
id: Path<Uuid>,
data: Data<Mutex<Storage>>,
worker: Data<Mutex<Worker>>,
) -> Result<impl Responder> {
let id = id.into_inner();
let mut room = {
let data = data.lock().unwrap();
match data.read(&id) {
Some(room) => room,
None => return Err(ErrorNotFound(format!("Not found: {}", id))),
}
};
match room.get_status() {
Ok(responses) => {
let mut worker = worker.lock().unwrap();
for resp in responses {
if let Err(e) = worker.queue_update(resp) {
error!("Failed to queue write: {}", e);
}
}
Ok(HttpResponse::Ok().json(room))
}
Err(e) => Err(ErrorServiceUnavailable(format!(
"Failed to fetch status: {}",
e
))),
}
}