Skip to content

Commit 6eb52b8

Browse files
committed
Check plugin updates in the background
1 parent 6ec659e commit 6eb52b8

File tree

3 files changed

+113
-0
lines changed

3 files changed

+113
-0
lines changed

Flow.Launcher.Core/Plugin/PluginInstaller.cs

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,97 @@ await DownloadFileAsync(
277277
}
278278
}
279279

280+
/// <summary>
281+
/// Updates the plugin to the latest version available from its source.
282+
/// </summary>
283+
/// <param name="silentUpdate">If true, do not show any messages when there is no udpate available.</param>
284+
/// <param name="usePrimaryUrlOnly">If true, only use the primary URL for updates.</param>
285+
/// <param name="token">Cancellation token to cancel the update operation.</param>
286+
/// <returns></returns>
287+
public static async Task UpdatePluginAsync(bool silentUpdate = true, bool usePrimaryUrlOnly = false, CancellationToken token = default)
288+
{
289+
// Update the plugin manifest
290+
await API.UpdatePluginManifestAsync(usePrimaryUrlOnly, token);
291+
292+
// Get all plugins that can be updated
293+
var resultsForUpdate = (
294+
from existingPlugin in API.GetAllPlugins()
295+
join pluginUpdateSource in API.GetPluginManifest()
296+
on existingPlugin.Metadata.ID equals pluginUpdateSource.ID
297+
where string.Compare(existingPlugin.Metadata.Version, pluginUpdateSource.Version,
298+
StringComparison.InvariantCulture) <
299+
0 // if current version precedes version of the plugin from update source (e.g. PluginsManifest)
300+
&& !API.PluginModified(existingPlugin.Metadata.ID)
301+
select
302+
new
303+
{
304+
existingPlugin.Metadata.ID,
305+
pluginUpdateSource.Name,
306+
pluginUpdateSource.Author,
307+
CurrentVersion = existingPlugin.Metadata.Version,
308+
NewVersion = pluginUpdateSource.Version,
309+
existingPlugin.Metadata.IcoPath,
310+
PluginExistingMetadata = existingPlugin.Metadata,
311+
PluginNewUserPlugin = pluginUpdateSource
312+
}).ToList();
313+
314+
// No updates
315+
if (!resultsForUpdate.Any())
316+
{
317+
if (!silentUpdate)
318+
{
319+
API.ShowMsg(API.GetTranslation("updateNoResultTitle"), API.GetTranslation("updateNoResultSubtitle"));
320+
}
321+
return;
322+
}
323+
324+
// If all plugins are modified, just return
325+
if (resultsForUpdate.All(x => API.PluginModified(x.ID)))
326+
{
327+
return;
328+
}
329+
330+
if (API.ShowMsgBox(
331+
string.Format(API.GetTranslation("updateAllPluginsSubtitle"),
332+
Environment.NewLine, string.Join(", ", resultsForUpdate.Select(x => x.PluginExistingMetadata.Name))),
333+
API.GetTranslation("updateAllPluginsTitle"),
334+
MessageBoxButton.YesNo) == MessageBoxResult.No)
335+
{
336+
return;
337+
}
338+
339+
// Update all plugins
340+
await Task.WhenAll(resultsForUpdate.Select(async plugin =>
341+
{
342+
var downloadToFilePath = Path.Combine(Path.GetTempPath(), $"{plugin.Name}-{plugin.NewVersion}.zip");
343+
344+
try
345+
{
346+
using var cts = new CancellationTokenSource();
347+
348+
await DownloadFileAsync(
349+
$"{API.GetTranslation("DownloadingPlugin")} {plugin.PluginNewUserPlugin.Name}",
350+
plugin.PluginNewUserPlugin.UrlDownload, downloadToFilePath, cts);
351+
352+
// check if user cancelled download before installing plugin
353+
if (cts.IsCancellationRequested)
354+
{
355+
return;
356+
}
357+
358+
if (!await API.UpdatePluginAsync(plugin.PluginExistingMetadata, plugin.PluginNewUserPlugin, downloadToFilePath))
359+
{
360+
return;
361+
}
362+
}
363+
catch (Exception e)
364+
{
365+
API.LogException(ClassName, "Failed to update plugin", e);
366+
API.ShowMsgError(API.GetTranslation("ErrorUpdatingPlugin"));
367+
}
368+
}));
369+
}
370+
280371
/// <summary>
281372
/// Downloads a file from a URL to a local path, optionally showing a progress box and handling cancellation.
282373
/// </summary>

Flow.Launcher/App.xaml.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,7 @@ await API.StopwatchLogInfoAsync(ClassName, "Startup cost", async () =>
239239

240240
AutoStartup();
241241
AutoUpdates();
242+
AutoPluginUpdates();
242243

243244
API.SaveAppAllSettings();
244245
API.LogInfo(ClassName, "End Flow Launcher startup ----------------------------------------------------");
@@ -289,6 +290,23 @@ private static void AutoUpdates()
289290
});
290291
}
291292

293+
private static void AutoPluginUpdates()
294+
{
295+
_ = Task.Run(async () =>
296+
{
297+
if (_settings.AutoUpdatePlugins)
298+
{
299+
// check plugin updates every 5 hour
300+
var timer = new PeriodicTimer(TimeSpan.FromHours(5));
301+
await PluginInstaller.UpdatePluginAsync();
302+
303+
while (await timer.WaitForNextTickAsync())
304+
// check updates on startup
305+
await PluginInstaller.UpdatePluginAsync();
306+
}
307+
});
308+
}
309+
292310
#endregion
293311

294312
#region Register Events

Flow.Launcher/Languages/en.xaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,10 @@
233233
<system:String x:Key="ZipFiles">Zip files</system:String>
234234
<system:String x:Key="SelectZipFile">Please select zip file</system:String>
235235
<system:String x:Key="installLocalPluginTooltip">Install plugin from local path</system:String>
236+
<system:String x:Key="updateNoResultTitle">No update available</system:String>
237+
<system:String x:Key="updateNoResultSubtitle">All plugins are up to date</system:String>
238+
<system:String x:Key="updateAllPluginsTitle">Update all plugins</system:String>
239+
<system:String x:Key="updateAllPluginsSubtitle">Would you like to update these plugins?{0}{0}{1}</system:String>
236240

237241
<!-- Setting Theme -->
238242
<system:String x:Key="theme">Theme</system:String>

0 commit comments

Comments
 (0)