Files
desktop/app/providers/AttachmentProvider/usePrepareAttachment.ts
RoyceDa e727529b89
Some checks failed
Linux Kernel Build / build (arm64, arm64) (push) Failing after 2m25s
Linux Kernel Build / build (x64, x86_64) (push) Successful in 2m56s
SP Builds / build (push) Successful in 3m35s
MacOS Kernel Build / build (arm64) (push) Successful in 11m54s
Windows Kernel Build / build (push) Successful in 16m16s
MacOS Kernel Build / build (x64) (push) Successful in 8m42s
Фикс CMD +, фикс зума, изменен верхний toolbar
2026-03-24 17:19:22 +02:00

155 lines
7.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { encodeWithPassword } from "@/app/workers/crypto/crypto";
import { MessageReply } from "../DialogProvider/useReplyMessages";
import { Attachment, AttachmentType } from "../ProtocolProvider/protocol/packets/packet.message";
import { base64ImageToBlurhash } from "@/app/workers/image/image";
import { MESSAGE_MAX_TIME_TO_DELEVERED_S } from "@/app/constants";
import { useContext, useRef } from "react";
import { useTransport } from "../TransportProvider/useTransport";
import { useDialogsList } from "../DialogListProvider/useDialogsList";
import { useDatabase } from "../DatabaseProvider/useDatabase";
import { useConsoleLogger } from "@/app/hooks/useConsoleLogger";
import { useDialogsCache } from "../DialogProvider/useDialogsCache";
import { DialogContext } from "../DialogProvider/DialogProvider";
export function usePrepareAttachment() {
const intervalsRef = useRef<NodeJS.Timeout>(null);
const {uploadFile} = useTransport();
const {updateDialog} = useDialogsList();
const {runQuery} = useDatabase();
const {info} = useConsoleLogger('usePrepareAttachment');
const {getDialogCache} = useDialogsCache();
const context = useContext(DialogContext);
const updateTimestampInDialogCache = (dialog : string, message_id: string) => {
const dialogCache = getDialogCache(dialog);
if(dialogCache == null){
return;
}
for(let i = 0; i < dialogCache.length; i++){
if(dialogCache[i].message_id == message_id){
dialogCache[i].timestamp = Date.now();
break;
}
}
}
/**
* Обновляет временную метку в сообщении, пока вложения отправляются,
* потому что если этого не делать, то сообщение может быть помечено как
* не доставленное из-за таймаута доставки
* @param attachments Вложения
*/
const doTimestampUpdateImMessageWhileAttachmentsSend = (message_id: string, dialog: string) => {
if(intervalsRef.current){
clearInterval(intervalsRef.current);
}
intervalsRef.current = setInterval(async () => {
/**
* Обновляем время в левом меню
*/
await runQuery("UPDATE messages SET timestamp = ? WHERE message_id = ?", [Date.now(), message_id]);
updateDialog(dialog);
/**
* Обновляем состояние в кэше диалогов
*/
updateTimestampInDialogCache(dialog, message_id);
if(context == null || !context){
/**
* Если этот диалог сейчас не открыт
*/
return;
}
context.setMessages((prev) => {
return prev.map((value) => {
if(value.message_id != message_id){
return value;
}
return {
...value,
timestamp: Date.now()
};
})
});
}, (MESSAGE_MAX_TIME_TO_DELEVERED_S / 2) * 1000);
}
/**
* Удаляет старый тег если вложения были подготовлены заново
* например при пересылке сообщений
*/
const removeOldTagIfAttachemtnsRePreapred = (preview : string) => {
if(preview.indexOf("::") == -1){
return preview;
}
let parts = preview.split("::");
return parts.slice(1).join("::");
}
/**
* Подготавливает вложения для отправки. Подготовка
* состоит в загрузке файлов на транспортный сервер, мы не делаем
* это через WebSocket из-за ограничений по размеру сообщений,
* а так же из-за надежности доставки файлов через HTTP
* @param attachments Attachments to prepare for sending
*/
const prepareAttachmentsToSend = async (message_id: string, dialog: string, password: string, attachments : Attachment[], rePrepared : boolean = false) : Promise<Attachment[]> => {
if(attachments.length <= 0){
return [];
}
let prepared : Attachment[] = [];
try{
for(let i = 0; i < attachments.length; i++){
const attachment : Attachment = attachments[i];
if(attachment.type == AttachmentType.CALL){
/**
* Звонк загружать не надо, по этому просто отправляем его как есть, там нет blob
*/
prepared.push(attachment);
continue;
}
if(attachment.type == AttachmentType.MESSAGES){
let reply : MessageReply[] = JSON.parse(attachment.blob)
for(let j = 0; j < reply.length; j++){
reply[j].attachments = await prepareAttachmentsToSend(message_id, dialog, password, reply[j].attachments, true);
}
prepared.push({
...attachment,
blob: await encodeWithPassword(password, JSON.stringify(reply))
});
continue;
}
if((attachment.type == AttachmentType.IMAGE
|| attachment.type == AttachmentType.AVATAR) && attachment.preview == ""){
/**
* Загружаем превью blurhash для изображения
*/
const blurhash = await base64ImageToBlurhash(attachment.blob);
attachment.preview = blurhash;
}
doTimestampUpdateImMessageWhileAttachmentsSend(message_id, dialog);
const content = await encodeWithPassword(password, attachment.blob);
const upid = attachment.id;
info(`Uploading attachment with upid: ${upid}`);
info(`Attachment content length: ${content.length}`);
let tag = await uploadFile(upid, content);
info(`Uploaded attachment with upid: ${upid}, received tag: ${tag}`);
if(intervalsRef.current != null){
clearInterval(intervalsRef.current);
}
prepared.push({
...attachment,
preview: tag + "::" + (rePrepared ? removeOldTagIfAttachemtnsRePreapred(attachment.preview) : attachment.preview),
blob: ""
});
}
return prepared;
}catch(e){
return prepared;
}
}
return {
prepareAttachmentsToSend
}
}