This commit is contained in:
2025-06-27 20:30:40 +02:00
parent 8463edd262
commit a843208422
4 changed files with 192 additions and 2 deletions

View File

@@ -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<PostStats[]>([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
const [health, setHealth] = useState<HealthReport | null>(null);
const [healthLoading, setHealthLoading] = useState(true);
const [healthError, setHealthError] = useState<string | null>(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() {
</div>
</div>
{/* Rest of your component remains the same */}
{/* Health Check Section */}
<div className="mb-6">
<h2 className="text-base sm:text-lg font-semibold mb-2">Health-Check</h2>
{healthLoading && <div className="text-center py-4 text-base">Lade Health-Check...</div>}
{healthError && <div className="text-red-500 text-center text-base">{healthError}</div>}
{health && (
<div className="bg-white rounded-lg shadow p-4 flex flex-col gap-2">
<div className="flex flex-wrap gap-4">
<div className="flex flex-col items-center">
<span className={`text-lg font-bold ${health.posts_dir_exists ? 'text-green-700' : 'text-red-700'}`}>{health.posts_dir_exists ? '✔' : '✖'}</span>
<span className="text-xs text-gray-600">Posts-Verzeichnis</span>
</div>
<div className="flex flex-col items-center">
<span className="text-lg font-bold text-blue-700">{health.posts_count}</span>
<span className="text-xs text-gray-600">Posts</span>
</div>
<div className="flex flex-col items-center">
<span className={`text-lg font-bold ${health.cache_file_exists ? 'text-green-700' : 'text-red-700'}`}>{health.cache_file_exists ? '✔' : '✖'}</span>
<span className="text-xs text-gray-600">Cache-Datei</span>
</div>
<div className="flex flex-col items-center">
<span className={`text-lg font-bold ${health.cache_stats_file_exists ? 'text-green-700' : 'text-red-700'}`}>{health.cache_stats_file_exists ? '✔' : '✖'}</span>
<span className="text-xs text-gray-600">Cache-Stats</span>
</div>
<div className="flex flex-col items-center">
<span className={`text-lg font-bold ${health.cache_readable ? 'text-green-700' : 'text-red-700'}`}>{health.cache_readable ? '✔' : '✖'}</span>
<span className="text-xs text-gray-600">Cache lesbar</span>
</div>
<div className="flex flex-col items-center">
<span className={`text-lg font-bold ${health.cache_stats_readable ? 'text-green-700' : 'text-red-700'}`}>{health.cache_stats_readable ? '✔' : '✖'}</span>
<span className="text-xs text-gray-600">Stats lesbar</span>
</div>
{typeof health.cache_post_count === 'number' && (
<div className="flex flex-col items-center">
<span className="text-lg font-bold text-blue-700">{health.cache_post_count}</span>
<span className="text-xs text-gray-600">Cache-Posts</span>
</div>
)}
{typeof health.cache_stats_count === 'number' && (
<div className="flex flex-col items-center">
<span className="text-lg font-bold text-blue-700">{health.cache_stats_count}</span>
<span className="text-xs text-gray-600">Stats-Einträge</span>
</div>
)}
</div>
{health.errors.length > 0 && (
<div className="mt-2 text-red-600 text-xs">
<b>Fehler:</b>
<ul className="list-disc ml-5">
{health.errors.map((err, i) => <li key={i}>{err}</li>)}
</ul>
</div>
)}
</div>
)}
</div>
{/* Summary Cards */}
<div className="grid grid-cols-2 sm:grid-cols-4 gap-3 sm:gap-4 mb-6">
<div className="bg-green-100 rounded-lg p-4 flex flex-col items-center shadow">

View File

@@ -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');