33using System . Collections . Generic ;
44using System . IO ;
55using System . Linq ;
6+ using System . Threading ;
67using System . Threading . Tasks ;
78using Flow . Launcher . Infrastructure ;
89using Flow . Launcher . Infrastructure . Logger ;
@@ -52,13 +53,14 @@ public static void Save()
5253 }
5354 }
5455
55- public static void ReloadData ( )
56+ public static async Task ReloadData ( )
5657 {
57- foreach ( var plugin in AllPlugins )
58+ await Task . WhenAll ( AllPlugins . Select ( plugin => plugin . Plugin switch
5859 {
59- var reloadablePlugin = plugin . Plugin as IReloadable ;
60- reloadablePlugin ? . ReloadData ( ) ;
61- }
60+ IReloadable p => Task . Run ( p . ReloadData ) ,
61+ IAsyncReloadable p => p . ReloadDataAsync ( ) ,
62+ _ => Task . CompletedTask ,
63+ } ) . ToArray ( ) ) ;
6264 }
6365
6466 static PluginManager ( )
@@ -86,50 +88,62 @@ public static void LoadPlugins(PluginsSettings settings)
8688 /// Call initialize for all plugins
8789 /// </summary>
8890 /// <returns>return the list of failed to init plugins or null for none</returns>
89- public static void InitializePlugins ( IPublicAPI api )
91+ public static async Task InitializePlugins ( IPublicAPI api )
9092 {
9193 API = api ;
9294 var failedPlugins = new ConcurrentQueue < PluginPair > ( ) ;
93- Parallel . ForEach ( AllPlugins , pair =>
95+
96+ var InitTasks = AllPlugins . Select ( pair => Task . Run ( async delegate
9497 {
9598 try
9699 {
97- var milliseconds = Stopwatch . Debug ( $ "|PluginManager.InitializePlugins|Init method time cost for < { pair . Metadata . Name } >" , ( ) =>
100+ var milliseconds = pair . Plugin switch
98101 {
99- pair . Plugin . Init ( new PluginInitContext
100- {
101- CurrentPluginMetadata = pair . Metadata ,
102- API = API
103- } ) ;
104- } ) ;
102+ IAsyncPlugin plugin
103+ => await Stopwatch . DebugAsync ( $ "|PluginManager.InitializePlugins|Init method time cost for <{ pair . Metadata . Name } >",
104+ ( ) => plugin . InitAsync ( new PluginInitContext ( pair . Metadata , API ) ) ) ,
105+ IPlugin plugin
106+ => Stopwatch . Debug ( $ "|PluginManager.InitializePlugins|Init method time cost for <{ pair . Metadata . Name } >",
107+ ( ) => plugin . Init ( new PluginInitContext ( pair . Metadata , API ) ) ) ,
108+ _ => throw new ArgumentException ( ) ,
109+ } ;
105110 pair . Metadata . InitTime += milliseconds ;
106- Log . Info ( $ "|PluginManager.InitializePlugins|Total init cost for <{ pair . Metadata . Name } > is <{ pair . Metadata . InitTime } ms>") ;
111+ Log . Info (
112+ $ "|PluginManager.InitializePlugins|Total init cost for <{ pair . Metadata . Name } > is <{ pair . Metadata . InitTime } ms>") ;
107113 }
108114 catch ( Exception e )
109115 {
110116 Log . Exception ( nameof ( PluginManager ) , $ "Fail to Init plugin: { pair . Metadata . Name } ", e ) ;
111- pair . Metadata . Disabled = true ;
117+ pair . Metadata . Disabled = true ;
112118 failedPlugins . Enqueue ( pair ) ;
113119 }
114- } ) ;
120+ } ) ) ;
121+
122+ await Task . WhenAll ( InitTasks ) ;
115123
116124 _contextMenuPlugins = GetPluginsForInterface < IContextMenu > ( ) ;
117125 foreach ( var plugin in AllPlugins )
118126 {
119- if ( IsGlobalPlugin ( plugin . Metadata ) )
120- GlobalPlugins . Add ( plugin ) ;
121-
122- // Plugins may have multiple ActionKeywords, eg. WebSearch
123- plugin . Metadata . ActionKeywords
124- . Where ( x => x != Query . GlobalPluginWildcardSign )
125- . ToList ( )
126- . ForEach ( x => NonGlobalPlugins [ x ] = plugin ) ;
127+ foreach ( var actionKeyword in plugin . Metadata . ActionKeywords )
128+ {
129+ switch ( actionKeyword )
130+ {
131+ case Query . GlobalPluginWildcardSign :
132+ GlobalPlugins . Add ( plugin ) ;
133+ break ;
134+ default :
135+ NonGlobalPlugins [ actionKeyword ] = plugin ;
136+ break ;
137+ }
138+ }
127139 }
128140
129141 if ( failedPlugins . Any ( ) )
130142 {
131143 var failed = string . Join ( "," , failedPlugins . Select ( x => x . Metadata . Name ) ) ;
132- API . ShowMsg ( $ "Fail to Init Plugins", $ "Plugins: { failed } - fail to load and would be disabled, please contact plugin creator for help", "" , false ) ;
144+ API . ShowMsg ( $ "Fail to Init Plugins",
145+ $ "Plugins: { failed } - fail to load and would be disabled, please contact plugin creator for help",
146+ "" , false ) ;
133147 }
134148 }
135149
@@ -146,24 +160,46 @@ public static List<PluginPair> ValidPluginsForQuery(Query query)
146160 }
147161 }
148162
149- public static List < Result > QueryForPlugin ( PluginPair pair , Query query )
163+ public static async Task < List < Result > > QueryForPlugin ( PluginPair pair , Query query , CancellationToken token )
150164 {
151165 var results = new List < Result > ( ) ;
152166 try
153167 {
154168 var metadata = pair . Metadata ;
155- var milliseconds = Stopwatch . Debug ( $ "|PluginManager.QueryForPlugin|Cost for { metadata . Name } ", ( ) =>
169+
170+ long milliseconds = - 1L ;
171+
172+ switch ( pair . Plugin )
156173 {
157- results = pair . Plugin . Query ( query ) ?? new List < Result > ( ) ;
158- UpdatePluginMetadata ( results , metadata , query ) ;
159- } ) ;
174+ case IAsyncPlugin plugin :
175+ milliseconds = await Stopwatch . DebugAsync ( $ "|PluginManager.QueryForPlugin|Cost for { metadata . Name } ",
176+ async ( ) => results = await plugin . QueryAsync ( query , token ) . ConfigureAwait ( false ) ) ;
177+ break ;
178+ case IPlugin plugin :
179+ await Task . Run ( ( ) => milliseconds = Stopwatch . Debug ( $ "|PluginManager.QueryForPlugin|Cost for { metadata . Name } ",
180+ ( ) => results = plugin . Query ( query ) ) , token ) . ConfigureAwait ( false ) ;
181+ break ;
182+ default :
183+ throw new ArgumentOutOfRangeException ( ) ;
184+ }
185+ token . ThrowIfCancellationRequested ( ) ;
186+ UpdatePluginMetadata ( results , metadata , query ) ;
187+
160188 metadata . QueryCount += 1 ;
161- metadata . AvgQueryTime = metadata . QueryCount == 1 ? milliseconds : ( metadata . AvgQueryTime + milliseconds ) / 2 ;
189+ metadata . AvgQueryTime =
190+ metadata . QueryCount == 1 ? milliseconds : ( metadata . AvgQueryTime + milliseconds ) / 2 ;
191+ token . ThrowIfCancellationRequested ( ) ;
192+ }
193+ catch ( OperationCanceledException )
194+ {
195+ // null will be fine since the results will only be added into queue if the token hasn't been cancelled
196+ return results = null ;
162197 }
163198 catch ( Exception e )
164199 {
165200 Log . Exception ( $ "|PluginManager.QueryForPlugin|Exception for plugin <{ pair . Metadata . Name } > when query <{ query } >", e ) ;
166201 }
202+
167203 return results ;
168204 }
169205
@@ -182,11 +218,6 @@ public static void UpdatePluginMetadata(List<Result> results, PluginMetadata met
182218 }
183219 }
184220
185- private static bool IsGlobalPlugin ( PluginMetadata metadata )
186- {
187- return metadata . ActionKeywords . Contains ( Query . GlobalPluginWildcardSign ) ;
188- }
189-
190221 /// <summary>
191222 /// get specified plugin, return null if not found
192223 /// </summary>
@@ -222,16 +253,19 @@ public static List<Result> GetContextMenusForPlugin(Result result)
222253 }
223254 catch ( Exception e )
224255 {
225- Log . Exception ( $ "|PluginManager.GetContextMenusForPlugin|Can't load context menus for plugin <{ pluginPair . Metadata . Name } >", e ) ;
256+ Log . Exception (
257+ $ "|PluginManager.GetContextMenusForPlugin|Can't load context menus for plugin <{ pluginPair . Metadata . Name } >",
258+ e ) ;
226259 }
227260 }
261+
228262 return results ;
229263 }
230264
231265 public static bool ActionKeywordRegistered ( string actionKeyword )
232266 {
233267 return actionKeyword != Query . GlobalPluginWildcardSign
234- && NonGlobalPlugins . ContainsKey ( actionKeyword ) ;
268+ && NonGlobalPlugins . ContainsKey ( actionKeyword ) ;
235269 }
236270
237271 /// <summary>
@@ -249,6 +283,7 @@ public static void AddActionKeyword(string id, string newActionKeyword)
249283 {
250284 NonGlobalPlugins [ newActionKeyword ] = plugin ;
251285 }
286+
252287 plugin . Metadata . ActionKeywords . Add ( newActionKeyword ) ;
253288 }
254289
@@ -262,16 +297,16 @@ public static void RemoveActionKeyword(string id, string oldActionkeyword)
262297 if ( oldActionkeyword == Query . GlobalPluginWildcardSign
263298 && // Plugins may have multiple ActionKeywords that are global, eg. WebSearch
264299 plugin . Metadata . ActionKeywords
265- . Where ( x => x == Query . GlobalPluginWildcardSign )
266- . ToList ( )
267- . Count == 1 )
300+ . Where ( x => x == Query . GlobalPluginWildcardSign )
301+ . ToList ( )
302+ . Count == 1 )
268303 {
269304 GlobalPlugins . Remove ( plugin ) ;
270305 }
271-
306+
272307 if ( oldActionkeyword != Query . GlobalPluginWildcardSign )
273308 NonGlobalPlugins . Remove ( oldActionkeyword ) ;
274-
309+
275310
276311 plugin . Metadata . ActionKeywords . Remove ( oldActionkeyword ) ;
277312 }
0 commit comments