plugins: ctx.stop to stop middlewares
Massimo Melina committed
Jun 5, 2024 at 11:30 UTC
c7cb2227cb813b117737400b6ed31bcf01d3f274
2 files changed
+27
-3
dev-plugins.md
+4
-2
@@ -80,7 +80,7 @@ used must be strictly JSON (thus, no single quotes, only double quotes for strin
80
You can also include external files, by entering a full URL. Multiple files can be specified as `['file1.css', 'file2.css']`.
81
- `frontend_js: string | string[]` path to one or more js files that you want the frontend to load. These are to be placed in the `public` folder (refer below).
82
You can also include external files, by entering a full URL.
83
-- `middleware: (Context) => Promisable<void | true | function>` a function that will be used as a middleware: use this to interfere with http activity.
83
+- `middleware: (Context) => Promisable<void | function>` a function that will be used as a middleware: use this to interfere with http activity.
84
85
```js
86
exports.middleware = ctx => {
@@ -89,7 +89,7 @@ used must be strictly JSON (thus, no single quotes, only double quotes for strin
89
}
90
```
91
You'll find more examples by studying plugins like `antidos` or `antibrute`.
92
- To interrupt other middlewares on this http request, return `true`.
92
+ To interrupt other middlewares on this http request, call `ctx.stop()`.
93
If you want to execute something in the "upstream" of middlewares, return a function. This function can be async.
94
You can read more in [the ctx object](#the-ctx-object) section.
95
@@ -589,6 +589,8 @@ If you want to override a text regardless of the language, use the special langu
589
- HFS.html
590
- HFS.useSnapState
591
- HFS.debounceAsync
592
+ - middleware: ctx.stop()
593
+ - the old way of returning true is now deprecated
594
- 8.72 (v0.52.0)
595
- HFS.toast
596
- HFS.misc functions
src/plugins.ts
+23
-1
@@ -24,6 +24,7 @@ import { watchLoadCustomHtml } from './customHtml'
24
import { KvStorage, KvStorageOptions } from '@rejetto/kvstorage'
25
import { onProcessExit } from './first'
26
import { notifyClient } from './frontEndApis'
27
+import { app } from './index'
28
29
export const PATH = 'plugins'
30
export const DISABLING_SUFFIX = '-disabled'
@@ -116,6 +117,13 @@ async function initPlugin<T>(pl: any, morePassedToInit?: T) {
117
}))
118
}
119
120
+const already = new Set()
121
+function warnOnce(msg: string) {
122
+ if (already.has(msg)) return
123
+ already.add(msg)
124
+ console.log('Warning: ' + msg)
125
+}
126
+
127
export const pluginsMiddleware: Koa.Middleware = async (ctx, next) => {
128
const after: Dict<CallMeAfter> = {}
129
// run middleware plugins
@@ -129,7 +137,11 @@ export const pluginsMiddleware: Koa.Middleware = async (ctx, next) => {
137
lastStatus = ctx.status
138
lastBody = ctx.body
139
}
132
- if (res === true)
140
+ if (res === true) { // true for legacy pre-0.53
141
+ ctx.stop()
142
+ warnOnce(`plugin ${id} is using deprecated API (return true on middleware) and may not work with future versions (check for an update to "${id}")`)
143
+ }
144
+ if (ctx.isStopped)
145
console.debug("plugin blocked request", ctx.pluginBlockedRequest = id)
146
if (typeof res === 'function')
147
after[id] = res
@@ -164,6 +176,16 @@ function printError(id: string, e: any) {
176
console.debug(e)
177
}
178
179
+declare module "koa" {
180
+ interface BaseContext {
181
+ stop(): void
182
+ }
183
+}
184
+events.once('app', () => Object.assign(app.context, {
185
+ isStopped: false,
186
+ stop() { this.isStopped = true }
187
+}))
188
+
189
// return false to ask to exclude this entry from results
190
interface OnDirEntryParams { entry:DirEntry, ctx:Koa.Context, node:VfsNode }
191
type OnDirEntry = (params:OnDirEntryParams) => void | false