@@ -35,7 +35,7 @@ public static class PluginManager
3535
3636        private  static   PluginsSettings  Settings ; 
3737        private  static   List < PluginMetadata >  _metadatas ; 
38-         private  static   List < string >  _modifiedPlugins  =  new   List < string > ( ) ; 
38+         private  static   List < string >  _modifiedPlugins  =  new ( ) ; 
3939
4040        /// <summary> 
4141        /// Directories that will hold Flow Launcher plugin directory 
@@ -72,15 +72,20 @@ public static async ValueTask DisposePluginsAsync()
7272        { 
7373            foreach  ( var  pluginPair  in  AllPlugins ) 
7474            { 
75-                 switch  ( pluginPair . Plugin ) 
76-                 { 
77-                     case  IDisposable  disposable : 
78-                         disposable . Dispose ( ) ; 
79-                         break ; 
80-                     case  IAsyncDisposable  asyncDisposable : 
81-                         await  asyncDisposable . DisposeAsync ( ) ; 
82-                         break ; 
83-                 } 
75+                 await  DisposePluginAsync ( pluginPair ) ; 
76+             } 
77+         } 
78+ 
79+         private  static   async  Task  DisposePluginAsync ( PluginPair  pluginPair ) 
80+         { 
81+             switch  ( pluginPair . Plugin ) 
82+             { 
83+                 case  IDisposable  disposable : 
84+                     disposable . Dispose ( ) ; 
85+                     break ; 
86+                 case  IAsyncDisposable  asyncDisposable : 
87+                     await  asyncDisposable . DisposeAsync ( ) ; 
88+                     break ; 
8489            } 
8590        } 
8691
@@ -155,6 +160,25 @@ public static void LoadPlugins(PluginsSettings settings)
155160            Settings  =  settings ; 
156161            Settings . UpdatePluginSettings ( _metadatas ) ; 
157162            AllPlugins  =  PluginsLoader . Plugins ( _metadatas ,  Settings ) ; 
163+             // Since dotnet plugins need to get assembly name first, we should update plugin directory after loading plugins 
164+             UpdatePluginDirectory ( _metadatas ) ; 
165+         } 
166+ 
167+         private  static   void  UpdatePluginDirectory ( List < PluginMetadata >  metadatas ) 
168+         { 
169+             foreach  ( var  metadata  in  metadatas ) 
170+             { 
171+                 if  ( AllowedLanguage . IsDotNet ( metadata . Language ) ) 
172+                 { 
173+                     metadata . PluginSettingsDirectoryPath  =  Path . Combine ( DataLocation . PluginSettingsDirectory ,  metadata . AssemblyName ) ; 
174+                     metadata . PluginCacheDirectoryPath  =  Path . Combine ( DataLocation . PluginCacheDirectory ,  metadata . AssemblyName ) ; 
175+                 } 
176+                 else 
177+                 { 
178+                     metadata . PluginSettingsDirectoryPath  =  Path . Combine ( DataLocation . PluginSettingsDirectory ,  metadata . Name ) ; 
179+                     metadata . PluginCacheDirectoryPath  =  Path . Combine ( DataLocation . PluginCacheDirectory ,  metadata . Name ) ; 
180+                 } 
181+             } 
158182        } 
159183
160184        /// <summary> 
@@ -225,10 +249,9 @@ public static ICollection<PluginPair> ValidPluginsForQuery(Query query)
225249            if  ( query  is  null ) 
226250                return  Array . Empty < PluginPair > ( ) ; 
227251
228-             if  ( ! NonGlobalPlugins . ContainsKey ( query . ActionKeyword ) ) 
252+             if  ( ! NonGlobalPlugins . TryGetValue ( query . ActionKeyword ,   out   var   plugin ) ) 
229253                return  GlobalPlugins ; 
230254
231-             var  plugin  =  NonGlobalPlugins [ query . ActionKeyword ] ; 
232255            return  new  List < PluginPair > 
233256            { 
234257                plugin 
@@ -442,10 +465,10 @@ public static bool PluginModified(string uuid)
442465        /// Update a plugin to new version, from a zip file. By default will remove the zip file if update is via url, 
443466        /// unless it's a local path installation 
444467        /// </summary> 
445-         public  static   void   UpdatePlugin ( PluginMetadata  existingVersion ,  UserPlugin  newVersion ,  string  zipFilePath ) 
468+         public  static   async   Task   UpdatePluginAsync ( PluginMetadata  existingVersion ,  UserPlugin  newVersion ,  string  zipFilePath ) 
446469        { 
447470            InstallPlugin ( newVersion ,  zipFilePath ,  checkModified : false ) ; 
448-             UninstallPlugin ( existingVersion ,  removePluginFromSettings : false ,  removePluginSettings : false ,  checkModified :  false ) ; 
471+             await   UninstallPluginAsync ( existingVersion ,  removePluginFromSettings : false ,  removePluginSettings : false ,  checkModified :  false ) ; 
449472            _modifiedPlugins . Add ( existingVersion . ID ) ; 
450473        } 
451474
@@ -460,9 +483,9 @@ public static void InstallPlugin(UserPlugin plugin, string zipFilePath)
460483        /// <summary> 
461484        /// Uninstall a plugin. 
462485        /// </summary> 
463-         public  static   void   UninstallPlugin ( PluginMetadata  plugin ,  bool  removePluginFromSettings  =  true ,  bool  removePluginSettings  =  false ) 
486+         public  static   async   Task   UninstallPluginAsync ( PluginMetadata  plugin ,  bool  removePluginFromSettings  =  true ,  bool  removePluginSettings  =  false ) 
464487        { 
465-             UninstallPlugin ( plugin ,  removePluginFromSettings ,  removePluginSettings ,  true ) ; 
488+             await   UninstallPluginAsync ( plugin ,  removePluginFromSettings ,  removePluginSettings ,  true ) ; 
466489        } 
467490
468491        #endregion
@@ -543,63 +566,62 @@ internal static void InstallPlugin(UserPlugin plugin, string zipFilePath, bool c
543566            } 
544567        } 
545568
546-         internal  static   void   UninstallPlugin ( PluginMetadata  plugin ,  bool  removePluginFromSettings ,  bool  removePluginSettings ,  bool  checkModified ) 
569+         internal  static   async   Task   UninstallPluginAsync ( PluginMetadata  plugin ,  bool  removePluginFromSettings ,  bool  removePluginSettings ,  bool  checkModified ) 
547570        { 
548571            if  ( checkModified  &&  PluginModified ( plugin . ID ) ) 
549572            { 
550573                throw  new  ArgumentException ( $ "Plugin { plugin . Name }  has been modified") ; 
551574            } 
552575
553-             if  ( removePluginSettings ) 
576+             if  ( removePluginSettings   ||   removePluginFromSettings ) 
554577            { 
555-                 if  ( AllowedLanguage . IsDotNet ( plugin . Language ) )   // for the plugin in .NET, we can use assembly loader 
578+                 // If we want to remove plugin from AllPlugins, 
579+                 // we need to dispose them so that they can release file handles 
580+                 // which can help FL to delete the plugin settings & cache folders successfully 
581+                 var  pluginPairs  =  AllPlugins . FindAll ( p =>  p . Metadata . ID  ==  plugin . ID ) ; 
582+                 foreach  ( var  pluginPair  in  pluginPairs ) 
556583                { 
557-                     var   assemblyLoader   =   new   PluginAssemblyLoader ( plugin . ExecuteFilePath ) ; 
558-                      var   assembly   =   assemblyLoader . LoadAssemblyAndDependencies ( ) ; 
559-                      var   assemblyName   =   assembly . GetName ( ) . Name ; 
584+                     await   DisposePluginAsync ( pluginPair ) ; 
585+                 } 
586+             } 
560587
561-                     // if user want to remove the plugin settings, we cannot call save method for the plugin json storage instance of this plugin 
562-                     // so we need to remove it from the api instance 
588+             if  ( removePluginSettings ) 
589+             { 
590+                 // For dotnet plugins, we need to remove their PluginJsonStorage instance 
591+                 if  ( AllowedLanguage . IsDotNet ( plugin . Language ) ) 
592+                 { 
563593                    var  method  =  API . GetType ( ) . GetMethod ( "RemovePluginSettings" ) ; 
564-                     var  pluginJsonStorage  =  method ? . Invoke ( API ,  new  object [ ]  {  assemblyName  } ) ; 
594+                     method ? . Invoke ( API ,  new  object [ ]  {  plugin . AssemblyName  } ) ; 
595+                 } 
565596
566-                     // if there exists a json storage for current plugin, we need to delete the directory path 
567-                     if  ( pluginJsonStorage  !=  null ) 
568-                     { 
569-                         var  deleteMethod  =  pluginJsonStorage . GetType ( ) . GetMethod ( "DeleteDirectory" ) ; 
570-                         try 
571-                         { 
572-                             deleteMethod ? . Invoke ( pluginJsonStorage ,  null ) ; 
573-                         } 
574-                         catch  ( Exception  e ) 
575-                         { 
576-                             Log . Exception ( $ "|PluginManager.UninstallPlugin|Failed to delete plugin json folder for { plugin . Name } ",  e ) ; 
577-                             API . ShowMsg ( API . GetTranslation ( "failedToRemovePluginSettingsTitle" ) , 
578-                                 string . Format ( API . GetTranslation ( "failedToRemovePluginSettingsMessage" ) ,  plugin . Name ) ) ; 
579-                         } 
580-                     } 
597+                 try 
598+                 { 
599+                     var  pluginSettingsDirectory  =  plugin . PluginSettingsDirectoryPath ; 
600+                     if  ( Directory . Exists ( pluginSettingsDirectory ) ) 
601+                         Directory . Delete ( pluginSettingsDirectory ,  true ) ; 
581602                } 
582-                 else    // the plugin with json prc interface 
603+                 catch   ( Exception   e ) 
583604                { 
584-                     var  pluginPair  =  AllPlugins . FirstOrDefault ( p =>  p . Metadata . ID  ==  plugin . ID ) ; 
585-                     if  ( pluginPair  !=  null  &&  pluginPair . Plugin  is  JsonRPCPlugin  jsonRpcPlugin ) 
586-                     { 
587-                         try 
588-                         { 
589-                             jsonRpcPlugin . DeletePluginSettingsDirectory ( ) ; 
590-                         } 
591-                         catch  ( Exception  e ) 
592-                         { 
593-                             Log . Exception ( $ "|PluginManager.UninstallPlugin|Failed to delete plugin json folder for { plugin . Name } ",  e ) ; 
594-                             API . ShowMsg ( API . GetTranslation ( "failedToRemovePluginSettingsTitle" ) , 
595-                                 string . Format ( API . GetTranslation ( "failedToRemovePluginSettingsMessage" ) ,  plugin . Name ) ) ; 
596-                         } 
597-                     } 
605+                     Log . Exception ( $ "|PluginManager.UninstallPlugin|Failed to delete plugin settings folder for { plugin . Name } ",  e ) ; 
606+                     API . ShowMsg ( API . GetTranslation ( "failedToRemovePluginSettingsTitle" ) , 
607+                         string . Format ( API . GetTranslation ( "failedToRemovePluginSettingsMessage" ) ,  plugin . Name ) ) ; 
598608                } 
599609            } 
600610
601611            if  ( removePluginFromSettings ) 
602612            { 
613+                 try 
614+                 { 
615+                     var  pluginCacheDirectory  =  plugin . PluginCacheDirectoryPath ; 
616+                     if  ( Directory . Exists ( pluginCacheDirectory ) ) 
617+                         Directory . Delete ( pluginCacheDirectory ,  true ) ; 
618+                 } 
619+                 catch  ( Exception  e ) 
620+                 { 
621+                     Log . Exception ( $ "|PluginManager.UninstallPlugin|Failed to delete plugin cache folder for { plugin . Name } ",  e ) ; 
622+                     API . ShowMsg ( API . GetTranslation ( "failedToRemovePluginCacheTitle" ) , 
623+                         string . Format ( API . GetTranslation ( "failedToRemovePluginCacheMessage" ) ,  plugin . Name ) ) ; 
624+                 } 
603625                Settings . Plugins . Remove ( plugin . ID ) ; 
604626                AllPlugins . RemoveAll ( p =>  p . Metadata . ID  ==  plugin . ID ) ; 
605627            } 
0 commit comments