diff --git a/Flow.Launcher.Core/Plugin/JsonRPCV2Models/JsonRPCPublicAPI.cs b/Flow.Launcher.Core/Plugin/JsonRPCV2Models/JsonRPCPublicAPI.cs index 8df2ce9ed..cf1c57f3e 100644 --- a/Flow.Launcher.Core/Plugin/JsonRPCV2Models/JsonRPCPublicAPI.cs +++ b/Flow.Launcher.Core/Plugin/JsonRPCV2Models/JsonRPCPublicAPI.cs @@ -185,5 +185,10 @@ namespace Flow.Launcher.Core.Plugin.JsonRPCV2Models { _api.StopLoadingBar(); } + + public void SavePluginCaches() + { + _api.SavePluginCaches(); + } } } diff --git a/Flow.Launcher.Core/Plugin/PluginManager.cs b/Flow.Launcher.Core/Plugin/PluginManager.cs index 4f869901c..fa4e43e07 100644 --- a/Flow.Launcher.Core/Plugin/PluginManager.cs +++ b/Flow.Launcher.Core/Plugin/PluginManager.cs @@ -66,6 +66,7 @@ namespace Flow.Launcher.Core.Plugin } API.SavePluginSettings(); + API.SavePluginCaches(); } public static async ValueTask DisposePluginsAsync() @@ -587,11 +588,13 @@ namespace Flow.Launcher.Core.Plugin if (removePluginSettings) { - // For dotnet plugins, we need to remove their PluginJsonStorage instance + // For dotnet plugins, we need to remove their PluginJsonStorage and PluginBinaryStorage instances if (AllowedLanguage.IsDotNet(plugin.Language)) { var method = API.GetType().GetMethod("RemovePluginSettings"); method?.Invoke(API, new object[] { plugin.AssemblyName }); + var method1 = API.GetType().GetMethod("RemovePluginCache"); + method1?.Invoke(API, new object[] { plugin.PluginCacheDirectoryPath }); } try diff --git a/Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs b/Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs index f178ebb90..be776b068 100644 --- a/Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs +++ b/Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs @@ -344,5 +344,38 @@ namespace Flow.Launcher.Plugin /// Stop the loading bar in main window /// public void StopLoadingBar(); + + /// + /// Save all Flow's plugins caches + /// + void SavePluginCaches(); + + /// + /// Load BinaryStorage for current plugin's cache. This is the method used to load cache from binary in Flow. + /// When the file is not exist, it will create a new instance for the specific type. + /// + /// Type for deserialization + /// Cache file name + /// Cache directory from plugin metadata + /// Default data to return + /// + /// + /// BinaryStorage utilize MemoryPack, which means the object must be MemoryPackSerializable + /// + Task LoadCacheBinaryStorageAsync(string cacheName, string cacheDirectory, T defaultData) where T : new(); + + /// + /// Save BinaryStorage for current plugin's cache. This is the method used to save cache to binary in Flow.Launcher + /// This method will save the original instance loaded with LoadCacheBinaryStorageAsync. + /// This API call is for manually Save. Flow will automatically save all cache type that has called LoadCacheBinaryStorageAsync or SaveCacheBinaryStorageAsync previously. + /// + /// Type for Serialization + /// Cache file name + /// Cache directory from plugin metadata + /// + /// + /// BinaryStorage utilize MemoryPack, which means the object must be MemoryPackSerializable + /// + Task SaveCacheBinaryStorageAsync(string cacheName, string cacheDirectory) where T : new(); } } diff --git a/Flow.Launcher.Plugin/Interfaces/ISavable.cs b/Flow.Launcher.Plugin/Interfaces/ISavable.cs index 77bd304e4..cabd26962 100644 --- a/Flow.Launcher.Plugin/Interfaces/ISavable.cs +++ b/Flow.Launcher.Plugin/Interfaces/ISavable.cs @@ -1,11 +1,12 @@ -namespace Flow.Launcher.Plugin +namespace Flow.Launcher.Plugin { /// /// Inherit this interface if additional data e.g. cache needs to be saved. /// /// /// For storing plugin settings, prefer - /// or . + /// or . + /// or . /// Once called, your settings will be automatically saved by Flow. /// public interface ISavable : IFeatures @@ -15,4 +16,4 @@ namespace Flow.Launcher.Plugin /// void Save(); } -} \ No newline at end of file +} diff --git a/Flow.Launcher/PublicAPIInstance.cs b/Flow.Launcher/PublicAPIInstance.cs index e19ad2fdc..17d7e103e 100644 --- a/Flow.Launcher/PublicAPIInstance.cs +++ b/Flow.Launcher/PublicAPIInstance.cs @@ -236,14 +236,6 @@ namespace Flow.Launcher ((PluginJsonStorage)_pluginJsonStorages[type]).Save(); } - public void SaveJsonStorage(T settings) where T : new() - { - var type = typeof(T); - _pluginJsonStorages[type] = new PluginJsonStorage(settings); - - ((PluginJsonStorage)_pluginJsonStorages[type]).Save(); - } - public void OpenDirectory(string DirectoryPath, string FileNameOrFilePath = null) { using var explorer = new Process(); @@ -342,6 +334,51 @@ namespace Flow.Launcher public Task ShowProgressBoxAsync(string caption, Func, Task> reportProgressAsync, Action cancelProgress = null) => ProgressBoxEx.ShowAsync(caption, reportProgressAsync, cancelProgress); + private readonly ConcurrentDictionary<(string, string, Type), object> _pluginBinaryStorages = new(); + + public void RemovePluginCache(string cacheDirectory) + { + foreach (var keyValuePair in _pluginBinaryStorages) + { + var key = keyValuePair.Key; + var currentCacheDirectory = key.Item2; + if (cacheDirectory == currentCacheDirectory) + { + _pluginBinaryStorages.Remove(key, out var _); + } + } + } + + /// + /// Save plugin caches. + /// + public void SavePluginCaches() + { + foreach (var value in _pluginBinaryStorages.Values) + { + var method = value.GetType().GetMethod("Save"); + method?.Invoke(value, null); + } + } + + public async Task LoadCacheBinaryStorageAsync(string cacheName, string cacheDirectory, T defaultData) where T : new() + { + var type = typeof(T); + if (!_pluginBinaryStorages.ContainsKey((cacheName, cacheDirectory, type))) + _pluginBinaryStorages[(cacheName, cacheDirectory, type)] = new PluginBinaryStorage(cacheName, cacheDirectory); + + return await ((PluginBinaryStorage)_pluginBinaryStorages[(cacheName, cacheDirectory, type)]).TryLoadAsync(defaultData); + } + + public async Task SaveCacheBinaryStorageAsync(string cacheName, string cacheDirectory) where T : new() + { + var type = typeof(T); + if (!_pluginBinaryStorages.ContainsKey((cacheName, cacheDirectory, type))) + _pluginBinaryStorages[(cacheName, cacheDirectory, type)] = new PluginBinaryStorage(cacheName, cacheDirectory); + + await ((PluginBinaryStorage)_pluginBinaryStorages[(cacheName, cacheDirectory, type)]).SaveAsync(); + } + #endregion #region Private Methods