mirror of
https://github.com/Flow-Launcher/Flow.Launcher.git
synced 2026-03-11 08:54:32 +00:00
Add locks for win32s & uwps
This commit is contained in:
parent
9f84a2d50a
commit
7da2884e84
3 changed files with 83 additions and 30 deletions
|
|
@ -27,6 +27,9 @@ namespace Flow.Launcher.Plugin.Program
|
||||||
internal static List<UWPApp> _uwps { get; private set; }
|
internal static List<UWPApp> _uwps { get; private set; }
|
||||||
internal static Settings _settings { get; private set; }
|
internal static Settings _settings { get; private set; }
|
||||||
|
|
||||||
|
internal static SemaphoreSlim _win32sLock = new(1, 1);
|
||||||
|
internal static SemaphoreSlim _uwpsLock = new(1, 1);
|
||||||
|
|
||||||
internal static PluginInitContext Context { get; private set; }
|
internal static PluginInitContext Context { get; private set; }
|
||||||
|
|
||||||
private static readonly List<Result> emptyResults = new();
|
private static readonly List<Result> emptyResults = new();
|
||||||
|
|
@ -82,8 +85,11 @@ namespace Flow.Launcher.Plugin.Program
|
||||||
{
|
{
|
||||||
var result = await cache.GetOrCreateAsync(query.Search, async entry =>
|
var result = await cache.GetOrCreateAsync(query.Search, async entry =>
|
||||||
{
|
{
|
||||||
var resultList = await Task.Run(() =>
|
var resultList = await Task.Run(async () =>
|
||||||
{
|
{
|
||||||
|
await _win32sLock.WaitAsync(token);
|
||||||
|
await _uwpsLock.WaitAsync(token);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Collect all UWP Windows app directories
|
// Collect all UWP Windows app directories
|
||||||
|
|
@ -95,22 +101,26 @@ namespace Flow.Launcher.Plugin.Program
|
||||||
.ToArray() : null;
|
.ToArray() : null;
|
||||||
|
|
||||||
return _win32s.Cast<IProgram>()
|
return _win32s.Cast<IProgram>()
|
||||||
.Concat(_uwps)
|
.Concat(_uwps)
|
||||||
.AsParallel()
|
.AsParallel()
|
||||||
.WithCancellation(token)
|
.WithCancellation(token)
|
||||||
.Where(HideUninstallersFilter)
|
.Where(HideUninstallersFilter)
|
||||||
.Where(p => HideDuplicatedWindowsAppFilter(p, uwpsDirectories))
|
.Where(p => HideDuplicatedWindowsAppFilter(p, uwpsDirectories))
|
||||||
.Where(p => p.Enabled)
|
.Where(p => p.Enabled)
|
||||||
.Select(p => p.Result(query.Search, Context.API))
|
.Select(p => p.Result(query.Search, Context.API))
|
||||||
.Where(r => r?.Score > 0)
|
.Where(r => r?.Score > 0)
|
||||||
.ToList();
|
.ToList();
|
||||||
}
|
}
|
||||||
catch (OperationCanceledException)
|
catch (OperationCanceledException)
|
||||||
{
|
{
|
||||||
Log.Debug("|Flow.Launcher.Plugin.Program.Main|Query operation cancelled");
|
Log.Debug("|Flow.Launcher.Plugin.Program.Main|Query operation cancelled");
|
||||||
return emptyResults;
|
return emptyResults;
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_uwpsLock.Release();
|
||||||
|
_win32sLock.Release();
|
||||||
|
}
|
||||||
}, token);
|
}, token);
|
||||||
|
|
||||||
resultList = resultList.Any() ? resultList : emptyResults;
|
resultList = resultList.Any() ? resultList : emptyResults;
|
||||||
|
|
@ -236,14 +246,25 @@ namespace Flow.Launcher.Plugin.Program
|
||||||
var newUWPCacheFile = Path.Combine(pluginCachePath, $"{UwpCacheName}.cache");
|
var newUWPCacheFile = Path.Combine(pluginCachePath, $"{UwpCacheName}.cache");
|
||||||
MoveFile(oldUWPCacheFile, newUWPCacheFile);
|
MoveFile(oldUWPCacheFile, newUWPCacheFile);
|
||||||
|
|
||||||
|
await _win32sLock.WaitAsync();
|
||||||
_win32s = await context.API.LoadCacheBinaryStorageAsync(Win32CacheName, pluginCachePath, new List<Win32>());
|
_win32s = await context.API.LoadCacheBinaryStorageAsync(Win32CacheName, pluginCachePath, new List<Win32>());
|
||||||
|
_win32sLock.Release();
|
||||||
|
|
||||||
|
await _uwpsLock.WaitAsync();
|
||||||
_uwps = await context.API.LoadCacheBinaryStorageAsync(UwpCacheName, pluginCachePath, new List<UWPApp>());
|
_uwps = await context.API.LoadCacheBinaryStorageAsync(UwpCacheName, pluginCachePath, new List<UWPApp>());
|
||||||
|
_uwpsLock.Release();
|
||||||
});
|
});
|
||||||
|
await _win32sLock.WaitAsync();
|
||||||
|
await _uwpsLock.WaitAsync();
|
||||||
|
|
||||||
Log.Info($"|Flow.Launcher.Plugin.Program.Main|Number of preload win32 programs <{_win32s.Count}>");
|
Log.Info($"|Flow.Launcher.Plugin.Program.Main|Number of preload win32 programs <{_win32s.Count}>");
|
||||||
Log.Info($"|Flow.Launcher.Plugin.Program.Main|Number of preload uwps <{_uwps.Count}>");
|
Log.Info($"|Flow.Launcher.Plugin.Program.Main|Number of preload uwps <{_uwps.Count}>");
|
||||||
|
|
||||||
bool cacheEmpty = !_win32s.Any() || !_uwps.Any();
|
bool cacheEmpty = !_win32s.Any() || !_uwps.Any();
|
||||||
|
|
||||||
|
_win32sLock.Release();
|
||||||
|
_uwpsLock.Release();
|
||||||
|
|
||||||
if (cacheEmpty || _settings.LastIndexTime.AddHours(30) < DateTime.Now)
|
if (cacheEmpty || _settings.LastIndexTime.AddHours(30) < DateTime.Now)
|
||||||
{
|
{
|
||||||
_ = Task.Run(async () =>
|
_ = Task.Run(async () =>
|
||||||
|
|
@ -267,11 +288,13 @@ namespace Flow.Launcher.Plugin.Program
|
||||||
public static async Task IndexWin32ProgramsAsync()
|
public static async Task IndexWin32ProgramsAsync()
|
||||||
{
|
{
|
||||||
var win32S = Win32.All(_settings);
|
var win32S = Win32.All(_settings);
|
||||||
|
await _win32sLock.WaitAsync();
|
||||||
_win32s.Clear();
|
_win32s.Clear();
|
||||||
foreach (var win32 in win32S)
|
foreach (var win32 in win32S)
|
||||||
{
|
{
|
||||||
_win32s.Add(win32);
|
_win32s.Add(win32);
|
||||||
}
|
}
|
||||||
|
_win32sLock.Release();
|
||||||
ResetCache();
|
ResetCache();
|
||||||
await Context.API.SaveCacheBinaryStorageAsync<List<Win32>>(Win32CacheName, Context.CurrentPluginMetadata.PluginCacheDirectoryPath);
|
await Context.API.SaveCacheBinaryStorageAsync<List<Win32>>(Win32CacheName, Context.CurrentPluginMetadata.PluginCacheDirectoryPath);
|
||||||
_settings.LastIndexTime = DateTime.Now;
|
_settings.LastIndexTime = DateTime.Now;
|
||||||
|
|
@ -280,11 +303,13 @@ namespace Flow.Launcher.Plugin.Program
|
||||||
public static async Task IndexUwpProgramsAsync()
|
public static async Task IndexUwpProgramsAsync()
|
||||||
{
|
{
|
||||||
var uwps = UWPPackage.All(_settings);
|
var uwps = UWPPackage.All(_settings);
|
||||||
|
await _uwpsLock.WaitAsync();
|
||||||
_uwps.Clear();
|
_uwps.Clear();
|
||||||
foreach (var uwp in uwps)
|
foreach (var uwp in uwps)
|
||||||
{
|
{
|
||||||
_uwps.Add(uwp);
|
_uwps.Add(uwp);
|
||||||
}
|
}
|
||||||
|
_uwpsLock.Release();
|
||||||
ResetCache();
|
ResetCache();
|
||||||
await Context.API.SaveCacheBinaryStorageAsync<List<UWPApp>>(UwpCacheName, Context.CurrentPluginMetadata.PluginCacheDirectoryPath);
|
await Context.API.SaveCacheBinaryStorageAsync<List<UWPApp>>(UwpCacheName, Context.CurrentPluginMetadata.PluginCacheDirectoryPath);
|
||||||
_settings.LastIndexTime = DateTime.Now;
|
_settings.LastIndexTime = DateTime.Now;
|
||||||
|
|
@ -358,26 +383,36 @@ namespace Flow.Launcher.Plugin.Program
|
||||||
return menuOptions;
|
return menuOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void DisableProgram(IProgram programToDelete)
|
private static async Task DisableProgram(IProgram programToDelete)
|
||||||
{
|
{
|
||||||
if (_settings.DisabledProgramSources.Any(x => x.UniqueIdentifier == programToDelete.UniqueIdentifier))
|
if (_settings.DisabledProgramSources.Any(x => x.UniqueIdentifier == programToDelete.UniqueIdentifier))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
await _uwpsLock.WaitAsync();
|
||||||
if (_uwps.Any(x => x.UniqueIdentifier == programToDelete.UniqueIdentifier))
|
if (_uwps.Any(x => x.UniqueIdentifier == programToDelete.UniqueIdentifier))
|
||||||
{
|
{
|
||||||
var program = _uwps.First(x => x.UniqueIdentifier == programToDelete.UniqueIdentifier);
|
var program = _uwps.First(x => x.UniqueIdentifier == programToDelete.UniqueIdentifier);
|
||||||
program.Enabled = false;
|
program.Enabled = false;
|
||||||
_settings.DisabledProgramSources.Add(new ProgramSource(program));
|
_settings.DisabledProgramSources.Add(new ProgramSource(program));
|
||||||
|
_uwpsLock.Release();
|
||||||
|
|
||||||
|
// Reindex UWP programs
|
||||||
_ = Task.Run(() =>
|
_ = Task.Run(() =>
|
||||||
{
|
{
|
||||||
_ = IndexUwpProgramsAsync();
|
_ = IndexUwpProgramsAsync();
|
||||||
});
|
});
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
else if (_win32s.Any(x => x.UniqueIdentifier == programToDelete.UniqueIdentifier))
|
|
||||||
|
await _win32sLock.WaitAsync();
|
||||||
|
if (_win32s.Any(x => x.UniqueIdentifier == programToDelete.UniqueIdentifier))
|
||||||
{
|
{
|
||||||
var program = _win32s.First(x => x.UniqueIdentifier == programToDelete.UniqueIdentifier);
|
var program = _win32s.First(x => x.UniqueIdentifier == programToDelete.UniqueIdentifier);
|
||||||
program.Enabled = false;
|
program.Enabled = false;
|
||||||
_settings.DisabledProgramSources.Add(new ProgramSource(program));
|
_settings.DisabledProgramSources.Add(new ProgramSource(program));
|
||||||
|
_win32sLock.Release();
|
||||||
|
|
||||||
|
// Reindex Win32 programs
|
||||||
_ = Task.Run(() =>
|
_ = Task.Run(() =>
|
||||||
{
|
{
|
||||||
_ = IndexWin32ProgramsAsync();
|
_ = IndexWin32ProgramsAsync();
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using Flow.Launcher.Plugin.Program.Views.Models;
|
using Flow.Launcher.Plugin.Program.Views.Models;
|
||||||
|
|
||||||
namespace Flow.Launcher.Plugin.Program.Views.Commands
|
namespace Flow.Launcher.Plugin.Program.Views.Commands
|
||||||
|
|
@ -15,21 +16,24 @@ namespace Flow.Launcher.Plugin.Program.Views.Commands
|
||||||
.ToList();
|
.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void DisplayAllPrograms()
|
internal static async Task DisplayAllProgramsAsync()
|
||||||
{
|
{
|
||||||
|
await Main._win32sLock.WaitAsync();
|
||||||
var win32 = Main._win32s
|
var win32 = Main._win32s
|
||||||
.Where(t1 => !ProgramSetting.ProgramSettingDisplayList.Any(x => x.UniqueIdentifier == t1.UniqueIdentifier))
|
.Where(t1 => !ProgramSetting.ProgramSettingDisplayList.Any(x => x.UniqueIdentifier == t1.UniqueIdentifier))
|
||||||
.Select(x => new ProgramSource(x));
|
.Select(x => new ProgramSource(x));
|
||||||
|
ProgramSetting.ProgramSettingDisplayList.AddRange(win32);
|
||||||
|
Main._win32sLock.Release();
|
||||||
|
|
||||||
|
await Main._uwpsLock.WaitAsync();
|
||||||
var uwp = Main._uwps
|
var uwp = Main._uwps
|
||||||
.Where(t1 => !ProgramSetting.ProgramSettingDisplayList.Any(x => x.UniqueIdentifier == t1.UniqueIdentifier))
|
.Where(t1 => !ProgramSetting.ProgramSettingDisplayList.Any(x => x.UniqueIdentifier == t1.UniqueIdentifier))
|
||||||
.Select(x => new ProgramSource(x));
|
.Select(x => new ProgramSource(x));
|
||||||
|
|
||||||
ProgramSetting.ProgramSettingDisplayList.AddRange(win32);
|
|
||||||
ProgramSetting.ProgramSettingDisplayList.AddRange(uwp);
|
ProgramSetting.ProgramSettingDisplayList.AddRange(uwp);
|
||||||
|
Main._uwpsLock.Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void SetProgramSourcesStatus(List<ProgramSource> selectedProgramSourcesToDisable, bool status)
|
internal static async Task SetProgramSourcesStatusAsync(List<ProgramSource> selectedProgramSourcesToDisable, bool status)
|
||||||
{
|
{
|
||||||
foreach(var program in ProgramSetting.ProgramSettingDisplayList)
|
foreach(var program in ProgramSetting.ProgramSettingDisplayList)
|
||||||
{
|
{
|
||||||
|
|
@ -39,14 +43,17 @@ namespace Flow.Launcher.Plugin.Program.Views.Commands
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach(var program in Main._win32s)
|
await Main._win32sLock.WaitAsync();
|
||||||
|
foreach (var program in Main._win32s)
|
||||||
{
|
{
|
||||||
if (selectedProgramSourcesToDisable.Any(x => x.UniqueIdentifier == program.UniqueIdentifier && program.Enabled != status))
|
if (selectedProgramSourcesToDisable.Any(x => x.UniqueIdentifier == program.UniqueIdentifier && program.Enabled != status))
|
||||||
{
|
{
|
||||||
program.Enabled = status;
|
program.Enabled = status;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Main._win32sLock.Release();
|
||||||
|
|
||||||
|
await Main._uwpsLock.WaitAsync();
|
||||||
foreach (var program in Main._uwps)
|
foreach (var program in Main._uwps)
|
||||||
{
|
{
|
||||||
if (selectedProgramSourcesToDisable.Any(x => x.UniqueIdentifier == program.UniqueIdentifier && program.Enabled != status))
|
if (selectedProgramSourcesToDisable.Any(x => x.UniqueIdentifier == program.UniqueIdentifier && program.Enabled != status))
|
||||||
|
|
@ -54,6 +61,7 @@ namespace Flow.Launcher.Plugin.Program.Views.Commands
|
||||||
program.Enabled = status;
|
program.Enabled = status;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Main._uwpsLock.Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void StoreDisabledInSettings()
|
internal static void StoreDisabledInSettings()
|
||||||
|
|
@ -72,12 +80,22 @@ namespace Flow.Launcher.Plugin.Program.Views.Commands
|
||||||
Main._settings.DisabledProgramSources.RemoveAll(t1 => t1.Enabled);
|
Main._settings.DisabledProgramSources.RemoveAll(t1 => t1.Enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static bool IsReindexRequired(this List<ProgramSource> selectedItems)
|
internal static async Task<bool> IsReindexRequiredAsync(this List<ProgramSource> selectedItems)
|
||||||
{
|
{
|
||||||
// Not in cache
|
// Not in cache
|
||||||
if (selectedItems.Any(t1 => t1.Enabled && !Main._uwps.Any(x => t1.UniqueIdentifier == x.UniqueIdentifier))
|
await Main._win32sLock.WaitAsync();
|
||||||
|
await Main._uwpsLock.WaitAsync();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (selectedItems.Any(t1 => t1.Enabled && !Main._uwps.Any(x => t1.UniqueIdentifier == x.UniqueIdentifier))
|
||||||
&& selectedItems.Any(t1 => t1.Enabled && !Main._win32s.Any(x => t1.UniqueIdentifier == x.UniqueIdentifier)))
|
&& selectedItems.Any(t1 => t1.Enabled && !Main._win32s.Any(x => t1.UniqueIdentifier == x.UniqueIdentifier)))
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Main._win32sLock.Release();
|
||||||
|
Main._uwpsLock.Release();
|
||||||
|
}
|
||||||
|
|
||||||
// ProgramSources holds list of user added directories,
|
// ProgramSources holds list of user added directories,
|
||||||
// so when we enable/disable we need to reindex to show/not show the programs
|
// so when we enable/disable we need to reindex to show/not show the programs
|
||||||
|
|
|
||||||
|
|
@ -183,7 +183,7 @@ namespace Flow.Launcher.Plugin.Program.Views
|
||||||
EditProgramSource(selectedProgramSource);
|
EditProgramSource(selectedProgramSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void EditProgramSource(ProgramSource selectedProgramSource)
|
private async void EditProgramSource(ProgramSource selectedProgramSource)
|
||||||
{
|
{
|
||||||
if (selectedProgramSource == null)
|
if (selectedProgramSource == null)
|
||||||
{
|
{
|
||||||
|
|
@ -202,13 +202,13 @@ namespace Flow.Launcher.Plugin.Program.Views
|
||||||
{
|
{
|
||||||
if (selectedProgramSource.Enabled)
|
if (selectedProgramSource.Enabled)
|
||||||
{
|
{
|
||||||
ProgramSettingDisplay.SetProgramSourcesStatus(new List<ProgramSource> { selectedProgramSource },
|
await ProgramSettingDisplay.SetProgramSourcesStatusAsync(new List<ProgramSource> { selectedProgramSource },
|
||||||
true); // sync status in win32, uwp and disabled
|
true); // sync status in win32, uwp and disabled
|
||||||
ProgramSettingDisplay.RemoveDisabledFromSettings();
|
ProgramSettingDisplay.RemoveDisabledFromSettings();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ProgramSettingDisplay.SetProgramSourcesStatus(new List<ProgramSource> { selectedProgramSource },
|
await ProgramSettingDisplay.SetProgramSourcesStatusAsync(new List<ProgramSource> { selectedProgramSource },
|
||||||
false);
|
false);
|
||||||
ProgramSettingDisplay.StoreDisabledInSettings();
|
ProgramSettingDisplay.StoreDisabledInSettings();
|
||||||
}
|
}
|
||||||
|
|
@ -277,14 +277,14 @@ namespace Flow.Launcher.Plugin.Program.Views
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void btnLoadAllProgramSource_OnClick(object sender, RoutedEventArgs e)
|
private async void btnLoadAllProgramSource_OnClick(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
ProgramSettingDisplay.DisplayAllPrograms();
|
await ProgramSettingDisplay.DisplayAllProgramsAsync();
|
||||||
|
|
||||||
ViewRefresh();
|
ViewRefresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void btnProgramSourceStatus_OnClick(object sender, RoutedEventArgs e)
|
private async void btnProgramSourceStatus_OnClick(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
var selectedItems = programSourceView
|
var selectedItems = programSourceView
|
||||||
.SelectedItems.Cast<ProgramSource>()
|
.SelectedItems.Cast<ProgramSource>()
|
||||||
|
|
@ -311,18 +311,18 @@ namespace Flow.Launcher.Plugin.Program.Views
|
||||||
}
|
}
|
||||||
else if (HasMoreOrEqualEnabledItems(selectedItems))
|
else if (HasMoreOrEqualEnabledItems(selectedItems))
|
||||||
{
|
{
|
||||||
ProgramSettingDisplay.SetProgramSourcesStatus(selectedItems, false);
|
await ProgramSettingDisplay.SetProgramSourcesStatusAsync(selectedItems, false);
|
||||||
|
|
||||||
ProgramSettingDisplay.StoreDisabledInSettings();
|
ProgramSettingDisplay.StoreDisabledInSettings();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ProgramSettingDisplay.SetProgramSourcesStatus(selectedItems, true);
|
await ProgramSettingDisplay.SetProgramSourcesStatusAsync(selectedItems, true);
|
||||||
|
|
||||||
ProgramSettingDisplay.RemoveDisabledFromSettings();
|
ProgramSettingDisplay.RemoveDisabledFromSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (selectedItems.IsReindexRequired())
|
if (await selectedItems.IsReindexRequiredAsync())
|
||||||
ReIndexing();
|
ReIndexing();
|
||||||
|
|
||||||
programSourceView.SelectedItems.Clear();
|
programSourceView.SelectedItems.Clear();
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue