mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-20 09:46:28 +08:00
ui: multi-thread bulk download
This commit is contained in:
1 parent
17a2d4732d
commit
375a06a98d
3 files changed
+41
-27
No files matched your search
@@ -4,6 +4,7 @@ import { createZipStream } from 'vj/utils/zip';
|
|||||||
import pipeStream from 'vj/utils/pipeStream';
|
import pipeStream from 'vj/utils/pipeStream';
|
||||||
import i18n from 'vj/utils/i18n';
|
import i18n from 'vj/utils/i18n';
|
||||||
import request from 'vj/utils/request';
|
import request from 'vj/utils/request';
|
||||||
|
import PQueue from 'p-queue/dist/index';
|
||||||
import Notification from 'vj/components/notification';
|
import Notification from 'vj/components/notification';
|
||||||
import api, { gql } from 'vj/utils/api';
|
import api, { gql } from 'vj/utils/api';
|
||||||
|
|
||||||
@@ -28,38 +29,49 @@ const waitForWritableStream = window.WritableStream
|
|||||||
streamsaver.WritableStream = window.WritableStream;
|
streamsaver.WritableStream = window.WritableStream;
|
||||||
});
|
});
|
||||||
|
|
||||||
export default async function download(name, targets) {
|
export default async function download(filename, targets) {
|
||||||
await waitForWritableStream;
|
await waitForWritableStream;
|
||||||
const fileStream = streamsaver.createWriteStream(name);
|
const fileStream = streamsaver.createWriteStream(filename);
|
||||||
|
const queue = new PQueue({ concurrency: 5 });
|
||||||
|
const abortCallbackReceiver = {};
|
||||||
|
function stopDownload() { abortCallbackReceiver.abort(); }
|
||||||
let i = 0;
|
let i = 0;
|
||||||
|
async function downloadFile(target) {
|
||||||
|
try {
|
||||||
|
let stream;
|
||||||
|
if (target.url) {
|
||||||
|
const response = await fetch(target.url);
|
||||||
|
if (!response.ok) throw response.statusText;
|
||||||
|
stream = response.body;
|
||||||
|
} else {
|
||||||
|
stream = new Blob([target.content]).stream();
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
name: target.filename,
|
||||||
|
stream,
|
||||||
|
};
|
||||||
|
} catch (e) {
|
||||||
|
stopDownload();
|
||||||
|
Notification.error(i18n('Download Error', [target.filename, e.toString()]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const handles = [];
|
||||||
|
for (const target of targets) {
|
||||||
|
handles.push(queue.add(() => downloadFile(target)));
|
||||||
|
}
|
||||||
|
queue.start();
|
||||||
const zipStream = createZipStream({
|
const zipStream = createZipStream({
|
||||||
// eslint-disable-next-line consistent-return
|
// eslint-disable-next-line consistent-return
|
||||||
async pull(ctrl) {
|
async pull(ctrl) {
|
||||||
if (i === targets.length) return ctrl.close();
|
if (!handles[i]) return ctrl.close();
|
||||||
try {
|
const { name, stream } = await handles[i];
|
||||||
if (targets[i].url) {
|
|
||||||
const response = await fetch(targets[i].url);
|
|
||||||
if (!response.ok) throw response.statusText;
|
|
||||||
ctrl.enqueue({
|
|
||||||
name: targets[i].filename,
|
|
||||||
stream: () => response.body,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
ctrl.enqueue({
|
|
||||||
name: targets[i].filename,
|
|
||||||
stream: () => new Blob([targets[i].content]).stream(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
||||||
stopDownload();
|
|
||||||
Notification.error(i18n('Download Error', [targets[i].filename, e.toString()]));
|
|
||||||
}
|
|
||||||
i++;
|
i++;
|
||||||
|
ctrl.enqueue({
|
||||||
|
name,
|
||||||
|
stream: () => stream,
|
||||||
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const abortCallbackReceiver = {};
|
|
||||||
function stopDownload() { abortCallbackReceiver.abort(); }
|
|
||||||
window.addEventListener('unload', stopDownload);
|
window.addEventListener('unload', stopDownload);
|
||||||
window.addEventListener('beforeunload', onBeforeUnload);
|
window.addEventListener('beforeunload', onBeforeUnload);
|
||||||
await pipeStream(zipStream, fileStream, abortCallbackReceiver);
|
await pipeStream(zipStream, fileStream, abortCallbackReceiver);
|
||||||
@@ -68,7 +80,7 @@ export default async function download(name, targets) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function downloadProblemSet(pids, name = 'Export') {
|
export async function downloadProblemSet(pids, name = 'Export') {
|
||||||
Notification.info('Downloading...');
|
Notification.info(i18n('Downloading...'));
|
||||||
const targets = [];
|
const targets = [];
|
||||||
try {
|
try {
|
||||||
for (const pid of pids) {
|
for (const pid of pids) {
|
||||||
@@ -131,7 +143,7 @@ export async function downloadProblemSet(pids, name = 'Export') {
|
|||||||
}
|
}
|
||||||
await download(`${name}.zip`, targets);
|
await download(`${name}.zip`, targets);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
Notification.warn(`${e.error?.message} ${e.error?.params?.[0]}`);
|
Notification.error(`${e.message} ${e.params?.[0]}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ async function load() {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
Notification.warn(`Failed to call '${type}Loading' of ${page.name}`);
|
Notification.warn(`Failed to call '${type}Loading' of ${page.name}`);
|
||||||
console.error(`Failed to call '${type}Loading' of ${page.name}\n${e.stack}`);
|
console.error(`Failed to call '${type}Loading' of ${page.name}\n${e.stack}`);
|
||||||
|
console.error(e);
|
||||||
}
|
}
|
||||||
if (process.env.NODE_ENV !== 'production') {
|
if (process.env.NODE_ENV !== 'production') {
|
||||||
console.time(`${page.name}: ${type}Loading`);
|
console.time(`${page.name}: ${type}Loading`);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@hydrooj/ui-default",
|
"name": "@hydrooj/ui-default",
|
||||||
"version": "4.34.19",
|
"version": "4.34.20",
|
||||||
"author": "undefined <i@undefined.moe>",
|
"author": "undefined <i@undefined.moe>",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"main": "hydro.js",
|
"main": "hydro.js",
|
||||||
@@ -122,6 +122,7 @@
|
|||||||
"markdown-it-table-of-contents": "^0.6.0",
|
"markdown-it-table-of-contents": "^0.6.0",
|
||||||
"mongodb": "^3.7.3",
|
"mongodb": "^3.7.3",
|
||||||
"nunjucks": "^3.2.3",
|
"nunjucks": "^3.2.3",
|
||||||
|
"p-queue": "^7.2.0",
|
||||||
"react-query": "^3.34.16",
|
"react-query": "^3.34.16",
|
||||||
"streamsaver": "^2.0.6",
|
"streamsaver": "^2.0.6",
|
||||||
"xss": "^1.0.11"
|
"xss": "^1.0.11"
|
||||||
|
|||||||
Reference in new issue
Block a user