diff --git a/crates/goose-server/src/commands/agent.rs b/crates/goose-server/src/commands/agent.rs index 84b828aca6..2002757100 100644 --- a/crates/goose-server/src/commands/agent.rs +++ b/crates/goose-server/src/commands/agent.rs @@ -60,13 +60,10 @@ pub async fn run() -> Result<()> { let local_addr = listener.local_addr()?; info!("listening on {}", local_addr); - let port = local_addr.port(); - *app_state.server_port.write().await = Some(port); - let app_state_clone = app_state.clone(); tokio::spawn(async move { - tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; // a tiny pause to not flood - app_state_clone.auto_start_tunnel(port).await; + tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; + app_state_clone.auto_start_tunnel().await; }); axum::serve(listener, app) diff --git a/crates/goose-server/src/lib.rs b/crates/goose-server/src/lib.rs index 2344ffd9de..aa5ae94f41 100644 --- a/crates/goose-server/src/lib.rs +++ b/crates/goose-server/src/lib.rs @@ -1,4 +1,6 @@ pub mod auth; +pub mod configuration; +pub mod error; pub mod openapi; pub mod routes; pub mod state; diff --git a/crates/goose-server/src/routes/tunnel.rs b/crates/goose-server/src/routes/tunnel.rs index 9459922e80..70d823aa42 100644 --- a/crates/goose-server/src/routes/tunnel.rs +++ b/crates/goose-server/src/routes/tunnel.rs @@ -27,21 +27,7 @@ pub struct ErrorResponse { )] #[axum::debug_handler] pub async fn start_tunnel(State(state): State>) -> Response { - let port = match *state.server_port.read().await { - Some(p) => p, - None => { - tracing::error!("Server port not set"); - return ( - StatusCode::INTERNAL_SERVER_ERROR, - Json(ErrorResponse { - error: "Server port not initialized".to_string(), - }), - ) - .into_response(); - } - }; - - match state.tunnel_manager.start(port).await { + match state.tunnel_manager.start().await { Ok(_info) => { let status = state.tunnel_manager.get_status().await; (StatusCode::OK, Json(status)).into_response() diff --git a/crates/goose-server/src/state.rs b/crates/goose-server/src/state.rs index cd5e09a79d..fb96792502 100644 --- a/crates/goose-server/src/state.rs +++ b/crates/goose-server/src/state.rs @@ -5,7 +5,7 @@ use std::collections::{HashMap, HashSet}; use std::path::PathBuf; use std::sync::atomic::AtomicUsize; use std::sync::Arc; -use tokio::sync::{Mutex, RwLock}; +use tokio::sync::Mutex; use crate::tunnel::TunnelManager; @@ -17,15 +17,13 @@ pub struct AppState { /// Tracks sessions that have already emitted recipe telemetry to prevent double counting. recipe_session_tracker: Arc>>, pub tunnel_manager: Arc, - pub server_port: Arc>>, } impl AppState { pub async fn new() -> anyhow::Result> { let agent_manager = AgentManager::instance().await?; - let tunnel_config = crate::tunnel::config::load_config().await; - let tunnel_manager = Arc::new(TunnelManager::new(tunnel_config.clone())); + let tunnel_manager = Arc::new(TunnelManager::new(tunnel_config)); Ok(Arc::new(Self { agent_manager, @@ -33,16 +31,15 @@ impl AppState { session_counter: Arc::new(AtomicUsize::new(0)), recipe_session_tracker: Arc::new(Mutex::new(HashSet::new())), tunnel_manager, - server_port: Arc::new(RwLock::new(None)), })) } - pub async fn auto_start_tunnel(&self, port: u16) { + pub async fn auto_start_tunnel(&self) { let status = self.tunnel_manager.get_status().await; if status.auto_start && status.state == crate::tunnel::TunnelState::Idle { - tracing::info!("Auto-starting tunnel on port {}", port); - match self.tunnel_manager.start(port).await { + tracing::info!("Auto-starting tunnel"); + match self.tunnel_manager.start().await { Ok(info) => { tracing::info!("Tunnel auto-started successfully: {}", info.url); } diff --git a/crates/goose-server/src/tunnel/mod.rs b/crates/goose-server/src/tunnel/mod.rs index 20c31de592..c17a3d4735 100644 --- a/crates/goose-server/src/tunnel/mod.rs +++ b/crates/goose-server/src/tunnel/mod.rs @@ -1,10 +1,16 @@ pub mod config; pub mod lapstone; +use crate::configuration::Settings; use serde::{Deserialize, Serialize}; use std::sync::Arc; use tokio::sync::{mpsc, RwLock}; +fn get_server_port() -> anyhow::Result { + let settings = Settings::new()?; + Ok(settings.port) +} + #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)] #[serde(rename_all = "lowercase")] pub enum TunnelState { @@ -89,7 +95,7 @@ impl TunnelManager { } } - pub async fn start(&self, port: u16) -> anyhow::Result { + pub async fn start(&self) -> anyhow::Result { let mut state = self.state.write().await; if *state != TunnelState::Idle { anyhow::bail!("Tunnel is already running or starting"); @@ -98,6 +104,7 @@ impl TunnelManager { drop(state); let config = self.config.read().await.clone(); + let server_port = get_server_port()?; let tunnel_secret = config.secret.clone().unwrap_or_else(generate_secret); let server_secret = @@ -114,7 +121,7 @@ impl TunnelManager { *self.restart_tx.write().await = Some(restart_tx.clone()); let result = lapstone::start( - port, + server_port, tunnel_secret, server_secret, agent_id, @@ -156,7 +163,7 @@ impl TunnelManager { *restart_tx_clone.write().await = Some(new_restart_tx.clone()); match lapstone::start( - port, + server_port, tunnel_secret, server_secret, agent_id, @@ -221,28 +228,3 @@ fn generate_agent_id() -> String { let bytes: [u8; 16] = rand::random(); hex::encode(bytes) } - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_generate_secret() { - let secret = generate_secret(); - assert_eq!(secret.len(), 64); // 32 bytes = 64 hex chars - } - - #[test] - fn test_generate_agent_id() { - let agent_id = generate_agent_id(); - assert_eq!(agent_id.len(), 32); // 16 bytes = 32 hex chars - } - - #[tokio::test] - async fn test_tunnel_manager_initial_state() { - let manager = TunnelManager::new(TunnelConfig::default()); - let status = manager.get_status().await; - assert_eq!(status.state, TunnelState::Idle); - assert!(status.info.is_none()); - } -}