integrat the app-code plugin to the signal-gateway-bin
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
//! Extended configuration for application source code browsing.
|
||||
|
||||
use serde::Deserialize;
|
||||
use signal_gateway_app_code::{AppCode, AppCodeConfig, ShaCallback};
|
||||
use std::sync::Arc;
|
||||
use tracing::warn;
|
||||
use url::Url;
|
||||
|
||||
/// Extended configuration for AppCode with HTTP-based SHA fetching.
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
pub struct AppCodeConfigExt {
|
||||
/// The base AppCode configuration.
|
||||
#[serde(flatten)]
|
||||
pub config: AppCodeConfig,
|
||||
/// URL to GET the current deployed version SHA.
|
||||
pub version_sha_http_get: Url,
|
||||
}
|
||||
|
||||
impl AppCodeConfigExt {
|
||||
/// Convert to an AppCode instance with HTTP-based SHA callback.
|
||||
pub fn into_app_code(self) -> Result<AppCode, std::io::Error> {
|
||||
let url = self.version_sha_http_get.clone();
|
||||
let client = reqwest::Client::new();
|
||||
|
||||
let sha_callback: ShaCallback = Arc::new(move || {
|
||||
let url = url.clone();
|
||||
let client = client.clone();
|
||||
Box::pin(async move {
|
||||
let response = client
|
||||
.get(url.as_str())
|
||||
.send()
|
||||
.await
|
||||
.map_err(|e| -> Box<dyn std::error::Error + Send + Sync> {
|
||||
Box::new(std::io::Error::other(format!(
|
||||
"HTTP request to {url} failed: {e}"
|
||||
)))
|
||||
})?;
|
||||
|
||||
if !response.status().is_success() {
|
||||
return Err(Box::new(std::io::Error::other(format!(
|
||||
"HTTP request to {url} returned {}",
|
||||
response.status()
|
||||
))) as Box<dyn std::error::Error + Send + Sync>);
|
||||
}
|
||||
|
||||
let mut sha = response
|
||||
.text()
|
||||
.await
|
||||
.map_err(|e| -> Box<dyn std::error::Error + Send + Sync> {
|
||||
Box::new(std::io::Error::other(format!(
|
||||
"Failed to read response from {url}: {e}"
|
||||
)))
|
||||
})?
|
||||
.trim()
|
||||
.to_string();
|
||||
|
||||
// Handle -dirty suffix
|
||||
if let Some(clean_sha) = sha.strip_suffix("-dirty") {
|
||||
warn!(
|
||||
"Version SHA has -dirty suffix, using clean SHA: {}",
|
||||
clean_sha
|
||||
);
|
||||
sha = clean_sha.to_string();
|
||||
}
|
||||
|
||||
Ok(sha)
|
||||
})
|
||||
});
|
||||
|
||||
AppCode::new(self.config, sha_callback)
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ use conf::Conf;
|
||||
use hyper::service::service_fn;
|
||||
use hyper_util::{rt::TokioIo, server::conn::auto};
|
||||
use signal_gateway::{CommandRouter, Gateway, GatewayConfig, Handling};
|
||||
use signal_gateway_app_code::AppCodeTools;
|
||||
use std::{env, fs, net::SocketAddr, path::PathBuf, sync::Arc, time::Duration};
|
||||
use tokio::net::TcpListener;
|
||||
use tokio_util::sync::CancellationToken;
|
||||
@@ -15,6 +16,9 @@ use tracing_subscriber::EnvFilter;
|
||||
mod admin_http;
|
||||
use admin_http::AdminHttpConfig;
|
||||
|
||||
mod app_code;
|
||||
use app_code::AppCodeConfigExt;
|
||||
|
||||
mod syslog;
|
||||
use syslog::SyslogConfig;
|
||||
|
||||
@@ -43,6 +47,9 @@ pub struct Config {
|
||||
/// Optional HTTP endpoint for forwarding admin messages.
|
||||
#[conf(flatten, prefix)]
|
||||
admin_http: Option<AdminHttpConfig>,
|
||||
/// Application source code configurations for Claude tools.
|
||||
#[conf(long, env, value_parser = serde_json::from_str)]
|
||||
app_code: Vec<AppCodeConfigExt>,
|
||||
#[conf(flatten, serde(flatten))]
|
||||
gateway: GatewayConfig,
|
||||
}
|
||||
@@ -123,11 +130,34 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
}
|
||||
|
||||
let command_router = router_builder.build();
|
||||
let gateway = Gateway::builder(config.gateway)
|
||||
|
||||
// Build AppCode tools if configured
|
||||
let app_code_tools = if !config.app_code.is_empty() {
|
||||
let mut apps = Vec::new();
|
||||
for app_config in config.app_code {
|
||||
let name = app_config.config.name.clone();
|
||||
match app_config.into_app_code() {
|
||||
Ok(app) => apps.push(app),
|
||||
Err(e) => {
|
||||
error!("Failed to initialize app code '{name}': {e}");
|
||||
return Err(e.into());
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(Arc::new(AppCodeTools::new(apps)))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let mut gateway_builder = Gateway::builder(config.gateway)
|
||||
.with_cancellation_token(token.clone())
|
||||
.with_command_router(command_router)
|
||||
.build()
|
||||
.await;
|
||||
.with_command_router(command_router);
|
||||
|
||||
if let Some(tools) = app_code_tools {
|
||||
gateway_builder = gateway_builder.with_tools(tools);
|
||||
}
|
||||
|
||||
let gateway = gateway_builder.build().await;
|
||||
|
||||
let listener = TcpListener::bind(config.http_listen_addr).await.unwrap();
|
||||
info!("Listening for http on {}", config.http_listen_addr);
|
||||
|
||||
Reference in New Issue
Block a user