Add global stats to UI (not desktop yet)
This commit is contained in:
parent
ae606fac4a
commit
61b7a643aa
6 changed files with 89 additions and 11 deletions
|
|
@ -34,6 +34,21 @@ export interface Speed {
|
||||||
human_readable: string;
|
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
|
// Interface for the Torrent Stats API response
|
||||||
export interface LiveTorrentStats {
|
export interface LiveTorrentStats {
|
||||||
snapshot: {
|
snapshot: {
|
||||||
|
|
@ -46,14 +61,7 @@ export interface LiveTorrentStats {
|
||||||
remaining_bytes: number;
|
remaining_bytes: number;
|
||||||
total_bytes: number;
|
total_bytes: number;
|
||||||
total_piece_download_ms: number;
|
total_piece_download_ms: number;
|
||||||
peer_stats: {
|
peer_stats: AggregatePeerStats;
|
||||||
queued: number;
|
|
||||||
connecting: number;
|
|
||||||
live: number;
|
|
||||||
seen: number;
|
|
||||||
dead: number;
|
|
||||||
not_needed: number;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
average_piece_download_time: {
|
average_piece_download_time: {
|
||||||
secs: number;
|
secs: number;
|
||||||
|
|
@ -182,4 +190,5 @@ export interface RqbitAPI {
|
||||||
start: (index: number) => Promise<void>;
|
start: (index: number) => Promise<void>;
|
||||||
forget: (index: number) => Promise<void>;
|
forget: (index: number) => Promise<void>;
|
||||||
delete: (index: number) => Promise<void>;
|
delete: (index: number) => Promise<void>;
|
||||||
|
stats: () => Promise<SessionStats>;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
12
crates/librqbit/webui/src/components/Footer.tsx
Normal file
12
crates/librqbit/webui/src/components/Footer.tsx
Normal 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>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
@ -19,7 +19,9 @@ export const TorrentsList = (props: {
|
||||||
<p className="text-center">No existing torrents found.</p>
|
<p className="text-center">No existing torrents found.</p>
|
||||||
) : (
|
) : (
|
||||||
props.torrents.map((t: TorrentId) => (
|
props.torrents.map((t: TorrentId) => (
|
||||||
<Torrent id={t.id} key={t.id} torrent={t} />
|
<>
|
||||||
|
<Torrent id={t.id} key={t.id} torrent={t} />
|
||||||
|
</>
|
||||||
))
|
))
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import {
|
||||||
ErrorDetails,
|
ErrorDetails,
|
||||||
ListTorrentsResponse,
|
ListTorrentsResponse,
|
||||||
RqbitAPI,
|
RqbitAPI,
|
||||||
|
SessionStats,
|
||||||
TorrentDetails,
|
TorrentDetails,
|
||||||
TorrentStats,
|
TorrentStats,
|
||||||
} from "./api-types";
|
} from "./api-types";
|
||||||
|
|
@ -82,6 +83,9 @@ export const API: RqbitAPI & { getVersion: () => Promise<string> } = {
|
||||||
getTorrentStats: (index: number): Promise<TorrentStats> => {
|
getTorrentStats: (index: number): Promise<TorrentStats> => {
|
||||||
return makeRequest("GET", `/torrents/${index}/stats/v1`);
|
return makeRequest("GET", `/torrents/${index}/stats/v1`);
|
||||||
},
|
},
|
||||||
|
stats: (): Promise<SessionStats> => {
|
||||||
|
return makeRequest("GET", "/stats");
|
||||||
|
},
|
||||||
|
|
||||||
uploadTorrent: (data, opts): Promise<AddTorrentResponse> => {
|
uploadTorrent: (data, opts): Promise<AddTorrentResponse> => {
|
||||||
let url = "/torrents?&overwrite=true";
|
let url = "/torrents?&overwrite=true";
|
||||||
|
|
@ -152,6 +156,6 @@ export const API: RqbitAPI & { getVersion: () => Promise<string> } = {
|
||||||
return url;
|
return url;
|
||||||
},
|
},
|
||||||
getPlaylistUrl: (index: number) => {
|
getPlaylistUrl: (index: number) => {
|
||||||
return (apiUrl || window.origin) + `/torrents/${index}/playlist`;
|
return (apiUrl || window.origin) + `/torrents/${index}/playlist`;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,8 @@ import { DarkMode } from "./helper/darkMode";
|
||||||
import { useTorrentStore } from "./stores/torrentStore";
|
import { useTorrentStore } from "./stores/torrentStore";
|
||||||
import { useErrorStore } from "./stores/errorStore";
|
import { useErrorStore } from "./stores/errorStore";
|
||||||
import { AlertModal } from "./components/modal/AlertModal";
|
import { AlertModal } from "./components/modal/AlertModal";
|
||||||
|
import { useStatsStore } from "./stores/statsStore";
|
||||||
|
import { Footer } from "./components/Footer";
|
||||||
|
|
||||||
export interface ErrorWithLabel {
|
export interface ErrorWithLabel {
|
||||||
text: string;
|
text: string;
|
||||||
|
|
@ -49,6 +51,8 @@ export const RqbitWebUI = (props: {
|
||||||
};
|
};
|
||||||
setRefreshTorrents(refreshTorrents);
|
setRefreshTorrents(refreshTorrents);
|
||||||
|
|
||||||
|
const setStats = useStatsStore((state) => state.setStats);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
return customSetInterval(
|
return customSetInterval(
|
||||||
async () =>
|
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 (
|
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} />
|
<Header title={props.title} version={props.version} />
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
{/* Menu buttons */}
|
{/* Menu buttons */}
|
||||||
|
|
@ -82,10 +103,14 @@ export const RqbitWebUI = (props: {
|
||||||
<BsMoon />
|
<BsMoon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="grow">
|
||||||
<RootContent />
|
<RootContent />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<Footer />
|
||||||
|
|
||||||
<LogStreamModal show={logsOpened} onClose={() => setLogsOpened(false)} />
|
<LogStreamModal show={logsOpened} onClose={() => setLogsOpened(false)} />
|
||||||
<AlertModal />
|
<AlertModal />
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
26
crates/librqbit/webui/src/stores/statsStore.ts
Normal file
26
crates/librqbit/webui/src/stores/statsStore.ts
Normal 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 });
|
||||||
|
},
|
||||||
|
}));
|
||||||
Loading…
Add table
Add a link
Reference in a new issue