plugins: automatic unload of api.subscribeConfig

Massimo Melina committed Feb 8, 2025 at 11:02 UTC 1b95811e35388606bfe227ac5675834b6d074e99
3 files changed +14 -8
dev-plugins.md
+3 -1
@@ -214,6 +214,7 @@ The `api` object you get as parameter of the `init` contains the following:
214 - `subscribeConfig(key: string | string[], callback: (value: any) => void): Unsubscriber`
215 will call `callback` with initial value and then at each change.
216 Passing an array of keys, the `value` parameter becomes an object with the specified keys and respective values.
217 + Will be automatically unsubscribed at plugin's unload.
218
219 - `getHfsConfig(key: string): any` similar to getConfig, but retrieves HFS' config instead.
220
@@ -761,12 +762,13 @@ If you want to override a text regardless of the language, use the special langu
762
763 ## API version history
764
764 -- 11.3 (v0.56.0)
765 +- 11.4 (v0.56.0)
766 - api.setError
767 - frontend events: afterBreadcrumbs, afterFolderStats, afterFilter
768 - config.type.vfs_path: folders, files
769 - api.subscribeConfig supports multiple keys
770 - api.getAccount, addAccount, delAccount, updateAccount, renameAccount, getUsernames
771 + - automatic unload of api.subscribeConfig
772 - 10.3 (v0.55.0)
773 - HFS.copyTextToClipboard
774 - HFS.urlParams
src/const.ts
+1 -1
@@ -9,7 +9,7 @@ import { formatTimestamp } from './cross'
9 import { argv } from './argv'
10 export * from './cross-const'
11
12 -export const API_VERSION = 11.3
12 +export const API_VERSION = 11.4
13 export const COMPATIBLE_API_VERSION = 1 // while changes in the api are not breaking, this number stays the same, otherwise it is made equal to API_VERSION
14
15 // you can add arguments with this file, currently used for the update process on mac/linux
src/plugins.ts
+10 -6
@@ -474,8 +474,9 @@ function watchPlugin(id: string, path: string) {
474 if (!module.startsWith(process.cwd())) //legacy pre-0.53.0, bundled plugins' storageDir was not under cwd
475 await rename(resolve(module, '..', STORAGE_FOLDER), storageDir).catch(() => {})
476 await mkdir(storageDir, { recursive: true })
477 - const dbs: KvStorage[] = []
478 - await initPlugin(pluginData, {
477 + const openDbs: KvStorage[] = []
478 + const subbedConfigs: Callback[] = []
479 + await initPlugin(pluginData, { // following properties are not available in server_code
480 id,
481 srcDir: __dirname,
482 storageDir,
@@ -483,7 +484,7 @@ function watchPlugin(id: string, path: string) {
484 if (!filename) throw Error("missing filename")
485 const db = new KvStorage(options)
486 await db.open(join(storageDir, filename))
486 - dbs.push(db)
487 + openDbs.push(db)
488 return db
489 },
490 log(...args: any[]) {
@@ -501,12 +502,14 @@ function watchPlugin(id: string, path: string) {
502 : this.getConfig(cfgKey)
503 let last = get()
504 cb(last)
504 - return pluginsConfig.sub(() => {
505 + const ret = pluginsConfig.sub(() => {
506 const now = get()
507 if (same(now, last)) return
508 try { cb(last = now) }
509 catch(e){ this.log(String(e)) }
510 })
511 + subbedConfigs.push(ret)
512 + return ret
513 },
514 async i18n(ctx: any) {
515 return i18nFromTranslations(await getLangData(ctx))
@@ -521,8 +524,9 @@ function watchPlugin(id: string, path: string) {
524 const plugin = new Plugin(id, folder, pluginData, async () => {
525 unwatchIcons()
526 unwatch()
524 - await Promise.allSettled(dbs.map(x => x.close()))
525 - dbs.length = 0
527 + for (const x of subbedConfigs) x()
528 + await Promise.allSettled(openDbs.map(x => x.close()))
529 + openDbs.length = 0
530 })
531 if (alreadyRunning)
532 events.emit('pluginUpdated', Object.assign(_.pick(plugin, 'started'), getPluginInfo(id)))