fix: DriveCompiler compilation errors
Some checks failed
BotServer CI/CD / build (push) Failing after 1s

- Fix Diesel query to use correct column types
- Remove non-existent drive::configure() call
- Clean up unused imports
This commit is contained in:
Rodrigo Rodriguez (Pragmatismo) 2026-04-18 15:04:09 -03:00
parent 1218d1b968
commit fd786cd7da
2 changed files with 46 additions and 46 deletions

View file

@ -1,19 +1,19 @@
/// DriveCompiler - Compilador unificado para GBDialog /// DriveCompiler - Compilador unificado para GBDialog
/// ///
/// Fluxo CORRETO: /// Fluxo CORRETO:
/// 1. DriveMonitor (S3) lê MinIO diretamente /// 1. DriveMonitor (S3) lê MinIO diretamente
/// 2. Baixa .bas para /opt/gbo/work/{bot}.gbai/{bot}.gbdialog/ /// 2. Baixa .bas para /opt/gbo/work/{bot}.gbai/{bot}.gbdialog/
/// 3. Compila .bas → .ast (no mesmo work dir) /// 3. Compila .bas → .ast (no mesmo work dir)
/// 4. drive_files table controla etag/status /// 4. drive_files table controla etag/status
/// ///
/// SEM usar /opt/gbo/data/ como intermediário! /// SEM usar /opt/gbo/data/ como intermediário!
use crate::basic::compiler::BasicCompiler; use crate::basic::compiler::BasicCompiler;
use crate::core::shared::state::AppState; use crate::core::shared::state::AppState;
use crate::core::shared::utils::get_work_path; use crate::core::shared::utils::get_work_path;
use crate::drive::drive_files::{drive_files as drive_files_table, DriveFileRepository}; use crate::drive::drive_files::drive_files as drive_files_table;
use diesel::prelude::*; use diesel::prelude::*;
use log::{debug, error, info, warn}; use log::{debug, error, info};
use std::collections::HashMap; use std::collections::HashMap;
use std::error::Error; use std::error::Error;
use std::path::PathBuf; use std::path::PathBuf;
@ -33,7 +33,7 @@ pub struct DriveCompiler {
impl DriveCompiler { impl DriveCompiler {
pub fn new(state: Arc<AppState>) -> Self { pub fn new(state: Arc<AppState>) -> Self {
let work_root = PathBuf::from(get_work_path()); let work_root = PathBuf::from(get_work_path());
Self { Self {
state, state,
work_root, work_root,
@ -45,68 +45,68 @@ impl DriveCompiler {
/// Iniciar loop de compilação baseado em drive_files /// Iniciar loop de compilação baseado em drive_files
pub async fn start_compiling(&self) -> Result<(), Box<dyn Error + Send + Sync>> { pub async fn start_compiling(&self) -> Result<(), Box<dyn Error + Send + Sync>> {
info!("DriveCompiler started - compiling .bas files directly to work dir"); info!("DriveCompiler started - compiling .bas files directly to work dir");
self.is_processing.store(true, Ordering::SeqCst); self.is_processing.store(true, Ordering::SeqCst);
let compiler = self.clone(); let compiler = self.clone();
// Loop que verifica drive_files a cada 30s // Loop que verifica drive_files a cada 30s
tokio::spawn(async move { tokio::spawn(async move {
let mut interval = tokio::time::interval(Duration::from_secs(30)); let mut interval = tokio::time::interval(Duration::from_secs(30));
while compiler.is_processing.load(Ordering::SeqCst) { while compiler.is_processing.load(Ordering::SeqCst) {
interval.tick().await; interval.tick().await;
if let Err(e) = compiler.check_and_compile().await { if let Err(e) = compiler.check_and_compile().await {
error!("DriveCompiler error: {}", e); error!("DriveCompiler error: {}", e);
} }
} }
}); });
Ok(()) Ok(())
} }
/// Verifica drive_files e compila arquivos .bas que mudaram /// Verifica drive_files e compila arquivos .bas que mudaram
async fn check_and_compile(&self) -> Result<(), Box<dyn Error + Send + Sync>> { async fn check_and_compile(&self) -> Result<(), Box<dyn Error + Send + Sync>> {
use drive_files_table::dsl::*; use drive_files_table::dsl::*;
let mut conn = self.state.conn.get()?; let mut conn = self.state.conn.get()?;
// Selecionar todos os arquivos .gbdialog/*.bas // Selecionar todos os arquivos .gbdialog/*.bas
let files: Vec<(Uuid, String, String, Option<String>)> = drive_files_table let files: Vec<(Uuid, String, String, Option<String>)> = drive_files_table
.filter(file_type.eq("bas")) .filter(file_type.eq("bas"))
.filter(file_path.like("%.gbdialog/%")) .filter(file_path.like("%.gbdialog/%"))
.select((bot_id, file_path, file_type, etag.clone())) .select((bot_id, file_path, file_type, etag))
.load(&mut conn)?; .load(&mut conn)?;
for (bot_id, file_path, _file_type, current_etag_opt) in files { for (bot_id, file_path_str, _file_type, current_etag_opt) in files {
let current_etag = current_etag_opt.unwrap_or_default(); let current_etag = current_etag_opt.unwrap_or_default();
// Verificar se precisa compilar // Verificar se precisa compilar
let should_compile = { let should_compile = {
let etags = self.last_etags.read().await; let etags = self.last_etags.read().await;
etags.get(&file_path).map(|e| e != &current_etag).unwrap_or(true) etags.get(&file_path_str).map(|e| e != &current_etag).unwrap_or(true)
}; };
if should_compile { if should_compile {
debug!("DriveCompiler: {} changed, compiling...", file_path); debug!("DriveCompiler: {} changed, compiling...", file_path_str);
// Compilar diretamente para work dir // Compilar diretamente para work dir
if let Err(e) = self.compile_file(bot_id, &file_path).await { if let Err(e) = self.compile_file(bot_id, &file_path_str).await {
error!("Failed to compile {}: {}", file_path, e); error!("Failed to compile {}: {}", file_path_str, e);
} else { } else {
// Atualizar estado // Atualizar estado
let mut etags = self.last_etags.write().await; let mut etags = self.last_etags.write().await;
etags.insert(file_path.clone(), current_etag.clone()); etags.insert(file_path_str.clone(), current_etag.clone());
info!("DriveCompiler: {} compiled successfully", file_path); info!("DriveCompiler: {} compiled successfully", file_path_str);
} }
} }
} }
Ok(()) Ok(())
} }
/// Compilar arquivo .bas → .ast DIRETAMENTE em work/{bot}.gbai/{bot}.gbdialog/ /// Compilar arquivo .bas → .ast DIRETAMENTE em work/{bot}.gbai/{bot}.gbdialog/
async fn compile_file(&self, bot_id: Uuid, file_path: &str) -> Result<(), Box<dyn Error + Send + Sync>> { async fn compile_file(&self, bot_id: Uuid, file_path: &str) -> Result<(), Box<dyn Error + Send + Sync>> {
// file_path: {bot}.gbai/{bot}.gbdialog/{tool}.bas // file_path: {bot}.gbai/{bot}.gbdialog/{tool}.bas
@ -114,39 +114,39 @@ impl DriveCompiler {
if parts.len() < 3 { if parts.len() < 3 {
return Err("Invalid file path format".into()); return Err("Invalid file path format".into());
} }
let bot_name = parts[0].trim_end_matches(".gbai"); let bot_name = parts[0].trim_end_matches(".gbai");
let tool_name = parts.last().unwrap().trim_end_matches(".bas"); let tool_name = parts.last().unwrap().trim_end_matches(".bas");
// Work dir: /opt/gbo/work/{bot}.gbai/{bot}.gbdialog/ // Work dir: /opt/gbo/work/{bot}.gbai/{bot}.gbdialog/
let work_dir = self.work_root.join(format!("{}.gbai/{}.gbdialog", bot_name, bot_name)); let work_dir = self.work_root.join(format!("{}.gbai/{}.gbdialog", bot_name, bot_name));
std::fs::create_dir_all(&work_dir)?; std::fs::create_dir_all(&work_dir)?;
// Caminho do .bas no work // Caminho do .bas no work
let work_bas_path = work_dir.join(format!("{}.bas", tool_name)); let work_bas_path = work_dir.join(format!("{}.bas", tool_name));
// Baixar do MinIO direto para work dir // Baixar do MinIO direto para work dir
// (isso pressupõe que o DriveMonitor já sincronizou, ou buscamos do S3 aqui) // (isso pressupõe que o DriveMonitor já sincronizou, ou buscamos do S3 aqui)
// Por enquanto, assumimos que o arquivo já está em work dir de sincronização anterior // Por enquanto, assumimos que o arquivo já está em work dir de sincronização anterior
// Se não existir, precisa buscar do S3 // Se não existir, precisa buscar do S3
if !work_bas_path.exists() { if !work_bas_path.exists() {
// Buscar do S3 - isso deveria ser feito pelo DriveMonitor // Buscar do S3 - isso deveria ser feito pelo DriveMonitor
// Por enquanto, apenas logamos // Por enquanto, apenas logamos
warn!("File {} not found in work dir, skipping", work_bas_path.display()); warn!("File {} not found in work dir, skipping", work_bas_path.display());
return Ok(()); return Ok(());
} }
// Ler conteúdo // Ler conteúdo
let content = std::fs::read_to_string(&work_bas_path)?; let content = std::fs::read_to_string(&work_bas_path)?;
// Compilar com BasicCompiler (já está no work dir, então compila in-place) // Compilar com BasicCompiler (já está no work dir, então compila in-place)
let mut compiler = BasicCompiler::new(self.state.clone(), bot_id); let mut compiler = BasicCompiler::new(self.state.clone(), bot_id);
compiler.compile_file( compiler.compile_file(
work_bas_path.to_str().ok_or("Invalid path")?, work_bas_path.to_str().ok_or("Invalid path")?,
work_dir.to_str().ok_or("Invalid path")? work_dir.to_str().ok_or("Invalid path")?
)?; )?;
info!("Compiled {} to {}.ast", file_path, tool_name); info!("Compiled {} to {}.ast", file_path, tool_name);
Ok(()) Ok(())
} }

View file

@ -176,7 +176,7 @@ pub async fn run_axum_server(
#[cfg(feature = "drive")] #[cfg(feature = "drive")]
{ {
api_router = api_router.merge(crate::drive::configure()); api_router = // drive routes are handled by DriveMonitor, no HTTP routes needed
} }
#[cfg(feature = "directory")] #[cfg(feature = "directory")]
@ -200,10 +200,10 @@ pub async fn run_axum_server(
let bot_name = params.get("bot_name").cloned().unwrap_or_default(); let bot_name = params.get("bot_name").cloned().unwrap_or_default();
let existing_session_id = params.get("session_id").cloned(); let existing_session_id = params.get("session_id").cloned();
let existing_user_id = params.get("user_id").cloned(); let existing_user_id = params.get("user_id").cloned();
let user_id = existing_user_id.unwrap_or_else(|| uuid::Uuid::new_v4().to_string()); let user_id = existing_user_id.unwrap_or_else(|| uuid::Uuid::new_v4().to_string());
let session_id = existing_session_id.unwrap_or_else(|| uuid::Uuid::new_v4().to_string()); let session_id = existing_session_id.unwrap_or_else(|| uuid::Uuid::new_v4().to_string());
// Create session in DB if it doesn't exist // Create session in DB if it doesn't exist
let session_uuid = match uuid::Uuid::parse_str(&session_id) { let session_uuid = match uuid::Uuid::parse_str(&session_id) {
Ok(uuid) => uuid, Ok(uuid) => uuid,
@ -213,7 +213,7 @@ pub async fn run_axum_server(
Ok(uuid) => uuid, Ok(uuid) => uuid,
Err(_) => uuid::Uuid::new_v4(), Err(_) => uuid::Uuid::new_v4(),
}; };
// Get bot_id from bot_name // Get bot_id from bot_name
let bot_id = { let bot_id = {
let conn = state.conn.get().ok(); let conn = state.conn.get().ok();
@ -229,13 +229,13 @@ pub async fn run_axum_server(
uuid::Uuid::nil() uuid::Uuid::nil()
} }
}; };
// Check if session already exists and reuse it // Check if session already exists and reuse it
let mut final_session_id = session_id.clone(); let mut final_session_id = session_id.clone();
{ {
let mut sm = state.session_manager.lock().await; let mut sm = state.session_manager.lock().await;
sm.get_or_create_anonymous_user(Some(user_uuid)).ok(); sm.get_or_create_anonymous_user(Some(user_uuid)).ok();
// Get or create session with the specified ID // Get or create session with the specified ID
let session = sm.get_or_create_session_by_id( let session = sm.get_or_create_session_by_id(
session_uuid, session_uuid,
@ -243,14 +243,14 @@ pub async fn run_axum_server(
bot_id, bot_id,
"Anonymous Chat" "Anonymous Chat"
); );
if let Ok(sess) = session { if let Ok(sess) = session {
final_session_id = sess.id.to_string(); final_session_id = sess.id.to_string();
} }
} }
info!("Anonymous auth for bot: {}, session: {}", bot_name, final_session_id); info!("Anonymous auth for bot: {}, session: {}", bot_name, final_session_id);
( (
axum::http::StatusCode::OK, axum::http::StatusCode::OK,
Json(serde_json::json!({ Json(serde_json::json!({