forked from lavina/lavina
1
0
Fork 0
This commit is contained in:
Nikita Vilunov 2024-04-29 01:56:51 +02:00
parent fdaf10660e
commit 7bc2216ebc
3 changed files with 56 additions and 0 deletions

View File

@ -281,6 +281,19 @@ impl PlayerRegistry {
inner.players.get(id).map(|(handle, _)| handle.clone())
}
pub async fn stop_player(&self, id: &PlayerId) -> Result<Option<()>> {
let mut inner = self.0.write().await;
if let Some((handle, fiber)) = inner.players.remove(id) {
handle.send(ActorCommand::Stop).await;
drop(handle);
fiber.await?;
inner.metric_active_players.dec();
Ok(Some(()))
} else {
Ok(None)
}
}
pub async fn get_or_launch_player(&mut self, id: &PlayerId) -> PlayerHandle {
let inner = self.0.read().await;
if let Some((handle, _)) = inner.players.get(id) {

View File

@ -11,6 +11,11 @@ pub struct CreatePlayerRequest<'a> {
pub name: &'a str,
}
#[derive(Serialize, Deserialize)]
pub struct StopPlayerRequest<'a> {
pub name: &'a str,
}
#[derive(Serialize, Deserialize)]
pub struct ChangePasswordRequest<'a> {
pub player_name: &'a str,
@ -19,6 +24,7 @@ pub struct ChangePasswordRequest<'a> {
pub mod paths {
pub const CREATE_PLAYER: &'static str = "/mgmt/create_player";
pub const STOP_PLAYER: &'static str = "/mgmt/stop_player";
pub const SET_PASSWORD: &'static str = "/mgmt/set_password";
}

View File

@ -13,6 +13,7 @@ use serde::{Deserialize, Serialize};
use tokio::net::TcpListener;
use lavina_core::auth::{Authenticator, UpdatePasswordResult};
use lavina_core::player::{PlayerId, PlayerRegistry};
use lavina_core::prelude::*;
use lavina_core::repo::Storage;
use lavina_core::room::RoomRegistry;
@ -85,6 +86,7 @@ async fn route(
(&Method::GET, "/metrics") => endpoint_metrics(registry),
(&Method::GET, "/rooms") => endpoint_rooms(core.rooms).await,
(&Method::POST, paths::CREATE_PLAYER) => endpoint_create_player(request, storage).await.or5xx(),
(&Method::POST, paths::STOP_PLAYER) => endpoint_stop_player(request, storage).await.or5xx(),
(&Method::POST, paths::SET_PASSWORD) => endpoint_set_password(request, storage).await.or5xx(),
_ => not_found(),
};
@ -120,6 +122,39 @@ async fn endpoint_create_player(
Ok(response)
}
async fn endpoint_stop_player(
request: Request<hyper::body::Incoming>,
players: PlayerRegistry,
) -> Result<Response<Full<Bytes>>> {
let str = request.collect().await?.to_bytes();
let Ok(res) = serde_json::from_slice::<StopPlayerRequest>(&str[..]) else {
return Ok(malformed_request());
};
let Ok(player_id) = PlayerId::from(res.name) else {
let payload = ErrorResponse {
code: errors::PLAYER_NOT_FOUND,
message: "No such player exists",
}
.to_body();
let mut response = Response::new(payload);
*response.status_mut() = StatusCode::UNPROCESSABLE_ENTITY;
return Ok(response);
};
let Some(()) = players.stop_player(&player_id).await? else {
let payload = ErrorResponse {
code: errors::PLAYER_NOT_FOUND,
message: "No such player exists",
}
.to_body();
let mut response = Response::new(payload);
*response.status_mut() = StatusCode::UNPROCESSABLE_ENTITY;
return Ok(response);
};
let mut response = Response::new(Full::<Bytes>::default());
*response.status_mut() = StatusCode::CREATED;
Ok(response)
}
async fn endpoint_set_password(
request: Request<hyper::body::Incoming>,
storage: Storage,
@ -174,6 +209,7 @@ fn malformed_request() -> Response<Full<Bytes>> {
trait Or5xx {
fn or5xx(self) -> Response<Full<Bytes>>;
}
impl Or5xx for Result<Response<Full<Bytes>>> {
fn or5xx(self) -> Response<Full<Bytes>> {
self.unwrap_or_else(|e| {
@ -187,6 +223,7 @@ impl Or5xx for Result<Response<Full<Bytes>>> {
trait ToBody {
fn to_body(&self) -> Full<Bytes>;
}
impl<T> ToBody for T
where
T: Serialize,