Новая система вложений
This commit is contained in:
@@ -89,7 +89,10 @@ export function DialogInput() {
|
|||||||
blob: fileContent,
|
blob: fileContent,
|
||||||
id: generateRandomKey(8),
|
id: generateRandomKey(8),
|
||||||
type: AttachmentType.FILE,
|
type: AttachmentType.FILE,
|
||||||
preview: files[0].size + "::" + files[0].name
|
preview: files[0].size + "::" + files[0].name,
|
||||||
|
transport_server: "",
|
||||||
|
transport_tag: "",
|
||||||
|
encoded_for: dialog
|
||||||
}]);
|
}]);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -116,7 +119,10 @@ export function DialogInput() {
|
|||||||
type: AttachmentType.MESSAGES,
|
type: AttachmentType.MESSAGES,
|
||||||
id: generateRandomKey(8),
|
id: generateRandomKey(8),
|
||||||
blob: JSON.stringify([...replyMessages.messages]),
|
blob: JSON.stringify([...replyMessages.messages]),
|
||||||
preview: ""
|
preview: "",
|
||||||
|
transport_server: "",
|
||||||
|
transport_tag: "",
|
||||||
|
encoded_for: dialog
|
||||||
}]);
|
}]);
|
||||||
if(editableDivRef.current){
|
if(editableDivRef.current){
|
||||||
editableDivRef.current.focus();
|
editableDivRef.current.focus();
|
||||||
@@ -230,7 +236,10 @@ export function DialogInput() {
|
|||||||
blob: avatars[0].avatar,
|
blob: avatars[0].avatar,
|
||||||
id: generateRandomKey(8),
|
id: generateRandomKey(8),
|
||||||
type: AttachmentType.AVATAR,
|
type: AttachmentType.AVATAR,
|
||||||
preview: ""
|
preview: "",
|
||||||
|
transport_server: "",
|
||||||
|
transport_tag: "",
|
||||||
|
encoded_for: dialog
|
||||||
}]);
|
}]);
|
||||||
if(editableDivRef.current){
|
if(editableDivRef.current){
|
||||||
editableDivRef.current.focus();
|
editableDivRef.current.focus();
|
||||||
@@ -270,7 +279,10 @@ export function DialogInput() {
|
|||||||
blob: base64Image,
|
blob: base64Image,
|
||||||
id: attachmentId,
|
id: attachmentId,
|
||||||
type: AttachmentType.IMAGE,
|
type: AttachmentType.IMAGE,
|
||||||
preview: ""
|
preview: "",
|
||||||
|
transport_server: "",
|
||||||
|
transport_tag: "",
|
||||||
|
encoded_for: dialog
|
||||||
}]);
|
}]);
|
||||||
}
|
}
|
||||||
if(editableDivRef.current){
|
if(editableDivRef.current){
|
||||||
@@ -304,7 +316,10 @@ export function DialogInput() {
|
|||||||
blob: fileContent,
|
blob: fileContent,
|
||||||
id: attachmentId,
|
id: attachmentId,
|
||||||
type: AttachmentType.FILE,
|
type: AttachmentType.FILE,
|
||||||
preview: files[0].size + "::" + files[0].name
|
preview: files[0].size + "::" + files[0].name,
|
||||||
|
transport_server: "",
|
||||||
|
transport_tag: "",
|
||||||
|
encoded_for: dialog
|
||||||
}]);
|
}]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ export function MessageImage(props: AttachmentProps) {
|
|||||||
const [blurhashPreview, setBlurhashPreview] = useState("");
|
const [blurhashPreview, setBlurhashPreview] = useState("");
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
console.info(props.attachment);
|
||||||
console.info("Consturcting image, download status: " + downloadStatus);
|
console.info("Consturcting image, download status: " + downloadStatus);
|
||||||
constructBlob();
|
constructBlob();
|
||||||
constructFromBlurhash();
|
constructFromBlurhash();
|
||||||
|
|||||||
@@ -27,11 +27,10 @@ export enum DownloadStatus {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function useAttachment(attachment: Attachment, parentMessage: MessageProps) {
|
export function useAttachment(attachment: Attachment, parentMessage: MessageProps) {
|
||||||
const uuidRegex = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
|
|
||||||
const uploadedPercentage = useUploadStatus(attachment.id);
|
const uploadedPercentage = useUploadStatus(attachment.id);
|
||||||
const downloadPercentage = useDownloadStatus(attachment.id);
|
const downloadPercentage = useDownloadStatus(attachment.id);
|
||||||
const [downloadStatus, setDownloadStatus] = useMemory("attachment-downloaded-status-" + attachment.id, DownloadStatus.PENDING, true);
|
const [downloadStatus, setDownloadStatus] = useMemory("attachment-downloaded-status-" + attachment.id, DownloadStatus.PENDING, true);
|
||||||
const [downloadTag, setDownloadTag] = useState("");
|
const [downloadTag, setDownloadTag] = useState(attachment.transport_tag || "");
|
||||||
const {readFile, writeFile, fileExists, size} = useFileStorage();
|
const {readFile, writeFile, fileExists, size} = useFileStorage();
|
||||||
const { downloadFile } = useTransport();
|
const { downloadFile } = useTransport();
|
||||||
const publicKey = usePublicKey();
|
const publicKey = usePublicKey();
|
||||||
@@ -50,30 +49,18 @@ export function useAttachment(attachment: Attachment, parentMessage: MessageProp
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const getPreview = () => {
|
const getPreview = () => {
|
||||||
if(attachment.preview.split("::")[0].match(uuidRegex)){
|
|
||||||
/**
|
|
||||||
* Это тег загрузки
|
|
||||||
*/
|
|
||||||
return attachment.preview.split("::").splice(1).join("::");
|
|
||||||
}
|
|
||||||
return attachment.preview;
|
return attachment.preview;
|
||||||
}
|
}
|
||||||
|
|
||||||
const calcDownloadStatus = async () => {
|
const calcDownloadStatus = async () => {
|
||||||
if(attachment.preview.split("::")[0].match(uuidRegex)){
|
if (downloadStatus == DownloadStatus.DOWNLOADED) {
|
||||||
/**
|
|
||||||
* Это тег загрузки
|
|
||||||
*/
|
|
||||||
setDownloadTag(attachment.preview.split("::")[0]);
|
|
||||||
}
|
|
||||||
if(!attachment.preview.split("::")[0].match(uuidRegex)){
|
|
||||||
/**
|
|
||||||
* Там не тег загрузки, значит это наш файл
|
|
||||||
*/
|
|
||||||
setDownloadStatus(DownloadStatus.DOWNLOADED);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (downloadStatus == DownloadStatus.DOWNLOADED) {
|
if(attachment.transport_tag == ""){
|
||||||
|
/**
|
||||||
|
* Транспортного тега нет только у сообщений отправленных нами, значит он точно наш
|
||||||
|
*/
|
||||||
|
setDownloadStatus(DownloadStatus.DOWNLOADED);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(attachment.type == AttachmentType.FILE){
|
if(attachment.type == AttachmentType.FILE){
|
||||||
@@ -143,7 +130,7 @@ export function useAttachment(attachment: Attachment, parentMessage: MessageProp
|
|||||||
let downloadedBlob = '';
|
let downloadedBlob = '';
|
||||||
try {
|
try {
|
||||||
downloadedBlob = await downloadFile(attachment.id,
|
downloadedBlob = await downloadFile(attachment.id,
|
||||||
downloadTag);
|
downloadTag, attachment.transport_server);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.info(e);
|
console.info(e);
|
||||||
info("Error downloading attachment: " + attachment.id);
|
info("Error downloading attachment: " + attachment.id);
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import { useDatabase } from "../DatabaseProvider/useDatabase";
|
|||||||
import { useConsoleLogger } from "@/app/hooks/useConsoleLogger";
|
import { useConsoleLogger } from "@/app/hooks/useConsoleLogger";
|
||||||
import { useDialogsCache } from "../DialogProvider/useDialogsCache";
|
import { useDialogsCache } from "../DialogProvider/useDialogsCache";
|
||||||
import { DialogContext } from "../DialogProvider/DialogProvider";
|
import { DialogContext } from "../DialogProvider/DialogProvider";
|
||||||
|
import { useTransportServer } from "../TransportProvider/useTransportServer";
|
||||||
|
|
||||||
export function usePrepareAttachment() {
|
export function usePrepareAttachment() {
|
||||||
const intervalsRef = useRef<NodeJS.Timeout>(null);
|
const intervalsRef = useRef<NodeJS.Timeout>(null);
|
||||||
@@ -19,6 +20,7 @@ export function usePrepareAttachment() {
|
|||||||
const {info} = useConsoleLogger('usePrepareAttachment');
|
const {info} = useConsoleLogger('usePrepareAttachment');
|
||||||
const {getDialogCache} = useDialogsCache();
|
const {getDialogCache} = useDialogsCache();
|
||||||
const context = useContext(DialogContext);
|
const context = useContext(DialogContext);
|
||||||
|
const transportServer = useTransportServer();
|
||||||
|
|
||||||
const updateTimestampInDialogCache = (dialog : string, message_id: string) => {
|
const updateTimestampInDialogCache = (dialog : string, message_id: string) => {
|
||||||
const dialogCache = getDialogCache(dialog);
|
const dialogCache = getDialogCache(dialog);
|
||||||
@@ -74,18 +76,6 @@ export function usePrepareAttachment() {
|
|||||||
}, (MESSAGE_MAX_TIME_TO_DELEVERED_S / 2) * 1000);
|
}, (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("::");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Подготавливает вложения для отправки. Подготовка
|
* Подготавливает вложения для отправки. Подготовка
|
||||||
* состоит в загрузке файлов на транспортный сервер, мы не делаем
|
* состоит в загрузке файлов на транспортный сервер, мы не делаем
|
||||||
@@ -127,6 +117,16 @@ export function usePrepareAttachment() {
|
|||||||
const blurhash = await base64ImageToBlurhash(attachment.blob);
|
const blurhash = await base64ImageToBlurhash(attachment.blob);
|
||||||
attachment.preview = blurhash;
|
attachment.preview = blurhash;
|
||||||
}
|
}
|
||||||
|
if(rePrepared && attachment.encoded_for == dialog){
|
||||||
|
/**
|
||||||
|
* Это пересланное сообщение и оно уже закодировано для этого диалога, значит не нужно его кодировать и загружать заново
|
||||||
|
*/
|
||||||
|
prepared.push({
|
||||||
|
...attachment,
|
||||||
|
blob: ""
|
||||||
|
});
|
||||||
|
continue;
|
||||||
|
}
|
||||||
doTimestampUpdateImMessageWhileAttachmentsSend(message_id, dialog);
|
doTimestampUpdateImMessageWhileAttachmentsSend(message_id, dialog);
|
||||||
const content = await encodeWithPassword(password, attachment.blob);
|
const content = await encodeWithPassword(password, attachment.blob);
|
||||||
const upid = attachment.id;
|
const upid = attachment.id;
|
||||||
@@ -139,7 +139,10 @@ export function usePrepareAttachment() {
|
|||||||
}
|
}
|
||||||
prepared.push({
|
prepared.push({
|
||||||
...attachment,
|
...attachment,
|
||||||
preview: tag + "::" + (rePrepared ? removeOldTagIfAttachemtnsRePreapred(attachment.preview) : attachment.preview),
|
transport_server: transportServer || "",
|
||||||
|
transport_tag: tag,
|
||||||
|
encoded_for: dialog,
|
||||||
|
preview: attachment.preview,
|
||||||
blob: ""
|
blob: ""
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -472,6 +472,9 @@ export function CallProvider(props : CallProviderProps) {
|
|||||||
id: generateRandomKey(16),
|
id: generateRandomKey(16),
|
||||||
preview: duration.toString(),
|
preview: duration.toString(),
|
||||||
type: AttachmentType.CALL,
|
type: AttachmentType.CALL,
|
||||||
|
transport_server: "",
|
||||||
|
transport_tag: "",
|
||||||
|
encoded_for: "",
|
||||||
blob: ""
|
blob: ""
|
||||||
}], true);
|
}], true);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,6 +46,9 @@ export interface AttachmentMeta {
|
|||||||
id: string;
|
id: string;
|
||||||
type: AttachmentType;
|
type: AttachmentType;
|
||||||
preview: string;
|
preview: string;
|
||||||
|
transport_tag: string;
|
||||||
|
encoded_for: string;
|
||||||
|
transport_server: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Message {
|
export interface Message {
|
||||||
@@ -469,9 +472,7 @@ export function DialogProvider(props: DialogProviderProps) {
|
|||||||
for(let i = 0; i < packet.getAttachments().length; i++) {
|
for(let i = 0; i < packet.getAttachments().length; i++) {
|
||||||
const attachment = packet.getAttachments()[i];
|
const attachment = packet.getAttachments()[i];
|
||||||
attachments.push({
|
attachments.push({
|
||||||
id: attachment.id,
|
...attachment,
|
||||||
preview: attachment.preview,
|
|
||||||
type: attachment.type,
|
|
||||||
blob: attachment.type == AttachmentType.MESSAGES ? await decodeWithPassword(chachaDecryptedKey.toString('utf-8'), attachment.blob) : ""
|
blob: attachment.type == AttachmentType.MESSAGES ? await decodeWithPassword(chachaDecryptedKey.toString('utf-8'), attachment.blob) : ""
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -549,9 +550,7 @@ export function DialogProvider(props: DialogProviderProps) {
|
|||||||
for(let i = 0; i < packet.getAttachments().length; i++) {
|
for(let i = 0; i < packet.getAttachments().length; i++) {
|
||||||
const attachment = packet.getAttachments()[i];
|
const attachment = packet.getAttachments()[i];
|
||||||
attachments.push({
|
attachments.push({
|
||||||
id: attachment.id,
|
...attachment,
|
||||||
preview: attachment.preview,
|
|
||||||
type: attachment.type,
|
|
||||||
blob: attachment.type == AttachmentType.MESSAGES ? await decodeWithPassword(groupKey, attachment.blob) : ""
|
blob: attachment.type == AttachmentType.MESSAGES ? await decodeWithPassword(groupKey, attachment.blob) : ""
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -627,9 +626,7 @@ export function DialogProvider(props: DialogProviderProps) {
|
|||||||
for(let i = 0; i < packet.getAttachments().length; i++) {
|
for(let i = 0; i < packet.getAttachments().length; i++) {
|
||||||
const attachment = packet.getAttachments()[i];
|
const attachment = packet.getAttachments()[i];
|
||||||
attachments.push({
|
attachments.push({
|
||||||
id: attachment.id,
|
...attachment,
|
||||||
preview: attachment.preview,
|
|
||||||
type: attachment.type,
|
|
||||||
blob: attachment.type == AttachmentType.MESSAGES ? await decodeWithPassword(chachaDecryptedKey.toString('utf-8'), attachment.blob) : ""
|
blob: attachment.type == AttachmentType.MESSAGES ? await decodeWithPassword(chachaDecryptedKey.toString('utf-8'), attachment.blob) : ""
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -707,9 +704,7 @@ export function DialogProvider(props: DialogProviderProps) {
|
|||||||
for(let i = 0; i < packet.getAttachments().length; i++) {
|
for(let i = 0; i < packet.getAttachments().length; i++) {
|
||||||
const attachment = packet.getAttachments()[i];
|
const attachment = packet.getAttachments()[i];
|
||||||
attachments.push({
|
attachments.push({
|
||||||
id: attachment.id,
|
...attachment,
|
||||||
preview: attachment.preview,
|
|
||||||
type: attachment.type,
|
|
||||||
blob: attachment.type == AttachmentType.MESSAGES ? await decodeWithPassword(groupKey, attachment.blob) : ""
|
blob: attachment.type == AttachmentType.MESSAGES ? await decodeWithPassword(groupKey, attachment.blob) : ""
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -964,7 +959,10 @@ export function DialogProvider(props: DialogProviderProps) {
|
|||||||
id: meta.id,
|
id: meta.id,
|
||||||
blob: blob,
|
blob: blob,
|
||||||
type: meta.type,
|
type: meta.type,
|
||||||
preview: meta.preview
|
preview: meta.preview,
|
||||||
|
transport_server: meta.transport_server,
|
||||||
|
transport_tag: meta.transport_tag,
|
||||||
|
encoded_for: meta.encoded_for
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return attachments;
|
return attachments;
|
||||||
|
|||||||
@@ -118,7 +118,10 @@ export function useDialog() : {
|
|||||||
attachmentsMeta.push({
|
attachmentsMeta.push({
|
||||||
id: attachment.id,
|
id: attachment.id,
|
||||||
type: attachment.type,
|
type: attachment.type,
|
||||||
preview: attachment.preview
|
preview: attachment.preview,
|
||||||
|
transport_server: attachment.transport_server,
|
||||||
|
transport_tag: attachment.transport_tag,
|
||||||
|
encoded_for: dialog
|
||||||
});
|
});
|
||||||
if(attachment.type == AttachmentType.FILE){
|
if(attachment.type == AttachmentType.FILE){
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import { useGroupInviteStatus } from "./useGroupInviteStatus";
|
|||||||
import { Attachment, AttachmentType, PacketMessage } from "../ProtocolProvider/protocol/packets/packet.message";
|
import { Attachment, AttachmentType, PacketMessage } from "../ProtocolProvider/protocol/packets/packet.message";
|
||||||
import { useUpdateSyncTime } from "./useUpdateSyncTime";
|
import { useUpdateSyncTime } from "./useUpdateSyncTime";
|
||||||
import { useFileStorage } from "@/app/hooks/useFileStorage";
|
import { useFileStorage } from "@/app/hooks/useFileStorage";
|
||||||
import { DeliveredMessageState, Message } from "./DialogProvider";
|
import { AttachmentMeta, DeliveredMessageState, Message } from "./DialogProvider";
|
||||||
import { MESSAGE_MAX_LOADED, TIME_TO_INACTIVE_FOR_MESSAGES_UNREAD } from "@/app/constants";
|
import { MESSAGE_MAX_LOADED, TIME_TO_INACTIVE_FOR_MESSAGES_UNREAD } from "@/app/constants";
|
||||||
import { useMemory } from "../MemoryProvider/useMemory";
|
import { useMemory } from "../MemoryProvider/useMemory";
|
||||||
import { useDialogsCache } from "./useDialogsCache";
|
import { useDialogsCache } from "./useDialogsCache";
|
||||||
@@ -165,7 +165,7 @@ export function useSynchronize() {
|
|||||||
const nonce = chachaDecryptedKey.slice(32);
|
const nonce = chachaDecryptedKey.slice(32);
|
||||||
const decryptedContent = await chacha20Decrypt(content, nonce.toString('hex'), key.toString('hex'));
|
const decryptedContent = await chacha20Decrypt(content, nonce.toString('hex'), key.toString('hex'));
|
||||||
await updateSyncTime(timestamp);
|
await updateSyncTime(timestamp);
|
||||||
let attachmentsMeta: any[] = [];
|
let attachmentsMeta: AttachmentMeta[] = [];
|
||||||
let messageAttachments: Attachment[] = [];
|
let messageAttachments: Attachment[] = [];
|
||||||
for (let i = 0; i < packet.getAttachments().length; i++) {
|
for (let i = 0; i < packet.getAttachments().length; i++) {
|
||||||
const attachment = packet.getAttachments()[i];
|
const attachment = packet.getAttachments()[i];
|
||||||
@@ -190,7 +190,10 @@ export function useSynchronize() {
|
|||||||
attachmentsMeta.push({
|
attachmentsMeta.push({
|
||||||
id: attachment.id,
|
id: attachment.id,
|
||||||
type: attachment.type,
|
type: attachment.type,
|
||||||
preview: attachment.preview
|
preview: attachment.preview,
|
||||||
|
encoded_for: attachment.encoded_for,
|
||||||
|
transport_server: attachment.transport_server,
|
||||||
|
transport_tag: attachment.transport_tag
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -347,7 +350,7 @@ export function useSynchronize() {
|
|||||||
decryptedContent = '';
|
decryptedContent = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
let attachmentsMeta: any[] = [];
|
let attachmentsMeta: AttachmentMeta[] = [];
|
||||||
let messageAttachments: Attachment[] = [];
|
let messageAttachments: Attachment[] = [];
|
||||||
for (let i = 0; i < packet.getAttachments().length; i++) {
|
for (let i = 0; i < packet.getAttachments().length; i++) {
|
||||||
const attachment = packet.getAttachments()[i];
|
const attachment = packet.getAttachments()[i];
|
||||||
@@ -372,7 +375,10 @@ export function useSynchronize() {
|
|||||||
attachmentsMeta.push({
|
attachmentsMeta.push({
|
||||||
id: attachment.id,
|
id: attachment.id,
|
||||||
type: attachment.type,
|
type: attachment.type,
|
||||||
preview: attachment.preview
|
preview: attachment.preview,
|
||||||
|
encoded_for: attachment.encoded_for,
|
||||||
|
transport_server: attachment.transport_server,
|
||||||
|
transport_tag: attachment.transport_tag
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { useConsoleLogger } from "@/app/hooks/useConsoleLogger";
|
|||||||
interface TransportContextValue {
|
interface TransportContextValue {
|
||||||
transportServer: string | null;
|
transportServer: string | null;
|
||||||
uploadFile: (id: string, content: string) => Promise<any>;
|
uploadFile: (id: string, content: string) => Promise<any>;
|
||||||
downloadFile: (id: string, tag: string) => Promise<string>;
|
downloadFile: (id: string, tag: string, transportServer: string) => Promise<string>;
|
||||||
uploading: TransportState[];
|
uploading: TransportState[];
|
||||||
downloading: TransportState[];
|
downloading: TransportState[];
|
||||||
}
|
}
|
||||||
@@ -86,14 +86,14 @@ export function TransportProvider(props: TransportProviderProps) {
|
|||||||
* @param tag тег файла
|
* @param tag тег файла
|
||||||
* @param chachaDecryptedKey ключ для расшифровки файла
|
* @param chachaDecryptedKey ключ для расшифровки файла
|
||||||
*/
|
*/
|
||||||
const downloadFile = (id: string, tag : string) : Promise<string> => {
|
const downloadFile = (id: string, tag : string, transportServer: string) : Promise<string> => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
if (!transportServerRef.current) {
|
if (!transportServer) {
|
||||||
throw new Error("Transport server is not set");
|
throw new Error("Transport server is not set");
|
||||||
}
|
}
|
||||||
setDownloading(prev => [...prev, { id: id, progress: 0 }]);
|
setDownloading(prev => [...prev, { id: id, progress: 0 }]);
|
||||||
const xhr = new XMLHttpRequest();
|
const xhr = new XMLHttpRequest();
|
||||||
xhr.open('GET', `${transportServerRef.current}/d/${tag}`);
|
xhr.open('GET', `${transportServer}/d/${tag}`);
|
||||||
xhr.responseType = 'text';
|
xhr.responseType = 'text';
|
||||||
|
|
||||||
xhr.onprogress = (event) => {
|
xhr.onprogress = (event) => {
|
||||||
|
|||||||
12
app/providers/TransportProvider/useTransportServer.ts
Normal file
12
app/providers/TransportProvider/useTransportServer.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import { useContext } from "react";
|
||||||
|
import { TransportContext } from "./TransportProvider";
|
||||||
|
|
||||||
|
export function useTransportServer() {
|
||||||
|
const context = useContext(TransportContext);
|
||||||
|
if(!context){
|
||||||
|
throw new Error("useTransportServer must be used within a TransportProvider");
|
||||||
|
}
|
||||||
|
const { transportServer } = context;
|
||||||
|
|
||||||
|
return transportServer;
|
||||||
|
}
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
export const SERVERS = [
|
export const SERVERS = [
|
||||||
//'wss://cdn.rosetta-im.com',
|
//'wss://cdn.rosetta-im.com',
|
||||||
//'ws://10.211.55.2:3000',
|
'ws://10.211.55.2:3000',
|
||||||
//'ws://192.168.6.82:3000',
|
//'ws://192.168.6.82:3000',
|
||||||
'wss://wss.rosetta.im'
|
//'wss://wss.rosetta.im'
|
||||||
];
|
];
|
||||||
|
|
||||||
export function selectServer(): string {
|
export function selectServer(): string {
|
||||||
|
|||||||
181
lib/main/main.ts
181
lib/main/main.ts
@@ -18,109 +18,128 @@ const size = process.platform === 'darwin' ? 18 : 22
|
|||||||
const logger = Logger('main')
|
const logger = Logger('main')
|
||||||
|
|
||||||
const icon = nativeImage
|
const icon = nativeImage
|
||||||
.createFromPath(join(__dirname, '../../resources/R.png'))
|
.createFromPath(join(__dirname, '../../resources/R.png'))
|
||||||
.resize({ width: size, height: size })
|
.resize({ width: size, height: size })
|
||||||
|
|
||||||
if (!lockInstance) {
|
if (!lockInstance) {
|
||||||
app.quit()
|
app.quit()
|
||||||
process.exit(0)
|
process.exit(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
process.on('unhandledRejection', (reason) => {
|
process.on('unhandledRejection', (reason) => {
|
||||||
logger.log(`main thread error, reason: ${reason}`)
|
logger.log(`main thread error, reason: ${reason}`)
|
||||||
})
|
})
|
||||||
|
|
||||||
app.disableHardwareAcceleration()
|
app.disableHardwareAcceleration()
|
||||||
|
|
||||||
app.on('second-instance', () => {
|
app.on('second-instance', () => {
|
||||||
const allWindows = BrowserWindow.getAllWindows()
|
const allWindows = BrowserWindow.getAllWindows()
|
||||||
if (allWindows.length) {
|
if (allWindows.length) {
|
||||||
const mainWindow = allWindows[0]
|
const mainWindow = allWindows[0]
|
||||||
if (mainWindow.isMinimized()) mainWindow.restore()
|
if (mainWindow.isMinimized()) mainWindow.restore()
|
||||||
if (!mainWindow.isVisible()) mainWindow.show()
|
if (!mainWindow.isVisible()) mainWindow.show()
|
||||||
mainWindow.focus()
|
mainWindow.focus()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
export const restoreApplicationAfterClickOnTrayOrDock = () => {
|
export const restoreApplicationAfterClickOnTrayOrDock = () => {
|
||||||
const allWindows = BrowserWindow.getAllWindows()
|
const allWindows = BrowserWindow.getAllWindows()
|
||||||
if (allWindows.length > 0) {
|
if (allWindows.length > 0) {
|
||||||
const mainWindow = allWindows[0]
|
const mainWindow = allWindows[0]
|
||||||
if (mainWindow.isMinimized()) {
|
if (mainWindow.isMinimized()) {
|
||||||
mainWindow.restore()
|
mainWindow.restore()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (!mainWindow.isVisible()) {
|
if (!mainWindow.isVisible()) {
|
||||||
mainWindow.show()
|
mainWindow.show()
|
||||||
}
|
}
|
||||||
mainWindow.focus()
|
mainWindow.focus()
|
||||||
} else {
|
} else {
|
||||||
createAppWindow()
|
createAppWindow()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
app.whenReady().then(async () => {
|
app.whenReady().then(async () => {
|
||||||
electronApp.setAppUserModelId('Rosetta')
|
electronApp.setAppUserModelId('Rosetta')
|
||||||
|
|
||||||
// Убираем File/View и оставляем только app + минимальный Edit (roles)
|
// Убираем File/View и оставляем только app + минимальный Edit (roles)
|
||||||
if (process.platform === 'darwin') {
|
if (process.platform === 'darwin') {
|
||||||
const minimalMenu = Menu.buildFromTemplate([
|
const minimalMenu = Menu.buildFromTemplate([
|
||||||
{
|
{
|
||||||
label: app.name,
|
label: app.name,
|
||||||
submenu: [
|
submenu: [
|
||||||
{ role: 'about' },
|
{ role: 'about' },
|
||||||
{ type: 'separator' },
|
{ type: 'separator' },
|
||||||
{ role: 'hide' },
|
{ role: 'hide' },
|
||||||
{ role: 'hideOthers' },
|
{ role: 'hideOthers' },
|
||||||
{ role: 'unhide' },
|
{ role: 'unhide' },
|
||||||
{ type: 'separator' },
|
{ type: 'separator' },
|
||||||
{ role: 'quit' }
|
{ role: 'quit' }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Edit',
|
label: 'Edit',
|
||||||
submenu: [
|
submenu: [
|
||||||
{ role: 'undo' },
|
{ role: 'undo' },
|
||||||
{ role: 'redo' },
|
{ role: 'redo' },
|
||||||
{ type: 'separator' },
|
{ type: 'separator' },
|
||||||
{ role: 'cut' },
|
{ role: 'cut' },
|
||||||
{ role: 'copy' },
|
{ role: 'copy' },
|
||||||
{ role: 'paste' },
|
{ role: 'paste' },
|
||||||
{ role: 'pasteAndMatchStyle' },
|
{ role: 'pasteAndMatchStyle' },
|
||||||
{ role: 'delete' },
|
{ role: 'delete' },
|
||||||
{ role: 'selectAll' }
|
{ role: 'selectAll' }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
Menu.setApplicationMenu(minimalMenu)
|
Menu.setApplicationMenu(minimalMenu)
|
||||||
} else {
|
} else {
|
||||||
Menu.setApplicationMenu(null)
|
Menu.setApplicationMenu(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
tray = new Tray(icon)
|
tray = new Tray(icon)
|
||||||
const contextMenu = Menu.buildFromTemplate([
|
const contextMenu = Menu.buildFromTemplate([
|
||||||
{ label: 'Open App', click: () => restoreApplicationAfterClickOnTrayOrDock() },
|
{ label: 'Open App', click: () => restoreApplicationAfterClickOnTrayOrDock() },
|
||||||
{ label: 'Quit', click: () => app.quit() }
|
{ label: 'Quit', click: () => app.quit() }
|
||||||
])
|
])
|
||||||
tray.setContextMenu(contextMenu)
|
tray.setContextMenu(contextMenu)
|
||||||
tray.setToolTip('Rosetta')
|
tray.setToolTip('Rosetta')
|
||||||
tray.on('click', () => {
|
tray.on('click', () => {
|
||||||
restoreApplicationAfterClickOnTrayOrDock()
|
restoreApplicationAfterClickOnTrayOrDock()
|
||||||
})
|
})
|
||||||
|
|
||||||
startApplication()
|
startApplication()
|
||||||
|
|
||||||
app.on('browser-window-created', (_, window) => {
|
const isDevBuild =
|
||||||
optimizer.watchWindowShortcuts(window)
|
!app.isPackaged ||
|
||||||
})
|
process.env.NODE_ENV === 'development' ||
|
||||||
|
Boolean(process.env.ELECTRON_RENDERER_URL)
|
||||||
|
|
||||||
app.on('activate', () => {
|
app.on('browser-window-created', (_, window) => {
|
||||||
restoreApplicationAfterClickOnTrayOrDock()
|
// В production оставляем стандартную защиту шорткатов
|
||||||
})
|
if (!isDevBuild) {
|
||||||
|
optimizer.watchWindowShortcuts(window)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// В dev явно разрешаем Ctrl+R и Cmd+R для перезагрузки, так как в режиме разработки это часто нужно
|
||||||
|
window.webContents.on('before-input-event', (event, input) => {
|
||||||
|
const key = input.key?.toLowerCase?.() ?? ''
|
||||||
|
const isReload = input.type === 'keyDown' && (input.meta || input.control) && key === 'r'
|
||||||
|
if (isReload) {
|
||||||
|
event.preventDefault()
|
||||||
|
window.webContents.reloadIgnoringCache()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
app.on('activate', () => {
|
||||||
|
restoreApplicationAfterClickOnTrayOrDock()
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
app.on('window-all-closed', () => {
|
app.on('window-all-closed', () => {
|
||||||
if (process.platform === 'darwin') {
|
if (process.platform === 'darwin') {
|
||||||
app.hide()
|
app.hide()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
Reference in New Issue
Block a user