refactor: inject AppState into automation & bot, drop Default impl

- Updated `execute_compact_prompt` to accept an `Arc<AppState>` instead of creating a new default state, enabling proper state sharing across tasks.
- Adjusted bot orchestration to clone and pass the existing `AppState` to the automation task, ensuring the same connection and configuration are used.
- Removed the `Default` implementation for `AppState`, preventing accidental creation of a default state with hard‑coded DB connections and services.
- Modified `BotOrchestrator::default` to panic, enforcing explicit construction via `BotOrchestrator::new(state)` for clearer dependency injection.

These changes improve testability, avoid hidden side‑effects from default state initialization, and ensure consistent use of the application state throughout the system.
This commit is contained in:
Rodrigo Rodriguez (Pragmatismo) 2025-11-07 16:13:47 -03:00
parent 856e2f0252
commit e7e84c6cfc
3 changed files with 12 additions and 45 deletions

View file

@ -182,14 +182,14 @@ impl AutomationService {
}
}
pub async fn execute_compact_prompt() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
pub async fn execute_compact_prompt(state: Arc<crate::shared::state::AppState>) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
use crate::shared::models::system_automations::dsl::{is_active, system_automations};
use diesel::prelude::*;
use log::info;
use std::sync::Arc;
let state = Arc::new(crate::shared::state::AppState::default());
let service = AutomationService::new(Arc::clone(&state));
let state_clone = state.clone();
let service = AutomationService::new(state_clone);
let mut conn = state
.conn

View file

@ -625,9 +625,10 @@ let compact_enabled = config_manager
.parse::<i32>()
.unwrap_or(0);
if compact_enabled > 0 {
let state = self.state.clone();
tokio::task::spawn_blocking(move || {
loop {
if let Err(e) = tokio::runtime::Handle::current().block_on(crate::automation::execute_compact_prompt()) {
if let Err(e) = tokio::runtime::Handle::current().block_on(crate::automation::execute_compact_prompt(state.clone())) {
error!("Failed to execute compact prompt: {}", e);
}
std::thread::sleep(Duration::from_secs(60));
@ -881,10 +882,7 @@ if compact_enabled > 0 {
impl Default for BotOrchestrator {
fn default() -> Self {
Self {
state: Arc::new(AppState::default()),
mounted_bots: Arc::new(AsyncMutex::new(HashMap::new())),
}
panic!("BotOrchestrator::default is not supported; instantiate with BotOrchestrator::new(state)");
}
}

View file

@ -45,34 +45,3 @@ impl Clone for AppState {
}
}
}
impl Default for AppState {
fn default() -> Self {
Self {
drive: None,
bucket_name: "default.gbai".to_string(),
config: None,
conn: Arc::new(Mutex::new(
diesel::PgConnection::establish("postgres://localhost/test").unwrap(),
)),
cache: None,
session_manager: Arc::new(tokio::sync::Mutex::new(SessionManager::new(
diesel::PgConnection::establish("postgres://localhost/test").unwrap(),
None,
))),
llm_provider: Arc::new(crate::llm::OpenAIClient::new(
"empty".to_string(),
Some("http://localhost:8081".to_string()),
)),
auth_service: Arc::new(tokio::sync::Mutex::new(AuthService::new(
))),
channels: Arc::new(Mutex::new(HashMap::new())),
response_channels: Arc::new(tokio::sync::Mutex::new(HashMap::new())),
web_adapter: Arc::new(WebChannelAdapter::new()),
voice_adapter: Arc::new(VoiceAdapter::new(
)),
}
}
}