'init'
This commit is contained in:
140
app/providers/TransportProvider/TransportProvider.tsx
Normal file
140
app/providers/TransportProvider/TransportProvider.tsx
Normal 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>
|
||||
)
|
||||
}
|
||||
13
app/providers/TransportProvider/useDownloadStatus.ts
Normal file
13
app/providers/TransportProvider/useDownloadStatus.ts
Normal 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;
|
||||
}
|
||||
13
app/providers/TransportProvider/useTransport.ts
Normal file
13
app/providers/TransportProvider/useTransport.ts
Normal 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 };
|
||||
}
|
||||
17
app/providers/TransportProvider/useUploadStatus.ts
Normal file
17
app/providers/TransportProvider/useUploadStatus.ts
Normal 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;
|
||||
}
|
||||
Reference in New Issue
Block a user