Skip to content

Commit 9dd5f06

Browse files
authored
Merge pull request #3460 from Flow-Launcher/ignore_plugin_source_http_exception
Improve log & Ignore plugin source http exception
2 parents 9b5d22a + 3fab9da commit 9dd5f06

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+282
-299
lines changed

Flow.Launcher.Core/Configuration/Portable.cs

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,22 @@
1-
using Microsoft.Win32;
2-
using Squirrel;
3-
using System;
1+
using System;
42
using System.IO;
3+
using System.Linq;
54
using System.Reflection;
65
using System.Windows;
6+
using CommunityToolkit.Mvvm.DependencyInjection;
77
using Flow.Launcher.Infrastructure;
8-
using Flow.Launcher.Infrastructure.Logger;
98
using Flow.Launcher.Infrastructure.UserSettings;
10-
using Flow.Launcher.Plugin.SharedCommands;
11-
using System.Linq;
12-
using CommunityToolkit.Mvvm.DependencyInjection;
139
using Flow.Launcher.Plugin;
10+
using Flow.Launcher.Plugin.SharedCommands;
11+
using Microsoft.Win32;
12+
using Squirrel;
1413

1514
namespace Flow.Launcher.Core.Configuration
1615
{
1716
public class Portable : IPortable
1817
{
18+
private static readonly string ClassName = nameof(Portable);
19+
1920
private readonly IPublicAPI API = Ioc.Default.GetRequiredService<IPublicAPI>();
2021

2122
/// <summary>
@@ -51,7 +52,7 @@ public void DisablePortableMode()
5152
}
5253
catch (Exception e)
5354
{
54-
Log.Exception("|Portable.DisablePortableMode|Error occurred while disabling portable mode", e);
55+
API.LogException(ClassName, "Error occurred while disabling portable mode", e);
5556
}
5657
}
5758

@@ -75,7 +76,7 @@ public void EnablePortableMode()
7576
}
7677
catch (Exception e)
7778
{
78-
Log.Exception("|Portable.EnablePortableMode|Error occurred while enabling portable mode", e);
79+
API.LogException(ClassName, "Error occurred while enabling portable mode", e);
7980
}
8081
}
8182

Flow.Launcher.Core/ExternalPlugins/CommunityPluginSource.cs

Lines changed: 45 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,32 @@
1-
using Flow.Launcher.Infrastructure.Http;
2-
using Flow.Launcher.Infrastructure.Logger;
3-
using Flow.Launcher.Plugin;
4-
using System;
1+
using System;
52
using System.Collections.Generic;
63
using System.Net;
74
using System.Net.Http;
85
using System.Net.Http.Json;
6+
using System.Net.Sockets;
97
using System.Text.Json;
108
using System.Text.Json.Serialization;
119
using System.Threading;
1210
using System.Threading.Tasks;
11+
using CommunityToolkit.Mvvm.DependencyInjection;
12+
using Flow.Launcher.Infrastructure.Http;
13+
using Flow.Launcher.Plugin;
1314

1415
namespace Flow.Launcher.Core.ExternalPlugins
1516
{
1617
public record CommunityPluginSource(string ManifestFileUrl)
1718
{
19+
// We should not initialize API in static constructor because it will create another API instance
20+
private static IPublicAPI api = null;
21+
private static IPublicAPI API => api ??= Ioc.Default.GetRequiredService<IPublicAPI>();
22+
23+
private static readonly string ClassName = nameof(CommunityPluginSource);
24+
1825
private string latestEtag = "";
1926

2027
private List<UserPlugin> plugins = new();
2128

22-
private static JsonSerializerOptions PluginStoreItemSerializationOption = new JsonSerializerOptions()
29+
private static readonly JsonSerializerOptions PluginStoreItemSerializationOption = new()
2330
{
2431
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault
2532
};
@@ -34,35 +41,49 @@ public record CommunityPluginSource(string ManifestFileUrl)
3441
/// </remarks>
3542
public async Task<List<UserPlugin>> FetchAsync(CancellationToken token)
3643
{
37-
Log.Info(nameof(CommunityPluginSource), $"Loading plugins from {ManifestFileUrl}");
44+
API.LogInfo(ClassName, $"Loading plugins from {ManifestFileUrl}");
3845

3946
var request = new HttpRequestMessage(HttpMethod.Get, ManifestFileUrl);
4047

4148
request.Headers.Add("If-None-Match", latestEtag);
4249

43-
using var response = await Http.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, token)
50+
try
51+
{
52+
using var response = await Http.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, token)
4453
.ConfigureAwait(false);
4554

46-
if (response.StatusCode == HttpStatusCode.OK)
47-
{
48-
this.plugins = await response.Content
49-
.ReadFromJsonAsync<List<UserPlugin>>(PluginStoreItemSerializationOption, cancellationToken: token)
50-
.ConfigureAwait(false);
51-
this.latestEtag = response.Headers.ETag?.Tag;
55+
if (response.StatusCode == HttpStatusCode.OK)
56+
{
57+
plugins = await response.Content
58+
.ReadFromJsonAsync<List<UserPlugin>>(PluginStoreItemSerializationOption, cancellationToken: token)
59+
.ConfigureAwait(false);
60+
latestEtag = response.Headers.ETag?.Tag;
5261

53-
Log.Info(nameof(CommunityPluginSource), $"Loaded {this.plugins.Count} plugins from {ManifestFileUrl}");
54-
return this.plugins;
55-
}
56-
else if (response.StatusCode == HttpStatusCode.NotModified)
57-
{
58-
Log.Info(nameof(CommunityPluginSource), $"Resource {ManifestFileUrl} has not been modified.");
59-
return this.plugins;
62+
API.LogInfo(ClassName, $"Loaded {plugins.Count} plugins from {ManifestFileUrl}");
63+
return plugins;
64+
}
65+
else if (response.StatusCode == HttpStatusCode.NotModified)
66+
{
67+
API.LogInfo(ClassName, $"Resource {ManifestFileUrl} has not been modified.");
68+
return plugins;
69+
}
70+
else
71+
{
72+
API.LogWarn(ClassName, $"Failed to load resource {ManifestFileUrl} with response {response.StatusCode}");
73+
return plugins;
74+
}
6075
}
61-
else
76+
catch (Exception e)
6277
{
63-
Log.Warn(nameof(CommunityPluginSource),
64-
$"Failed to load resource {ManifestFileUrl} with response {response.StatusCode}");
65-
throw new Exception($"Failed to load resource {ManifestFileUrl} with response {response.StatusCode}");
78+
if (e is HttpRequestException or WebException or SocketException || e.InnerException is TimeoutException)
79+
{
80+
API.LogException(ClassName, $"Check your connection and proxy settings to {ManifestFileUrl}.", e);
81+
}
82+
else
83+
{
84+
API.LogException(ClassName, "Error Occurred", e);
85+
}
86+
return plugins;
6687
}
6788
}
6889
}

Flow.Launcher.Core/ExternalPlugins/Environments/AbstractPluginEnvironment.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
using System.Windows;
66
using System.Windows.Forms;
77
using CommunityToolkit.Mvvm.DependencyInjection;
8-
using Flow.Launcher.Infrastructure.Logger;
98
using Flow.Launcher.Infrastructure.UserSettings;
109
using Flow.Launcher.Plugin;
1110
using Flow.Launcher.Plugin.SharedCommands;
@@ -14,6 +13,8 @@ namespace Flow.Launcher.Core.ExternalPlugins.Environments
1413
{
1514
public abstract class AbstractPluginEnvironment
1615
{
16+
private static readonly string ClassName = nameof(AbstractPluginEnvironment);
17+
1718
protected readonly IPublicAPI API = Ioc.Default.GetRequiredService<IPublicAPI>();
1819

1920
internal abstract string Language { get; }
@@ -120,7 +121,7 @@ internal IEnumerable<PluginPair> Setup()
120121
else
121122
{
122123
API.ShowMsgBox(string.Format(API.GetTranslation("runtimePluginUnableToSetExecutablePath"), Language));
123-
Log.Error("PluginsLoader",
124+
API.LogError(ClassName,
124125
$"Not able to successfully set {EnvName} path, setting's plugin executable path variable is still an empty string.",
125126
$"{Language}Environment");
126127

Flow.Launcher.Core/ExternalPlugins/Environments/JavaScriptEnvironment.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
namespace Flow.Launcher.Core.ExternalPlugins.Environments
66
{
7-
87
internal class JavaScriptEnvironment : TypeScriptEnvironment
98
{
109
internal override string Language => AllowedLanguage.JavaScript;

Flow.Launcher.Core/ExternalPlugins/Environments/JavaScriptV2Environment.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
namespace Flow.Launcher.Core.ExternalPlugins.Environments
66
{
7-
87
internal class JavaScriptV2Environment : TypeScriptV2Environment
98
{
109
internal override string Language => AllowedLanguage.JavaScriptV2;

Flow.Launcher.Core/ExternalPlugins/Environments/PythonEnvironment.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using Flow.Launcher.Infrastructure.UserSettings;
66
using Flow.Launcher.Plugin;
77
using Flow.Launcher.Plugin.SharedCommands;
8+
using Microsoft.VisualStudio.Threading;
89

910
namespace Flow.Launcher.Core.ExternalPlugins.Environments
1011
{
@@ -30,13 +31,15 @@ internal override string PluginsSettingsFilePath
3031

3132
internal PythonEnvironment(List<PluginMetadata> pluginMetadataList, PluginsSettings pluginSettings) : base(pluginMetadataList, pluginSettings) { }
3233

34+
private JoinableTaskFactory JTF { get; } = new JoinableTaskFactory(new JoinableTaskContext());
35+
3336
internal override void InstallEnvironment()
3437
{
3538
FilesFolders.RemoveFolderIfExists(InstallPath, (s) => API.ShowMsgBox(s));
3639

3740
// Python 3.11.4 is no longer Windows 7 compatible. If user is on Win 7 and
3841
// uses Python plugin they need to custom install and use v3.8.9
39-
DroplexPackage.Drop(App.python_3_11_4_embeddable, InstallPath).Wait();
42+
JTF.Run(() => DroplexPackage.Drop(App.python_3_11_4_embeddable, InstallPath));
4043

4144
PluginsSettingsFilePath = ExecutablePath;
4245
}

Flow.Launcher.Core/ExternalPlugins/Environments/TypeScriptEnvironment.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using Flow.Launcher.Infrastructure.UserSettings;
66
using Flow.Launcher.Plugin;
77
using Flow.Launcher.Plugin.SharedCommands;
8+
using Microsoft.VisualStudio.Threading;
89

910
namespace Flow.Launcher.Core.ExternalPlugins.Environments
1011
{
@@ -27,11 +28,13 @@ internal override string PluginsSettingsFilePath
2728

2829
internal TypeScriptEnvironment(List<PluginMetadata> pluginMetadataList, PluginsSettings pluginSettings) : base(pluginMetadataList, pluginSettings) { }
2930

31+
private JoinableTaskFactory JTF { get; } = new JoinableTaskFactory(new JoinableTaskContext());
32+
3033
internal override void InstallEnvironment()
3134
{
3235
FilesFolders.RemoveFolderIfExists(InstallPath, (s) => API.ShowMsgBox(s));
3336

34-
DroplexPackage.Drop(App.nodejs_16_18_0, InstallPath).Wait();
37+
JTF.Run(() => DroplexPackage.Drop(App.nodejs_16_18_0, InstallPath));
3538

3639
PluginsSettingsFilePath = ExecutablePath;
3740
}

Flow.Launcher.Core/ExternalPlugins/Environments/TypeScriptV2Environment.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using Flow.Launcher.Infrastructure.UserSettings;
66
using Flow.Launcher.Plugin;
77
using Flow.Launcher.Plugin.SharedCommands;
8+
using Microsoft.VisualStudio.Threading;
89

910
namespace Flow.Launcher.Core.ExternalPlugins.Environments
1011
{
@@ -27,11 +28,13 @@ internal override string PluginsSettingsFilePath
2728

2829
internal TypeScriptV2Environment(List<PluginMetadata> pluginMetadataList, PluginsSettings pluginSettings) : base(pluginMetadataList, pluginSettings) { }
2930

31+
private JoinableTaskFactory JTF { get; } = new JoinableTaskFactory(new JoinableTaskContext());
32+
3033
internal override void InstallEnvironment()
3134
{
3235
FilesFolders.RemoveFolderIfExists(InstallPath, (s) => API.ShowMsgBox(s));
3336

34-
DroplexPackage.Drop(App.nodejs_16_18_0, InstallPath).Wait();
37+
JTF.Run(() => DroplexPackage.Drop(App.nodejs_16_18_0, InstallPath));
3538

3639
PluginsSettingsFilePath = ExecutablePath;
3740
}

Flow.Launcher.Core/ExternalPlugins/PluginsManifest.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ namespace Flow.Launcher.Core.ExternalPlugins
99
{
1010
public static class PluginsManifest
1111
{
12+
private static readonly string ClassName = nameof(PluginsManifest);
13+
1214
private static readonly CommunityPluginStore mainPluginStore =
1315
new("https://raw.githubusercontent.com/Flow-Launcher/Flow.Launcher.PluginsManifest/plugin_api_v2/plugins.json",
1416
"https://fastly.jsdelivr.net/gh/Flow-Launcher/Flow.Launcher.PluginsManifest@plugin_api_v2/plugins.json",
@@ -44,7 +46,7 @@ public static async Task<bool> UpdateManifestAsync(bool usePrimaryUrlOnly = fals
4446
}
4547
catch (Exception e)
4648
{
47-
Ioc.Default.GetRequiredService<IPublicAPI>().LogException(nameof(PluginsManifest), "Http request failed", e);
49+
Ioc.Default.GetRequiredService<IPublicAPI>().LogException(ClassName, "Http request failed", e);
4850
}
4951
finally
5052
{

Flow.Launcher.Core/Plugin/PluginConfig.cs

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,20 @@
33
using System.Linq;
44
using System.IO;
55
using Flow.Launcher.Infrastructure;
6-
using Flow.Launcher.Infrastructure.Logger;
76
using Flow.Launcher.Plugin;
87
using System.Text.Json;
8+
using CommunityToolkit.Mvvm.DependencyInjection;
99

1010
namespace Flow.Launcher.Core.Plugin
1111
{
1212
internal abstract class PluginConfig
1313
{
14+
private static readonly string ClassName = nameof(PluginConfig);
15+
16+
// We should not initialize API in static constructor because it will create another API instance
17+
private static IPublicAPI api = null;
18+
private static IPublicAPI API => api ??= Ioc.Default.GetRequiredService<IPublicAPI>();
19+
1420
/// <summary>
1521
/// Parse plugin metadata in the given directories
1622
/// </summary>
@@ -32,7 +38,7 @@ public static List<PluginMetadata> Parse(string[] pluginDirectories)
3238
}
3339
catch (Exception e)
3440
{
35-
Log.Exception($"|PluginConfig.ParsePLuginConfigs|Can't delete <{directory}>", e);
41+
API.LogException(ClassName, $"Can't delete <{directory}>", e);
3642
}
3743
}
3844
else
@@ -49,11 +55,11 @@ public static List<PluginMetadata> Parse(string[] pluginDirectories)
4955

5056
duplicateList
5157
.ForEach(
52-
x => Log.Warn("PluginConfig",
53-
string.Format("Duplicate plugin name: {0}, id: {1}, version: {2} " +
54-
"not loaded due to version not the highest of the duplicates",
55-
x.Name, x.ID, x.Version),
56-
"GetUniqueLatestPluginMetadata"));
58+
x => API.LogWarn(ClassName,
59+
string.Format("Duplicate plugin name: {0}, id: {1}, version: {2} " +
60+
"not loaded due to version not the highest of the duplicates",
61+
x.Name, x.ID, x.Version),
62+
"GetUniqueLatestPluginMetadata"));
5763

5864
return uniqueList;
5965
}
@@ -101,7 +107,7 @@ private static PluginMetadata GetPluginMetadata(string pluginDirectory)
101107
string configPath = Path.Combine(pluginDirectory, Constant.PluginMetadataFileName);
102108
if (!File.Exists(configPath))
103109
{
104-
Log.Error($"|PluginConfig.GetPluginMetadata|Didn't find config file <{configPath}>");
110+
API.LogError(ClassName, $"Didn't find config file <{configPath}>");
105111
return null;
106112
}
107113

@@ -117,19 +123,19 @@ private static PluginMetadata GetPluginMetadata(string pluginDirectory)
117123
}
118124
catch (Exception e)
119125
{
120-
Log.Exception($"|PluginConfig.GetPluginMetadata|invalid json for config <{configPath}>", e);
126+
API.LogException(ClassName, $"Invalid json for config <{configPath}>", e);
121127
return null;
122128
}
123129

124130
if (!AllowedLanguage.IsAllowed(metadata.Language))
125131
{
126-
Log.Error($"|PluginConfig.GetPluginMetadata|Invalid language <{metadata.Language}> for config <{configPath}>");
132+
API.LogError(ClassName, $"Invalid language <{metadata.Language}> for config <{configPath}>");
127133
return null;
128134
}
129135

130136
if (!File.Exists(metadata.ExecuteFilePath))
131137
{
132-
Log.Error($"|PluginConfig.GetPluginMetadata|execute file path didn't exist <{metadata.ExecuteFilePath}> for conifg <{configPath}");
138+
API.LogError(ClassName, $"Execute file path didn't exist <{metadata.ExecuteFilePath}> for conifg <{configPath}");
133139
return null;
134140
}
135141

0 commit comments

Comments
 (0)