better code: use new function
Massimo Melina committed
Dec 9, 2024 at 19:58 UTC
938578da4bfaaa0162e5481578bd82223bf4d4d0
5 files changed
+17
-17
frontend/src/UserPanel.ts
+1
-1
@@ -2,7 +2,7 @@
2
3
import { useSnapState } from './state'
4
import { createElement as h } from 'react'
5
-import { alertDialog, closeDialog, newDialog, promptDialog } from './dialog'
5
+import { alertDialog, newDialog, promptDialog } from './dialog'
6
import { createVerifierAndSalt, SRPParameters, SRPRoutines } from 'tssrp6a'
7
import { apiCall } from '@hfs/shared/api'
8
import { logout } from './login'
shared/api.ts
+4
-2
@@ -123,9 +123,11 @@ type EventHandler = (type:string, data?:any) => void
123
124
export function apiEvents(cmd: string, params: Dict, cb:EventHandler) {
125
params = _.omitBy(params, _.isUndefined)
126
- console.debug('API EVENTS', cmd, params)
126
const source = new EventSource(getPrefixUrl() + API_URL + cmd + buildUrlQueryString(params))
128
- source.onopen = () => cb('connected')
127
+ source.onopen = () => {
128
+ console.debug('API EVENTS', cmd, params)
129
+ cb('connected')
130
+ }
131
source.onerror = err => cb('error', err)
132
source.onmessage = ({ data }) => {
133
if (!data) {
src/auth.ts
+5
-5
@@ -3,7 +3,8 @@ import { HTTP_NOT_ACCEPTABLE, HTTP_SERVER_ERROR } from './cross-const'
3
import { SRPParameters, SRPRoutines, SRPServerSession } from 'tssrp6a'
4
import { Context } from 'koa'
5
import { srpClientPart } from './srp'
6
-import { CFG, DAY, getOrSet } from './cross'
6
+import { CFG, DAY } from './cross'
7
+import { expiringCache } from './expiringCache'
8
import { createHash } from 'node:crypto'
9
import events from './events'
10
@@ -20,16 +21,15 @@ export async function srpServerStep1(account: Account) {
21
return { srpServer, salt, pubKey: String(srpServer.B) } // cast to string cause bigint can't be jsonized
22
}
23
23
-const cache: any = {}
24
+const cache = expiringCache<Promise<boolean>>(60_000)
25
export async function srpCheck(username: string, password: string) {
26
const account = getAccount(username)
27
if (!account?.srp || !password) return
28
const k = createHash('sha256').update(username + password + account.srp).digest("hex")
28
- const good = await getOrSet(cache, k, async () => {
29
+ const good = await cache.try(k, async () => {
30
const { srpServer, salt, pubKey } = await srpServerStep1(account)
31
const client = await srpClientPart(username, password, salt, pubKey)
31
- setTimeout(() => delete cache[k], 60_000)
32
- return srpServer.step2(client.A, client.M1).then(() => 1, () => 0)
32
+ return srpServer.step2(client.A, client.M1).then(() => true, () => false)
33
})
34
return good ? account : undefined
35
}
src/expiringCache.ts
+2
-2
@@ -6,8 +6,8 @@ export function expiringCache<T, K=string>(ttl: number) {
6
if (ret === undefined) {
7
ret = creator()
8
o.set(k, ret)
9
- Promise.resolve(ret).then(() =>
10
- setTimeout(() => o.delete(k), ttl))
9
+ Promise.resolve(ret).then(() => // in case of async, wait for it to be done before starting the timer
10
+ setTimeout(() => o.delete(k), ttl) )
11
}
12
return ret
13
},
src/upload.ts
+5
-7
@@ -19,6 +19,7 @@ import { setCommentFor } from './comments'
19
import _ from 'lodash'
20
import events from './events'
21
import { rename, rm } from 'fs/promises'
22
+import { expiringCache } from './expiringCache'
23
24
export const deleteUnfinishedUploadsAfter = defineConfig<undefined|number>('delete_unfinished_uploads_after', 86_400)
25
export const minAvailableMb = defineConfig('min_available_mb', 100)
@@ -40,7 +41,7 @@ function setUploadMeta(path: string, ctx: Koa.Context) {
41
}
42
43
// stay sync because we use this function with formidable()
43
-const diskSpaceCache: any = {}
44
+const diskSpaceCache = expiringCache<ReturnType<typeof getDiskSpaceSync>>(3_000) // invalidate shortly
45
const openFiles = new Set()
46
export function uploadWriter(base: VfsNode, baseUri: string, path: string, ctx: Koa.Context) {
47
let fullPath = ''
@@ -70,12 +71,9 @@ export function uploadWriter(base: VfsNode, baseUri: string, path: string, ctx:
71
while (closestVfsNode?.parent && !closestVfsNode.original)
72
closestVfsNode = closestVfsNode.parent! // if it's not original, it surely has a parent
73
const statDir = closestVfsNode!.source!
73
- if (!Object.hasOwn(diskSpaceCache, statDir)) {
74
- const c = diskSpaceCache[statDir] = getDiskSpaceSync(statDir)
75
- if (!c) throw 'miss'
76
- setTimeout(() => delete diskSpaceCache[statDir], 3_000) // invalidate shortly
77
- }
78
- const { free } = diskSpaceCache[statDir]
74
+ const res = diskSpaceCache.try(statDir, () => getDiskSpaceSync(statDir))
75
+ if (!res) throw 'miss'
76
+ const { free } = res
77
if (typeof free !== 'number' || isNaN(free))
78
throw ''
79
if (reqSize > free - (min || 0))