Add global stats to UI (not desktop yet)

This commit is contained in:
Igor Katson 2024-08-21 12:58:15 +01:00
parent ae606fac4a
commit 61b7a643aa
No known key found for this signature in database
GPG key ID: B4EC22B66D61A3F5
6 changed files with 89 additions and 11 deletions

View file

@ -34,6 +34,21 @@ export interface Speed {
human_readable: string;
}
export interface AggregatePeerStats {
queued: number;
connecting: number;
live: number;
seen: number;
dead: number;
not_needed: number;
}
export interface SessionStats {
download_speed: Speed;
upload_speed: Speed;
peers: AggregatePeerStats;
}
// Interface for the Torrent Stats API response
export interface LiveTorrentStats {
snapshot: {
@ -46,14 +61,7 @@ export interface LiveTorrentStats {
remaining_bytes: number;
total_bytes: number;
total_piece_download_ms: number;
peer_stats: {
queued: number;
connecting: number;
live: number;
seen: number;
dead: number;
not_needed: number;
};
peer_stats: AggregatePeerStats;
};
average_piece_download_time: {
secs: number;
@ -182,4 +190,5 @@ export interface RqbitAPI {
start: (index: number) => Promise<void>;
forget: (index: number) => Promise<void>;
delete: (index: number) => Promise<void>;
stats: () => Promise<SessionStats>;
}

View file

@ -0,0 +1,12 @@
import { useStatsStore } from "../stores/statsStore";
import { Speed } from "./Speed";
export const Footer: React.FC<{}> = () => {
let stats = useStatsStore((stats) => stats.stats);
return (
<div className="sticky bottom-0 bg-white/10 dark:text-gray-200 backdrop-blur text-nowrap text-xs font-medium text-gray-500 flex p-1 gap-x-3 justify-center">
<div> {stats.download_speed.human_readable}</div>
<div> {stats.upload_speed.human_readable}</div>
</div>
);
};

View file

@ -19,7 +19,9 @@ export const TorrentsList = (props: {
<p className="text-center">No existing torrents found.</p>
) : (
props.torrents.map((t: TorrentId) => (
<Torrent id={t.id} key={t.id} torrent={t} />
<>
<Torrent id={t.id} key={t.id} torrent={t} />
</>
))
)}
</div>

View file

@ -3,6 +3,7 @@ import {
ErrorDetails,
ListTorrentsResponse,
RqbitAPI,
SessionStats,
TorrentDetails,
TorrentStats,
} from "./api-types";
@ -82,6 +83,9 @@ export const API: RqbitAPI & { getVersion: () => Promise<string> } = {
getTorrentStats: (index: number): Promise<TorrentStats> => {
return makeRequest("GET", `/torrents/${index}/stats/v1`);
},
stats: (): Promise<SessionStats> => {
return makeRequest("GET", "/stats");
},
uploadTorrent: (data, opts): Promise<AddTorrentResponse> => {
let url = "/torrents?&overwrite=true";
@ -152,6 +156,6 @@ export const API: RqbitAPI & { getVersion: () => Promise<string> } = {
return url;
},
getPlaylistUrl: (index: number) => {
return (apiUrl || window.origin) + `/torrents/${index}/playlist`;
return (apiUrl || window.origin) + `/torrents/${index}/playlist`;
},
};

View file

@ -11,6 +11,8 @@ import { DarkMode } from "./helper/darkMode";
import { useTorrentStore } from "./stores/torrentStore";
import { useErrorStore } from "./stores/errorStore";
import { AlertModal } from "./components/modal/AlertModal";
import { useStatsStore } from "./stores/statsStore";
import { Footer } from "./components/Footer";
export interface ErrorWithLabel {
text: string;
@ -49,6 +51,8 @@ export const RqbitWebUI = (props: {
};
setRefreshTorrents(refreshTorrents);
const setStats = useStatsStore((state) => state.setStats);
useEffect(() => {
return customSetInterval(
async () =>
@ -67,8 +71,25 @@ export const RqbitWebUI = (props: {
);
}, []);
useEffect(() => {
return customSetInterval(
async () =>
API.stats().then(
(stats) => {
setStats(stats);
return 1000;
},
(e) => {
console.error(e);
return 5000;
}
),
0
);
}, []);
return (
<div className="dark:bg-gray-900 dark:text-gray-200 min-h-screen">
<div className="dark:bg-gray-900 dark:text-gray-200 min-h-screen flex flex-col">
<Header title={props.title} version={props.version} />
<div className="relative">
{/* Menu buttons */}
@ -82,10 +103,14 @@ export const RqbitWebUI = (props: {
<BsMoon />
</IconButton>
</div>
</div>
<div className="grow">
<RootContent />
</div>
<Footer />
<LogStreamModal show={logsOpened} onClose={() => setLogsOpened(false)} />
<AlertModal />
</div>

View file

@ -0,0 +1,26 @@
import { create } from "zustand";
import { SessionStats } from "../api-types";
export interface StatsStore {
stats: SessionStats;
setStats: (stats: SessionStats) => void;
}
export const useStatsStore = create<StatsStore>((set) => ({
stats: {
download_speed: { human_readable: "N/A", mbps: 0 },
upload_speed: { human_readable: "N/A", mbps: 0 },
peers: {
connecting: 0,
dead: 0,
live: 0,
not_needed: 0,
queued: 0,
seen: 0,
},
},
setStats: (stats) => {
set({ stats });
},
}));