pub mod commands;
pub mod handler;
pub mod keyboard;
pub mod prompt_inbox;
pub mod state;
pub mod transport;
use std::collections::HashMap;
use std::sync::Arc;
use teloxide::prelude::*;
use tracing::{info, warn};
use crate::config::TelePiConfig;
use crate::pi::registry::SessionRegistry;
use handler::HandlerState;
const MAX_CONFLICT_RETRIES: u32 = 5;
const CONFLICT_RETRY_DELAY: std::time::Duration = std::time::Duration::from_secs(3);
pub async fn run(config: TelePiConfig) -> anyhow::Result<()> {
let bot = Bot::new(&config.telegram_bot_token);
let config = Arc::new(config);
bot.delete_webhook().send().await?;
info!("cleared existing webhook");
commands::register_menu(&bot).await?;
info!("registered telegram bot commands");
let sessions = SessionRegistry::new(config.clone());
let chat_state = state::BotChatState::new();
let handler_state = HandlerState {
config: config.clone(),
sessions,
chat_state,
model_lists: Arc::new(tokio::sync::Mutex::new(HashMap::new())),
};
let message_handler = Update::filter_message()
.branch(
dptree::entry()
.filter_command::<commands::Command>()
.endpoint(commands::dispatch),
)
.branch(
dptree::filter(|msg: Message| msg.voice().is_some() || msg.audio().is_some())
.endpoint(handler::voice_handler),
)
.branch(
dptree::filter(|msg: Message| msg.photo().is_some() || msg.document().is_some())
.endpoint(handler::photo_handler),
)
.branch(
dptree::filter(|msg: Message| msg.text().is_some())
.endpoint(handler::text_handler),
);
let callback_handler = Update::filter_callback_query()
.endpoint(commands::model::handle_model_callback);
let handler = dptree::entry()
.branch(message_handler)
.branch(callback_handler);
let _inbox_handle = prompt_inbox::start_prompt_inbox_polling(
config.clone(),
handler_state.clone(),
);
let mut attempt = 0;
loop {
attempt += 1;
info!(attempt, "starting bot polling");
let mut dispatcher = Dispatcher::builder(bot.clone(), handler.clone())
.dependencies(dptree::deps![handler_state.clone()])
.enable_ctrlc_handler()
.build();
dispatcher.dispatch().await;
if attempt >= MAX_CONFLICT_RETRIES {
warn!(attempts = attempt, "polling stopped after max retries");
break;
}
info!(
attempt,
delay_secs = CONFLICT_RETRY_DELAY.as_secs(),
"polling stopped, retrying after delay"
);
tokio::time::sleep(CONFLICT_RETRY_DELAY).await;
}
Ok(())
}