use std::{any::Any, clone, env, fmt::Display, sync::LazyLock}; use actix_web::{ App, HttpResponse, HttpResponseBuilder, HttpServer, Responder, ResponseError, Result, get, http::{self, StatusCode}, web, }; use kube::{Api, Resource, api::ListParams, core::object::HasSpec}; use serde::{Deserialize, Serialize}; use crate::crds::GameServer; static SELF_ENDPOINT: LazyLock = LazyLock::new(|| env::var("SELF_ENDPOINT").expect("SELF_ENDPOINT is not specified")); #[derive(Clone, Debug, Serialize)] struct ResourceNameDescriptor { name: String, resource: String, } #[derive(Debug)] struct KubeError(kube::Error); impl Display for KubeError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { self.0.fmt(f) } } impl ResponseError for KubeError { fn status_code(&self) -> http::StatusCode { StatusCode::INTERNAL_SERVER_ERROR } fn error_response(&self) -> HttpResponse { HttpResponseBuilder::new(self.status_code()).body(self.0.to_string()) } } #[derive(Debug, Deserialize)] struct HashParam { hash: Option, } #[get("/gameserver/discover")] async fn gameservers(kube_client: web::Data) -> Result { let servers: Api = Api::all(kube_client.get_ref().clone()); let servers = servers .list_metadata(&ListParams::default()) .await .map_err(KubeError)?; let list: Vec<_> = servers .into_iter() .map(|v| ResourceNameDescriptor { name: v.metadata.name.clone().unwrap(), resource: format!( "{}/gameserver/{}", &*SELF_ENDPOINT, v.metadata.name.unwrap() ), }) .collect(); Ok(web::Json(list)) } #[get("/gameserver/{game_name}")] async fn get_gameserver( kube_client: web::Data, path: web::Path<(String)>, ) -> Result { let (game_name) = path.into_inner(); let servers: Api = Api::all(kube_client.get_ref().clone()); let game_server = servers.get(&game_name).await.map_err(KubeError)?; let game_server_spec = game_server.spec(); Ok(web::Json(game_server_spec.clone())) } #[get("/gameserver/{game_name}/auth_proxy")] async fn get_gameserver_proxy( kube_client: web::Data, path: web::Path, param: web::Query, ) -> Result { let game_name = path.into_inner(); let hash = param.0.hash.unwrap_or(0); let servers: Api = Api::all(kube_client.get_ref().clone()); let game_server = servers.get(&game_name).await.map_err(KubeError)?; let game_server_spec = game_server.spec(); Ok(web::Json(game_server_spec.clone())) } pub async fn start_webserver(kube_client: kube::Client) { HttpServer::new(move || { App::new() .app_data(web::Data::new(kube_client.clone())) .service(gameservers) .service(get_gameserver) .service(get_gameserver_proxy) }) .bind(("127.0.0.1", 8080)) .expect("failed to start webserver") .run() .await .expect("error occurred whilest running webserver"); }