use crate::{PublicEntry, Registry}; use anyhow::Result; use rocket::{ get, http::MediaType, request::{self, FromRequest, Outcome}, response::content::{RawHtml, RawJson}, Either, Request, State, }; use std::sync::Arc; use tokio::sync::RwLock; #[get("/v1/list")] pub(super) async fn r_list( registry: &State>>, json: AcceptJson, ) -> Either>, RawHtml>> { if json.0 { Either::Left(RawJson(registry.read().await.json_response.clone())) } else { Either::Right(RawHtml(registry.read().await.html_response.clone())) } } pub(super) fn generate_json_list(entries: &[PublicEntry]) -> Result> { Ok(serde_json::to_string(&entries)?.into()) } pub(super) fn generate_html_list(entries: &[PublicEntry]) -> Result> { Ok(ListPage { entries }.to_string().into()) } markup::define!( ListPage<'a>(entries: &'a [PublicEntry]) { @markup::doctype() html { head { title { "Hurry Curry! Server Registry" } } body { table { tr { th {"Server"} th { "Players" } th { "Protocol" } } @for e in *entries { tr { td { details { summary { @e.name } ul { @for a in &e.address { li { @a } }} } } td { @e.players_online } td { @e.version.0 "." @e.version.1 } }} } } } } ); pub struct AcceptJson(bool); impl<'r> FromRequest<'r> for AcceptJson { type Error = (); fn from_request<'life0, 'async_trait>( request: &'r Request<'life0>, ) -> ::core::pin::Pin< Box< dyn ::core::future::Future> + ::core::marker::Send + 'async_trait, >, > where 'r: 'async_trait, 'life0: 'async_trait, Self: 'async_trait, { Box::pin(async move { Outcome::Success(AcceptJson( request .accept() .map(|a| a.preferred().exact_eq(&MediaType::JSON)) .unwrap_or(false), )) }) } }