fix(server): hata yönetimini ve dayanıklılığı iyileştir

Loop scheduler ve timer worker için hata yakalama ekle. qBit client'ta
geçici ağ hatalarını tanıyarak login durumunu sıfırla. Scheduler
hatalarında durum güncellemesi gönder ve timer worker crash önle.
This commit is contained in:
2026-01-31 11:25:51 +03:00
parent 9b495b7bf7
commit 967eb2d2a4
5 changed files with 6097 additions and 356 deletions

View File

@@ -2,6 +2,7 @@ import React, { useEffect, useMemo, useState } from "react";
import { Card, CardContent, CardHeader, CardTitle } from "../components/ui/Card";
import { Button } from "../components/ui/Button";
import { Input } from "../components/ui/Input";
import { ScrollArea } from "../components/ui/ScrollArea";
import { api } from "../api/client";
import { useAppStore } from "../store/useAppStore";
import { useUiStore } from "../store/useUiStore";
@@ -360,13 +361,21 @@ export const TimerPage = () => {
<SelectItem
key={option.value}
value={option.value}
onClick={() => {
onPointerDown={() => {
if (option.value === sortKey) {
setSortDirection((current) =>
current === "asc" ? "desc" : "asc"
);
}
}}
onKeyDown={(event) => {
if (option.value !== sortKey) return;
if (event.key === "Enter" || event.key === " ") {
setSortDirection((current) =>
current === "asc" ? "desc" : "asc"
);
}
}}
>
{option.label}
</SelectItem>
@@ -435,39 +444,43 @@ export const TimerPage = () => {
Silinen Torrent Logları
</CardTitle>
</CardHeader>
<CardContent className="space-y-3">
<CardContent className="space-y-3 overflow-hidden">
{timerLogs.length === 0 ? (
<div className="text-sm text-slate-500">Henüz log yok.</div>
) : (
<div className="space-y-3">
{timerLogs.map((log) => (
<div
key={log.id}
className="rounded-lg border border-slate-200 bg-white px-3 py-2"
>
<div className="flex items-start justify-between gap-3">
<div>
<div className="text-sm font-semibold text-slate-900">
{log.name}
<div className="overflow-hidden" style={{ height: 560 }}>
<ScrollArea className="h-full w-full" type="always">
<div className="space-y-3 pr-3">
{timerLogs.map((log) => (
<div
key={log.id}
className="rounded-lg border border-slate-200 bg-white px-3 py-2"
>
<div className="flex items-start justify-between gap-3">
<div>
<div className="text-sm font-semibold text-slate-900">
{log.name}
</div>
<div className="text-xs text-slate-500">
{formatBytes(log.sizeBytes)} {" "}
{trackerLabel(log.tracker)}
</div>
</div>
<div className="text-xs text-slate-400">
{new Date(log.deletedAt).toLocaleString()}
</div>
</div>
<div className="text-xs text-slate-500">
{formatBytes(log.sizeBytes)} {" "}
{trackerLabel(log.tracker)}
<div className="mt-2 flex flex-wrap gap-2 text-xs text-slate-600">
<span>Seed: {formatDuration(log.seedingTimeSeconds)}</span>
<span>Upload: {formatBytes(log.uploadedBytes)}</span>
{log.tags?.length ? (
<span>Tags: {log.tags.join(", ")}</span>
) : null}
</div>
</div>
<div className="text-xs text-slate-400">
{new Date(log.deletedAt).toLocaleString()}
</div>
</div>
<div className="mt-2 flex flex-wrap gap-2 text-xs text-slate-600">
<span>Seed: {formatDuration(log.seedingTimeSeconds)}</span>
<span>Upload: {formatBytes(log.uploadedBytes)}</span>
{log.tags?.length ? (
<span>Tags: {log.tags.join(", ")}</span>
) : null}
</div>
))}
</div>
))}
</ScrollArea>
</div>
)}
</CardContent>