From a843208422f7f942852665c788d52e14bbe5f06d Mon Sep 17 00:00:00 2001 From: rattatwinko Date: Fri, 27 Jun 2025 20:30:40 +0200 Subject: [PATCH] shitfuck --- markdown_backend/src/main.rs | 7 ++ markdown_backend/src/markdown.rs | 78 +++++++++++++++++++- src/app/admin/manage/rust-status/page.tsx | 89 ++++++++++++++++++++++- src/app/api/admin/posts/route.ts | 20 +++++ 4 files changed, 192 insertions(+), 2 deletions(-) diff --git a/markdown_backend/src/main.rs b/markdown_backend/src/main.rs index 176d972..b1663cb 100644 --- a/markdown_backend/src/main.rs +++ b/markdown_backend/src/main.rs @@ -1,3 +1,4 @@ +#[warn(unused_imports)] use clap::{Parser, Subcommand}; mod markdown; use markdown::{get_all_posts, get_post_by_slug, get_posts_by_tag, watch_posts}; @@ -28,6 +29,8 @@ enum Commands { Watch, /// Show Rust parser statistics Rsparseinfo, + /// Check backend health + Checkhealth, } fn main() { @@ -73,5 +76,9 @@ fn main() { Commands::Rsparseinfo => { println!("{}", markdown::rsparseinfo()); } + Commands::Checkhealth => { + let health = markdown::checkhealth(); + println!("{}", serde_json::to_string_pretty(&health).unwrap()); + } } } \ No newline at end of file diff --git a/markdown_backend/src/markdown.rs b/markdown_backend/src/markdown.rs index db93bcf..2dfb905 100644 --- a/markdown_backend/src/markdown.rs +++ b/markdown_backend/src/markdown.rs @@ -8,7 +8,7 @@ BLAZINGLY FAST! */ - +#[warn(unused_imports)] use std::fs; use std::path::{Path, PathBuf}; use chrono::{DateTime, Utc}; @@ -29,6 +29,7 @@ use std::collections::HashMap; use std::sync::RwLock; use serde_json; use sysinfo::{System, Pid, RefreshKind, CpuRefreshKind, ProcessRefreshKind}; +use serde::Serialize; const POSTS_CACHE_PATH: &str = "./cache/posts_cache.json"; const POST_STATS_PATH: &str = "./cache/post_stats.json"; @@ -68,6 +69,19 @@ static POST_CACHE: Lazy>> = Lazy::new(|| RwLock::ne static ALL_POSTS_CACHE: Lazy>>> = Lazy::new(|| RwLock::new(None)); static POST_STATS: Lazy>> = Lazy::new(|| RwLock::new(HashMap::new())); +#[derive(Debug, Serialize)] +pub struct HealthReport { + pub posts_dir_exists: bool, + pub posts_count: usize, + pub cache_file_exists: bool, + pub cache_stats_file_exists: bool, + pub cache_readable: bool, + pub cache_stats_readable: bool, + pub cache_post_count: Option, + pub cache_stats_count: Option, + pub errors: Vec, +} + fn get_posts_directory() -> PathBuf { let candidates = [ "./posts", @@ -439,4 +453,66 @@ pub fn save_post_cache_to_disk() { let _ = fs::create_dir_all("./cache"); let _ = fs::write(POST_STATS_PATH, map); } +} + +pub fn checkhealth() -> HealthReport { + let mut errors = Vec::new(); + let posts_dir = get_posts_directory(); + let posts_dir_exists = posts_dir.exists() && posts_dir.is_dir(); + let mut posts_count = 0; + if posts_dir_exists { + match std::fs::read_dir(&posts_dir) { + Ok(entries) => { + posts_count = entries.filter_map(|e| e.ok()) + .filter(|e| e.path().extension().map(|ext| ext == "md").unwrap_or(false)) + .count(); + }, + Err(e) => errors.push(format!("Failed to read posts dir: {}", e)), + } + } else { + errors.push("Posts directory does not exist".to_string()); + } + let cache_file_exists = Path::new(POSTS_CACHE_PATH).exists(); + let cache_stats_file_exists = Path::new(POST_STATS_PATH).exists(); + let (mut cache_readable, mut cache_post_count) = (false, None); + if cache_file_exists { + match std::fs::read_to_string(POSTS_CACHE_PATH) { + Ok(data) => { + match serde_json::from_str::>(&data) { + Ok(map) => { + cache_readable = true; + cache_post_count = Some(map.len()); + }, + Err(e) => errors.push(format!("Cache file not valid JSON: {}", e)), + } + }, + Err(e) => errors.push(format!("Failed to read cache file: {}", e)), + } + } + let (mut cache_stats_readable, mut cache_stats_count) = (false, None); + if cache_stats_file_exists { + match std::fs::read_to_string(POST_STATS_PATH) { + Ok(data) => { + match serde_json::from_str::>(&data) { + Ok(map) => { + cache_stats_readable = true; + cache_stats_count = Some(map.len()); + }, + Err(e) => errors.push(format!("Cache stats file not valid JSON: {}", e)), + } + }, + Err(e) => errors.push(format!("Failed to read cache stats file: {}", e)), + } + } + HealthReport { + posts_dir_exists, + posts_count, + cache_file_exists, + cache_stats_file_exists, + cache_readable, + cache_stats_readable, + cache_post_count, + cache_stats_count, + errors, + } } \ No newline at end of file diff --git a/src/app/admin/manage/rust-status/page.tsx b/src/app/admin/manage/rust-status/page.tsx index 315092e..de4aabd 100644 --- a/src/app/admin/manage/rust-status/page.tsx +++ b/src/app/admin/manage/rust-status/page.tsx @@ -9,10 +9,25 @@ interface PostStats { last_compile_time_ms: number; } +interface HealthReport { + posts_dir_exists: boolean; + posts_count: number; + cache_file_exists: boolean; + cache_stats_file_exists: boolean; + cache_readable: boolean; + cache_stats_readable: boolean; + cache_post_count?: number; + cache_stats_count?: number; + errors: string[]; +} + export default function RustStatusPage() { const [stats, setStats] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); + const [health, setHealth] = useState(null); + const [healthLoading, setHealthLoading] = useState(true); + const [healthError, setHealthError] = useState(null); // Summary calculations const totalHits = stats.reduce((sum, s) => sum + s.cache_hits, 0); @@ -35,8 +50,24 @@ export default function RustStatusPage() { } }; + const fetchHealth = async () => { + setHealthLoading(true); + setHealthError(null); + try { + const res = await fetch('/api/admin/posts?checkhealth=1'); + if (!res.ok) throw new Error('Fehler beim Laden des Health-Checks'); + const data = await res.json(); + setHealth(data); + } catch (e: any) { + setHealthError(e.message || 'Unbekannter Fehler'); + } finally { + setHealthLoading(false); + } + }; + useEffect(() => { fetchStats(); + fetchHealth(); }, []); return ( @@ -88,7 +119,63 @@ export default function RustStatusPage() { - {/* Rest of your component remains the same */} + {/* Health Check Section */} +
+

Health-Check

+ {healthLoading &&
Lade Health-Check...
} + {healthError &&
{healthError}
} + {health && ( +
+
+
+ {health.posts_dir_exists ? '✔' : '✖'} + Posts-Verzeichnis +
+
+ {health.posts_count} + Posts +
+
+ {health.cache_file_exists ? '✔' : '✖'} + Cache-Datei +
+
+ {health.cache_stats_file_exists ? '✔' : '✖'} + Cache-Stats +
+
+ {health.cache_readable ? '✔' : '✖'} + Cache lesbar +
+
+ {health.cache_stats_readable ? '✔' : '✖'} + Stats lesbar +
+ {typeof health.cache_post_count === 'number' && ( +
+ {health.cache_post_count} + Cache-Posts +
+ )} + {typeof health.cache_stats_count === 'number' && ( +
+ {health.cache_stats_count} + Stats-Einträge +
+ )} +
+ {health.errors.length > 0 && ( +
+ Fehler: +
    + {health.errors.map((err, i) =>
  • {err}
  • )} +
+
+ )} +
+ )} +
+ {/* Summary Cards */}
diff --git a/src/app/api/admin/posts/route.ts b/src/app/api/admin/posts/route.ts index b2397c7..4b2fd27 100644 --- a/src/app/api/admin/posts/route.ts +++ b/src/app/api/admin/posts/route.ts @@ -70,6 +70,26 @@ export async function GET(request: Request) { }); } } + const checkhealth = searchParams.get('checkhealth'); + if (checkhealth === '1') { + // Call the Rust backend for health check + const rustResult = spawnSync( + process.cwd() + '/markdown_backend/target/release/markdown_backend', + ['checkhealth'], + { encoding: 'utf-8' } + ); + if (rustResult.status === 0 && rustResult.stdout) { + return new Response(rustResult.stdout, { + status: 200, + headers: { 'Content-Type': 'application/json' }, + }); + } else { + return new Response(JSON.stringify({ error: rustResult.stderr || rustResult.error }), { + status: 500, + headers: { 'Content-Type': 'application/json' }, + }); + } + } // Return the current pinned.json object try { const pinnedPath = path.join(process.cwd(), 'posts', 'pinned.json');