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; downloadFile: (id: string, tag: string) => Promise; uploading: TransportState[]; downloading: TransportState[]; } export const TransportContext = createContext(null); interface TransportProviderProps { children: React.ReactNode; } export interface TransportState { id: string; progress: number; } /** * Этот провайдер занимается тем, что передает * файлы на сервер и получает их с сервера */ export function TransportProvider(props: TransportProviderProps) { const transportServerRef = useRef(null); const [uploading, setUploading] = useState([]); const [downloading, setDownloading] = useState([]); 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 => { 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 ( {props.children} ) }