|
|
|
@ -97,6 +97,7 @@ export default function Downloader({
|
|
|
|
const [shouldAttemptConnection, setShouldAttemptConnection] = useState(false)
|
|
|
|
const [shouldAttemptConnection, setShouldAttemptConnection] = useState(false)
|
|
|
|
const [open, setOpen] = useState(false)
|
|
|
|
const [open, setOpen] = useState(false)
|
|
|
|
const [downloading, setDownloading] = useState(false)
|
|
|
|
const [downloading, setDownloading] = useState(false)
|
|
|
|
|
|
|
|
const [done, setDone] = useState(false)
|
|
|
|
const [errorMessage, setErrorMessage] = useState<string | null>(null)
|
|
|
|
const [errorMessage, setErrorMessage] = useState<string | null>(null)
|
|
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
useEffect(() => {
|
|
|
|
@ -177,32 +178,59 @@ export default function Downloader({
|
|
|
|
const handleStartDownload = useCallback(() => {
|
|
|
|
const handleStartDownload = useCallback(() => {
|
|
|
|
setDownloading(true)
|
|
|
|
setDownloading(true)
|
|
|
|
|
|
|
|
|
|
|
|
const fileStreams = filesInfo.map((_info) => {
|
|
|
|
const fileStreamByPath: Record<
|
|
|
|
return new ReadableStream({
|
|
|
|
string,
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
stream: ReadableStream
|
|
|
|
|
|
|
|
enqueue: (chunk: any) => void
|
|
|
|
|
|
|
|
close: () => void
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
> = {}
|
|
|
|
|
|
|
|
const fileStreams = filesInfo.map((info) => {
|
|
|
|
|
|
|
|
let enqueue: ((chunk: any) => void) | null = null
|
|
|
|
|
|
|
|
let close: (() => void) | null = null
|
|
|
|
|
|
|
|
const stream = new ReadableStream({
|
|
|
|
start(ctrl) {
|
|
|
|
start(ctrl) {
|
|
|
|
console.log('START')
|
|
|
|
enqueue = (chunk: any) => ctrl.enqueue(chunk)
|
|
|
|
console.log(ctrl)
|
|
|
|
close = () => ctrl.close()
|
|
|
|
},
|
|
|
|
|
|
|
|
async pull(ctrl) {
|
|
|
|
|
|
|
|
console.log('PULL')
|
|
|
|
|
|
|
|
console.log(ctrl)
|
|
|
|
|
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
fileStreamByPath[info.fullPath] = {
|
|
|
|
|
|
|
|
stream,
|
|
|
|
|
|
|
|
enqueue,
|
|
|
|
|
|
|
|
close,
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return stream
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
const fileStreamByPath: Record<string, ReadableStream> = {}
|
|
|
|
let nextFileIndex = 0
|
|
|
|
fileStreams.forEach((stream, i) => {
|
|
|
|
const startNextFileOrFinish = (): void => {
|
|
|
|
fileStreamByPath[filesInfo[i].fullPath] = stream
|
|
|
|
if (nextFileIndex >= filesInfo.length) {
|
|
|
|
})
|
|
|
|
return
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const request: t.TypeOf<typeof Message> = {
|
|
|
|
|
|
|
|
type: MessageType.Start,
|
|
|
|
|
|
|
|
fullPath: filesInfo[nextFileIndex].fullPath,
|
|
|
|
|
|
|
|
offset: 0,
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
dataConnection.send(request)
|
|
|
|
|
|
|
|
nextFileIndex++
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const processChunkFunc = (message: t.TypeOf<typeof ChunkMessage>): void => {
|
|
|
|
const processChunkFunc = (message: t.TypeOf<typeof ChunkMessage>): void => {
|
|
|
|
const stream = fileStreamByPath[message.fullPath]
|
|
|
|
const fileStream = fileStreamByPath[message.fullPath]
|
|
|
|
if (!stream) {
|
|
|
|
if (!fileStream) {
|
|
|
|
console.error('no stream found for ' + message.fullPath)
|
|
|
|
console.error('no stream found for ' + message.fullPath)
|
|
|
|
return
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
console.log(stream)
|
|
|
|
const uInt8 = new Uint8Array(message.bytes as ArrayBuffer)
|
|
|
|
|
|
|
|
fileStream.enqueue(uInt8)
|
|
|
|
|
|
|
|
if (message.final) {
|
|
|
|
|
|
|
|
fileStream.close()
|
|
|
|
|
|
|
|
startNextFileOrFinish()
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
processChunk.current = processChunkFunc
|
|
|
|
processChunk.current = processChunkFunc
|
|
|
|
|
|
|
|
|
|
|
|
@ -223,20 +251,23 @@ export default function Downloader({
|
|
|
|
|
|
|
|
|
|
|
|
downloadPromise
|
|
|
|
downloadPromise
|
|
|
|
.then(() => {
|
|
|
|
.then(() => {
|
|
|
|
console.log('DONE')
|
|
|
|
const request: t.TypeOf<typeof Message> = {
|
|
|
|
|
|
|
|
type: MessageType.Done,
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
dataConnection.send(request)
|
|
|
|
|
|
|
|
setDone(true)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
.catch((err) => {
|
|
|
|
.catch((err) => {
|
|
|
|
console.error(err)
|
|
|
|
console.error(err)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
const request: t.TypeOf<typeof Message> = {
|
|
|
|
startNextFileOrFinish()
|
|
|
|
type: MessageType.Start,
|
|
|
|
|
|
|
|
fullPath: filesInfo[0].fullPath,
|
|
|
|
|
|
|
|
offset: 0,
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
dataConnection.send(request)
|
|
|
|
|
|
|
|
}, [dataConnection, filesInfo])
|
|
|
|
}, [dataConnection, filesInfo])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (done) {
|
|
|
|
|
|
|
|
return <div>Done!</div>
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (downloading) {
|
|
|
|
if (downloading) {
|
|
|
|
return <div>Downloading</div>
|
|
|
|
return <div>Downloading</div>
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|