Skip to content

Commit a769da4

Browse files
committed
refactor: improve plugin management logic
1 parent fb13f56 commit a769da4

File tree

5 files changed

+74
-86
lines changed

5 files changed

+74
-86
lines changed

frontend/src/stores/plugins.ts

Lines changed: 62 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@ import { defineStore } from 'pinia'
22
import { parse } from 'yaml'
33
import { computed, ref, watch } from 'vue'
44

5+
import { useConfirm } from '@/hooks'
56
import { PluginsFilePath } from '@/constant/app'
6-
import { HttpGet, Readfile, Writefile } from '@/bridge'
7+
import { HttpGet, Readfile, Removefile, Writefile } from '@/bridge'
78
import { PluginTrigger, PluginTriggerEvent } from '@/enums/app'
89
import { useAppSettingsStore, type ProfileType, type SubscribeType } from '@/stores'
910
import {
@@ -55,13 +56,7 @@ export type PluginType = {
5556
running?: boolean
5657
}
5758

58-
const PluginsCache: Record<
59-
string,
60-
{
61-
plugin: PluginType
62-
code: string
63-
}
64-
> = {}
59+
const PluginsCache: Recordable<{ plugin: PluginType; code: string }> = {}
6560

6661
const PluginsTriggerMap: {
6762
[key in PluginTrigger]: {
@@ -95,26 +90,10 @@ const PluginsTriggerMap: {
9590
},
9691
}
9792

98-
const getPluginMetadata = (plugin: PluginType) => {
93+
export const usePluginsStore = defineStore('plugins', () => {
94+
const { confirm } = useConfirm()
9995
const appSettingsStore = useAppSettingsStore()
100-
let configuration = appSettingsStore.app.pluginSettings[plugin.id]
101-
if (!configuration) {
102-
configuration = {}
103-
plugin.configuration.forEach(({ key, value }) => (configuration[key] = value))
104-
}
105-
return { ...plugin, ...configuration }
106-
}
107-
108-
const isPluginUnavailable = (cache: any) => {
109-
return (
110-
!cache ||
111-
!cache.plugin ||
112-
cache.plugin.disabled ||
113-
(cache.plugin.install && !cache.plugin.installed)
114-
)
115-
}
11696

117-
export const usePluginsStore = defineStore('plugins', () => {
11897
const plugins = ref<PluginType[]>([])
11998

12099
const setupPlugins = async () => {
@@ -133,36 +112,59 @@ export const usePluginsStore = defineStore('plugins', () => {
133112
}
134113
}
135114

136-
const reloadPlugin = async (plugin: PluginType, code = '') => {
115+
const getPluginMetadata = (plugin: PluginType) => {
116+
let configuration = appSettingsStore.app.pluginSettings[plugin.id]
117+
if (!configuration) {
118+
configuration = {}
119+
plugin.configuration.forEach(({ key, value }) => (configuration[key] = value))
120+
}
121+
return { ...plugin, ...configuration }
122+
}
123+
124+
const isPluginUnavailable = (cache: any) => {
125+
return (
126+
!cache ||
127+
!cache.plugin ||
128+
cache.plugin.disabled ||
129+
(cache.plugin.install && !cache.plugin.installed)
130+
)
131+
}
132+
133+
const reloadPlugin = async (plugin: PluginType, code = '', reloadTrigger = false) => {
137134
const { path } = plugin
138135
if (!code) {
139136
code = await Readfile(path)
140137
}
141138
PluginsCache[plugin.id] = { plugin, code }
139+
reloadTrigger && updatePluginTrigger(plugin)
142140
}
143141

144142
// FIXME: Plug-in execution order is wrong
145-
const updatePluginTrigger = (plugin: PluginType) => {
143+
const updatePluginTrigger = (plugin: PluginType, isUpdate = true) => {
146144
const triggers = Object.keys(PluginsTriggerMap) as PluginTrigger[]
147145
triggers.forEach((trigger) => {
148146
PluginsTriggerMap[trigger].observers = PluginsTriggerMap[trigger].observers.filter(
149147
(v) => v !== plugin.id,
150148
)
151149
})
152-
plugin.triggers.forEach((trigger) => {
153-
PluginsTriggerMap[trigger].observers.push(plugin.id)
154-
})
150+
if (isUpdate) {
151+
plugin.triggers.forEach((trigger) => {
152+
PluginsTriggerMap[trigger].observers.push(plugin.id)
153+
})
154+
}
155155
}
156156

157157
const savePlugins = debounce(async () => {
158158
const p = omitArray(plugins.value, ['key', 'updating', 'loading', 'running'])
159159
await Writefile(PluginsFilePath, stringifyNoFolding(p))
160160
}, 100)
161161

162-
const addPlugin = async (p: PluginType) => {
163-
plugins.value.push(p)
162+
const addPlugin = async (plugin: PluginType) => {
163+
plugins.value.push(plugin)
164164
try {
165+
await _doUpdatePlugin(plugin)
165166
await savePlugins()
167+
updatePluginTrigger(plugin)
166168
} catch (error) {
167169
plugins.value.pop()
168170
throw error
@@ -172,26 +174,33 @@ export const usePluginsStore = defineStore('plugins', () => {
172174
const deletePlugin = async (id: string) => {
173175
const idx = plugins.value.findIndex((v) => v.id === id)
174176
if (idx === -1) return
175-
const backup = plugins.value.splice(idx, 1)[0]
176-
const backupCode = PluginsCache[id]
177-
delete PluginsCache[id]
177+
const plugin = plugins.value.splice(idx, 1)[0]
178178
try {
179179
await savePlugins()
180+
delete PluginsCache[id]
181+
updatePluginTrigger(plugin, false)
180182
} catch (error) {
181-
plugins.value.splice(idx, 0, backup)
182-
PluginsCache[id] = backupCode
183+
plugins.value.splice(idx, 0, plugin)
183184
throw error
184185
}
186+
plugin.path.startsWith('data') && Removefile(plugin.path)
187+
// Remove configuration
188+
if (appSettingsStore.app.pluginSettings[plugin.id]) {
189+
if (await confirm('Tips', 'plugins.removeConfiguration').catch(() => 0)) {
190+
delete appSettingsStore.app.pluginSettings[plugin.id]
191+
}
192+
}
185193
}
186194

187-
const editPlugin = async (id: string, p: PluginType) => {
195+
const editPlugin = async (id: string, newPlugin: PluginType) => {
188196
const idx = plugins.value.findIndex((v) => v.id === id)
189197
if (idx === -1) return
190-
const backup = plugins.value.splice(idx, 1, p)[0]
198+
const plugin = plugins.value.splice(idx, 1, newPlugin)[0]
191199
try {
192200
await savePlugins()
201+
updatePluginTrigger(newPlugin)
193202
} catch (error) {
194-
plugins.value.splice(idx, 1, backup)
203+
plugins.value.splice(idx, 1, plugin)
195204
throw error
196205
}
197206
}
@@ -200,7 +209,7 @@ export const usePluginsStore = defineStore('plugins', () => {
200209
let code = ''
201210

202211
if (plugin.type === 'File') {
203-
code = await Readfile(plugin.path)
212+
code = await Readfile(plugin.path).catch(() => '')
204213
}
205214

206215
if (plugin.type === 'Http') {
@@ -216,16 +225,15 @@ export const usePluginsStore = defineStore('plugins', () => {
216225
}
217226

218227
const updatePlugin = async (id: string) => {
219-
const p = plugins.value.find((v) => v.id === id)
220-
if (!p) throw id + ' Not Found'
221-
if (p.disabled) throw p.name + ' Disabled'
228+
const plugin = plugins.value.find((v) => v.id === id)
229+
if (!plugin) throw id + ' Not Found'
230+
if (plugin.disabled) throw plugin.name + ' is Disabled'
222231
try {
223-
p.updating = true
224-
await _doUpdatePlugin(p)
225-
await savePlugins()
226-
return `Plugin [${p.name}] updated successfully.`
232+
plugin.updating = true
233+
await _doUpdatePlugin(plugin)
234+
return `Plugin [${plugin.name}] updated successfully.`
227235
} finally {
228-
p.updating = false
236+
plugin.updating = false
229237
}
230238
}
231239

@@ -339,7 +347,7 @@ export const usePluginsStore = defineStore('plugins', () => {
339347
if (!plugin) throw id + ' Not Found'
340348
const cache = PluginsCache[plugin.id]
341349
if (!cache) throw `${plugin.name} is Missing source code`
342-
if (cache.plugin.disabled) throw `${plugin.name} Disabled`
350+
if (cache.plugin.disabled) throw `${plugin.name} is Disabled`
343351
const metadata = getPluginMetadata(plugin)
344352
const _args = args.map((arg) => JSON.stringify(arg))
345353
try {
@@ -374,7 +382,9 @@ export const usePluginsStore = defineStore('plugins', () => {
374382
)
375383

376384
watch([_watchMenus, _watchDisabled], () => {
377-
updateTrayMenus()
385+
if (appSettingsStore.app.addPluginToMenu) {
386+
updateTrayMenus()
387+
}
378388
})
379389

380390
return {

frontend/src/views/PluginsView/components/PluginForm.vue

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { ref, inject } from 'vue'
33
import { useI18n } from 'vue-i18n'
44
55
import { useBool, useMessage } from '@/hooks'
6-
import { deepClone, ignoredError, sampleID } from '@/utils'
6+
import { deepClone, sampleID } from '@/utils'
77
import { usePluginsStore, type PluginType } from '@/stores'
88
import { PluginTrigger } from '@/enums/app'
99
import { PluginsTriggerOptions, DraggableOptions } from '@/constant'
@@ -19,7 +19,6 @@ const props = withDefaults(defineProps<Props>(), {
1919
})
2020
2121
const loading = ref(false)
22-
const oldPluginTriggers = ref()
2322
const pluginID = sampleID()
2423
const plugin = ref<PluginType>({
2524
id: pluginID,
@@ -51,14 +50,8 @@ const handleSubmit = async () => {
5150
// Refresh the key to re-render the view
5251
plugin.value.key = sampleID()
5352
await pluginsStore.editPlugin(props.id, plugin.value)
54-
if (plugin.value.triggers.sort().join('') !== oldPluginTriggers.value) {
55-
pluginsStore.updatePluginTrigger(plugin.value)
56-
}
5753
} else {
5854
await pluginsStore.addPlugin(plugin.value)
59-
// Try to autoload the plugin
60-
await ignoredError(pluginsStore.reloadPlugin, plugin.value)
61-
pluginsStore.updatePluginTrigger(plugin.value)
6255
}
6356
handleCancel()
6457
} catch (error: any) {
@@ -128,7 +121,6 @@ if (props.isUpdate) {
128121
const p = pluginsStore.getPluginById(props.id)
129122
if (p) {
130123
plugin.value = deepClone(p)
131-
oldPluginTriggers.value = p.triggers.sort().join('')
132124
}
133125
}
134126
</script>

frontend/src/views/PluginsView/components/PluginHub.vue

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { ref } from 'vue'
33
import { useI18n } from 'vue-i18n'
44
55
import { useMessage } from '@/hooks'
6-
import { ignoredError } from '@/utils'
6+
import { ignoredError, sleep } from '@/utils'
77
import { HttpGet, Readfile, Writefile } from '@/bridge'
88
import { usePluginsStore, type PluginType } from '@/stores'
99
@@ -45,17 +45,14 @@ const getList = async () => {
4545
}
4646
4747
const handleAddPlugin = async (plugin: PluginType) => {
48+
const { success, error, destroy } = message.info('plugins.updating', 60 * 1000)
4849
try {
4950
await pluginsStore.addPlugin(plugin)
50-
// Try to autoload the plugin
51-
await ignoredError(pluginsStore.reloadPlugin, plugin)
52-
pluginsStore.updatePluginTrigger(plugin)
53-
const { id } = message.info('plugins.updating')
54-
await pluginsStore.updatePlugin(plugin.id)
55-
message.update(id, 'common.success', 'success')
56-
} catch (error: any) {
57-
console.error(error)
58-
message.error(error.message || error)
51+
success('common.success')
52+
} catch (err: any) {
53+
error(err.message || err)
54+
} finally {
55+
sleep(1000).then(destroy)
5956
}
6057
}
6158

frontend/src/views/PluginsView/components/PluginView.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ const handleSave = async () => {
3131
loading.value = true
3232
try {
3333
await Writefile(plugin.value.path, code.value)
34-
await pluginsStore.reloadPlugin(plugin.value, code.value)
34+
await pluginsStore.reloadPlugin(plugin.value, code.value, false)
3535
handleSubmit()
3636
} catch (error: any) {
3737
message.error(error)

frontend/src/views/PluginsView/index.vue

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22
import { ref, computed } from 'vue'
33
import { useI18n, I18nT } from 'vue-i18n'
44
5-
import { useMessage, useConfirm } from '@/hooks'
6-
import { debounce, ignoredError } from '@/utils'
7-
import { Removefile, BrowserOpenURL } from '@/bridge'
5+
import { useMessage } from '@/hooks'
6+
import { debounce } from '@/utils'
7+
import { BrowserOpenURL } from '@/bridge'
88
import { DraggableOptions } from '@/constant/app'
99
import { PluginTriggerEvent, PluginTrigger, View } from '@/enums/app'
1010
import { usePluginsStore, useAppSettingsStore, useEnvStore, type PluginType } from '@/stores'
@@ -48,7 +48,6 @@ const menuList: Menu[] = [
4848
4949
const { t } = useI18n()
5050
const { message } = useMessage()
51-
const { confirm } = useConfirm()
5251
5352
const envStore = useEnvStore()
5453
const pluginsStore = usePluginsStore()
@@ -90,17 +89,7 @@ const handleUpdatePlugin = async (s: PluginType) => {
9089
9190
const handleDeletePlugin = async (p: PluginType) => {
9291
try {
93-
if (p.path.startsWith('data')) {
94-
await ignoredError(Removefile, p.path)
95-
}
9692
await pluginsStore.deletePlugin(p.id)
97-
98-
// Remove configuration
99-
if (appSettingsStore.app.pluginSettings[p.id]) {
100-
if (await confirm('Tips', 'plugins.removeConfiguration').catch(() => 0)) {
101-
delete appSettingsStore.app.pluginSettings[p.id]
102-
}
103-
}
10493
} catch (error: any) {
10594
console.error('handleDeletePlugin: ', error)
10695
message.error(error)

0 commit comments

Comments
 (0)