refactor: compile the crate once — main.rs uses the library

main.rs re-declared nearly every module (`mod ai; mod database; …`)
that lib.rs also declared, so the ~100k-line crate compiled twice in
every build (lib for the src/bin tools, bin for the server) and the
test suite ran most tests twice. watcher.rs even reached into the lib
copy via `image_api::` from inside the bin copy.

The six bin-only modules (backfill, handlers, hls_stats, knowledge,
reels, watcher) move into lib.rs; main.rs keeps only startup wiring
over `use image_api::…`. A few items main calls become `pub`, and the
dead_code allowances that only existed because each copy saw half the
callers are gone. CLAUDE.md says not to reintroduce `mod` in main.rs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Cameron CordesandClaude Opus 5.5 committed 2026-10-17 01:13:15 -04:00
1 parent 22d28ee80f
commit 2e207c5fa0
9 files changed
+27 -82

No files matched your search

+14 -62
View File
@@ -1,9 +1,7 @@
//! The server binary. Everything it runs lives in the `image_api`
//! library so the crate compiles once, shared with the `src/bin` tools.
#![allow(clippy::too_many_arguments)]
#[macro_use]
extern crate diesel;
extern crate rayon;
use actix_web::web::Data;
use actix_web_prom::PrometheusMetricsBuilder;
use diesel_migrations::{EmbeddedMigrations, MigrationHarness, embed_migrations};
@@ -18,62 +16,16 @@ use actix_web::{App, HttpResponse, HttpServer, middleware, web};
use diesel::sqlite::Sqlite;
use std::error::Error;
use crate::ai::InsightGenerator;
use crate::auth::login;
use crate::data::*;
use crate::database::*;
use crate::files::{RealFileSystem, move_file};
use crate::service::ServiceBuilder;
use crate::state::AppState;
use crate::tags::*;
use image_api::ai::InsightGenerator;
use image_api::auth::login;
use image_api::database::*;
use image_api::files::{RealFileSystem, move_file};
use image_api::service::ServiceBuilder;
use image_api::state::AppState;
use image_api::tags::*;
use image_api::*;
use log::{error, info};
mod ai;
mod auth;
mod backfill;
// Display-zone helpers land in the read-side cutover (#119/#120); the
// binary's private copy of this module doesn't use them yet.
#[allow(dead_code)]
mod camera_tz;
mod clip_search;
mod clip_watch;
mod content_hash;
mod data;
mod database;
mod date_resolver;
mod date_view;
mod duplicates;
mod error;
mod exif;
mod face_watch;
mod faces;
mod file_scan;
mod file_types;
mod files;
mod geo;
mod handlers;
mod hls_stats;
mod libraries;
mod library_maintenance;
mod perceptual_hash;
mod state;
mod tags;
mod thumbnails;
mod unified_search;
mod utils;
mod video;
mod watcher;
mod knowledge;
mod memories;
mod otel;
mod personas;
mod prefs;
mod reels;
mod service;
#[cfg(test)]
mod testhelpers;
pub const MIGRATIONS: EmbeddedMigrations = embed_migrations!();
fn main() -> std::io::Result<()> {
@@ -85,7 +37,7 @@ fn main() -> std::io::Result<()> {
// Recover orphaned insight generation jobs from a previous crash.
{
use crate::database::{InsightGenerationJobDao, SqliteInsightGenerationJobDao};
use image_api::database::{InsightGenerationJobDao, SqliteInsightGenerationJobDao};
let mut dao = SqliteInsightGenerationJobDao::new();
match dao.recover_orphaned_jobs() {
Ok(n) if n > 0 => {
@@ -228,9 +180,9 @@ fn main() -> std::io::Result<()> {
// Spawn background job to generate daily conversation summaries
{
use crate::ai::generate_daily_summaries;
use crate::database::{DailySummaryDao, SqliteDailySummaryDao};
use chrono::NaiveDate;
use image_api::ai::generate_daily_summaries;
use image_api::database::{DailySummaryDao, SqliteDailySummaryDao};
// Configure date range for summary generation
// Default: August 2024 ±30 days (July 1 - September 30, 2024)
@@ -453,7 +405,7 @@ fn main() -> std::io::Result<()> {
Box::new(database::SqlitePersonaDao::new()),
)))
.app_data::<Data<Mutex<faces::SqliteFaceDao>>>(Data::new(Mutex::new(face_dao)))
.app_data::<Data<crate::ai::face_client::FaceClient>>(Data::new(
.app_data::<Data<image_api::ai::face_client::FaceClient>>(Data::new(
app_data.face_client.clone(),
))
.app_data(mp::form::MultipartFormConfig::default().total_limit(1024 * 1024 * 1024)) // 1GB upload limit