forked from lavina/lavina
endpoint
This commit is contained in:
parent
fdaf10660e
commit
7bc2216ebc
|
@ -281,6 +281,19 @@ impl PlayerRegistry {
|
||||||
inner.players.get(id).map(|(handle, _)| handle.clone())
|
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 {
|
pub async fn get_or_launch_player(&mut self, id: &PlayerId) -> PlayerHandle {
|
||||||
let inner = self.0.read().await;
|
let inner = self.0.read().await;
|
||||||
if let Some((handle, _)) = inner.players.get(id) {
|
if let Some((handle, _)) = inner.players.get(id) {
|
||||||
|
|
|
@ -11,6 +11,11 @@ pub struct CreatePlayerRequest<'a> {
|
||||||
pub name: &'a str,
|
pub name: &'a str,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub struct StopPlayerRequest<'a> {
|
||||||
|
pub name: &'a str,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct ChangePasswordRequest<'a> {
|
pub struct ChangePasswordRequest<'a> {
|
||||||
pub player_name: &'a str,
|
pub player_name: &'a str,
|
||||||
|
@ -19,6 +24,7 @@ pub struct ChangePasswordRequest<'a> {
|
||||||
|
|
||||||
pub mod paths {
|
pub mod paths {
|
||||||
pub const CREATE_PLAYER: &'static str = "/mgmt/create_player";
|
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";
|
pub const SET_PASSWORD: &'static str = "/mgmt/set_password";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
37
src/http.rs
37
src/http.rs
|
@ -13,6 +13,7 @@ use serde::{Deserialize, Serialize};
|
||||||
use tokio::net::TcpListener;
|
use tokio::net::TcpListener;
|
||||||
|
|
||||||
use lavina_core::auth::{Authenticator, UpdatePasswordResult};
|
use lavina_core::auth::{Authenticator, UpdatePasswordResult};
|
||||||
|
use lavina_core::player::{PlayerId, PlayerRegistry};
|
||||||
use lavina_core::prelude::*;
|
use lavina_core::prelude::*;
|
||||||
use lavina_core::repo::Storage;
|
use lavina_core::repo::Storage;
|
||||||
use lavina_core::room::RoomRegistry;
|
use lavina_core::room::RoomRegistry;
|
||||||
|
@ -85,6 +86,7 @@ async fn route(
|
||||||
(&Method::GET, "/metrics") => endpoint_metrics(registry),
|
(&Method::GET, "/metrics") => endpoint_metrics(registry),
|
||||||
(&Method::GET, "/rooms") => endpoint_rooms(core.rooms).await,
|
(&Method::GET, "/rooms") => endpoint_rooms(core.rooms).await,
|
||||||
(&Method::POST, paths::CREATE_PLAYER) => endpoint_create_player(request, storage).await.or5xx(),
|
(&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(),
|
(&Method::POST, paths::SET_PASSWORD) => endpoint_set_password(request, storage).await.or5xx(),
|
||||||
_ => not_found(),
|
_ => not_found(),
|
||||||
};
|
};
|
||||||
|
@ -120,6 +122,39 @@ async fn endpoint_create_player(
|
||||||
Ok(response)
|
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(
|
async fn endpoint_set_password(
|
||||||
request: Request<hyper::body::Incoming>,
|
request: Request<hyper::body::Incoming>,
|
||||||
storage: Storage,
|
storage: Storage,
|
||||||
|
@ -174,6 +209,7 @@ fn malformed_request() -> Response<Full<Bytes>> {
|
||||||
trait Or5xx {
|
trait Or5xx {
|
||||||
fn or5xx(self) -> Response<Full<Bytes>>;
|
fn or5xx(self) -> Response<Full<Bytes>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Or5xx for Result<Response<Full<Bytes>>> {
|
impl Or5xx for Result<Response<Full<Bytes>>> {
|
||||||
fn or5xx(self) -> Response<Full<Bytes>> {
|
fn or5xx(self) -> Response<Full<Bytes>> {
|
||||||
self.unwrap_or_else(|e| {
|
self.unwrap_or_else(|e| {
|
||||||
|
@ -187,6 +223,7 @@ impl Or5xx for Result<Response<Full<Bytes>>> {
|
||||||
trait ToBody {
|
trait ToBody {
|
||||||
fn to_body(&self) -> Full<Bytes>;
|
fn to_body(&self) -> Full<Bytes>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> ToBody for T
|
impl<T> ToBody for T
|
||||||
where
|
where
|
||||||
T: Serialize,
|
T: Serialize,
|
||||||
|
|
Loading…
Reference in New Issue