Skip to main content

zap/
config.rs

1//! Configuration for ZAP
2
3use serde::{Deserialize, Serialize};
4use std::path::PathBuf;
5
6/// ZAP configuration
7#[derive(Debug, Clone, Serialize, Deserialize)]
8pub struct Config {
9    /// Listen address for the gateway
10    #[serde(default = "default_listen")]
11    pub listen: String,
12
13    /// Port number
14    #[serde(default = "default_port")]
15    pub port: u16,
16
17    /// Connected servers
18    #[serde(default)]
19    pub servers: Vec<ServerConfig>,
20
21    /// Logging level
22    #[serde(default = "default_log_level")]
23    pub log_level: String,
24}
25
26/// Server configuration
27#[derive(Debug, Clone, Serialize, Deserialize)]
28pub struct ServerConfig {
29    /// Server name
30    pub name: String,
31
32    /// Server URL (stdio://, http://, ws://, zap://, unix://)
33    pub url: String,
34
35    /// Transport type
36    #[serde(default)]
37    pub transport: Transport,
38
39    /// Connection timeout in milliseconds
40    #[serde(default = "default_timeout")]
41    pub timeout: u32,
42
43    /// Authentication
44    #[serde(default)]
45    pub auth: Option<Auth>,
46}
47
48/// Transport type
49#[derive(Debug, Clone, Default, Serialize, Deserialize)]
50#[serde(rename_all = "lowercase")]
51pub enum Transport {
52    #[default]
53    Stdio,
54    Http,
55    WebSocket,
56    Zap,
57    Unix,
58}
59
60/// Authentication
61#[derive(Debug, Clone, Serialize, Deserialize)]
62#[serde(tag = "type", rename_all = "lowercase")]
63pub enum Auth {
64    Bearer { token: String },
65    Basic { username: String, password: String },
66}
67
68fn default_listen() -> String {
69    "0.0.0.0".to_string()
70}
71
72fn default_port() -> u16 {
73    9999
74}
75
76fn default_timeout() -> u32 {
77    30000
78}
79
80fn default_log_level() -> String {
81    "info".to_string()
82}
83
84impl Default for Config {
85    fn default() -> Self {
86        Self {
87            listen: default_listen(),
88            port: default_port(),
89            servers: Vec::new(),
90            log_level: default_log_level(),
91        }
92    }
93}
94
95impl Config {
96    /// Load config from file
97    pub fn load(path: &PathBuf) -> crate::Result<Self> {
98        let content = std::fs::read_to_string(path)?;
99        let config: Config = toml::from_str(&content)
100            .map_err(|e| crate::Error::Config(e.to_string()))?;
101        Ok(config)
102    }
103
104    /// Save config to file
105    pub fn save(&self, path: &PathBuf) -> crate::Result<()> {
106        let content = toml::to_string_pretty(self)
107            .map_err(|e| crate::Error::Config(e.to_string()))?;
108        std::fs::write(path, content)?;
109        Ok(())
110    }
111
112    /// Get default config path
113    pub fn default_path() -> PathBuf {
114        directories::ProjectDirs::from("ai", "hanzo", "zap")
115            .map(|dirs| dirs.config_dir().join("config.toml"))
116            .unwrap_or_else(|| PathBuf::from("zap.toml"))
117    }
118}