use axum::{ extract::{ws::WebSocketUpgrade, Extension, Query, TypedHeader}, headers, response::IntoResponse, routing::{get, post}, Json, Router, }; use std::sync::Arc; use tracing::{info, instrument, warn}; use zone_core::{Container, ContainerOptions, FilterContainer}; use zone_nspawn::NSpawn; use crate::{ws, Error, Result, State}; #[instrument()] pub fn build_routes() -> Router { Router::new() .route("/test", get(test_endpoint)) .route("/container", post(clone_container)) .route("/container/list?", get(container_list)) .route("/ws", get(ws_upgrade)) } /// # Test endpoint /// /// Returns a list of containers based on the query. #[instrument(ret, skip(state))] async fn test_endpoint(Extension(state): Extension>) -> Json { Json(state.zfs.config.pool_name.to_owned()) } /// List containers /// /// Returns a list of containers based on the query. #[instrument(err, ret)] async fn container_list( container: Option>, ) -> Result>> { let mut containers = NSpawn::get_containers()?.into_iter().filter_map(|c| { Container::try_from(c) .map_err(|err| warn!("Ignoring invalid nspawn container {:?}", err)) .ok() }); match container { Some(Query(params)) => Ok(containers.filter_container(params).into()), _ => Ok(containers.collect::>().into()), } } /// Create container /// /// Creates a new container volume from the provided container json data #[instrument(err, ret, skip(state))] async fn clone_container( Json(container): Json, Extension(state): Extension>, ) -> Result> { state .zfs .clone_from_latest( format!("{}-{}", container.user, container.id).into(), container.template.into(), )? .try_into() .map_err(Error::from) .map(Container::into) } /// Upgrade to websocket /// /// Creates a new container volume from the provided container json data #[instrument(ret, skip_all)] async fn ws_upgrade( ws: WebSocketUpgrade, user_agent: Option>, Extension(state): Extension>, ) -> impl IntoResponse { let ua = user_agent.map_or("Unknown".to_string(), |u| u.to_string()); info!(%ua, "Client connected"); ws.on_upgrade(|socket| ws::handler(socket, state)) } #[cfg(test)] mod tests { #[test] fn hello_world() { // use super::*; assert!("true" == "true"); } }