semantic bufo search find-bufo.com
bufo
at fix-query-length-error-handling 75 lines 2.4 kB view raw
1mod config; 2mod embedding; 3mod search; 4mod turbopuffer; 5 6use actix_cors::Cors; 7use actix_files as fs; 8use actix_governor::{Governor, GovernorConfigBuilder}; 9use actix_web::{middleware, web, App, HttpResponse, HttpServer}; 10use anyhow::Result; 11use config::Config; 12use opentelemetry_instrumentation_actix_web::{RequestMetrics, RequestTracing}; 13use tracing::level_filters::LevelFilter; 14 15async fn index() -> HttpResponse { 16 HttpResponse::Ok() 17 .content_type("text/html; charset=utf-8") 18 .body(include_str!("../static/index.html")) 19} 20 21#[actix_web::main] 22async fn main() -> Result<()> { 23 dotenv::dotenv().ok(); 24 25 // initialize logfire with info level filter to exclude trace/debug spans 26 let logfire = logfire::configure() 27 .with_default_level_filter(LevelFilter::INFO) 28 .finish() 29 .map_err(|e| anyhow::anyhow!("failed to initialize logfire: {}", e))?; 30 31 let _guard = logfire.shutdown_guard(); 32 33 let config = Config::from_env()?; 34 let host = config.host.clone(); 35 let port = config.port; 36 37 logfire::info!("starting bufo search server", 38 host = &host, 39 port = port as i64 40 ); 41 42 // rate limiter: 10 requests per minute per IP 43 let governor_conf = GovernorConfigBuilder::default() 44 .milliseconds_per_request(6000) // 1 request per 6 seconds = 10 per minute 45 .burst_size(10) 46 .finish() 47 .unwrap(); 48 49 HttpServer::new(move || { 50 let cors = Cors::permissive(); 51 52 App::new() 53 // opentelemetry tracing and metrics FIRST 54 .wrap(RequestTracing::new()) 55 .wrap(RequestMetrics::default()) 56 // existing middleware 57 .wrap(middleware::Logger::default()) 58 .wrap(cors) 59 .app_data(web::Data::new(config.clone())) 60 .route("/", web::get().to(index)) 61 .service( 62 web::scope("/api") 63 .wrap(Governor::new(&governor_conf)) 64 .route("/search", web::post().to(search::search)) 65 .route("/search", web::get().to(search::search_get)) 66 .route("/health", web::get().to(|| async { HttpResponse::Ok().body("ok") })) 67 ) 68 .service(fs::Files::new("/static", "./static").show_files_listing()) 69 }) 70 .bind((host.as_str(), port))? 71 .run() 72 .await?; 73 74 Ok(()) 75}