optimization for large folders with masks

Massimo Melina committed Apr 10, 2023 at 15:50 UTC 78609b3f8d2339bd85b40e49029c8e5cef5bed4f
1 file changed +16 -10
src/vfs.ts
+16 -10
@@ -2,7 +2,7 @@
2
3 import fs from 'fs/promises'
4 import { basename, dirname, join, resolve } from 'path'
5 -import { matches, dirStream, dirTraversal, enforceFinal, getOrSet, isDirectory, typedKeys } from './misc'
5 +import { dirStream, dirTraversal, enforceFinal, getOrSet, isDirectory, typedKeys, makeMatcher } from './misc'
6 import Koa from 'koa'
7 import _ from 'lodash'
8 import { defineConfig, setConfig } from './config'
@@ -96,7 +96,7 @@ export async function urlToNode(url: string, ctx?: Koa.Context, parent: VfsNode=
96 isTemp: true,
97 }
98 inheritMasks(ret, parent, name)
99 - applyMasks(ret, parent, name)
99 + parentMaskApplier(parent)(ret, name)
100 inheritFromParent(parent, ret)
101 if (child) // yes
102 return urlToNode(rest, ctx, ret, getRest)
@@ -171,6 +171,7 @@ export function statusCodeForMissingPerm(node: VfsNode, perm: keyof VfsPerm, ctx
171 export async function* walkNode(parent:VfsNode, ctx?: Koa.Context, depth:number=0, prefixPath:string='', requiredPerm?: keyof VfsPerm): AsyncIterableIterator<VfsNode> {
172 const { children, source } = parent
173 const took = prefixPath ? undefined : new Set()
174 + const maskApplier = parentMaskApplier(parent)
175 if (children)
176 for (const child of children) {
177 const nodeName = getNodeName(child)
@@ -225,7 +226,7 @@ export async function* walkNode(parent:VfsNode, ctx?: Koa.Context, depth:number=
226 // item will be changed, so be sure to pass a temp node
227 function canSee(item: VfsNode) {
228 // we basename for depth>0 where we already have the rest of the path in the parent's url, and would be duplicated
228 - applyMasks(item, parent, basename(getNodeName(item)))
229 + maskApplier(item, basename(getNodeName(item)))
230 inheritFromParent(parent, item)
231 if (ctx && !hasPermission(item, 'can_see', ctx)) return
232 item.isTemp = true
@@ -238,13 +239,18 @@ export function masksCouldGivePermission(masks: Masks | undefined, perm: keyof V
239 props[perm] || masksCouldGivePermission(props.masks, perm))
240 }
241
241 -function applyMasks(item: VfsNode, parent: VfsNode, virtualBasename: string) {
242 - const { masks } = parent
243 - if (!masks) return
244 - for (const [k,v] of Object.entries(masks))
245 - if (k.startsWith('**/') && matches(virtualBasename, k.slice(3))
246 - || !k.includes('/') && matches(virtualBasename, k))
247 - _.defaults(item, v)
242 +function parentMaskApplier(parent: VfsNode) {
243 + const matchers = Object.entries(parent.masks || {}).map(([k, v]) => {
244 + k = k.startsWith('**/') ? k.slice(3) : !k.includes('/') ? k : ''
245 + if (!k) return
246 + const m = makeMatcher(k)
247 + return [m, v] as [typeof m, typeof v]
248 + })
249 + return (item: VfsNode, virtualBasename: string) => {
250 + for (const entry of matchers)
251 + if (entry?.[0]?.(virtualBasename))
252 + _.defaults(item, entry[1])
253 + }
254 }
255
256 function inheritMasks(item: VfsNode, parent: VfsNode, virtualBasename:string) {