diff --git a/app/src/config/bazaar.ts b/app/src/config/bazaar.ts index 2fa0c3226af..0e9c0a9d70b 100644 --- a/app/src/config/bazaar.ts +++ b/app/src/config/bazaar.ts @@ -798,7 +798,8 @@ export const bazaar = { app.plugins.find((item: Plugin) => { if (item.name === dataObj.name) { reloadPlugin(app, { - upsertPlugins: [dataObj.name], + upsertCodePlugins: [dataObj.name], + upsertDataPlugins: [], removePlugins: [] }); return true; diff --git a/app/src/plugin/index.ts b/app/src/plugin/index.ts index 8796c0569f0..90854b8538a 100644 --- a/app/src/plugin/index.ts +++ b/app/src/plugin/index.ts @@ -113,6 +113,10 @@ export class Plugin { // 卸载 } + public onDataChanged() { + // 存储数据变更 + } + public async updateCards(options: ICardData) { return options; } diff --git a/app/src/plugin/loader.ts b/app/src/plugin/loader.ts index 0428bf2e108..c8e48f8826d 100644 --- a/app/src/plugin/loader.ts +++ b/app/src/plugin/loader.ts @@ -210,20 +210,48 @@ export const afterLoadPlugin = (plugin: Plugin) => { /// #endif }; -export const reloadPlugin = async (app: App, data: { upsertPlugins: string[], removePlugins: string[] }) => { - data.removePlugins.forEach((item) => { +export const reloadPlugin = async (app: App, data: { upsertCodePlugins?: string[], upsertDataPlugins?: string[], removePlugins?: string[] } = {}) => { + const { upsertCodePlugins = [], upsertDataPlugins = [], removePlugins = [] } = data; + const reloadPlugins: string[] = []; + + removePlugins.forEach((item) => { uninstall(app, item, true); }); - data.upsertPlugins.forEach((item) => { - uninstall(app, item, false); + + upsertCodePlugins.forEach((pluginName) => { + reloadPlugins.push(pluginName); }); - loadPlugins(app, data.upsertPlugins).then(() => { - app.plugins.forEach(item => { - if (data.upsertPlugins.includes(item.name)) { - afterLoadPlugin(item); + + upsertDataPlugins.forEach((pluginName) => { + const plugin = app.plugins.find(p => p.name === pluginName); + // 检查插件是否重写了 onDataChanged 方法(不是基类的默认实现) + const hasOverriddenOnDataChanged = plugin && + typeof plugin.onDataChanged === "function" && + plugin.onDataChanged !== Plugin.prototype.onDataChanged; + if (hasOverriddenOnDataChanged) { + try { + plugin.onDataChanged(); + return; + } catch (e) { + console.error(`plugin ${pluginName} onDataChanged error:`, e); } - }); + } + reloadPlugins.push(pluginName); }); + + reloadPlugins.forEach((item) => { + uninstall(app, item, false); + }); + if (reloadPlugins.length > 0) { + loadPlugins(app, reloadPlugins).then(() => { + app.plugins.forEach(item => { + if (reloadPlugins.includes(item.name)) { + afterLoadPlugin(item); + } + }); + }); + } + /// #if !MOBILE saveLayout(); /// #endif diff --git a/kernel/api/petal.go b/kernel/api/petal.go index 738d7cdcb71..706a669a56d 100644 --- a/kernel/api/petal.go +++ b/kernel/api/petal.go @@ -67,10 +67,10 @@ func setPetalEnabled(c *gin.Context) { app = arg["app"].(string) } if enabled { - upsertPluginSet := hashset.New(packageName) - model.PushReloadPlugin(upsertPluginSet, nil, app) + upsertPluginCodeSet := hashset.New(packageName) + model.PushReloadPlugin(upsertPluginCodeSet, nil, nil, app) } else { removePluginSet := hashset.New(packageName) - model.PushReloadPlugin(nil, removePluginSet, app) + model.PushReloadPlugin(nil, nil, removePluginSet, app) } } diff --git a/kernel/model/bazzar.go b/kernel/model/bazzar.go index fd1d28f1b4a..b8c626a58ea 100644 --- a/kernel/model/bazzar.go +++ b/kernel/model/bazzar.go @@ -257,7 +257,7 @@ func UninstallBazaarPlugin(pluginName, frontend string) error { savePetals(petals) removePluginSet := hashset.New(pluginName) - pushReloadPlugin(nil, removePluginSet, "") + PushReloadPlugin(nil, nil, removePluginSet, "") return nil } diff --git a/kernel/model/push_reload.go b/kernel/model/push_reload.go index 84a50615847..ea597243223 100644 --- a/kernel/model/push_reload.go +++ b/kernel/model/push_reload.go @@ -38,15 +38,38 @@ import ( "github.com/siyuan-note/siyuan/kernel/util" ) -func PushReloadPlugin(upsertPluginSet, removePluginNameSet *hashset.Set, excludeApp string) { - pushReloadPlugin(upsertPluginSet, removePluginNameSet, excludeApp) -} +func PushReloadPlugin(upsertCodePluginSet, upsertDataPluginSet, removePluginNameSet *hashset.Set, excludeApp string) { + if nil != removePluginNameSet { + for _, n := range removePluginNameSet.Values() { + pluginName := n.(string) + // 如果插件在 removePluginSet 中,从其他集合中移除 + if nil != upsertCodePluginSet { + upsertCodePluginSet.Remove(pluginName) + } + if nil != upsertDataPluginSet { + upsertDataPluginSet.Remove(pluginName) + } + } + } + if nil != upsertCodePluginSet { + for _, n := range upsertCodePluginSet.Values() { + pluginName := n.(string) + // 如果插件在 upsertCodePluginSet 中,从 upsertDataPluginSet 中移除 + if nil != upsertDataPluginSet { + upsertDataPluginSet.Remove(pluginName) + } + } + } -func pushReloadPlugin(upsertPluginSet, removePluginNameSet *hashset.Set, excludeApp string) { - upsertPlugins, removePlugins := []string{}, []string{} - if nil != upsertPluginSet { - for _, n := range upsertPluginSet.Values() { - upsertPlugins = append(upsertPlugins, n.(string)) + upsertCodePlugins, upsertDataPlugins, removePlugins := []string{}, []string{}, []string{} + if nil != upsertCodePluginSet { + for _, n := range upsertCodePluginSet.Values() { + upsertCodePlugins = append(upsertCodePlugins, n.(string)) + } + } + if nil != upsertDataPluginSet { + for _, n := range upsertDataPluginSet.Values() { + upsertDataPlugins = append(upsertDataPlugins, n.(string)) } } if nil != removePluginNameSet { @@ -55,22 +78,24 @@ func pushReloadPlugin(upsertPluginSet, removePluginNameSet *hashset.Set, exclude } } - pushReloadPlugin0(upsertPlugins, removePlugins, excludeApp) + pushReloadPlugin0(upsertCodePlugins, upsertDataPlugins, removePlugins, excludeApp) } -func pushReloadPlugin0(upsertPlugins, removePlugins []string, excludeApp string) { - logging.LogInfof("reload plugins [upserts=%v, removes=%v]", upsertPlugins, removePlugins) +func pushReloadPlugin0(upsertCodePlugins, upsertDataPlugins, removePlugins []string, excludeApp string) { + logging.LogInfof("reload plugins [codeChanges=%v, dataChanges=%v, removes=%v]", upsertCodePlugins, upsertDataPlugins, removePlugins) if "" == excludeApp { util.BroadcastByType("main", "reloadPlugin", 0, "", map[string]interface{}{ - "upsertPlugins": upsertPlugins, - "removePlugins": removePlugins, + "upsertCodePlugins": upsertCodePlugins, + "upsertDataPlugins": upsertDataPlugins, + "removePlugins": removePlugins, }) return } util.BroadcastByTypeAndExcludeApp(excludeApp, "main", "reloadPlugin", 0, "", map[string]interface{}{ - "upsertPlugins": upsertPlugins, - "removePlugins": removePlugins, + "upsertCodePlugins": upsertCodePlugins, + "upsertDataPlugins": upsertDataPlugins, + "removePlugins": removePlugins, }) } diff --git a/kernel/model/repository.go b/kernel/model/repository.go index d6cd3d3e5c5..5d228665006 100644 --- a/kernel/model/repository.go +++ b/kernel/model/repository.go @@ -1592,7 +1592,8 @@ func processSyncMergeResult(exit, byHand bool, mergeResult *dejavu.MergeResult, var upsertTrees int // 可能需要重新加载部分功能 var needReloadFlashcard, needReloadOcrTexts, needReloadPlugin bool - upsertPluginSet := hashset.New() + upsertCodePluginSet := hashset.New() // 插件代码变更 data/plugins/ + upsertDataPluginSet := hashset.New() // 插件存储数据变更 data/storage/petal/ needUnindexBoxes, needIndexBoxes := map[string]bool{}, map[string]bool{} for _, file := range mergeResult.Upserts { upserts = append(upserts, file.Path) @@ -1615,7 +1616,7 @@ func processSyncMergeResult(exit, byHand bool, mergeResult *dejavu.MergeResult, needReloadPlugin = true if parts := strings.Split(file.Path, "/"); 3 < len(parts) { if pluginName := parts[3]; "petals.json" != pluginName { - upsertPluginSet.Add(pluginName) + upsertDataPluginSet.Add(pluginName) } } } @@ -1623,7 +1624,7 @@ func processSyncMergeResult(exit, byHand bool, mergeResult *dejavu.MergeResult, if strings.HasPrefix(file.Path, "/plugins/") { if parts := strings.Split(file.Path, "/"); 2 < len(parts) { needReloadPlugin = true - upsertPluginSet.Add(parts[2]) + upsertCodePluginSet.Add(parts[2]) } } @@ -1653,7 +1654,7 @@ func processSyncMergeResult(exit, byHand bool, mergeResult *dejavu.MergeResult, needReloadPlugin = true if parts := strings.Split(file.Path, "/"); 3 < len(parts) { if pluginName := parts[3]; "petals.json" != pluginName { - removePluginSet.Add(pluginName) + upsertDataPluginSet.Add(pluginName) } } } @@ -1674,7 +1675,7 @@ func processSyncMergeResult(exit, byHand bool, mergeResult *dejavu.MergeResult, for _, upsertPetal := range mergeResult.UpsertPetals { needReloadPlugin = true - upsertPluginSet.Add(upsertPetal) + upsertCodePluginSet.Add(upsertPetal) } for _, removePetal := range mergeResult.RemovePetals { needReloadPlugin = true @@ -1690,7 +1691,7 @@ func processSyncMergeResult(exit, byHand bool, mergeResult *dejavu.MergeResult, } if needReloadPlugin { - pushReloadPlugin(upsertPluginSet, removePluginSet, "") + PushReloadPlugin(upsertCodePluginSet, upsertDataPluginSet, removePluginSet, "") } for _, widgetDir := range removeWidgetDirSet.Values() {