moved vfs to config

Massimo Melina committed Dec 27, 2021 at 17:10 UTC 0e9ac4443fe13bf3b4fe0d3d153035b6f745ee7e
5 files changed +42 -69
README.md
+3 -4
@@ -28,6 +28,7 @@ General configuration is read by default from file `config.yaml`.
28 When not specified, default values will be used.
29 Supported entries are:
30 - `port` where to accept http connections. Default is 80.
31 +- `vfs` the files and folders you want to expose. For details see the dedicated following section.
32 - `mime` command what mime-type to be returned with some files.
33 E.g.: `"*.jpg": image/jpeg`
34 You can specify multiple entries, or separate multiple file masks with a p|pe.
@@ -35,10 +36,8 @@ Supported entries are:
36
37 ## Virtual File System (VFS)
38
38 -The virtual file system is a tree of nodes.
39 -By default, it's in the file `vfs.yaml`.
40 -You can decide a different file by passing it as first parameter at command line.
41 -A node is folder, unless you provide for it a source that's not a folder itself.
39 +The virtual file system is a tree of files and folders, collectively called *nodes*.
40 +By default a node is folder, unless you provide for it a source that's a file.
41 Valid keys in a node are:
42 - `name`: how to display it. If not provided HFS will infer it from the source.
43 - `source`: where to get its content from. Absolute or relative file path, or even http url.
config.yaml
+20
@@ -1,3 +1,23 @@
1 port: 80
2 mime:
3 "*.jpg|*.png|*.mp3|*.txt": auto
4 +vfs:
5 + children:
6 + - name: f1
7 + children:
8 + - name: f2
9 + children:
10 + - source: tests/alfa.txt
11 + - name: pic
12 + mime: png
13 + source: tests/page/gpl.png
14 + - name: page
15 + default: index.html
16 + source: tests/page
17 + - name: proxy
18 + source: https://raw.githubusercontent.com/nodejs/node/master/README.md
19 + - name: for-admins
20 + perm:
21 + admin: r
22 + children:
23 + - source: tests/alfa.txt
package.json
+1 -1
@@ -10,7 +10,7 @@
10 "license": "GPL-3.0",
11 "author": "Massimo Melina <a@rejetto.com>",
12 "scripts": {
13 - "watch-server": "nodemon --ignore tests/ --watch src -e ts,tsx --exec ts-node src/index.ts vfs.yaml",
13 + "watch-server": "nodemon --ignore tests/ --watch src -e ts,tsx --exec ts-node src/index.ts",
14 "start": "node dist",
15 "start-frontend": "cd frontend && npm run start",
16 "build": "node timestamp && tsc && cp package*.json *.yaml dist && cd dist && npm ci --production",
src/vfs.ts
+18 -45
@@ -1,14 +1,12 @@
1 -import { argv } from './const'
2 -import yaml from 'yaml'
1 import fs from 'fs/promises'
4 -import { FSWatcher, watch } from 'fs'
5 -import { dirname, basename } from 'path'
2 +import { basename } from 'path'
3 import { isMatch } from 'micromatch'
7 -import { complySlashes, enforceFinal, prefix, readFileBusy } from './misc'
4 +import { complySlashes, enforceFinal, prefix } from './misc'
5 import { getCurrentUsernameExpanded } from './perm'
6 import Koa from 'koa'
7 import glob from 'fast-glob'
8 import _ from 'lodash'
9 +import { subscribe } from './config'
10
11 export enum VfsNodeType {
12 root,
@@ -37,51 +35,15 @@ export const MIME_AUTO = 'auto'
35
36 export class Vfs {
37 root: VfsNode = EMPTY
40 - watcher?: FSWatcher
41 - basePath: string
42 -
43 - constructor(path?:string) {
44 - this.basePath = ''
45 - if (path)
46 - this.load(path).then(()=>
47 - this.basePath = dirname(path))
48 - else
49 - this.reset()
38 +
39 + constructor() {
40 + this.reset()
41 }
42
43 reset(){
44 this.root = { ...EMPTY }
45 }
46
56 - async load(path: string, watchFile:boolean=true) {
57 - console.debug('loading',path)
58 - try {
59 - const data = await readFileBusy(path)
60 - this.root = yaml.parse(data)
61 - // we should validate content now
62 - }
63 - catch(e) {
64 - console.error(`Load failed for ${path}`,e)
65 - }
66 - this.watcher?.close()
67 - this.watcher = undefined
68 - recur(this.root)
69 - if (!watchFile) return
70 - let doing = false
71 - this.watcher = watch(path, async () => {
72 - if (doing) return
73 - doing = true
74 - try { await this.load(path).catch() }
75 - finally { doing = false }
76 - })
77 -
78 - function recur(node:VfsNode) {
79 - if (node.type !== VfsNodeType.root && !node.name && node.source)
80 - node.name = basename(node.source)
81 - node.children?.forEach(recur)
82 - }
83 - }
84 -
47 async urlToNode(url: string, ctx: Koa.Context) : Promise<VfsNode | undefined> {
48 const users = await getCurrentUsernameExpanded(ctx)
49 let run = this.root
@@ -108,7 +70,18 @@ export class Vfs {
70
71 }
72
111 -export const vfs = new Vfs(argv._[0] || 'vfs.yaml')
73 +export const vfs = new Vfs()
74 +subscribe('vfs', data => {
75 + // we should validate content now
76 + recur(data)
77 + vfs.root = data
78 +
79 + function recur(node:VfsNode) {
80 + if (node.type !== VfsNodeType.root && !node.name && node.source)
81 + node.name = basename(node.source)
82 + node.children?.forEach(recur)
83 + }
84 +})
85
86 function findChildByName(name:string, node:VfsNode) {
87 const { rename } = node
vfs.yaml deleted
-19
@@ -1,19 +0,0 @@
1 -children:
2 - - name: f1
3 - children:
4 - - name: f2
5 - children:
6 - - source: tests/alfa.txt
7 - - name: pic
8 - mime: png
9 - source: tests/page/gpl.png
10 - - name: page
11 - default: index.html
12 - source: tests/page
13 - - name: proxy
14 - source: https://raw.githubusercontent.com/nodejs/node/master/README.md
15 - - name: for-admins
16 - perm:
17 - admin: r
18 - children:
19 - - source: tests/alfa.txt