This commit is contained in:
rosetta
2026-01-30 05:01:05 +02:00
commit 83f38dc63f
327 changed files with 18725 additions and 0 deletions

View File

@@ -0,0 +1,140 @@
import { createContext, useEffect, useRef, useState } from "react";
import { PacketRequestTransport } from "../ProtocolProvider/protocol/packets/packet.requesttransport";
import { useSender } from "../ProtocolProvider/useSender";
import { usePacket } from "../ProtocolProvider/usePacket";
import { useConsoleLogger } from "@/app/hooks/useConsoleLogger";
interface TransportContextValue {
transportServer: string | null;
uploadFile: (id: string, content: string) => Promise<any>;
downloadFile: (id: string, tag: string) => Promise<string>;
uploading: TransportState[];
downloading: TransportState[];
}
export const TransportContext = createContext<TransportContextValue | null>(null);
interface TransportProviderProps {
children: React.ReactNode;
}
export interface TransportState {
id: string;
progress: number;
}
/**
* Этот провайдер занимается тем, что передает
* файлы на сервер и получает их с сервера
*/
export function TransportProvider(props: TransportProviderProps) {
const transportServerRef = useRef<string | null>(null);
const [uploading, setUploading] = useState<TransportState[]>([]);
const [downloading, setDownloading] = useState<TransportState[]>([]);
const send = useSender();
const { info } = useConsoleLogger('TransportProvider');
useEffect(() => {
let packet = new PacketRequestTransport();
send(packet);
}, []);
usePacket(0x0F, (packet: PacketRequestTransport) => {
transportServerRef.current = packet.getTransportServer();
info(`Transport server ${transportServerRef.current}`);
});
const uploadFile = async (id: string, content: string) => {
return new Promise((resolve, reject) => {
if (!transportServerRef.current) {
throw new Error("Transport server is not set");
}
setUploading(prev => [...prev, { id: id, progress: 0 }]);
const formData = new FormData();
formData.append('file', new Blob([content]), id);
const xhr = new XMLHttpRequest();
xhr.open('POST', `${transportServerRef.current}/u`);
xhr.upload.onprogress = (event) => {
if (event.lengthComputable) {
const progress = Math.round((event.loaded / event.total) * 100);
setUploading(prev =>
prev.map(u =>
u.id === id ? { ...u, progress } : u
)
);
}
};
xhr.onload = () => {
resolve(JSON.parse(xhr.responseText).t);
setUploading(prev => prev.filter(u => u.id !== id));
};
xhr.onerror = () => {
reject();
setUploading(prev => prev.filter(u => u.id !== id));
};
xhr.send(formData);
});
}
/**
* Скачивает файл с транспортного сервера
* @param tag тег файла
* @param chachaDecryptedKey ключ для расшифровки файла
*/
const downloadFile = (id: string, tag : string) : Promise<string> => {
return new Promise((resolve, reject) => {
if (!transportServerRef.current) {
throw new Error("Transport server is not set");
}
setDownloading(prev => [...prev, { id: id, progress: 0 }]);
const xhr = new XMLHttpRequest();
xhr.open('GET', `${transportServerRef.current}/d/${tag}`);
xhr.responseType = 'text';
xhr.onprogress = (event) => {
if (event.lengthComputable) {
const progress = Math.round((event.loaded / event.total) * 100);
setDownloading(prev =>
prev.map(u =>
u.id === id ? { ...u, progress } : u
)
);
}
};
xhr.onload = async () => {
if(xhr.status != 200){
reject();
return;
}
setDownloading(prev => prev.filter(u => u.id !== tag));
let blob = xhr.responseText;
resolve(blob);
};
xhr.onerror = () => {
setDownloading(prev => prev.filter(u => u.id !== tag));
reject();
};
xhr.send();
});
}
return (
<TransportContext.Provider value={{
transportServer: transportServerRef.current,
uploadFile,
downloadFile,
uploading,
downloading
}}>
{props.children}
</TransportContext.Provider>
)
}

View File

@@ -0,0 +1,13 @@
import { useContext } from "react";
import { TransportContext } from "./TransportProvider";
export function useDownloadStatus(tag: string) {
const context = useContext(TransportContext);
if (!context) {
throw new Error("useDownloadStatus must be used within a TransportProvider");
}
const { downloading } = context;
let downloadState = downloading.find(u => u.id === tag);
return downloadState ? downloadState.progress : 0;
}

View File

@@ -0,0 +1,13 @@
import { useContext } from "react";
import { TransportContext } from "./TransportProvider";
export function useTransport() {
const context = useContext(TransportContext);
if(!context){
throw new Error("useTransport must be used within a TransportProvider");
}
const { uploadFile, downloadFile } = context;
return { downloadFile, uploadFile };
}

View File

@@ -0,0 +1,17 @@
import { useContext } from "react";
import { TransportContext } from "./TransportProvider";
/**
* Хук для получения статуса загрузки файла по его upid
* @returns Функцию для получения статуса загрузки файла по его upid
*/
export function useUploadStatus(upid: string) {
const context = useContext(TransportContext);
if (!context) {
throw new Error("useUploadStatus must be used within a TransportProvider");
}
const { uploading } = context;
let uploadState = uploading.find(u => u.id === upid);
return uploadState ? uploadState.progress : 0;
}