use crate::commands::Commands;
use crate::config::Config;
use crate::errors::prelude::{CliError, Result as CliResult};
use vkteams_bot::prelude::*;
pub fn create_bot_instance(config: &Config) -> CliResult<Bot> {
let token = config.api.token.as_ref()
.ok_or_else(|| CliError::InputError(
"API token is required. Set VKTEAMS_BOT_API_TOKEN or configure via 'vkteams-bot-cli setup'".to_string()
))?;
let url = config.api.url.as_ref().ok_or_else(|| {
CliError::InputError(
"API URL is required. Set VKTEAMS_BOT_API_URL or configure via 'vkteams-bot-cli setup'"
.to_string(),
)
})?;
setup_bot_environment(config);
Bot::with_params(&APIVersionUrl::V1, token.as_str(), url.as_str()).map_err(CliError::ApiError)
}
pub fn create_dummy_bot() -> Bot {
Bot::with_params(&APIVersionUrl::V1, "dummy_token", "https://dummy.api.com").unwrap_or_else(
|_| {
panic!("Failed to create dummy bot - this should not happen")
},
)
}
pub fn needs_bot_instance(command: &Commands) -> bool {
match command {
Commands::Config(_) => false,
Commands::Diagnostic(crate::commands::diagnostic::DiagnosticCommands::SystemInfo) => false,
Commands::Diagnostic(_) => true,
Commands::Files(_) => true, Commands::Storage(storage_cmd) => {
match storage_cmd {
crate::commands::storage::StorageCommands::Database { .. } => false,
crate::commands::storage::StorageCommands::Search { .. } => false,
crate::commands::storage::StorageCommands::Context { .. } => false,
}
}
_ => true,
}
}
pub fn setup_bot_environment(config: &Config) {
if let Some(token) = &config.api.token {
unsafe {
std::env::set_var("VKTEAMS_BOT_API_TOKEN", token);
}
}
if let Some(url) = &config.api.url {
unsafe {
std::env::set_var("VKTEAMS_BOT_API_URL", url);
}
}
if let Some(proxy) = &config.proxy {
unsafe {
std::env::set_var("VKTEAMS_PROXY", &proxy.url);
}
if let Some(user) = &proxy.user {
unsafe {
std::env::set_var("VKTEAMS_PROXY_USER", user);
}
}
if let Some(password) = &proxy.password {
unsafe {
std::env::set_var("VKTEAMS_PROXY_PASSWORD", password);
}
}
}
}
pub async fn test_bot_connectivity(bot: &Bot) -> CliResult<()> {
let request = RequestSelfGet::new(());
bot.send_api_request(request)
.await
.map_err(CliError::ApiError)
.map(|_| ())
}
pub fn create_bot_instance_with_retry(config: &Config, max_retries: u32) -> CliResult<Bot> {
let mut last_error = None;
for attempt in 0..=max_retries {
match create_bot_instance(config) {
Ok(bot) => return Ok(bot),
Err(e) => {
last_error = Some(e);
if attempt < max_retries {
std::thread::sleep(std::time::Duration::from_millis(
100 * (attempt + 1) as u64,
));
}
}
}
}
Err(last_error.unwrap_or_else(|| {
CliError::UnexpectedError("Failed to create bot instance after retries".to_string())
}))
}
#[cfg(test)]
mod tests {
use super::*;
use std::env;
use tokio::runtime::Runtime;
#[test]
fn test_needs_bot_instance() {
let config_cmd = Commands::Config(crate::commands::config::ConfigCommands::Setup);
assert!(!needs_bot_instance(&config_cmd));
let system_info_cmd =
Commands::Diagnostic(crate::commands::diagnostic::DiagnosticCommands::SystemInfo);
assert!(!needs_bot_instance(&system_info_cmd));
}
#[test]
fn test_validate_config() {
let mut config = toml::from_str("").unwrap();
println!("{config:?}");
assert!(crate::utils::config_helpers::validate_config(&config).is_err());
config.api.token = Some("test_token_12345".to_string());
assert!(crate::utils::config_helpers::validate_config(&config).is_err());
config.api.url = Some("https://example.com".to_string());
assert!(
crate::utils::config_helpers::validate_config(&config)
.map_err(|e| eprintln!("{e}"))
.is_ok()
);
config.api.url = Some("invalid-url".to_string());
assert!(crate::utils::config_helpers::validate_config(&config).is_err());
config.api.token = Some("short".to_string());
config.api.url = Some("https://example.com".to_string());
assert!(crate::utils::config_helpers::validate_config(&config).is_err());
}
#[test]
fn test_create_dummy_bot() {
let _dummy_bot = create_dummy_bot();
}
#[test]
fn test_setup_bot_environment_sets_vars() {
let mut config: crate::config::Config = toml::from_str("").unwrap();
config.api.token = Some("test_token_env".to_string());
config.api.url = Some("https://api.example.com".to_string());
config.proxy = Some(crate::config::ProxyConfig {
url: "http://proxy.example.com".to_string(),
user: Some("user1".to_string()),
password: Some("pass1".to_string()),
});
setup_bot_environment(&config);
assert_eq!(env::var("VKTEAMS_BOT_API_TOKEN").unwrap(), "test_token_env");
assert_eq!(
env::var("VKTEAMS_BOT_API_URL").unwrap(),
"https://api.example.com"
);
assert_eq!(
env::var("VKTEAMS_PROXY").unwrap(),
"http://proxy.example.com"
);
assert_eq!(env::var("VKTEAMS_PROXY_USER").unwrap(), "user1");
assert_eq!(env::var("VKTEAMS_PROXY_PASSWORD").unwrap(), "pass1");
}
#[test]
fn test_create_bot_instance_with_retry_error() {
let config: crate::config::Config = toml::from_str("").unwrap();
let res = create_bot_instance_with_retry(&config, 2);
assert!(res.is_err());
}
#[test]
fn test_create_bot_instance_with_retry_success() {
let mut config: crate::config::Config = toml::from_str("").unwrap();
config.api.token = Some("test_token_12345".to_string());
config.api.url = Some("https://example.com".to_string());
let res = create_bot_instance_with_retry(&config, 0);
let _ = res;
}
#[test]
fn test_create_bot_instance_with_retry_max_retries() {
let config: crate::config::Config = toml::from_str("").unwrap();
let res = create_bot_instance_with_retry(&config, 3);
assert!(res.is_err());
}
#[test]
fn test_test_bot_connectivity_api_error() {
let bot =
Bot::with_params(&APIVersionUrl::V1, "dummy_token", "https://dummy.api.com").unwrap();
let rt = Runtime::new().unwrap();
let res = rt.block_on(test_bot_connectivity(&bot));
assert!(res.is_err());
}
}