fix: plugins weren't stopped while updating

Massimo Melina committed Jun 1, 2023 at 11:35 UTC 09aaf3204433c9a39b5a0914128029343aa9d873
3 files changed +32 -13
admin/src/InstalledPlugins.ts
+2 -2
@@ -59,7 +59,7 @@ export default function InstalledPlugins({ updates }: { updates?: true }) {
59 color: 'success',
60 onClick: () =>
61 apiCall('set_plugin', { id, enabled: false }).then(() =>
62 - toast("Plugin is stopping", h(StopCircle, { color: 'warning' })))
62 + toast("Plugin stopped", h(StopCircle, { color: 'warning' })))
63 } : {
64 icon: PlayCircle,
65 title: `Start ${id}`,
@@ -161,5 +161,5 @@ export function UpdateButton({ id, then }: { id: string, then: (id:string)=>void
161
162 export function startPlugin(id: string) {
163 return apiCall('set_plugin', { id, enabled: true }).then(() =>
164 - toast("Plugin is starting", h(PlayCircle, { color: 'success' })))
164 + toast("Plugin started", h(PlayCircle, { color: 'success' })))
165 }
src/api.plugins.ts
+20 -9
@@ -6,13 +6,19 @@ import {
6 getAvailablePlugins,
7 getPluginConfigFields,
8 mapPlugins,
9 - Plugin, pluginsConfig,
10 - PATH as PLUGINS_PATH, isPluginRunning, enablePlugin, getPluginInfo, setPluginConfig
9 + Plugin,
10 + pluginsConfig,
11 + PATH as PLUGINS_PATH,
12 + enablePlugin,
13 + getPluginInfo,
14 + setPluginConfig,
15 + findPluginByRepo,
16 + isPluginEnabled
17 } from './plugins'
18 import _ from 'lodash'
19 import assert from 'assert'
14 -import { Callback, newObj, onOff, wait } from './misc'
15 -import { ApiHandlers, SendListReadable } from './apiMiddleware'
20 +import { Callback, newObj, onOff } from './misc'
21 +import { ApiError, ApiHandlers, SendListReadable } from './apiMiddleware'
22 import events from './events'
23 import { rm } from 'fs/promises'
24 import { downloadPlugin, getFolder2repo, getRepoInfo, readOnlinePlugin, searchPlugins } from './github'
@@ -59,10 +65,10 @@ const apis: ApiHandlers = {
65
66 async set_plugin({ id, enabled, config }) {
67 assert(id, 'id')
62 - if (enabled !== undefined)
63 - enablePlugin(id, enabled)
68 if (config)
65 - setPluginConfig(id, config)
69 + setPluginConfig(id, config) // since we may wait the plugin to start, we save other changes first
70 + if (enabled !== undefined)
71 + await enablePlugin(id, enabled)
72 return {}
73 },
74
@@ -127,13 +133,18 @@ const apis: ApiHandlers = {
133 },
134
135 async update_plugin(pl) {
130 - await enablePlugin(pl.id, false, true)
136 + const found = findPluginByRepo(pl.id) // github id !== local id
137 + if (!found)
138 + return new ApiError(404)
139 + const enabled = isPluginEnabled(found.id)
140 + await enablePlugin(found.id, false)
141 await downloadPlugin(pl.id, pl.branch, true)
142 + enablePlugin(found.id, enabled).then() // don't wait, in case it fails to start
143 return {}
144 },
145
146 async uninstall_plugin({ id }) {
136 - await enablePlugin(id, false, true)
147 + await enablePlugin(id, false)
148 await rm(PLUGINS_PATH + '/' + id, { recursive: true, force: true })
149 return {}
150 }
src/plugins.ts
+10 -2
@@ -40,13 +40,16 @@ export function isPluginRunning(id: string) {
40 return Boolean(plugins[id]?.started)
41 }
42
43 -export async function enablePlugin(id: string, state=true, waitForIt=false) {
43 +export function isPluginEnabled(id: string) {
44 + return enablePlugins.get().includes(id)
45 +}
46 +
47 +export async function enablePlugin(id: string, state=true) {
48 enablePlugins.set( arr =>
49 arr.includes(id) === state ? arr
50 : state ? [...arr, id]
51 : arr.filter((x: string) => x !== id)
52 )
49 - if (!waitForIt) return
53 while (isPluginRunning(id) !== state)
54 await wait(500)
55 }
@@ -76,6 +79,11 @@ export function mapPlugins<T>(cb:(plugin:Readonly<Plugin>, pluginName:string)=>
79 }).filter(x => x !== undefined) as Exclude<T,undefined>[]
80 }
81
82 +export function findPluginByRepo<T>(repo: string) {
83 + return _.find(plugins, pl => pl.getData()?.repo === repo)
84 + || _.find(availablePlugins, { repo })
85 +}
86 +
87 export function getPluginConfigFields(id: string) {
88 return plugins[id]?.getData().config
89 }