1use crate::services::{content, search};
2use crate::{web, Config, Database};
3use anyhow::Result;
4use std::path::Path;
5use std::time::Duration;
6use tokio::task::JoinHandle;
7
8pub async fn run(config_path: &Path, host: &str, port: u16) -> Result<()> {
9 let config = Config::load(config_path)?;
10 let db = Database::open(&config.database.path)?;
11
12 db.migrate()?;
13
14 if let Ok(count) = search::rebuild_fts_index(&db) {
15 tracing::info!("Search index rebuilt: {} documents indexed", count);
16 }
17
18 let (shutdown_tx, shutdown_rx) = tokio::sync::watch::channel(false);
19 let mut bg_handles: Vec<JoinHandle<()>> = Vec::new();
20
21 let scheduler_db = db.clone();
22 let mut scheduler_rx = shutdown_rx.clone();
23 bg_handles.push(tokio::spawn(async move {
24 let mut interval = tokio::time::interval(Duration::from_secs(60));
25 loop {
26 tokio::select! {
27 _ = interval.tick() => {
28 if let Ok(count) = content::publish_scheduled(&scheduler_db) {
29 if count > 0 {
30 tracing::info!("Scheduled publisher: {} post(s) published", count);
31 }
32 }
33 }
34 _ = scheduler_rx.changed() => {
35 tracing::info!("Scheduled publisher stopping...");
36 break;
37 }
38 }
39 }
40 }));
41
42 if config.backup.auto_enabled {
44 let backup_config = config.backup.clone();
45 let backup_site_config = config.clone();
46 let mut backup_rx = shutdown_rx.clone();
47 bg_handles.push(tokio::spawn(async move {
48 let interval_secs = backup_config.interval_hours.max(1) * 3600;
49 let mut interval = tokio::time::interval(Duration::from_secs(interval_secs));
50 interval.tick().await;
52 loop {
53 tokio::select! {
54 _ = interval.tick() => {
55 let backup_dir = std::path::Path::new(&backup_config.directory);
56 match crate::cli::backup::create_backup(&backup_site_config, backup_dir) {
57 Ok(()) => {
58 tracing::info!("Auto-backup completed successfully");
59 let _ = crate::cli::backup::enforce_retention(
60 backup_dir,
61 backup_config.retention_count,
62 );
63 }
64 Err(e) => {
65 tracing::error!("Auto-backup failed: {}", e);
66 }
67 }
68 }
69 _ = backup_rx.changed() => {
70 tracing::info!("Auto-backup scheduler stopping...");
71 break;
72 }
73 }
74 }
75 }));
76 tracing::info!(
77 "Auto-backup enabled: every {} hours, keeping {} backups in {}",
78 config.backup.interval_hours,
79 config.backup.retention_count,
80 config.backup.directory
81 );
82 }
83
84 let addr = format!("{}:{}", host, port);
85 tracing::info!("Starting server at http://{}", addr);
86
87 web::serve(config, config_path.to_path_buf(), db, &addr, Some(shutdown_rx)).await?;
88
89 let _ = shutdown_tx.send(true);
91 for handle in bg_handles {
92 handle.abort();
93 }
94
95 Ok(())
96}