@glodon-aiot/react-components
Version:
aiot react components
154 lines (153 loc) • 5.79 kB
JavaScript
var U = (c, Z, f) => new Promise((I, u) => {
var P = (w) => {
try {
E(f.next(w));
} catch (t) {
u(t);
}
}, p = (w) => {
try {
E(f.throw(w));
} catch (t) {
u(t);
}
}, E = (w) => w.done ? I(w.value) : Promise.resolve(w.value).then(P, p);
E((f = f.apply(c, Z)).next());
});
import { useState as h, useEffect as _, useCallback as M } from "react";
import { configure as A, BlobReader as L, ZipReader as R, HttpRangeReader as k, BlobWriter as H } from "@zip.js/zip.js";
import { ZIP_CHUNK_SIZE as O, MAX_FALLBACK_SIZE as y, MAX_ZIP_FILES as m, ZIP_ENTRIES_TIMEOUT as B, MAX_ZIP_FILE_SIZE as C, SAFE_FILE_TYPES as D } from "../constants.mjs";
import { checkRangeSupport as j, getFileSize as v } from "../utils.mjs";
import { getFileExtension as x, getFileType as W } from "../../../utils/file.mjs";
const S = {
filenameEncoding: "utf-8"
}, Q = (c) => {
const [Z, f] = h([]), [I, u] = h(!0), [P, p] = h(null), [E, w] = h(null), [t, T] = h(null);
_(() => {
if (!c) {
p("文件URL不能为空"), u(!1);
return;
}
u(!0), p(null), f([]), w(null), t != null && t.blobUrl && (URL.revokeObjectURL(t.blobUrl), T(null));
let e = null;
U(void 0, null, function* () {
try {
A({
chunkSize: O,
useWebWorkers: !1
});
const {
supportsRange: n,
fileSize: r
} = yield j(c);
if (n) {
const o = new k(c);
e = new R(o, S);
const b = (yield Promise.race([e.getEntries(), new Promise((i, a) => setTimeout(() => a(new Error("读取 ZIP 目录结构超时")), B))])).filter((i) => !i.directory).map((i) => ({
name: i.filename,
size: i.uncompressedSize || 0,
isDirectory: !1
}));
b.sort((i, a) => i.name.localeCompare(a.name)), b.length > m ? (p(`ZIP 文件包含 ${b.length} 个文件,仅显示前 ${m} 个`), f(b.slice(0, m))) : f(b);
} else {
if (r > y)
throw new Error(`服务器不支持 HTTP Range 请求,且文件过大(${Math.round(r / 1024 / 1024)}MB),无法预览。请下载后查看。`);
const o = yield fetch(c);
if (!o.ok)
throw new Error(`HTTP error! status: ${o.status}`);
const g = yield o.blob(), b = new L(g);
e = new R(b, S);
const a = (yield e.getEntries()).filter((s) => !s.directory).map((s) => ({
name: s.filename,
size: s.uncompressedSize || 0,
isDirectory: !1
}));
a.sort((s, l) => s.name.localeCompare(l.name)), a.length > m ? (p(`ZIP 文件包含 ${a.length} 个文件,仅显示前 ${m} 个`), f(a.slice(0, m))) : f(a);
}
e && (yield e.close()), u(!1);
} catch (n) {
if (e)
try {
yield e.close();
} catch (o) {
}
const r = n.message || n.toString() || "加载 ZIP 文件失败";
if (r.includes("Range") || r.includes("range") || r.includes("HTTP Range not supported") || r.includes("超时"))
try {
const o = yield v(c);
if (o > y)
throw new Error(`文件过大(${Math.round(o / 1024 / 1024)}MB),无法通过 Range 请求加载,且文件过大无法下载整个文件预览。请下载后查看。`);
const g = yield fetch(c);
if (!g.ok)
throw new Error(`HTTP error! status: ${g.status}`);
const b = yield g.blob(), i = new L(b);
e = new R(i, S);
const s = (yield e.getEntries()).filter((l) => !l.directory).map((l) => ({
name: l.filename,
size: l.uncompressedSize || 0,
isDirectory: !1
}));
s.sort((l, d) => l.name.localeCompare(d.name)), s.length > m ? (p(`ZIP 文件包含 ${s.length} 个文件,仅显示前 ${m} 个`), f(s.slice(0, m))) : f(s), e && (yield e.close()), u(!1);
return;
} catch (o) {
const g = o.message || o.toString();
p(`ZIP 文件加载失败: ${r}。Fallback 方案也失败: ${g}`);
}
else
p(r);
u(!1);
}
});
}, [c]);
const z = M((e) => U(void 0, null, function* () {
if (E === e && t) {
w(null), t.blobUrl && URL.revokeObjectURL(t.blobUrl), T(null);
return;
}
w(e);
try {
let n = null, r;
try {
const s = new k(c);
n = new R(s, S), r = (yield n.getEntries()).find((d) => d.filename === e);
} catch (s) {
const l = yield fetch(c);
if (!l.ok)
throw new Error(`HTTP error! status: ${l.status}`);
const d = yield l.blob(), $ = new L(d);
n = new R($, S), r = (yield n.getEntries()).find((F) => F.filename === e);
}
if (!r)
throw new Error("文件不存在");
if (r.directory)
throw new Error("无法预览目录");
if ((r.uncompressedSize || 0) > C)
throw new Error("文件过大(超过 100MB),无法预览");
const g = yield r.getData(new H()), b = URL.createObjectURL(g), i = x(e), a = W(i);
if (!D.includes(a))
throw new Error(`不支持预览 ${i || "未知"} 格式的文件`);
T({
name: e,
blobUrl: b,
type: a
}), n && (yield n.close());
} catch (n) {
const r = n.message || n.toString() || "预览文件失败";
p(r);
}
}), [c, E, t]);
return _(() => () => {
t != null && t.blobUrl && URL.revokeObjectURL(t.blobUrl);
}, [t]), {
zipFiles: Z,
zipLoading: I,
zipError: P,
selectedZipFile: E,
zipFileContent: t,
handleFileClick: z,
setSelectedZipFile: w
};
};
export {
Q as useZipViewer
};