140 lines
4.8 KiB
TypeScript
140 lines
4.8 KiB
TypeScript
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>
|
||
)
|
||
} |