Skip to content

Commit 8b29785

Browse files
committed
progress bar
1 parent 8f9b094 commit 8b29785

File tree

4 files changed

+109
-45
lines changed

4 files changed

+109
-45
lines changed

src/Lighthouse/upload/files/browser.ts

Lines changed: 22 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ export default async <T extends boolean>(
1313
accessToken: string,
1414
multi: boolean,
1515
dealParameters: DealParameters | undefined,
16-
uploadProgressCallback: (data: IUploadProgressCallback) => void
16+
uploadProgressCallback?: (data: IUploadProgressCallback) => void
1717
): Promise<{ data: UploadFileReturnType<T> }> => {
1818
try {
1919
const endpoint =
@@ -35,35 +35,32 @@ export default async <T extends boolean>(
3535
: 'null',
3636
})
3737

38-
const response = await retryFetch(endpoint, {
39-
method: 'POST',
40-
body: formData,
41-
headers: headers,
42-
timeout: 7200000,
43-
})
38+
const response = uploadProgressCallback
39+
? await retryFetch(endpoint, {
40+
method: 'POST',
41+
body: formData,
42+
headers: headers,
43+
timeout: 7200000,
44+
onProgress: (progress) => {
45+
uploadProgressCallback({
46+
progress: progress,
47+
total: 100, // We don't have the total size here, so we're using 100 as a percentage
48+
uploaded: progress * 100,
49+
})
50+
},
51+
})
52+
: await retryFetch(endpoint, {
53+
method: 'POST',
54+
body: formData,
55+
headers: headers,
56+
timeout: 7200000,
57+
})
4458

4559
if (!response.ok) {
4660
throw new Error(`Request failed with status code ${response.status}`)
4761
}
4862

49-
const reader = response.body?.getReader()
50-
const decoder = new TextDecoder()
51-
let responseText = ''
52-
53-
if (reader) {
54-
let totalBytes = 0
55-
while (true) {
56-
const { done, value } = await reader.read()
57-
if (done) break
58-
totalBytes += value?.length || 0
59-
responseText += decoder.decode(value, { stream: true })
60-
uploadProgressCallback({
61-
progress: 1, // We can't accurately calculate progress without knowing the total size
62-
total: totalBytes,
63-
uploaded: totalBytes,
64-
})
65-
}
66-
}
63+
const responseText = await response.text()
6764

6865
let data
6966
if (typeof responseText === 'string') {

src/Lighthouse/upload/files/index.ts

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,7 @@ async function uploadFiles(
4141
apiKey,
4242
true,
4343
dealParameters,
44-
uploadProgressCallback ||
45-
(() => {
46-
return
47-
})
44+
uploadProgressCallback
4845
)
4946
}
5047
} else {
@@ -57,10 +54,7 @@ async function uploadFiles(
5754
apiKey,
5855
false,
5956
dealParameters,
60-
uploadProgressCallback ||
61-
(() => {
62-
return
63-
})
57+
uploadProgressCallback
6458
)
6559
}
6660
}

src/Lighthouse/utils/util.ts

Lines changed: 76 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { ethers } from 'ethers'
22

33
interface FetchOptions extends RequestInit {
44
timeout?: number
5+
onProgress?: (progress: number) => void
56
}
67

78
const isCID = (cid: string) => {
@@ -41,17 +42,85 @@ async function fetchWithTimeout(
4142
resource: string,
4243
options: FetchOptions
4344
): Promise<Response> {
44-
const { timeout = 8000, ...rest } = options
45+
const { timeout = 8000, onProgress, ...rest } = options
4546

4647
const controller = new AbortController()
4748
const id = setTimeout(() => controller.abort(), timeout)
49+
4850
try {
49-
const response = await fetch(resource, {
50-
...rest,
51-
signal: controller.signal,
52-
})
53-
clearTimeout(id)
54-
return response
51+
if (onProgress && rest.body instanceof FormData) {
52+
return new Promise<Response>((resolve, reject) => {
53+
const xhr = new XMLHttpRequest()
54+
xhr.open(rest.method || 'GET', resource)
55+
56+
if (rest.headers) {
57+
if (rest.headers instanceof Headers) {
58+
rest.headers.forEach((value, key) => {
59+
xhr.setRequestHeader(key, value)
60+
})
61+
} else if (typeof rest.headers === 'object') {
62+
for (const [key, value] of Object.entries(rest.headers)) {
63+
xhr.setRequestHeader(key, value as string)
64+
}
65+
}
66+
}
67+
68+
xhr.timeout = timeout
69+
xhr.onload = () => {
70+
const headers = new Headers()
71+
xhr
72+
.getAllResponseHeaders()
73+
.trim()
74+
.split(/[\r\n]+/)
75+
.forEach((line) => {
76+
const parts = line.split(': ')
77+
const header = parts.shift()
78+
const value = parts.join(': ')
79+
if (header) headers.set(header, value)
80+
})
81+
82+
resolve(
83+
new Response(xhr.response, {
84+
status: xhr.status,
85+
statusText: xhr.statusText,
86+
headers: headers,
87+
})
88+
)
89+
}
90+
xhr.onerror = () => reject(new Error('Network error'))
91+
xhr.ontimeout = () => reject(new Error('Request timed out'))
92+
xhr.upload.onprogress = (event: ProgressEvent) => {
93+
if (event.lengthComputable) {
94+
onProgress(event.loaded / event.total)
95+
}
96+
}
97+
98+
// Handle different body types
99+
if (rest.body instanceof FormData) {
100+
xhr.send(rest.body)
101+
} else if (rest.body instanceof ReadableStream) {
102+
// Convert ReadableStream to Blob and then send
103+
new Response(rest.body).blob().then((blob) => xhr.send(blob))
104+
} else if (
105+
typeof rest.body === 'string' ||
106+
rest.body instanceof Blob ||
107+
rest.body instanceof ArrayBuffer
108+
) {
109+
xhr.send(rest.body)
110+
} else if (rest.body == null) {
111+
xhr.send()
112+
} else {
113+
reject(new Error('Unsupported body type'))
114+
}
115+
})
116+
} else {
117+
const response = await fetch(resource, {
118+
...rest,
119+
signal: controller.signal,
120+
})
121+
clearTimeout(id)
122+
return response
123+
}
55124
} catch (error) {
56125
clearTimeout(id)
57126
throw error

tsconfig.json

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,11 @@
22
"compilerOptions": {
33
"outDir": "dist",
44
"target": "es2022",
5-
"lib": [
6-
"es2019"
7-
],
5+
"lib": ["es2019", "es6", "dom"],
86
"module": "commonjs",
97
"sourceMap": false,
108
"strict": true,
11-
"esModuleInterop": true,
9+
"esModuleInterop": true,
1210
"skipLibCheck": true,
1311
"forceConsistentCasingInFileNames": true,
1412
"experimentalDecorators": true,
@@ -19,5 +17,11 @@
1917
"resolveJsonModule": true
2018
},
2119
"include": ["src"],
22-
"exclude": ["node_modules", "**/*.spec.ts","**/*.test.ts",".vscode",".d.ts"]
20+
"exclude": [
21+
"node_modules",
22+
"**/*.spec.ts",
23+
"**/*.test.ts",
24+
".vscode",
25+
".d.ts"
26+
]
2327
}

0 commit comments

Comments
 (0)