kittynode_web/
lib.rs

1use axum::{
2    Router,
3    extract::{Path, Query},
4    http::StatusCode,
5    response::Json,
6    routing::{get, post},
7};
8use eyre::Result;
9use kittynode_core::api;
10use kittynode_core::api::DockerStartStatus;
11use kittynode_core::api::types::{
12    Config, LogsQuery, OperationalState, Package, PackageConfig, PackageRuntimeState, SystemInfo,
13};
14use serde::Deserialize;
15use std::collections::HashMap;
16use tokio::net::TcpListener;
17
18pub async fn hello_world() -> &'static str {
19    "Hello World!"
20}
21
22pub async fn add_capability(Path(name): Path<String>) -> Result<StatusCode, (StatusCode, String)> {
23    api::add_capability(&name).map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
24    Ok(StatusCode::OK)
25}
26
27pub async fn remove_capability(
28    Path(name): Path<String>,
29) -> Result<StatusCode, (StatusCode, String)> {
30    api::remove_capability(&name)
31        .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
32    Ok(StatusCode::OK)
33}
34
35pub async fn get_capabilities() -> Result<Json<Vec<String>>, (StatusCode, String)> {
36    api::get_capabilities()
37        .map(Json)
38        .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))
39}
40
41pub async fn get_packages() -> Result<Json<HashMap<String, Package>>, (StatusCode, String)> {
42    api::get_packages()
43        .map(Json)
44        .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))
45}
46
47pub async fn get_config() -> Result<Json<Config>, (StatusCode, String)> {
48    api::get_config()
49        .map(Json)
50        .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))
51}
52
53pub async fn install_package(Path(name): Path<String>) -> Result<StatusCode, (StatusCode, String)> {
54    api::install_package(&name)
55        .await
56        .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
57    Ok(StatusCode::OK)
58}
59
60#[derive(Default, Deserialize)]
61pub struct DeletePackageQuery {
62    include_images: Option<bool>,
63}
64
65pub async fn delete_package(
66    Path(name): Path<String>,
67    Query(params): Query<DeletePackageQuery>,
68) -> Result<StatusCode, (StatusCode, String)> {
69    let include_images = params.include_images.unwrap_or(false);
70    api::delete_package(&name, include_images)
71        .await
72        .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
73    Ok(StatusCode::OK)
74}
75
76pub async fn stop_package(Path(name): Path<String>) -> Result<StatusCode, (StatusCode, String)> {
77    api::stop_package(&name)
78        .await
79        .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
80    Ok(StatusCode::OK)
81}
82
83pub async fn resume_package(Path(name): Path<String>) -> Result<StatusCode, (StatusCode, String)> {
84    api::resume_package(&name)
85        .await
86        .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
87    Ok(StatusCode::OK)
88}
89
90#[derive(Deserialize)]
91pub struct RuntimeStatesRequest {
92    names: Vec<String>,
93}
94
95pub async fn get_package_runtime_state(
96    Path(name): Path<String>,
97) -> Result<Json<PackageRuntimeState>, (StatusCode, String)> {
98    api::get_package_runtime_state(&name)
99        .await
100        .map(Json)
101        .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))
102}
103
104pub async fn get_package_runtime_states(
105    Json(payload): Json<RuntimeStatesRequest>,
106) -> Result<Json<HashMap<String, PackageRuntimeState>>, (StatusCode, String)> {
107    api::get_packages_runtime_state(&payload.names)
108        .await
109        .map(Json)
110        .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))
111}
112
113pub async fn get_installed_packages() -> Result<Json<Vec<Package>>, (StatusCode, String)> {
114    api::get_installed_packages()
115        .await
116        .map(Json)
117        .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))
118}
119
120pub async fn is_docker_running() -> Result<StatusCode, (StatusCode, String)> {
121    match api::is_docker_running().await {
122        true => Ok(StatusCode::OK),
123        false => Err((
124            StatusCode::SERVICE_UNAVAILABLE,
125            "Docker is not running".to_string(),
126        )),
127    }
128}
129
130pub async fn init_kittynode() -> Result<StatusCode, (StatusCode, String)> {
131    api::init_kittynode().map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
132    Ok(StatusCode::OK)
133}
134
135pub async fn delete_kittynode() -> Result<StatusCode, (StatusCode, String)> {
136    api::delete_kittynode().map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
137    Ok(StatusCode::OK)
138}
139
140pub async fn get_system_info() -> Result<Json<SystemInfo>, (StatusCode, String)> {
141    api::get_system_info()
142        .map(Json)
143        .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))
144}
145
146pub async fn get_container_logs(
147    Path(container_name): Path<String>,
148    Query(params): Query<LogsQuery>,
149) -> Result<Json<Vec<String>>, (StatusCode, String)> {
150    api::get_container_logs(&container_name, params.tail)
151        .await
152        .map(Json)
153        .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))
154}
155
156pub async fn get_package_config(
157    Path(name): Path<String>,
158) -> Result<Json<PackageConfig>, (StatusCode, String)> {
159    api::get_package_config(&name)
160        .await
161        .map(Json)
162        .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))
163}
164
165pub async fn update_package_config(
166    Path(name): Path<String>,
167    Json(config): Json<PackageConfig>,
168) -> Result<StatusCode, (StatusCode, String)> {
169    api::update_package_config(&name, config)
170        .await
171        .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
172    Ok(StatusCode::OK)
173}
174
175pub async fn start_docker_if_needed() -> Result<Json<DockerStartStatus>, (StatusCode, String)> {
176    api::start_docker_if_needed()
177        .await
178        .map(Json)
179        .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))
180}
181
182pub async fn get_operational_state() -> Result<Json<OperationalState>, (StatusCode, String)> {
183    api::get_operational_state()
184        .await
185        .map(Json)
186        .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))
187}
188
189pub fn app() -> Router {
190    Router::new()
191        .route("/", get(hello_world))
192        .route("/add_capability/:name", post(add_capability))
193        .route("/remove_capability/:name", post(remove_capability))
194        .route("/get_capabilities", get(get_capabilities))
195        .route("/get_packages", get(get_packages))
196        .route("/get_config", get(get_config))
197        .route("/install_package/:name", post(install_package))
198        .route("/delete_package/:name", post(delete_package))
199        .route("/stop_package/:name", post(stop_package))
200        .route("/resume_package/:name", post(resume_package))
201        .route("/get_installed_packages", get(get_installed_packages))
202        .route("/package_runtime", post(get_package_runtime_states))
203        .route("/package_runtime/:name", get(get_package_runtime_state))
204        .route("/is_docker_running", get(is_docker_running))
205        .route("/init_kittynode", post(init_kittynode))
206        .route("/delete_kittynode", post(delete_kittynode))
207        .route("/get_system_info", get(get_system_info))
208        .route("/logs/:container_name", get(get_container_logs))
209        .route("/get_package_config/:name", get(get_package_config))
210        .route("/update_package_config/:name", post(update_package_config))
211        .route("/start_docker_if_needed", post(start_docker_if_needed))
212        .route("/get_operational_state", get(get_operational_state))
213}
214
215pub async fn run() -> Result<()> {
216    tracing_subscriber::fmt::init();
217    let app = app();
218    let listener = TcpListener::bind("0.0.0.0:3000").await?;
219    axum::serve(listener, app).await?;
220    Ok(())
221}