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 }