allow local code (plugins) to read SendList errors https://github.com/rejetto/hfs/issues/54
Massimo Melina committed
Jun 16, 2022 at 23:42 UTC
9463ec4a6047d9ac038809a5dbd5aa988275aaf8
4 files changed
+48
-45
server/src/api.file_list.ts
+5
-4
@@ -1,7 +1,7 @@
1
// This file is part of HFS - Copyright 2021-2022, Massimo Melina <a@rejetto.com> - License https://www.gnu.org/licenses/gpl-3.0.txt
2
3
import { cantReadStatusCode, getNodeName, hasPermission, nodeIsDirectory, urlToNode, VfsNode, walkNode } from './vfs'
4
-import { ApiError, ApiHandler, sendList } from './apiMiddleware'
4
+import { ApiError, ApiHandler, SendListReadable } from './apiMiddleware'
5
import { stat } from 'fs/promises'
6
import { mapPlugins } from './plugins'
7
import { asyncGeneratorToArray, dirTraversal, pattern2filter } from './misc'
@@ -9,7 +9,7 @@ import _ from 'lodash'
9
10
export const file_list: ApiHandler = async ({ path, offset, limit, search, omit, sse }, ctx) => {
11
let node = await urlToNode(path || '/', ctx)
12
- const list = sendList()
12
+ const list = new SendListReadable()
13
if (!node)
14
return fail(404)
15
if (!hasPermission(node,'can_read',ctx))
@@ -32,13 +32,14 @@ export const file_list: ApiHandler = async ({ path, offset, limit, search, omit,
32
list.add(entry)
33
list.end()
34
})
35
- return list.return
35
+ return list
36
37
function fail(code: any) {
38
if (!sse)
39
return new ApiError(code)
40
list.error(code)
41
- return list.return
41
+ list.destroy(code)
42
+ return list
43
}
44
45
async function* produceEntries() {
server/src/api.monitor.ts
+2
-2
@@ -1,7 +1,7 @@
1
import _ from 'lodash'
2
import { Connection, getConnections } from './connections'
3
import { pendingPromise } from './misc'
4
-import { ApiHandlers, sendList } from './apiMiddleware'
4
+import { ApiHandlers, SendListReadable } from './apiMiddleware'
5
import Koa from 'koa'
6
7
const apis: ApiHandlers = {
@@ -17,7 +17,7 @@ const apis: ApiHandlers = {
17
},
18
19
get_connections({}, ctx) {
20
- const list = sendList( getConnections().map(c => serializeConnection(c)) )
20
+ const list = new SendListReadable( getConnections().map(c => serializeConnection(c)) )
21
return list.events(ctx, {
22
connection: conn => list.add(serializeConnection(conn)),
23
connectionClosed(conn: Connection) {
server/src/api.plugins.ts
+6
-6
@@ -10,7 +10,7 @@ import {
10
import _ from 'lodash'
11
import assert from 'assert'
12
import { objSameKeys, onOff, wait } from './misc'
13
-import { ApiHandlers, sendList } from './apiMiddleware'
13
+import { ApiHandlers, SendListReadable } from './apiMiddleware'
14
import events from './events'
15
import { rm } from 'fs/promises'
16
import { downloadPlugin, getFolder2repo, getRepoInfo, readOnlinePlugin, searchPlugins } from './github'
@@ -18,7 +18,7 @@ import { downloadPlugin, getFolder2repo, getRepoInfo, readOnlinePlugin, searchPl
18
const apis: ApiHandlers = {
19
20
get_plugins({}, ctx) {
21
- const list = sendList([ ...mapPlugins(serialize), ...getAvailablePlugins() ])
21
+ const list = new SendListReadable([ ...mapPlugins(serialize), ...getAvailablePlugins() ])
22
return list.events(ctx, {
23
pluginInstalled: p => list.add(serialize(p)),
24
'pluginStarted pluginStopped pluginUpdated': p => {
@@ -35,7 +35,7 @@ const apis: ApiHandlers = {
35
},
36
37
async get_plugin_updates() {
38
- const list = sendList()
38
+ const list = new SendListReadable()
39
setTimeout(async () => {
40
for (const [folder, repo] of Object.entries(getFolder2repo()))
41
try {
@@ -51,7 +51,7 @@ const apis: ApiHandlers = {
51
}
52
list.end()
53
})
54
- return list.return
54
+ return list
55
},
56
57
async set_plugin({ id, enabled, config }) {
@@ -74,7 +74,7 @@ const apis: ApiHandlers = {
74
},
75
76
search_online_plugins({ text }, ctx) {
77
- const list = sendList()
77
+ const list = new SendListReadable()
78
setTimeout(async () => {
79
try {
80
const folder2repo = getFolder2repo()
@@ -103,7 +103,7 @@ const apis: ApiHandlers = {
103
}
104
list.end()
105
})
106
- return list.return
106
+ return list
107
},
108
109
async download_plugin(pl) {
server/src/apiMiddleware.ts
+35
-33
@@ -67,40 +67,42 @@ async function getJsonFromReq(req: IncomingMessage): Promise<any> {
67
})
68
}
69
70
-// offer an api for a generic dynamic list
71
-export function sendList<T>(addAtStart?: T[]) {
72
- const stream = new Readable({ objectMode: true, read(){} })
73
- const ret = {
74
- return: stream,
75
- add(rec: T) {
76
- stream.push({ add: rec })
77
- },
78
- remove(key: Partial<T>) {
79
- stream.push({ remove: [key] })
80
- },
81
- update(search: Partial<T>, change: Partial<T>) {
82
- stream.push({ update:[{ search, change }] })
83
- },
84
- end() {
85
- stream.push(null)
86
- },
87
- error(msg: string | number) {
88
- stream.push({ error: msg })
89
- },
90
- custom(data: any) {
91
- stream.push(data)
92
- },
93
- events(ctx: Koa.Context, eventMap: Parameters<typeof onOff>[1]) {
94
- const off = onOff(events, eventMap)
95
- ctx.res.once('close', off)
96
- return stream
70
+// offer an api for a generic dynamic list. Suitable to be the result of an api.
71
+export class SendListReadable<T> extends Readable {
72
+ protected lastError: string | number | undefined
73
+ constructor(addAtStart?: T[]) {
74
+ super({ objectMode: true, read(){} })
75
+ if (addAtStart) {
76
+ for (const x of addAtStart)
77
+ this.add(x)
78
+ this.push('init')
79
}
80
}
99
- if (addAtStart) {
100
- for (const x of addAtStart)
101
- ret.add(x)
102
- stream.push('init')
81
+ add(rec: T) {
82
+ this.push({ add: rec })
83
+ }
84
+ remove(key: Partial<T>) {
85
+ this.push({ remove: [key] })
86
+ }
87
+ update(search: Partial<T>, change: Partial<T>) {
88
+ this.push({ update:[{ search, change }] })
89
+ }
90
+ end() {
91
+ this.push(null)
92
+ }
93
+ error(msg: NonNullable<typeof this.lastError>) {
94
+ this.push({ error: msg })
95
+ this.lastError = msg
96
+ }
97
+ getLastError() {
98
+ return this.lastError
99
+ }
100
+ custom(data: any) {
101
+ this.push(data)
102
+ }
103
+ events(ctx: Koa.Context, eventMap: Parameters<typeof onOff>[1]) {
104
+ const off = onOff(events, eventMap)
105
+ ctx.res.once('close', off)
106
+ return this
107
}
104
- return ret
108
}
106
-