diff --git a/Cargo.lock b/Cargo.lock index 362bb9c..5304f94 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -103,6 +103,7 @@ checksum = "f8175979259124331c1d7bf6586ee7e0da434155e4b2d48ec2c8386281d8df39" dependencies = [ "async-trait", "axum-core", + "axum-macros", "bitflags 1.3.2", "bytes", "futures-util", @@ -144,6 +145,18 @@ dependencies = [ "tower-service", ] +[[package]] +name = "axum-macros" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdca6a10ecad987bda04e95606ef85a5417dcaac1a78455242d72e031e2b6b62" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.29", +] + [[package]] name = "backtrace" version = "0.3.69" @@ -251,6 +264,8 @@ dependencies = [ "axum", "clap", "dotenv", + "serde", + "serde_json", "tokio", "tracing", "tracing-subscriber", diff --git a/Cargo.toml b/Cargo.toml index 8b489aa..5c72ced 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,9 @@ tracing = { version = "0.1", features = ["log"] } tracing-subscriber = { version = "0.3.17" } clap = { version = "4.3.4", features = ["derive", "env"] } dotenv = { version = "0.15.0" } -axum = { version = "0.6.18" } +axum = { version = "0.6.18", features = ["macros"] } async-trait = "*" +serde = {version = "1", features = ["derive"]} +serde_json = "1" reqwest = {version = "0.11.20", features = ["json"]} diff --git a/crates/churn-server/Cargo.toml b/crates/churn-server/Cargo.toml index 47afd6a..22e7753 100644 --- a/crates/churn-server/Cargo.toml +++ b/crates/churn-server/Cargo.toml @@ -12,4 +12,6 @@ tracing.workspace = true tracing-subscriber.workspace = true clap.workspace = true dotenv.workspace = true -axum.workspace = true \ No newline at end of file +axum.workspace = true +serde.workspace = true +serde_json.workspace = true \ No newline at end of file diff --git a/crates/churn-server/src/main.rs b/crates/churn-server/src/main.rs index b95bf55..0de245e 100644 --- a/crates/churn-server/src/main.rs +++ b/crates/churn-server/src/main.rs @@ -2,10 +2,15 @@ use std::collections::HashMap; use std::net::SocketAddr; use std::sync::Arc; -use axum::response::IntoResponse; +use anyhow::Error; +use axum::extract::State; +use axum::http::StatusCode; +use axum::response::{IntoResponse, Response}; use axum::routing::{get, post}; -use axum::{async_trait, Router}; +use axum::{async_trait, Json, Router}; use clap::{Parser, Subcommand}; +use serde::{Deserialize, Serialize}; +use serde_json::json; use tokio::sync::Mutex; #[derive(Parser)] @@ -23,8 +28,17 @@ enum Commands { }, } +#[derive(Clone)] struct AgentService(Arc); +impl std::ops::Deref for AgentService { + type Target = Arc; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + impl Default for AgentService { fn default() -> Self { Self(Arc::new(DefaultAgentService::default())) @@ -43,23 +57,40 @@ impl Default for DefaultAgentService { } } -#[async_trait] -impl AgentServiceTrait for DefaultAgentService { - async fn enroll(&self, agent: Agent) -> anyhow::Result { - todo!() - } -} - #[async_trait] trait AgentServiceTrait { async fn enroll(&self, agent: Agent) -> anyhow::Result; } +#[async_trait] +impl AgentServiceTrait for DefaultAgentService { + async fn enroll(&self, agent: Agent) -> anyhow::Result { + let mut agents = self.agents.lock().await; + + match agents.insert(agent.name.clone(), agent.clone()) { + Some(_) => { + tracing::debug!("agents store already contained agent, replaced existing"); + + Ok(agent.name) + } + None => { + tracing::debug!("agents store didn't contain agent, inserted"); + + Ok(agent.name) + } + } + } +} + +#[derive(Clone, Debug, Deserialize, Serialize)] struct Agent { pub name: String, } -struct AppState {} +#[derive(Clone)] +struct AppState { + agent: AgentService, +} #[tokio::main] async fn main() -> anyhow::Result<()> { @@ -81,7 +112,9 @@ async fn main() -> anyhow::Result<()> { .route("/ping", post(agent_ping)) .route("/events", post(get_tasks)), ) - .with_state(); + .with_state(AppState { + agent: AgentService::default(), + }); tracing::info!("churn server listening on {}", host); axum::Server::bind(&host) @@ -95,8 +128,42 @@ async fn main() -> anyhow::Result<()> { Ok(()) } -async fn enroll() -> impl IntoResponse { - todo!() +enum AppError { + Internal(Error), +} + +impl IntoResponse for AppError { + fn into_response(self) -> Response { + let (status, error_message) = match self { + AppError::Internal(e) => { + tracing::error!("failed with error: {}", e); + + ( + StatusCode::INTERNAL_SERVER_ERROR, + "failed with internal error", + ) + } + }; + + let body = Json(json!({ + "error": error_message, + })); + + (status, body).into_response() + } +} + +async fn enroll( + State(state): State, + Json(agent): Json, +) -> Result, AppError> { + let _ = state + .agent + .enroll(agent.clone()) + .await + .map_err(|e| AppError::Internal(e)); + + Ok(Json(agent)) } async fn agent_ping() -> impl IntoResponse { diff --git a/crates/churning/src/main.rs b/crates/churning/src/main.rs index 2c824f9..6e7ea91 100644 --- a/crates/churning/src/main.rs +++ b/crates/churning/src/main.rs @@ -59,7 +59,7 @@ async fn build_container( .iter() .map(|s| s.to_string()) .collect::>(), - architecture: dagger_rust::build::BuildArchitecture::Arm64, + architecture: dagger_rust::build::BuildArchitecture::Amd64, }], &bin_name, )