⚡️ feat: Optimize websocket binding method, optimize download speed event current limit
This commit is contained in:
parent
23c5758e0f
commit
d3f81c9a14
9 changed files with 234 additions and 158 deletions
|
|
@ -110,7 +110,7 @@ public class AutoDownloadVerticle extends AbstractVerticle {
|
|||
});
|
||||
vertx.eventBus().consumer(EventEnum.SETTING_UPDATE.address(SettingKey.autoDownloadLimit.name()), message -> {
|
||||
log.debug("Auto download limit update: %s".formatted(message.body()));
|
||||
this.limit = Convert.toInt(message.body());
|
||||
this.limit = Convert.toInt(message.body(), DEFAULT_LIMIT);
|
||||
});
|
||||
vertx.eventBus().consumer(EventEnum.MESSAGE_RECEIVED.address(), message -> {
|
||||
log.trace("Auto download message received: %s".formatted(message.body()));
|
||||
|
|
|
|||
|
|
@ -23,6 +23,14 @@ public enum EventEnum {
|
|||
* body = JSONObject with "telegramId", "chatId", "messageId"
|
||||
*/
|
||||
MESSAGE_RECEIVED,
|
||||
|
||||
/**
|
||||
* suffix = null <br>
|
||||
* body = JSONObject with "telegramId", "payload"
|
||||
*
|
||||
* @see telegram.files.EventPayload
|
||||
*/
|
||||
TELEGRAM_EVENT,
|
||||
;
|
||||
|
||||
public String address() {
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import io.vertx.core.http.CookieSameSite;
|
|||
import io.vertx.core.http.HttpMethod;
|
||||
import io.vertx.core.http.HttpServerOptions;
|
||||
import io.vertx.core.http.HttpServerResponse;
|
||||
import io.vertx.core.json.Json;
|
||||
import io.vertx.core.json.JsonArray;
|
||||
import io.vertx.core.json.JsonObject;
|
||||
import io.vertx.ext.healthchecks.HealthCheckHandler;
|
||||
|
|
@ -55,6 +56,7 @@ public class HttpVerticle extends AbstractVerticle {
|
|||
initHttpServer()
|
||||
.compose(r -> initTelegramVerticles())
|
||||
.compose(r -> initAutoDownloadVerticle())
|
||||
.compose(r -> initEventConsumer())
|
||||
.onSuccess(startPromise::complete)
|
||||
.onFailure(startPromise::fail);
|
||||
}
|
||||
|
|
@ -216,12 +218,37 @@ public class HttpVerticle extends AbstractVerticle {
|
|||
.mapEmpty();
|
||||
}
|
||||
|
||||
private Future<Void> initEventConsumer() {
|
||||
vertx.eventBus().consumer(EventEnum.TELEGRAM_EVENT.address(), message -> {
|
||||
log.debug("Received telegram event: %s".formatted(message.body()));
|
||||
JsonObject jsonObject = (JsonObject) message.body();
|
||||
String telegramId = jsonObject.getString("telegramId");
|
||||
EventPayload payload = jsonObject.getJsonObject("payload").mapTo(EventPayload.class);
|
||||
|
||||
sessionTelegramVerticles.entrySet().stream()
|
||||
.filter(e -> Objects.equals(Convert.toStr(e.getValue().getId()), telegramId))
|
||||
.map(Map.Entry::getKey)
|
||||
.forEach(sessionId -> {
|
||||
String wsHandlerId = clients.get(sessionId);
|
||||
if (StrUtil.isNotBlank(wsHandlerId)) {
|
||||
vertx.eventBus().send(wsHandlerId, Json.encode(payload));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return Future.succeededFuture();
|
||||
}
|
||||
|
||||
private void handleWebSocket(RoutingContext ctx) {
|
||||
String sessionId = ctx.session().id();
|
||||
String telegramId = ctx.request().getParam("telegramId");
|
||||
ctx.request().toWebSocket()
|
||||
.onSuccess(ws -> {
|
||||
log.debug("Upgraded to WebSocket. SessionId: %s".formatted(sessionId));
|
||||
clients.put(sessionId, ws.textHandlerID());
|
||||
if (StrUtil.isNotBlank(telegramId) && !handleTelegramChange(sessionId, telegramId)) {
|
||||
log.debug("Failed to change telegram verticle. SessionId: %s".formatted(sessionId));
|
||||
}
|
||||
|
||||
long timerId = vertx.setPeriodic(30000, id -> {
|
||||
if (!ws.isClosed()) {
|
||||
|
|
@ -237,9 +264,7 @@ public class HttpVerticle extends AbstractVerticle {
|
|||
log.debug("WebSocket closed. SessionId: %s".formatted(sessionId));
|
||||
});
|
||||
|
||||
ws.textMessageHandler(text -> {
|
||||
log.debug("Received WebSocket message: " + text);
|
||||
});
|
||||
ws.textMessageHandler(text -> log.debug("Received WebSocket message: " + text));
|
||||
})
|
||||
.onFailure(err -> log.warn("Failed to upgrade to WebSocket: %s".formatted(err.getMessage())));
|
||||
}
|
||||
|
|
@ -303,7 +328,6 @@ public class HttpVerticle extends AbstractVerticle {
|
|||
String proxyName = jsonObject.getString("proxyName");
|
||||
|
||||
TelegramVerticle newTelegramVerticle = new TelegramVerticle(DataVerticle.telegramRepository.getRootPath());
|
||||
newTelegramVerticle.bindHttpSession(sessionId);
|
||||
newTelegramVerticle.setProxy(proxyName);
|
||||
sessionTelegramVerticles.put(sessionId, newTelegramVerticle);
|
||||
telegramVerticles.add(newTelegramVerticle);
|
||||
|
|
@ -356,11 +380,10 @@ public class HttpVerticle extends AbstractVerticle {
|
|||
String query = ctx.request().getParam("query");
|
||||
String chatId = ctx.request().getParam("chatId");
|
||||
getTelegramVerticle(telegramId)
|
||||
.ifPresentOrElse(telegramVerticle -> {
|
||||
telegramVerticle.getChats(Convert.toLong(chatId), query)
|
||||
.onSuccess(ctx::json)
|
||||
.onFailure(ctx::fail);
|
||||
}, () -> ctx.fail(404));
|
||||
.ifPresentOrElse(telegramVerticle ->
|
||||
telegramVerticle.getChats(Convert.toLong(chatId), query)
|
||||
.onSuccess(ctx::json)
|
||||
.onFailure(ctx::fail), () -> ctx.fail(404));
|
||||
}
|
||||
|
||||
private void handleTelegramFiles(RoutingContext ctx) {
|
||||
|
|
@ -427,16 +450,24 @@ public class HttpVerticle extends AbstractVerticle {
|
|||
private void handleTelegramChange(RoutingContext ctx) {
|
||||
String sessionId = ctx.session().id();
|
||||
String telegramId = ctx.request().getParam("telegramId");
|
||||
if (handleTelegramChange(sessionId, telegramId)) {
|
||||
ctx.end();
|
||||
} else {
|
||||
ctx.fail(400);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean handleTelegramChange(String sessionId, String telegramId) {
|
||||
if (StrUtil.isBlank(telegramId)) {
|
||||
sessionTelegramVerticles.remove(sessionId);
|
||||
ctx.end();
|
||||
return true;
|
||||
}
|
||||
getTelegramVerticle(telegramId)
|
||||
.ifPresentOrElse(telegramVerticle -> {
|
||||
telegramVerticle.bindHttpSession(sessionId);
|
||||
sessionTelegramVerticles.put(sessionId, telegramVerticle);
|
||||
ctx.end();
|
||||
}, () -> ctx.fail(404));
|
||||
Optional<TelegramVerticle> optionalTelegramVerticle = getTelegramVerticle(telegramId);
|
||||
if (optionalTelegramVerticle.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
sessionTelegramVerticles.put(sessionId, optionalTelegramVerticle.get());
|
||||
return true;
|
||||
}
|
||||
|
||||
private void handleTelegramToggleProxy(RoutingContext ctx) {
|
||||
|
|
@ -478,13 +509,11 @@ public class HttpVerticle extends AbstractVerticle {
|
|||
ctx.fail(400);
|
||||
return;
|
||||
}
|
||||
String sessionId = ctx.session().id();
|
||||
TelegramVerticle telegramVerticle = getTelegramVerticle(ctx);
|
||||
if (telegramVerticle == null) {
|
||||
return;
|
||||
}
|
||||
JsonObject params = ctx.body().asJsonObject();
|
||||
telegramVerticle.bindHttpSession(sessionId);
|
||||
telegramVerticle.execute(method, params == null ? null : params.getMap())
|
||||
.onSuccess(code -> ctx.json(JsonObject.of("code", code)))
|
||||
.onFailure(ctx::fail);
|
||||
|
|
@ -637,10 +666,6 @@ public class HttpVerticle extends AbstractVerticle {
|
|||
.findFirst();
|
||||
}
|
||||
|
||||
public static String getWSHandlerId(String sessionId) {
|
||||
return clients.get(sessionId);
|
||||
}
|
||||
|
||||
private TelegramVerticle getTelegramVerticle(RoutingContext ctx) {
|
||||
String sessionId = ctx.session().id();
|
||||
TelegramVerticle telegramVerticle = sessionTelegramVerticles.get(sessionId);
|
||||
|
|
|
|||
|
|
@ -42,8 +42,6 @@ public class TelegramVerticle extends AbstractVerticle {
|
|||
|
||||
private Client client;
|
||||
|
||||
private volatile String httpSessionId;
|
||||
|
||||
public boolean authorized = false;
|
||||
|
||||
public TdApi.AuthorizationState lastAuthorizationState;
|
||||
|
|
@ -62,6 +60,10 @@ public class TelegramVerticle extends AbstractVerticle {
|
|||
|
||||
private long avgSpeedPersistenceTimerId;
|
||||
|
||||
private long lastFileEventTime;
|
||||
|
||||
private long lastFileDownloadEventTime;
|
||||
|
||||
static {
|
||||
Client.setLogMessageHandler(0, new LogMessageHandler());
|
||||
|
||||
|
|
@ -137,10 +139,6 @@ public class TelegramVerticle extends AbstractVerticle {
|
|||
return true;
|
||||
}
|
||||
|
||||
public void bindHttpSession(String httpSessionId) {
|
||||
this.httpSessionId = httpSessionId;
|
||||
}
|
||||
|
||||
public Future<JsonObject> getTelegramAccount() {
|
||||
return Future.future(promise -> {
|
||||
if (!authorized) {
|
||||
|
|
@ -441,11 +439,6 @@ public class TelegramVerticle extends AbstractVerticle {
|
|||
|
||||
return this.execute(new TdApi.ToggleDownloadIsPaused(fileId, isPaused));
|
||||
})
|
||||
.onSuccess(r ->
|
||||
sendHttpEvent(EventPayload.build(EventPayload.TYPE_FILE_STATUS, new JsonObject()
|
||||
.put("fileId", fileId)
|
||||
.put("downloadStatus", isPaused ? FileRecord.DownloadStatus.paused : FileRecord.DownloadStatus.downloading)
|
||||
)))
|
||||
.mapEmpty();
|
||||
}
|
||||
|
||||
|
|
@ -644,14 +637,8 @@ public class TelegramVerticle extends AbstractVerticle {
|
|||
}
|
||||
|
||||
private void sendHttpEvent(EventPayload payload) {
|
||||
if (this.httpSessionId == null) return;
|
||||
|
||||
String address = HttpVerticle.getWSHandlerId(httpSessionId);
|
||||
if (address == null) {
|
||||
log.debug("[%s] Can not found websocket textHandlerID for session id:%s".formatted(getRootId(), httpSessionId));
|
||||
return;
|
||||
}
|
||||
vertx.eventBus().send(address, Json.encode(payload));
|
||||
vertx.eventBus().send(EventEnum.TELEGRAM_EVENT.address(),
|
||||
JsonObject.of("telegramId", this.getId(), "payload", JsonObject.mapFrom(payload)));
|
||||
}
|
||||
|
||||
private void handleAuthorizationResult(TdApi.Object object) {
|
||||
|
|
@ -797,6 +784,7 @@ public class TelegramVerticle extends AbstractVerticle {
|
|||
if (file != null) {
|
||||
String localPath = null;
|
||||
Long completionDate = null;
|
||||
long downloadedSize = file.local == null ? 0 : file.local.downloadedSize;
|
||||
if (file.local != null && file.local.isDownloadingCompleted) {
|
||||
localPath = file.local.path;
|
||||
completionDate = System.currentTimeMillis();
|
||||
|
|
@ -814,16 +802,23 @@ public class TelegramVerticle extends AbstractVerticle {
|
|||
.put("downloadStatus", r.getString("downloadStatus"))
|
||||
.put("localPath", r.getString("localPath"))
|
||||
.put("completionDate", r.getLong("completionDate"))
|
||||
.put("downloadedSize", downloadedSize)
|
||||
));
|
||||
});
|
||||
}
|
||||
sendHttpEvent(EventPayload.build(EventPayload.TYPE_FILE, updateFile));
|
||||
if (lastFileEventTime == 0 || System.currentTimeMillis() - lastFileEventTime > 1000) {
|
||||
sendHttpEvent(EventPayload.build(EventPayload.TYPE_FILE, updateFile));
|
||||
lastFileEventTime = System.currentTimeMillis();
|
||||
}
|
||||
}
|
||||
|
||||
private void onFileDownloadsUpdated(TdApi.UpdateFileDownloads updateFileDownloads) {
|
||||
log.trace("[%s] Receive file downloads update: %s".formatted(getRootId(), updateFileDownloads));
|
||||
avgSpeed.update(updateFileDownloads.downloadedSize, System.currentTimeMillis());
|
||||
sendHttpEvent(EventPayload.build(EventPayload.TYPE_FILE_DOWNLOAD, updateFileDownloads));
|
||||
if (lastFileDownloadEventTime == 0 || System.currentTimeMillis() - lastFileDownloadEventTime > 1000) {
|
||||
sendHttpEvent(EventPayload.build(EventPayload.TYPE_FILE_DOWNLOAD, updateFileDownloads));
|
||||
lastFileDownloadEventTime = System.currentTimeMillis();
|
||||
}
|
||||
}
|
||||
|
||||
private void onMessageReceived(TdApi.Message message) {
|
||||
|
|
|
|||
|
|
@ -171,8 +171,8 @@ export default function AccountCreator({
|
|||
|
||||
if (!authState && !isMethodExecuting) {
|
||||
return (
|
||||
<div className="flex items-center justify-center space-x-2 text-xl">
|
||||
<p>Waiting for the telegram account to be initialized, please wait</p>
|
||||
<div className="flex flex-col items-center justify-center space-y-2 rounded bg-gray-50 p-2">
|
||||
<p>Waiting for the telegram account to be initialized, please wait.</p>
|
||||
<p>If it takes too long, please refresh the page or try again later.</p>
|
||||
<Ellipsis className="h-4 w-4 animate-pulse" />
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -25,110 +25,141 @@ interface FileExtraProps {
|
|||
rowHeight: RowHeight;
|
||||
}
|
||||
|
||||
export default function FileExtra({ file, rowHeight }: FileExtraProps) {
|
||||
function FileName({ file }: { file: TelegramFile }) {
|
||||
if (!file.fileName) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<SpoiledWrapper hasSensitiveContent={file.hasSensitiveContent}>
|
||||
<p className="flex items-center gap-2">
|
||||
<Mountain className="h-4 w-4" />
|
||||
<span className="rounded px-1 text-sm hover:bg-gray-100">
|
||||
{file.fileName}
|
||||
</span>
|
||||
</p>
|
||||
</SpoiledWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
function FileCaption({ file, rowHeight }: FileExtraProps) {
|
||||
if (!file.caption) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<SpoiledWrapper hasSensitiveContent={file.hasSensitiveContent}>
|
||||
<Tooltip>
|
||||
<TooltipTrigger>
|
||||
<div className="flex items-center gap-2">
|
||||
<Captions className="h-4 w-4 flex-shrink-0" />
|
||||
<p
|
||||
className={cn(
|
||||
rowHeight !== "l" && "line-clamp-1",
|
||||
"overflow-hidden truncate text-ellipsis text-wrap text-start text-sm",
|
||||
)}
|
||||
>
|
||||
{file.caption}
|
||||
</p>
|
||||
</div>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<p
|
||||
className="max-w-80 text-wrap rounded p-2"
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: file.caption.replaceAll("\n", "<br />"),
|
||||
}}
|
||||
></p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</SpoiledWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
function FilePath({ file }: { file: TelegramFile }) {
|
||||
const [, copyToClipboard] = useCopyToClipboard();
|
||||
|
||||
if (!file.localPath) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<Tooltip>
|
||||
<TooltipTrigger>
|
||||
<div className="flex items-center gap-2 text-sm">
|
||||
<FileCheck className="h-4 w-4 flex-shrink-0" />
|
||||
<p
|
||||
className="group line-clamp-1 cursor-pointer overflow-hidden truncate text-ellipsis text-wrap rounded px-1 hover:bg-gray-100"
|
||||
onClick={() => copyToClipboard(file.localPath)}
|
||||
>
|
||||
{file.localPath.split("/").pop()}
|
||||
<Copy className="ml-1 inline-flex h-4 w-4 opacity-0 group-hover:opacity-100" />
|
||||
</p>
|
||||
</div>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<div className="max-w-80 text-wrap rounded p-2">{file.localPath}</div>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
|
||||
function FileTime({ file }: { file: TelegramFile }) {
|
||||
return (
|
||||
<div className="flex items-center gap-2">
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<p className="flex items-center gap-2">
|
||||
<Clock className="h-4 w-4" />
|
||||
<span className="rounded px-1 text-sm text-muted-foreground hover:bg-gray-100">
|
||||
{formatDistanceToNow(new Date(file.date * 1000), {
|
||||
addSuffix: true,
|
||||
})}
|
||||
</span>
|
||||
</p>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<div className="max-w-80 text-wrap rounded p-2">
|
||||
{`Message received at ${new Date(file.date * 1000).toLocaleString()}`}
|
||||
</div>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
{file.completionDate && (
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<p className="flex items-center gap-2">
|
||||
<ClockArrowDown className="h-4 w-4" />
|
||||
<span className="rounded px-1 text-sm text-muted-foreground hover:bg-gray-100">
|
||||
{formatDistanceToNow(new Date(file.completionDate), {
|
||||
addSuffix: true,
|
||||
})}
|
||||
</span>
|
||||
</p>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<div className="max-w-80 text-wrap rounded p-2">
|
||||
{`File downloaded at ${new Date(file.completionDate).toLocaleString()}`}
|
||||
</div>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default function FileExtra({ file, rowHeight }: FileExtraProps) {
|
||||
if (rowHeight === "s") {
|
||||
return (
|
||||
<TooltipProvider>
|
||||
{file.fileName ? <FileName file={file} /> : <FileTime file={file} />}
|
||||
</TooltipProvider>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="relative flex flex-col space-y-1 overflow-hidden">
|
||||
<TooltipProvider>
|
||||
{file.fileName && (
|
||||
<SpoiledWrapper hasSensitiveContent={file.hasSensitiveContent}>
|
||||
<p className="flex items-center gap-2">
|
||||
<Mountain className="h-4 w-4" />
|
||||
<span className="rounded px-1 text-sm hover:bg-gray-100">
|
||||
{file.fileName}
|
||||
</span>
|
||||
</p>
|
||||
</SpoiledWrapper>
|
||||
)}
|
||||
{rowHeight !== "s" && file.caption && (
|
||||
<SpoiledWrapper hasSensitiveContent={file.hasSensitiveContent}>
|
||||
<Tooltip>
|
||||
<TooltipTrigger>
|
||||
<div className="flex items-center gap-2">
|
||||
<Captions className="h-4 w-4 flex-shrink-0" />
|
||||
<p
|
||||
className={cn(
|
||||
rowHeight !== "l" && "line-clamp-1",
|
||||
"overflow-hidden truncate text-ellipsis text-wrap text-start text-sm",
|
||||
)}
|
||||
>
|
||||
{file.caption}
|
||||
</p>
|
||||
</div>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<p
|
||||
className="max-w-80 text-wrap rounded p-2"
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: file.caption.replaceAll("\n", "<br />"),
|
||||
}}
|
||||
></p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</SpoiledWrapper>
|
||||
)}
|
||||
{rowHeight !== "s" && file.localPath && (
|
||||
<Tooltip>
|
||||
<TooltipTrigger>
|
||||
<div className="flex items-center gap-2 text-sm">
|
||||
<FileCheck className="h-4 w-4 flex-shrink-0" />
|
||||
<p
|
||||
className="group line-clamp-1 cursor-pointer overflow-hidden truncate text-ellipsis text-wrap rounded px-1 hover:bg-gray-100"
|
||||
onClick={() => copyToClipboard(file.localPath)}
|
||||
>
|
||||
{file.localPath.split("/").pop()}
|
||||
<Copy className="ml-1 inline-flex h-4 w-4 opacity-0 group-hover:opacity-100" />
|
||||
</p>
|
||||
</div>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<div className="max-w-80 text-wrap rounded p-2">
|
||||
{file.localPath}
|
||||
</div>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
)}
|
||||
{rowHeight !== "s" && (
|
||||
<div className="flex items-center gap-2">
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<p className="flex items-center gap-2">
|
||||
<Clock className="h-4 w-4" />
|
||||
<span className="rounded px-1 text-sm text-muted-foreground hover:bg-gray-100">
|
||||
{formatDistanceToNow(new Date(file.date * 1000), {
|
||||
addSuffix: true,
|
||||
})}
|
||||
</span>
|
||||
</p>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<div className="max-w-80 text-wrap rounded p-2">
|
||||
{`Message received at ${new Date(file.date * 1000).toLocaleString()}`}
|
||||
</div>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
{file.completionDate && (
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<p className="flex items-center gap-2">
|
||||
<ClockArrowDown className="h-4 w-4" />
|
||||
<span className="rounded px-1 text-sm text-muted-foreground hover:bg-gray-100">
|
||||
{formatDistanceToNow(new Date(file.completionDate), {
|
||||
addSuffix: true,
|
||||
})}
|
||||
</span>
|
||||
</p>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<div className="max-w-80 text-wrap rounded p-2">
|
||||
{`File downloaded at ${new Date(file.completionDate).toLocaleString()}`}
|
||||
</div>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
<FileName file={file} />
|
||||
<FileCaption file={file} rowHeight={rowHeight} />
|
||||
<FilePath file={file} />
|
||||
<FileTime file={file} />
|
||||
</TooltipProvider>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -14,9 +14,14 @@ export function useFileSpeed(fileId: number) {
|
|||
lastTimestamp: 0,
|
||||
});
|
||||
|
||||
const [debounceSpeed] = useDebounce(downloadSpeed.speed, 1000, {
|
||||
const [debounceSpeed] = useDebounce(downloadSpeed.speed, 300, {
|
||||
leading: true,
|
||||
maxWait: 2000,
|
||||
maxWait: 1000,
|
||||
});
|
||||
|
||||
const [debounceProgress] = useDebounce(downloadProgress, 300, {
|
||||
leading: true,
|
||||
maxWait: 1000,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
|
|
@ -94,7 +99,7 @@ export function useFileSpeed(fileId: number) {
|
|||
}, []);
|
||||
|
||||
return {
|
||||
downloadProgress,
|
||||
downloadProgress: debounceProgress,
|
||||
downloadSpeed: debounceSpeed,
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import useSWRInfinite from "swr/infinite";
|
|||
import { useWebsocket } from "@/hooks/use-websocket";
|
||||
import { WebSocketMessageType } from "@/lib/websocket-types";
|
||||
import useLocalStorage from "@/hooks/use-local-storage";
|
||||
import {useDebounce} from "use-debounce";
|
||||
import { useDebounce } from "use-debounce";
|
||||
|
||||
const DEFAULT_FILTERS: FileFilter = {
|
||||
search: "",
|
||||
|
|
@ -31,6 +31,7 @@ export function useFiles(accountId: string, chatId: string) {
|
|||
downloadStatus: DownloadStatus;
|
||||
localPath: string;
|
||||
completionDate: number;
|
||||
downloadedSize: number;
|
||||
}
|
||||
>
|
||||
>({});
|
||||
|
|
@ -76,6 +77,7 @@ export function useFiles(accountId: string, chatId: string) {
|
|||
downloadStatus: DownloadStatus;
|
||||
localPath: string;
|
||||
completionDate: number;
|
||||
downloadedSize: number;
|
||||
};
|
||||
|
||||
setLatestFileStatus((prev) => ({
|
||||
|
|
@ -84,7 +86,10 @@ export function useFiles(accountId: string, chatId: string) {
|
|||
downloadStatus:
|
||||
data.downloadStatus ?? prev[data.fileId]?.downloadStatus,
|
||||
localPath: data.localPath ?? prev[data.fileId]?.localPath,
|
||||
completionDate: data.completionDate ?? prev[data.fileId]?.completionDate,
|
||||
completionDate:
|
||||
data.completionDate ?? prev[data.fileId]?.completionDate,
|
||||
downloadedSize:
|
||||
data.downloadedSize ?? prev[data.fileId]?.downloadedSize,
|
||||
},
|
||||
}));
|
||||
}, [lastJsonMessage]);
|
||||
|
|
@ -101,6 +106,8 @@ export function useFiles(accountId: string, chatId: string) {
|
|||
localPath: latestFilesStatus[file.id]?.localPath ?? file.localPath,
|
||||
completionDate:
|
||||
latestFilesStatus[file.id]?.completionDate ?? file.completionDate,
|
||||
downloadedSize:
|
||||
latestFilesStatus[file.id]?.downloadedSize ?? file.downloadedSize,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import {
|
|||
import { useToast } from "./use-toast";
|
||||
import { useDebounce } from "use-debounce";
|
||||
import { getWsUrl } from "@/lib/api";
|
||||
import { useParams } from "next/navigation";
|
||||
|
||||
const WS_URL = `${getWsUrl()}`;
|
||||
|
||||
|
|
@ -39,6 +40,7 @@ interface WebSocketProviderProps {
|
|||
export const WebSocketProvider: React.FC<WebSocketProviderProps> = ({
|
||||
children,
|
||||
}) => {
|
||||
const params = useParams();
|
||||
const [isReady, setIsReady] = useState(false);
|
||||
const [accountDownloadSpeed, setAccountDownloadSpeed] = useState({
|
||||
speed: 0,
|
||||
|
|
@ -46,17 +48,20 @@ export const WebSocketProvider: React.FC<WebSocketProviderProps> = ({
|
|||
lastTimestamp: 0,
|
||||
});
|
||||
const { toast } = useToast();
|
||||
const [debounceSpeed] = useDebounce(accountDownloadSpeed.speed, 1000, {
|
||||
const [debounceSpeed] = useDebounce(accountDownloadSpeed.speed, 300, {
|
||||
leading: true,
|
||||
maxWait: 2000,
|
||||
maxWait: 1000,
|
||||
});
|
||||
|
||||
const { sendMessage, lastJsonMessage, readyState } =
|
||||
useWebSocket<WebSocketMessage>(WS_URL, {
|
||||
shouldReconnect: (closeEvent) => true,
|
||||
reconnectAttempts: 3,
|
||||
reconnectInterval: 3000,
|
||||
});
|
||||
useWebSocket<WebSocketMessage>(
|
||||
`${WS_URL}?telegramId=${(params.accountId as string) ?? ""}`,
|
||||
{
|
||||
shouldReconnect: (closeEvent) => true,
|
||||
reconnectAttempts: 3,
|
||||
reconnectInterval: 3000,
|
||||
},
|
||||
);
|
||||
|
||||
const connectionStatus = {
|
||||
[ReadyState.CONNECTING]: "Connecting",
|
||||
|
|
@ -106,7 +111,7 @@ export const WebSocketProvider: React.FC<WebSocketProviderProps> = ({
|
|||
lastDownloadedSize: downloadedSize,
|
||||
};
|
||||
const timeDiff = (timestamp - prev.lastTimestamp) / 1000;
|
||||
if (prev.lastTimestamp === 0 || timeDiff <= 0) {
|
||||
if (prev.lastTimestamp === 0 || timeDiff <= 0 || downloadedSize <= prev.lastDownloadedSize) {
|
||||
return {
|
||||
...state,
|
||||
speed: prev.speed,
|
||||
|
|
|
|||
Loading…
Reference in a new issue