Новый тип вложений - Attachment.CALL с активными звонками
This commit is contained in:
148
app/providers/AttachmentProvider/usePrepareAttachment.ts
Normal file
148
app/providers/AttachmentProvider/usePrepareAttachment.ts
Normal file
@@ -0,0 +1,148 @@
|
||||
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.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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user