api.file_list: support for { offset, limit }
Massimo Melina committed
Dec 19, 2021 at 21:43 UTC
19d45f6cbf8acdb47cf6553915e1bb79dbac21ba
3 files changed
+31
-17
dev-notes.md
+1
@@ -8,6 +8,7 @@
8
- when reloading vfs wait for it to be unlocked
9
- search
10
- sticky breadcrumbs
11
+- frontend: ensure icons are loaded before going on
12
- frontend: dialogs
13
- vfs: serve an html for a folder?
14
- "default" property for vfsNode?
src/apis.ts
+30
-6
@@ -1,11 +1,12 @@
1
import Koa from 'koa'
2
import { directPermOnNode, vfs, VfsNode } from './vfs'
3
-import { globDir } from './misc'
3
+import { complySlashes, enforceFinal } from './misc'
4
import { Stats } from 'fs'
5
import { stat } from 'fs/promises'
6
import _ from 'lodash'
7
import { getCurrentUser, verifyLogin } from './perm'
8
import { sessions } from './sessions'
9
+import glob from 'fast-glob'
10
11
export const SESSION_COOKIE = 'hfs_$id'
12
@@ -37,7 +38,7 @@ export function apiMw(apis: ApiHandlers) : Koa.Middleware {
38
}
39
40
export const frontEndApis: ApiHandlers = {
40
- async file_list({ path }, ctx) {
41
+ async file_list({ path, offset, limit }, ctx) {
42
let node = await vfs.urlToNode(path || '/', ctx)
43
if (!node)
44
return
@@ -45,11 +46,34 @@ export const frontEndApis: ApiHandlers = {
46
const list = await Promise.all((node.children ||[]).map(node =>
47
!node.hidden && directPermOnNode(node,who) && nodeToFile(node) ))
48
_.remove(list, x => !x)
48
- const source = node.source
49
- if (source) {
50
- const res = await globDir(source, [node.hide, node.remove])
51
- list.push( ...res.map(x => statToFile(node!.rename?.[x.name] || x.name, x.stats!)) )
49
+ if (offset)
50
+ offset -= list.splice(0, offset).length
51
+ const { source } = node
52
+ if (list.length > limit)
53
+ list.splice(limit)
54
+ else if (source) {
55
+ const base = enforceFinal('/', complySlashes(source)) // fast-glob lib wants forward-slashes
56
+ const ignore = [node.hide, node.remove].flat().filter(Boolean).map(x => base!+x)
57
+ const dirStream = glob.stream(base+'*', {
58
+ dot: true,
59
+ onlyFiles: false,
60
+ ignore,
61
+ })
62
+ for await (let path of dirStream) {
63
+ if (offset) {
64
+ offset--
65
+ continue
66
+ }
67
+ if (limit === list.length)
68
+ break
69
+ if (path instanceof Buffer)
70
+ path = path.toString('utf8')
71
+ const stats = await stat(path)
72
+ const name = path.slice(base.length)
73
+ list.push(statToFile(node!.rename?.[name] || name, stats))
74
+ }
75
}
76
+
77
return { list }
78
},
79
async login({ user, password }, ctx) {
src/misc.ts
-11
@@ -23,17 +23,6 @@ export function prefix(pre:string, v:string|number, post:string='') {
23
return v ? pre+v+post : ''
24
}
25
26
-export async function globDir(path: string, ignore?: any[]) {
27
- path = enforceFinal('/', complySlashes(path)) // fast-glob lib wants forward-slashes
28
- return await glob(path + '*', {
29
- stats: true,
30
- dot: true,
31
- markDirectories: true,
32
- onlyFiles: false,
33
- ignore: ignore?.flat().filter(Boolean).map(x => path!+x),
34
- })
35
-}
36
-
26
export function setHidden(dest: object, src:object) {
27
Object.defineProperties(dest, objSameKeys(src, value => ({ enumerable:false, value })))
28
}