Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/lang/en/home.json
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@
"no_files_drag": "No files were dragged in.",
"upload_files": "Choose Files",
"upload_folder": "Choose Folder",
"hashing": "Hashing",
"pending": "Pending",
"uploading": "Uploading",
"backending": "Uploading in the backend",
Expand Down
6 changes: 5 additions & 1 deletion src/pages/home/uploads/form.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,15 @@ export const FormUpload: Upload = async (
Overwrite: overwrite.toString(),
}
if (rapid) {
const { md5, sha1, sha256 } = await calculateHash(file)
setUpload("status", "hashing")
const { md5, sha1, sha256 } = await calculateHash(file, (p) => {
setUpload("progress", p | 0)
})
headers["X-File-Md5"] = md5
headers["X-File-Sha1"] = sha1
headers["X-File-Sha256"] = sha256
}
setUpload("status", "uploading")
const resp: EmptyResp = await r.put("/fs/form", form, {
headers: headers,
onUploadProgress: (progressEvent) => {
Expand Down
38 changes: 38 additions & 0 deletions src/pages/home/uploads/hash-worker.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { createMD5, createSHA1, createSHA256 } from "hash-wasm"

self.onmessage = async (e: MessageEvent<{ file: File }>) => {
const { file } = e.data
try {
const md5Digest = await createMD5()
const sha1Digest = await createSHA1()
const sha256Digest = await createSHA256()
const reader = file.stream().getReader()
let loaded = 0
while (true) {
const { done, value } = await reader.read()
if (done) {
break
}
loaded += value.length
md5Digest.update(value)
sha1Digest.update(value)
sha256Digest.update(value)
self.postMessage({
type: "progress",
progress: (loaded / file.size) * 100,
})
}
const md5 = md5Digest.digest("hex")
const sha1 = sha1Digest.digest("hex")
const sha256 = sha256Digest.digest("hex")
self.postMessage({
type: "result",
hash: { md5, sha1, sha256 },
})
} catch (error) {
self.postMessage({
type: "error",
error: error instanceof Error ? error.message : String(error),
})
}
}
6 changes: 5 additions & 1 deletion src/pages/home/uploads/stream.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,15 @@ export const StreamUpload: Upload = async (
Overwrite: overwrite.toString(),
}
if (rapid) {
const { md5, sha1, sha256 } = await calculateHash(file)
setUpload("status", "hashing")
const { md5, sha1, sha256 } = await calculateHash(file, (p) => {
setUpload("progress", p | 0)
})
headers["X-File-Md5"] = md5
headers["X-File-Sha1"] = sha1
headers["X-File-Sha256"] = sha256
}
setUpload("status", "uploading")
const resp: EmptyResp = await r.put("/fs/put", file, {
headers: headers,
onUploadProgress: (progressEvent) => {
Expand Down
9 changes: 8 additions & 1 deletion src/pages/home/uploads/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
type Status = "pending" | "uploading" | "backending" | "success" | "error"
type Status =
| "pending"
| "hashing"
| "uploading"
| "backending"
| "success"
| "error"
export interface UploadFileProps {
name: string
path: string
Expand All @@ -10,6 +16,7 @@ export interface UploadFileProps {
}
export const StatusBadge = {
pending: "neutral",
hashing: "warning",
uploading: "info",
backending: "info",
success: "success",
Expand Down
49 changes: 28 additions & 21 deletions src/pages/home/uploads/util.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { UploadFileProps } from "./types"
import { createMD5, createSHA1, createSHA256 } from "hash-wasm"

export const traverseFileTree = async (entry: FileSystemEntry) => {
let res: File[] = []
Expand Down Expand Up @@ -68,24 +67,32 @@ export const File2Upload = (file: File): UploadFileProps => {
}
}

export const calculateHash = async (file: File) => {
const md5Digest = await createMD5()
const sha1Digest = await createSHA1()
const sha256Digest = await createSHA256()
const reader = file.stream().getReader()
const read = async () => {
const { done, value } = await reader.read()
if (done) {
return
}
md5Digest.update(value)
sha1Digest.update(value)
sha256Digest.update(value)
await read()
}
await read()
const md5 = md5Digest.digest("hex")
const sha1 = sha1Digest.digest("hex")
const sha256 = sha256Digest.digest("hex")
return { md5, sha1, sha256 }
export const calculateHash = async (
file: File,
onProgress?: (progress: number) => void,
) => {
return new Promise<{ md5: string; sha1: string; sha256: string }>(
(resolve, reject) => {
const worker = new Worker(new URL("./hash-worker.ts", import.meta.url), {
type: "module",
})
worker.postMessage({ file })
worker.onmessage = (e) => {
const { type, progress, hash, error } = e.data
if (type === "progress") {
onProgress?.(progress)
} else if (type === "result") {
worker.terminate()
resolve(hash)
} else if (type === "error") {
worker.terminate()
reject(new Error(error))
}
}
worker.onerror = (e) => {
worker.terminate()
reject(e)
}
},
)
}