Skip to main content

beam_core/
config.rs

1use std::collections::HashMap;
2
3use serde::{Deserialize, Serialize};
4use serde_json::{Map, Value};
5
6#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
7#[serde(rename_all = "lowercase")]
8pub enum BackendType {
9    Pty,
10    Tmux,
11    Zellij,
12}
13
14impl Default for BackendType {
15    fn default() -> Self {
16        Self::Tmux
17    }
18}
19
20#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
21pub struct DaemonConfig {
22    #[serde(default)]
23    pub backend_type: BackendType,
24    #[serde(default)]
25    pub quiet_restart: bool,
26    #[serde(default = "default_working_dirs")]
27    pub working_dirs: Vec<String>,
28}
29
30fn default_working_dirs() -> Vec<String> {
31    vec!["~".to_string()]
32}
33
34impl Default for DaemonConfig {
35    fn default() -> Self {
36        Self {
37            backend_type: BackendType::default(),
38            quiet_restart: false,
39            working_dirs: default_working_dirs(),
40        }
41    }
42}
43
44#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
45pub struct WebConfig {
46    #[serde(default = "default_web_host")]
47    pub host: String,
48    #[serde(default = "default_proxy_base_port")]
49    pub proxy_base_port: u16,
50}
51
52fn default_web_host() -> String {
53    "0.0.0.0".to_string()
54}
55
56fn default_proxy_base_port() -> u16 {
57    8800
58}
59
60impl Default for WebConfig {
61    fn default() -> Self {
62        Self {
63            host: default_web_host(),
64            proxy_base_port: default_proxy_base_port(),
65        }
66    }
67}
68
69#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Default)]
70pub struct Config {
71    #[serde(default)]
72    pub daemon: DaemonConfig,
73    #[serde(default)]
74    pub web: WebConfig,
75    #[serde(default)]
76    pub lark: LarkConfig,
77    #[serde(default, rename = "screenAnalyzer")]
78    pub screen_analyzer: ScreenAnalyzerConfig,
79}
80
81#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
82pub struct BotConfig {
83    #[serde(default)]
84    pub name: Option<String>,
85    #[serde(rename = "larkAppId")]
86    pub lark_app_id: String,
87    #[serde(rename = "larkAppSecret")]
88    pub lark_app_secret: String,
89    #[serde(rename = "cliId")]
90    pub cli_id: String,
91    #[serde(rename = "cliBin", default)]
92    pub cli_bin: Option<String>,
93    #[serde(default)]
94    pub model: Option<String>,
95    #[serde(rename = "workingDir", default)]
96    pub working_dir: Option<String>,
97    #[serde(rename = "backendType", default)]
98    pub backend_type: Option<BackendType>,
99    #[serde(rename = "larkEncryptKey", default)]
100    pub lark_encrypt_key: Option<String>,
101    #[serde(rename = "larkVerificationToken", default)]
102    pub lark_verification_token: Option<String>,
103    #[serde(rename = "allowedUsers", default)]
104    pub allowed_users: Vec<String>,
105    #[serde(rename = "privateCard", default)]
106    pub private_card: bool,
107    #[serde(rename = "allowedChatGroups", default)]
108    pub allowed_chat_groups: Vec<String>,
109    #[serde(rename = "chatGrants", default)]
110    pub chat_grants: std::collections::HashMap<String, Vec<String>>,
111    #[serde(rename = "globalGrants", default)]
112    pub global_grants: Vec<String>,
113    #[serde(rename = "oncallChats", default)]
114    pub oncall_chats: Vec<OncallChatBinding>,
115    #[serde(rename = "restrictGrantCommands", default)]
116    pub restrict_grant_commands: bool,
117    #[serde(rename = "messageQuota", default)]
118    pub message_quota: Option<MessageQuotaConfig>,
119    #[serde(rename = "quotaState", default)]
120    pub quota_state: std::collections::HashMap<String, QuotaEntry>,
121}
122
123#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
124pub struct OncallChatBinding {
125    #[serde(rename = "chatId")]
126    pub chat_id: String,
127    #[serde(rename = "workingDir", default)]
128    pub working_dir: Option<String>,
129}
130
131#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
132pub struct MessageQuotaConfig {
133    #[serde(rename = "defaultLimit", default)]
134    pub default_limit: Option<u32>,
135}
136
137#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
138pub struct QuotaEntry {
139    pub limit: u32,
140    pub used: u32,
141}
142
143#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
144pub struct LarkConfig {
145    #[serde(default = "default_lark_event_mode")]
146    pub event_mode: String,
147    #[serde(default)]
148    pub verification_token: Option<String>,
149    #[serde(default)]
150    pub encrypt_key: Option<String>,
151}
152
153#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq, Eq)]
154pub struct ScreenAnalyzerConfig {
155    #[serde(default)]
156    pub enabled: bool,
157    #[serde(default)]
158    pub base_url: String,
159    #[serde(default)]
160    pub api_key: String,
161    #[serde(default)]
162    pub model: String,
163    #[serde(default = "default_screen_analyzer_interval_ms")]
164    pub interval_ms: u64,
165    #[serde(default = "default_screen_analyzer_stable_count")]
166    pub stable_count: u32,
167    #[serde(default = "default_screen_analyzer_snapshot_max_chars")]
168    pub snapshot_max_chars: usize,
169    #[serde(default)]
170    pub extra_headers: HashMap<String, String>,
171    #[serde(default)]
172    pub extra_body: Map<String, Value>,
173}
174
175fn default_screen_analyzer_interval_ms() -> u64 {
176    2_000
177}
178
179fn default_screen_analyzer_stable_count() -> u32 {
180    6
181}
182
183fn default_screen_analyzer_snapshot_max_chars() -> usize {
184    8_000
185}
186
187impl Default for ScreenAnalyzerConfig {
188    fn default() -> Self {
189        Self {
190            enabled: false,
191            base_url: String::new(),
192            api_key: String::new(),
193            model: String::new(),
194            interval_ms: default_screen_analyzer_interval_ms(),
195            stable_count: default_screen_analyzer_stable_count(),
196            snapshot_max_chars: default_screen_analyzer_snapshot_max_chars(),
197            extra_headers: HashMap::new(),
198            extra_body: Map::new(),
199        }
200    }
201}
202
203fn default_lark_event_mode() -> String {
204    "http".to_string()
205}
206
207impl Default for LarkConfig {
208    fn default() -> Self {
209        Self {
210            event_mode: default_lark_event_mode(),
211            verification_token: None,
212            encrypt_key: None,
213        }
214    }
215}