1pub mod query;
28pub mod state;
29
30use serde_json::Value;
31use std::collections::HashMap;
32use std::env;
33use std::fs;
34use std::fmt;
35
36#[derive(Debug)]
38pub enum ParseError {
39 MissingBotId,
41 MissingBotConfig,
43 InvalidJson(serde_json::Error),
45}
46
47impl fmt::Display for ParseError {
48 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
49 match self {
50 ParseError::MissingBotId => write!(f, "BOT_ID environment variable not set"),
51 ParseError::MissingBotConfig => write!(f, "BOT_CONFIG environment variable not set"),
52 ParseError::InvalidJson(e) => write!(f, "Failed to parse BOT_CONFIG as JSON: {}", e),
53 }
54 }
55}
56
57impl std::error::Error for ParseError {
58 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
59 match self {
60 ParseError::InvalidJson(e) => Some(e),
61 _ => None,
62 }
63 }
64}
65
66pub mod input {
68 use super::*;
69
70 pub use crate::ParseError;
72
73 fn result_file_path() -> String {
75 let mount_dir = env::var("CODE_MOUNT_DIR").unwrap_or_else(|_| "bot".to_string());
76 format!("/{}/result.json", mount_dir)
77 }
78
79 fn write_result(content: &str) {
81 let path = result_file_path();
82 if let Err(e) = fs::write(&path, content) {
83 eprintln!("RESULT_ERROR: Failed to write result file: {}", e);
84 }
85 }
86
87 pub fn parse() -> Result<(String, Value), ParseError> {
95 let id = env::var("BOT_ID").map_err(|_| ParseError::MissingBotId)?;
96 let config_str = env::var("BOT_CONFIG").map_err(|_| ParseError::MissingBotConfig)?;
97 let config: Value = serde_json::from_str(&config_str).map_err(ParseError::InvalidJson)?;
98 Ok((id, config))
99 }
100
101 pub fn parse_as_map() -> Result<(String, HashMap<String, Value>), ParseError> {
109 let id = env::var("BOT_ID").map_err(|_| ParseError::MissingBotId)?;
110 let config_str = env::var("BOT_CONFIG").map_err(|_| ParseError::MissingBotConfig)?;
111 let config: HashMap<String, Value> =
112 serde_json::from_str(&config_str).map_err(ParseError::InvalidJson)?;
113 Ok((id, config))
114 }
115
116 pub fn success(message: &str) {
120 let escaped = message.replace('\\', "\\\\").replace('"', "\\\"");
121 write_result(&format!(r#"{{"status":"success","message":"{}"}}"#, escaped));
122 }
123
124 pub fn error(message: &str) -> ! {
129 let escaped = message.replace('\\', "\\\\").replace('"', "\\\"");
130 write_result(&format!(r#"{{"status":"error","message":"{}"}}"#, escaped));
131 std::process::exit(1);
132 }
133
134 pub fn result(data: &Value) {
138 write_result(&serde_json::to_string(data).expect("Failed to serialize result"));
139 }
140
141 pub fn metric(metric_type: &str, data: &Value) {
145 let timestamp = current_timestamp();
146 let mut output = data.as_object().cloned().unwrap_or_default();
147 output.insert("_metric".to_string(), Value::String(metric_type.to_string()));
148 output.insert("timestamp".to_string(), Value::Number(serde_json::Number::from(timestamp)));
149 println!("{}", serde_json::to_string(&output).expect("Failed to serialize metric"));
150 }
151
152 #[derive(Debug, Clone, Copy)]
154 pub enum LogLevel {
155 Info,
156 Warn,
157 Error,
158 }
159
160 impl LogLevel {
161 fn as_str(&self) -> &'static str {
162 match self {
163 LogLevel::Info => "info",
164 LogLevel::Warn => "warn",
165 LogLevel::Error => "error",
166 }
167 }
168 }
169
170 pub fn log(message: &str, data: Option<&Value>, level: Option<LogLevel>) {
193 let log_level = level.unwrap_or(LogLevel::Info);
194 let timestamp = current_timestamp();
195
196 let mut output = match data {
197 Some(v) => v.as_object().cloned().unwrap_or_default(),
198 None => serde_json::Map::new(),
199 };
200
201 output.insert("level".to_string(), Value::String(log_level.as_str().to_string()));
202 output.insert("message".to_string(), Value::String(message.to_string()));
203 output.insert("timestamp".to_string(), Value::Number(serde_json::Number::from(timestamp)));
204
205 eprintln!("{}", serde_json::to_string(&output).expect("Failed to serialize log"));
206 }
207
208 pub fn log_info(message: &str, data: Option<&Value>) {
210 log(message, data, Some(LogLevel::Info));
211 }
212
213 pub fn log_warn(message: &str, data: Option<&Value>) {
215 log(message, data, Some(LogLevel::Warn));
216 }
217
218 pub fn log_error(message: &str, data: Option<&Value>) {
220 log(message, data, Some(LogLevel::Error));
221 }
222
223 fn current_timestamp() -> u64 {
225 use std::time::{SystemTime, UNIX_EPOCH};
226 let duration = SystemTime::now()
227 .duration_since(UNIX_EPOCH)
228 .unwrap();
229 duration.as_secs() * 1000 + duration.subsec_millis() as u64
230 }
231}