better code
Massimo Melina committed
Apr 14, 2023 at 16:24 UTC
6ec53112b2b5d1f83aa73afdea2c402e1eeca1c9
5 files changed
+37
-35
frontend/src/i18n.ts
+2
-3
@@ -1,6 +1,5 @@
1
-import { findFirst, getHFS, urlParams } from './misc'
2
-import { createElement as h, Fragment, useEffect } from 'react'
3
-import { useApi } from './api'
1
+import { findFirst, getHFS } from './misc'
2
+import { createElement as h, Fragment } from 'react'
3
import { proxy, useSnapshot } from 'valtio'
4
5
const state = proxy<{ langs: string[], embedded: string }>({ embedded: '', langs: [] })
frontend/src/upload.ts
+25
-26
@@ -281,33 +281,32 @@ async function startUpload(f: File, to: string, resume=0) {
281
req.send(form)
282
283
async function subscribeNotifications() {
284
- if (!notificationChannel) {
285
- notificationChannel = 'upload-' + Math.random().toString(36).slice(2)
286
- notificationSource = await getNotification(notificationChannel, async (name, data) => {
287
- const {uploading} = uploadState
288
- if (!uploading) return
289
- if (name === 'upload.resumable') {
290
- const size = data?.[path(uploading)]
291
- if (!size || size > f.size) return
292
- const {expires} = data
293
- const timeout = typeof expires !== 'number' ? 0
294
- : (Number(new Date(expires)) - Date.now()) / 1000
295
- closeLast?.()
296
- const msg = t('confirm_resume', "Resume upload?") + ` (${formatPerc(size/f.size)} = ${formatBytes(size)})`
297
- if (!await confirmDialog(msg, { timeout, getClose: x => closeLast=x })) return
298
- if (uploading !== uploadState.uploading) return // too late
299
- resuming = true
284
+ if (notificationChannel) return
285
+ notificationChannel = 'upload-' + Math.random().toString(36).slice(2)
286
+ notificationSource = await getNotification(notificationChannel, async (name, data) => {
287
+ const {uploading} = uploadState
288
+ if (!uploading) return
289
+ if (name === 'upload.resumable') {
290
+ const size = data?.[path(uploading)]
291
+ if (!size || size > f.size) return
292
+ const {expires} = data
293
+ const timeout = typeof expires !== 'number' ? 0
294
+ : (Number(new Date(expires)) - Date.now()) / 1000
295
+ closeLast?.()
296
+ const msg = t('confirm_resume', "Resume upload?") + ` (${formatPerc(size/f.size)} = ${formatBytes(size)})`
297
+ if (!await confirmDialog(msg, { timeout, getClose: x => closeLast=x })) return
298
+ if (uploading !== uploadState.uploading) return // too late
299
+ resuming = true
300
+ abortCurrentUpload()
301
+ return startUpload(f, to, size)
302
+ }
303
+ if (name === 'upload.status') {
304
+ overrideStatus = data?.[path(uploading)]
305
+ if (overrideStatus >= 400)
306
abortCurrentUpload()
301
- return startUpload(f, to, size)
302
- }
303
- if (name === 'upload.status') {
304
- overrideStatus = data?.[path(uploading)]
305
- if (overrideStatus >= 400)
306
- abortCurrentUpload()
307
- return
308
- }
309
- })
310
- }
307
+ return
308
+ }
309
+ })
310
}
311
312
function error(status: number) {
src/debounceAsync.ts
+3
-3
@@ -22,7 +22,7 @@ export default function debounceAsync<CB extends (...args: any[]) => Promise<R>,
22
23
async function debouncer(...args:any[]) {
24
if (runningCallback)
25
- return await runningCallback
25
+ return runningCallback
26
whoIsWaiting = args
27
waitingSince ||= Date.now()
28
const waitingCap = maxWait - (Date.now() - (waitingSince || started))
@@ -33,7 +33,7 @@ export default function debounceAsync<CB extends (...args: any[]) => Promise<R>,
33
return void(waitingSince = 0)
34
if (whoIsWaiting !== args) // another fresher call is waiting
35
return runningDebouncer
36
- return await exec()
36
+ return exec()
37
}
38
39
async function exec() {
@@ -42,7 +42,7 @@ export default function debounceAsync<CB extends (...args: any[]) => Promise<R>,
42
started = Date.now()
43
try {
44
runningCallback = callback.apply(null, whoIsWaiting)
45
- return await runningCallback
45
+ return await runningCallback // await necessary to go-finally at the right time and even on exceptions
46
}
47
finally {
48
whoIsWaiting = undefined
src/lang.ts
+3
-3
@@ -1,5 +1,5 @@
1
import Koa from 'koa'
2
-import { wantArray } from './misc'
2
+import { hasProp, wantArray } from './misc'
3
import { readFile } from 'fs/promises'
4
import { defineConfig } from './config'
5
import { watchLoad } from './watchLoad'
@@ -30,8 +30,8 @@ export async function getLangData(ctx: Koa.Context) {
30
if (!k || k === EMBEDDED_LANGUAGE) break
31
try { ret[k!] = JSON.parse(await readFile(`hfs-lang-${k}.json`, 'utf8')) }
32
catch {
33
- if (k in EMBEDDED_TRANSLATIONS)
34
- ret[k] = EMBEDDED_TRANSLATIONS[k as keyof typeof EMBEDDED_TRANSLATIONS]
33
+ if (hasProp(EMBEDDED_TRANSLATIONS, k))
34
+ ret[k] = EMBEDDED_TRANSLATIONS[k]
35
else {
36
do { k = k.substring(0, k.lastIndexOf('-'))
37
} while (k && langs.includes(k))
src/misc.ts
+4
@@ -164,6 +164,10 @@ export function typedKeys<T extends {}>(o: T) {
164
return Object.keys(o) as (keyof T)[]
165
}
166
167
+export function hasProp<T extends object>(obj: T, key: PropertyKey): key is keyof T {
168
+ return key in obj;
169
+}
170
+
171
export function with_<T,RT>(par:T, cb: (par:T) => RT) {
172
return cb(par)
173
}