Integrate Docker support into Archipelago and Neode UI

- Added StateManager and data_model modules to manage application state.
- Updated ApiHandler to utilize StateManager for WebSocket connections.
- Enhanced Server initialization to include StateManager.
- Implemented Docker container querying in Neode UI to populate app data dynamically.
- Removed temporary dummy app configurations in favor of real Docker-based applications.
- Improved WebSocket reconnection logic and error handling in the UI.
- Updated package.json and package-lock.json to include dockerode dependency.
This commit is contained in:
Dorian
2026-01-27 23:06:18 +00:00
parent 7afefafec1
commit 3b3f70276f
15 changed files with 1318 additions and 329 deletions

View File

@@ -1,5 +1,6 @@
use crate::api::rpc::RpcHandler;
use crate::config::Config;
use crate::state::StateManager;
use anyhow::Result;
use futures_util::{SinkExt, StreamExt};
use hyper::{Method, Request, Response, StatusCode};
@@ -11,15 +12,17 @@ use tracing::{debug, info};
pub struct ApiHandler {
_config: Config,
rpc_handler: Arc<RpcHandler>,
state_manager: Arc<StateManager>,
}
impl ApiHandler {
pub async fn new(config: Config) -> Result<Self> {
pub async fn new(config: Config, state_manager: Arc<StateManager>) -> Result<Self> {
let rpc_handler = Arc::new(RpcHandler::new(config.clone()).await?);
Ok(Self {
_config: config,
rpc_handler,
state_manager,
})
}
@@ -32,7 +35,7 @@ impl ApiHandler {
// WebSocket upgrade must be handled before consuming the body
if method == Method::GET && path == "/ws/db" {
return Self::handle_websocket(req).await;
return Self::handle_websocket(req, self.state_manager.clone()).await;
}
// Convert body to bytes for non-WS routes
@@ -58,6 +61,7 @@ impl ApiHandler {
async fn handle_websocket(
req: Request<hyper::Body>,
state_manager: Arc<StateManager>,
) -> Result<Response<hyper::Body>> {
let (response, ws_fut_opt) = hyper_ws_listener::create_ws(req)
.map_err(|e| anyhow::anyhow!("WebSocket upgrade failed: {}", e))?;
@@ -80,6 +84,16 @@ impl ApiHandler {
let (mut tx, mut rx) = ws_stream.split();
// Send initial data dump
let initial_msg = state_manager.get_initial_message().await;
if let Ok(json_msg) = serde_json::to_string(&initial_msg) {
if let Err(e) = tx.send(Message::Text(json_msg)).await {
debug!("Failed to send initial data: {}", e);
return;
}
debug!("Sent initial data dump at revision {}", initial_msg.rev);
}
// Send periodic pings to keep connection alive
let ping_interval = tokio::time::interval(tokio::time::Duration::from_secs(30));
tokio::pin!(ping_interval);