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))