feat: Return network statistics and update the download statistics component layout.

This commit is contained in:
jarvis2f 2024-12-24 10:31:22 +08:00
parent a844c15ac8
commit 3ce64a3cc3
3 changed files with 95 additions and 33 deletions

View file

@ -410,7 +410,27 @@ public class TelegramVerticle extends AbstractVerticle {
} }
public Future<JsonObject> getDownloadStatistics() { public Future<JsonObject> getDownloadStatistics() {
return DataVerticle.fileRepository.getDownloadStatistics(this.telegramRecord.id()); return Future.all(DataVerticle.fileRepository.getDownloadStatistics(this.telegramRecord.id()),
this.execute(new TdApi.GetNetworkStatistics())
).map(r -> {
JsonObject jsonObject = r.resultAt(0);
TdApi.NetworkStatistics networkStatistics = r.resultAt(1);
Tuple2<Long, Long> bytes = Arrays.stream(networkStatistics.entries)
.filter(e -> e instanceof TdApi.NetworkStatisticsEntryFile)
.map(e -> {
TdApi.NetworkStatisticsEntryFile entry = (TdApi.NetworkStatisticsEntryFile) e;
return Tuple.tuple(entry.sentBytes, entry.receivedBytes);
})
.reduce((a, b) -> Tuple.tuple(a.v1 + b.v1, a.v2 + b.v2))
.orElse(Tuple.tuple(0L, 0L));
jsonObject.put("networkStatistics", JsonObject.of()
.put("sinceDate", networkStatistics.sinceDate)
.put("sentBytes", bytes.v1)
.put("receivedBytes", bytes.v2)
);
return jsonObject;
});
} }
public Future<TdApi.Proxy> enableProxy(String proxyName) { public Future<TdApi.Proxy> enableProxy(String proxyName) {

View file

@ -2,16 +2,20 @@ import React from "react";
import useSWR from "swr"; import useSWR from "swr";
import { import {
AlertTriangle, AlertTriangle,
CheckCircle, CloudDownload, CheckCircle,
CloudDownload,
Download, Download,
File, File,
FileText, FileText,
Image, Image,
Music, Music,
PauseCircle, Network,
PauseCircle, Upload,
Video, Video,
} from "lucide-react"; } from "lucide-react";
import { request } from "@/lib/api"; // Define a fetcher function to handle the API request import { request } from "@/lib/api";
import prettyBytes from "pretty-bytes";
import { formatDistanceToNow } from "date-fns"; // Define a fetcher function to handle the API request
// Interface defining the structure of the data returned from the API // Interface defining the structure of the data returned from the API
interface StatisticsData { interface StatisticsData {
@ -24,6 +28,11 @@ interface StatisticsData {
video: number; video: number;
audio: number; audio: number;
file: number; file: number;
networkStatistics: {
sinceDate: number;
sentBytes: number;
receivedBytes: number;
};
} }
// Props interface for the component, expecting a telegramId as input // Props interface for the component, expecting a telegramId as input
@ -100,8 +109,10 @@ const FileStatistics: React.FC<FileStatisticsProps> = ({ telegramId }) => {
<div className="space-y-6 rounded-lg bg-gray-50 p-6"> <div className="space-y-6 rounded-lg bg-gray-50 p-6">
<div className="flex-1 rounded-lg bg-white p-4 shadow-md"> <div className="flex-1 rounded-lg bg-white p-4 shadow-md">
<div className="flex items-center space-x-3 border-gray-200"> <div className="flex items-center space-x-3 border-gray-200">
<CloudDownload className="h-6 w-6 text-blue-600" /> <h3 className="text-md flex items-center space-x-2 font-semibold text-gray-700">
<h2 className="text-xl font-bold text-gray-800">Download Statistics</h2> <CloudDownload className="h-5 w-5 text-blue-600" />
<span>Download Statistics</span>
</h3>
</div> </div>
<div className="mt-4 grid grid-cols-2 gap-4 md:grid-cols-5"> <div className="mt-4 grid grid-cols-2 gap-4 md:grid-cols-5">
<div className="rounded-lg bg-gray-50 p-4 shadow-sm"> <div className="rounded-lg bg-gray-50 p-4 shadow-sm">
@ -109,7 +120,7 @@ const FileStatistics: React.FC<FileStatisticsProps> = ({ telegramId }) => {
<FileText className="h-5 w-5 text-gray-600" /> <FileText className="h-5 w-5 text-gray-600" />
<span className="text-sm text-gray-600">Total Files</span> <span className="text-sm text-gray-600">Total Files</span>
</div> </div>
<div className="mt-2 text-lg text-center font-semibold text-gray-800"> <div className="mt-2 text-center text-lg font-semibold text-gray-800">
{total} {total}
</div> </div>
</div> </div>
@ -118,7 +129,7 @@ const FileStatistics: React.FC<FileStatisticsProps> = ({ telegramId }) => {
<Download className="h-5 w-5 text-blue-600" /> <Download className="h-5 w-5 text-blue-600" />
<span className="text-sm text-gray-600">Downloading</span> <span className="text-sm text-gray-600">Downloading</span>
</div> </div>
<div className="mt-2 text-lg text-center font-semibold text-gray-800"> <div className="mt-2 text-center text-lg font-semibold text-gray-800">
{downloading} {downloading}
</div> </div>
</div> </div>
@ -127,7 +138,7 @@ const FileStatistics: React.FC<FileStatisticsProps> = ({ telegramId }) => {
<PauseCircle className="h-5 w-5 text-yellow-500" /> <PauseCircle className="h-5 w-5 text-yellow-500" />
<span className="text-sm text-gray-600">Paused</span> <span className="text-sm text-gray-600">Paused</span>
</div> </div>
<div className="mt-2 text-lg text-center font-semibold text-gray-800"> <div className="mt-2 text-center text-lg font-semibold text-gray-800">
{paused} {paused}
</div> </div>
</div> </div>
@ -136,7 +147,7 @@ const FileStatistics: React.FC<FileStatisticsProps> = ({ telegramId }) => {
<CheckCircle className="h-5 w-5 text-green-600" /> <CheckCircle className="h-5 w-5 text-green-600" />
<span className="text-sm text-gray-600">Completed</span> <span className="text-sm text-gray-600">Completed</span>
</div> </div>
<div className="mt-2 text-lg text-center font-semibold text-gray-800"> <div className="mt-2 text-center text-lg font-semibold text-gray-800">
{completed} {completed}
</div> </div>
</div> </div>
@ -145,34 +156,65 @@ const FileStatistics: React.FC<FileStatisticsProps> = ({ telegramId }) => {
<AlertTriangle className="h-5 w-5 text-red-600" /> <AlertTriangle className="h-5 w-5 text-red-600" />
<span className="text-sm text-gray-600">Error</span> <span className="text-sm text-gray-600">Error</span>
</div> </div>
<div className="mt-2 text-lg text-center font-semibold text-gray-800"> <div className="mt-2 text-center text-lg font-semibold text-gray-800">
{errorCount} {errorCount}
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div className="flex-1 rounded-lg bg-white p-4 shadow-md"> <div className="grid grid-cols-1 gap-6 md:grid-cols-3">
<h3 className="text-md flex items-center space-x-2 font-semibold text-gray-700"> <div className="flex-1 rounded-lg bg-white p-4 shadow-md md:col-span-2">
<CheckCircle className="h-5 w-5 text-green-600" /> <h3 className="text-md flex items-center space-x-2 font-semibold text-gray-700">
<span>Completed by Type</span> <CheckCircle className="h-5 w-5 text-green-600" />
</h3> <span>Completed by Type</span>
<ul className="mt-4 grid grid-cols-2 gap-4"> </h3>
{completedTypes.map((type) => ( <ul className="mt-4 grid grid-cols-2 gap-4">
<li {completedTypes.map((type) => (
key={type.label} <li
className="rounded-lg bg-gray-50 p-3 shadow-sm" key={type.label}
> className="rounded-lg bg-gray-50 p-3 shadow-sm"
<div className="flex items-center space-x-2"> >
{type.icon} <div className="flex items-center space-x-2">
<span className="text-sm text-gray-600">{type.label}</span> {type.icon}
</div> <span className="text-sm text-gray-600">{type.label}</span>
<div className="mt-2 text-lg font-semibold text-gray-800"> </div>
{type.value} <div className="mt-2 text-lg font-semibold text-gray-800">
</div> {type.value}
</li> </div>
))} </li>
</ul> ))}
</ul>
</div>
<div className="flex-1 rounded-lg bg-white p-4 shadow-md">
<h3 className="text-md flex items-center space-x-2 font-semibold text-gray-700">
<Network className="h-5 w-5 text-gray-500" />
<span>Network Statistics</span>
</h3>
<div className="mt-4 h-full">
<div className="flex justify-center items-center space-x-2 rounded-lg bg-gray-50 p-4 shadow-sm">
<Upload className="h-5 w-5 text-yellow-500" />
<span className="text-lg font-semibold text-gray-800">
{prettyBytes(data.networkStatistics.sentBytes)}
</span>
</div>
<div className="mt-4 flex justify-center items-center space-x-2 rounded-lg bg-gray-50 p-4 shadow-sm">
<Download className="h-5 w-5 text-blue-600" />
<span className="text-lg font-semibold text-gray-800">
{prettyBytes(data.networkStatistics.receivedBytes)}
</span>
</div>
<p className="mt-2 text-right text-sm text-gray-400">
Since: {formatDistanceToNow(
new Date(data.networkStatistics.sinceDate * 1000),
{
addSuffix: true,
},
)}
</p>
</div>
</div>
</div> </div>
</div> </div>
); );

View file

@ -53,7 +53,7 @@ export const SettingsDialog: React.FC = () => {
<SettingsForm /> <SettingsForm />
</TabsContent> </TabsContent>
<TabsContent value="statistics" className="h-full overflow-hidden"> <TabsContent value="statistics" className="h-full overflow-hidden">
<div className="flex flex-col overflow-y-scroll"> <div className="h-full flex flex-col overflow-y-scroll">
{accountId ? ( {accountId ? (
<FileStatistics telegramId={accountId} /> <FileStatistics telegramId={accountId} />
) : ( ) : (