Skip to content

Commit

Permalink
Release 0.9.9.7 (#541)
Browse files Browse the repository at this point in the history
* Introduce support for browser extensions

* Setup ublock origin

* Release 0.9.9.7 branch

* Automatically backup settings
Closes #539

* Compare settings with remote
  • Loading branch information
AlexMacocian authored Jan 23, 2024
1 parent c534561 commit 5765c27
Show file tree
Hide file tree
Showing 16 changed files with 419 additions and 79 deletions.
4 changes: 4 additions & 0 deletions Daybreak/Configuration/Options/LauncherOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,8 @@ public sealed class LauncherOptions
[JsonProperty(nameof(BetaUpdate))]
[OptionName(Name = "Beta Update", Description = "If true, the launcher will use the new update procedure")]
public bool BetaUpdate { get; set; } = true;

[JsonProperty(nameof(AutoBackupSettings))]
[OptionName(Name = "Auto Backup Settings", Description = "If true, the launcher will attempt to backup settings periodically")]
public bool AutoBackupSettings { get; set; } = false;
}
26 changes: 20 additions & 6 deletions Daybreak/Configuration/ProjectConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@
using Daybreak.Views.Onboarding.DirectSong;
using Daybreak.Services.SevenZip;
using Daybreak.Services.ReShade.Notifications;
using Daybreak.Services.BrowserExtensions;
using Daybreak.Services.UBlockOrigin;

namespace Daybreak.Configuration;

Expand Down Expand Up @@ -155,6 +157,10 @@ public override void RegisterResolvers(IServiceManager serviceManager)
.RegisterHttpClient<UModService>()
.WithMessageHandler(this.SetupLoggingAndMetrics<UModService>)
.WithDefaultRequestHeadersSetup(this.SetupDaybreakUserAgent)
.Build()
.RegisterHttpClient<UBlockOriginService>()
.WithMessageHandler(this.SetupLoggingAndMetrics<UBlockOriginService>)
.WithDefaultRequestHeadersSetup(this.SetupDaybreakUserAgent)
.Build();
}

Expand Down Expand Up @@ -190,19 +196,19 @@ public override void RegisterServices(IServiceCollection services)
services.AddSingleton<IPostUpdateActionProducer>(sp => sp.GetRequiredService<PostUpdateActionManager>());
services.AddSingleton<IPostUpdateActionProvider>(sp => sp.GetRequiredService<PostUpdateActionManager>());
services.AddSingleton<IMenuService, MenuService>();
services.AddSingleton<IMenuServiceInitializer, MenuService>(sp => sp.GetRequiredService<IMenuService>().As<MenuService>()!);
services.AddSingleton<IMenuServiceInitializer, MenuService>(sp => sp.GetRequiredService<IMenuService>().Cast<MenuService>());
services.AddSingleton<ILiteDatabase, LiteDatabase>(sp => new LiteDatabase("Daybreak.db"));
services.AddSingleton<IMutexHandler, MutexHandler>();
services.AddSingleton<IShortcutManager, ShortcutManager>();
services.AddSingleton<IMetricsService, MetricsService>();
services.AddSingleton<IStartupActionProducer, StartupActionManager>();
services.AddSingleton<IOptionsProducer, OptionsManager>(sp => sp.GetRequiredService<IOptionsManager>().As<OptionsManager>()!);
services.AddSingleton<IOptionsUpdateHook, OptionsManager>(sp => sp.GetRequiredService<IOptionsManager>().As<OptionsManager>()!);
services.AddSingleton<IOptionsProvider, OptionsManager>(sp => sp.GetRequiredService<IOptionsManager>().As<OptionsManager>()!);
services.AddSingleton<IOptionsProducer, OptionsManager>(sp => sp.GetRequiredService<IOptionsManager>().Cast<OptionsManager>());
services.AddSingleton<IOptionsUpdateHook, OptionsManager>(sp => sp.GetRequiredService<IOptionsManager>().Cast<OptionsManager>());
services.AddSingleton<IOptionsProvider, OptionsManager>(sp => sp.GetRequiredService<IOptionsManager>().Cast<OptionsManager>());
services.AddSingleton<IThemeManager, ThemeManager>();
services.AddSingleton<INotificationService, NotificationService>();
services.AddSingleton<INotificationProducer, NotificationService>(sp => sp.GetRequiredService<INotificationService>().As<NotificationService>()!);
services.AddSingleton<INotificationHandlerProducer, NotificationService>(sp => sp.GetRequiredService<INotificationService>().As<NotificationService>()!);
services.AddSingleton<INotificationProducer, NotificationService>(sp => sp.GetRequiredService<INotificationService>().Cast<NotificationService>());
services.AddSingleton<INotificationHandlerProducer, NotificationService>(sp => sp.GetRequiredService<INotificationService>().Cast<NotificationService>());
services.AddSingleton<ILiveChartInitializer, LiveChartInitializer>();
services.AddSingleton<IImageCache, ImageCache>();
services.AddSingleton<ISoundService, SoundService>();
Expand All @@ -220,6 +226,8 @@ public override void RegisterServices(IServiceCollection services)
services.AddSingleton<ISevenZipExtractor, SevenZipExtractor>();
services.AddSingleton<IGraphClient, GraphClient>();
services.AddSingleton<IOptionsSynchronizationService, OptionsSynchronizationService>();
services.AddScoped<IBrowserExtensionsManager, BrowserExtensionsManager>();
services.AddScoped<IBrowserExtensionsProducer, BrowserExtensionsManager>(sp => sp.GetRequiredService<IBrowserExtensionsManager>().Cast<BrowserExtensionsManager>());
services.AddScoped<ICredentialManager, CredentialManager>();
services.AddScoped<IApplicationLauncher, ApplicationLauncher>();
services.AddScoped<IScreenshotProvider, ScreenshotProvider>();
Expand Down Expand Up @@ -446,6 +454,12 @@ public override void RegisterMods(IModsManager modsManager)
modsManager.RegisterMod<IDirectSongService, DirectSongService>(singleton: true);
}

public override void RegisterBrowserExtensions(IBrowserExtensionsProducer browserExtensionsProducer)
{
browserExtensionsProducer.ThrowIfNull();
browserExtensionsProducer.RegisterExtension<UBlockOriginService>();
}

private void RegisterLiteCollections(IServiceCollection services)
{
this.RegisterLiteCollection<Models.Log, LoggingOptions>(services);
Expand Down
62 changes: 34 additions & 28 deletions Daybreak/Controls/ChromiumBrowserWrapper.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using Daybreak.Models;
using Daybreak.Models.Browser;
using Daybreak.Models.Guildwars;
using Daybreak.Services.BrowserExtensions;
using Daybreak.Services.BuildTemplates;
using Daybreak.Utils;
using Microsoft.Extensions.DependencyInjection;
Expand Down Expand Up @@ -40,9 +41,9 @@ public partial class ChromiumBrowserWrapper : UserControl
private const string BrowserDownloadLink = "https://developer.microsoft.com/en-us/microsoft-edge/webview2/";

private static readonly Regex WebAddressRegex = new("^((http|ftp|https)://)?([\\w_-]+(?:(?:\\.[\\w_-]+)+))([\\w.,@?^=%&:/~+#-]*[\\w@?^=%&/~+#-])?", RegexOptions.Compiled);
private static readonly object Lock = new();
private static readonly SemaphoreSlim SemaphoreSlim = new(1, 1);

private static CoreWebView2Environment? CoreWebView2Environment;
private static CoreWebView2Environment? CoreWebView2Environment;

public event EventHandler<string>? FavoriteUriChanged;
public event EventHandler? MaximizeClicked;
Expand All @@ -55,7 +56,8 @@ public partial class ChromiumBrowserWrapper : UserControl
private readonly ILiveOptions<BrowserOptions> liveOptions;
private readonly ILogger<ChromiumBrowserWrapper> logger;
private readonly IBuildTemplateManager buildTemplateManager;

private readonly IBrowserExtensionsManager browserExtensionsManager;

[GenerateDependencyProperty(InitialValue = true)]
private bool canDownloadBuild;
[GenerateDependencyProperty(InitialValue = true)]
Expand Down Expand Up @@ -96,24 +98,27 @@ public string Address
}

public ChromiumBrowserWrapper()
: this(Launch.Launcher.Instance.ApplicationServiceProvider.GetRequiredService<IHttpClient<ChromiumBrowserWrapper>>(),
: this(
Launch.Launcher.Instance.ApplicationServiceProvider.GetRequiredService<IBrowserExtensionsManager>(),
Launch.Launcher.Instance.ApplicationServiceProvider.GetRequiredService<IHttpClient<ChromiumBrowserWrapper>>(),
Launch.Launcher.Instance.ApplicationServiceProvider.GetRequiredService<ILiveOptions<BrowserOptions>>(),
Launch.Launcher.Instance.ApplicationServiceProvider.GetRequiredService<IBuildTemplateManager>(),
Launch.Launcher.Instance.ApplicationServiceProvider.GetRequiredService<ILogger<ChromiumBrowserWrapper>>())
{
}

public ChromiumBrowserWrapper(
IBrowserExtensionsManager browserExtensionsManager,
IHttpClient<ChromiumBrowserWrapper> httpClient,
ILiveOptions<BrowserOptions> liveOptions,
IBuildTemplateManager buildTemplateManager,
ILogger<ChromiumBrowserWrapper> logger)
{
this.browserExtensionsManager = browserExtensionsManager.ThrowIfNull();
this.httpClient = httpClient.ThrowIfNull();
this.liveOptions = liveOptions.ThrowIfNull();
this.buildTemplateManager = buildTemplateManager.ThrowIfNull();
this.logger = logger.ThrowIfNull();
this.InitializeEnvironment();
this.InitializeComponent();

this.initializationTask = Task.Run(this.InitializeBrowserSafe);
Expand Down Expand Up @@ -149,24 +154,22 @@ private void InitializeEnvironment()
{
try
{
lock (Lock)
if (CoreWebView2Environment is not null)
{
if (CoreWebView2Environment is not null)
{
this.BrowserSupported = true;
return;
}

CoreWebView2Environment ??= System.Extensions.TaskExtensions.RunSync(() => CoreWebView2Environment.CreateAsync(null, "BrowserData", new CoreWebView2EnvironmentOptions
{
EnableTrackingPrevention = true,
AllowSingleSignOnUsingOSPrimaryAccount = true
}));

this.BrowserSupported = true;
return;
}

CoreWebView2Environment ??= System.Extensions.TaskExtensions.RunSync(() => CoreWebView2Environment.CreateAsync(null, "BrowserData", new CoreWebView2EnvironmentOptions
{
EnableTrackingPrevention = true,
AllowSingleSignOnUsingOSPrimaryAccount = true,
AreBrowserExtensionsEnabled = true,
}));

this.BrowserSupported = true;
}
catch(Exception e)
catch (Exception e)
{
this.logger!.LogWarning($"Browser initialization failed. Details: {e}");
this.BrowserSupported = false;
Expand All @@ -177,10 +180,7 @@ private async Task InitializeBrowserSafe()
{
await this.Dispatcher.InvokeAsync(async () =>
{
while (!Monitor.TryEnter(Lock))
{
await Task.Delay(100);
}
await SemaphoreSlim.WaitAsync();
try
{
Expand All @@ -189,7 +189,7 @@ await this.Dispatcher.InvokeAsync(async () =>
}
finally
{
Monitor.Exit(Lock);
SemaphoreSlim.Release();
}
});
}
Expand All @@ -201,12 +201,18 @@ private async Task InitializeBrowser()
if (!this.BrowserSupported ||
!this.BrowserEnabled)
{


return;
}

if (this.WebBrowser.CoreWebView2 is not null)
{
return;
}

this.ShowBrowserDisabledMessage = false;
await this.WebBrowser.EnsureCoreWebView2Async(CoreWebView2Environment);
await this.WebBrowser.EnsureCoreWebView2Async(CoreWebView2Environment).ConfigureAwait(true);
await this.browserExtensionsManager.InitializeBrowserEnvironment(this.WebBrowser.CoreWebView2!.Profile, CoreWebView2Environment!.BrowserVersionString).ConfigureAwait(true);
if (this.Address is not null &&
Uri.TryCreate(this.Address, UriKind.RelativeOrAbsolute, out var uri))
{
Expand Down Expand Up @@ -376,7 +382,7 @@ private void CoreWebView2_WebMessageReceived(object sender, CoreWebView2WebMessa
{
payload = args.WebMessageAsJson.Deserialize<BrowserPayload>();
}
catch(Exception e)
catch (Exception e)
{
this.logger!.LogError(e, $"Exception encountered when deserializing {nameof(BrowserPayload)}");
}
Expand Down Expand Up @@ -411,7 +417,7 @@ private void CoreWebView2_WebMessageReceived(object sender, CoreWebView2WebMessa
this.ContextMenu.IsOpen = true;
});
}
catch(Exception e)
catch (Exception e)
{
this.logger!.LogWarning($"Exception when decoding template {maybeTemplate}. Details {e}");
}
Expand Down
2 changes: 1 addition & 1 deletion Daybreak/Daybreak.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<LangVersion>preview</LangVersion>
<ApplicationIcon>Daybreak.ico</ApplicationIcon>
<IncludePackageReferencesDuringMarkupCompilation>true</IncludePackageReferencesDuringMarkupCompilation>
<Version>0.9.9.6</Version>
<Version>0.9.9.7</Version>
<EnableWindowsTargeting>true</EnableWindowsTargeting>
<UserSecretsId>cfb2a489-db80-448d-a969-80270f314c46</UserSecretsId>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
Expand Down
7 changes: 6 additions & 1 deletion Daybreak/Launch/Launcher.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Daybreak.Configuration;
using Daybreak.Models.Progress;
using Daybreak.Services.BrowserExtensions;
using Daybreak.Services.Drawing;
using Daybreak.Services.ExceptionHandling;
using Daybreak.Services.Mods;
Expand Down Expand Up @@ -95,6 +96,7 @@ protected override void ApplicationStarting()
var drawingModuleProducer = this.ServiceProvider.GetRequiredService<IDrawingModuleProducer>();
var notificationHandlerProducer = this.ServiceProvider.GetRequiredService<INotificationHandlerProducer>();
var modsManager = this.ServiceProvider.GetRequiredService<IModsManager>();
var browserExtensionsProducer = this.ServiceProvider.GetRequiredService<IBrowserExtensionsProducer>();

startupStatus.CurrentStep = StartupStatus.Custom("Loading views");
this.projectConfiguration.RegisterViews(viewProducer);
Expand All @@ -108,6 +110,8 @@ protected override void ApplicationStarting()
this.projectConfiguration.RegisterNotificationHandlers(notificationHandlerProducer);
startupStatus.CurrentStep = StartupStatus.Custom("Loading mods");
this.projectConfiguration.RegisterMods(modsManager);
startupStatus.CurrentStep = StartupStatus.Custom("Loading browser extensions");
this.projectConfiguration.RegisterBrowserExtensions(browserExtensionsProducer);

this.logger = this.ServiceProvider.GetRequiredService<ILogger<Launcher>>();
this.exceptionHandler = this.ServiceProvider.GetRequiredService<IExceptionHandler>();
Expand All @@ -123,7 +127,8 @@ protected override void ApplicationStarting()
startupActionProducer,
drawingModuleProducer,
notificationHandlerProducer,
modsManager);
modsManager,
browserExtensionsProducer);
}
catch(Exception e)
{
Expand Down
2 changes: 1 addition & 1 deletion Daybreak/Launch/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -112,9 +112,9 @@ protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)

private void Window_Loaded(object sender, RoutedEventArgs e)
{
this.splashScreenService.HideSplashScreen();
this.SetupImageCycle();
this.viewManager.ShowView<LauncherView>();
this.splashScreenService.HideSplashScreen();
}

private void SynchronizeButton_Click(object sender, EventArgs e)
Expand Down
2 changes: 2 additions & 0 deletions Daybreak/Models/Plugins/PluginConfigurationBase.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Daybreak.Configuration.Options;
using Daybreak.Services.BrowserExtensions;
using Daybreak.Services.Drawing;
using Daybreak.Services.Metrics;
using Daybreak.Services.Mods;
Expand Down Expand Up @@ -34,6 +35,7 @@ public virtual void RegisterDrawingModules(IDrawingModuleProducer drawingModuleP
public virtual void RegisterOptions(IOptionsProducer optionsProducer) { }
public virtual void RegisterNotificationHandlers(INotificationHandlerProducer notificationHandlerProducer) { }
public virtual void RegisterMods(IModsManager modsManager) { }
public virtual void RegisterBrowserExtensions(IBrowserExtensionsProducer browserExtensionsProducer) { }

public PluginConfigurationBase()
{
Expand Down
49 changes: 49 additions & 0 deletions Daybreak/Services/BrowserExtensions/BrowserExtensionsManager.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
using Microsoft.Web.WebView2.Core;
using Slim;
using System.Core.Extensions;
using System.Extensions;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace Daybreak.Services.BrowserExtensions;

public sealed class BrowserExtensionsManager : IBrowserExtensionsManager, IBrowserExtensionsProducer
{
private readonly IServiceManager serviceManager;

public BrowserExtensionsManager(
IServiceManager serviceManager)
{
this.serviceManager = serviceManager.ThrowIfNull();
}

public void RegisterExtension<T>()
where T : class, IBrowserExtension
{
this.serviceManager.RegisterScoped<T, T>();
}

public async Task InitializeBrowserEnvironment(CoreWebView2Profile coreWebView2Profile, string browserVersion)
{
var existingExtensions = await coreWebView2Profile.GetBrowserExtensionsAsync();
foreach (var extension in this.serviceManager.GetServicesOfType<IBrowserExtension>()
.Where(e => existingExtensions.None(ee => ee.Id == e.ExtensionId)))
{
await extension.CheckAndUpdate(browserVersion);
var extensionPath = await extension.GetExtensionPath();
if (!Directory.Exists(extensionPath))
{
continue;
}

if (!File.Exists(Path.Combine(extensionPath, "manifest.json")))
{
continue;
}

await coreWebView2Profile.AddBrowserExtensionAsync(extensionPath);
}
}
}
10 changes: 10 additions & 0 deletions Daybreak/Services/BrowserExtensions/IBrowserExtension.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using System.Threading.Tasks;

namespace Daybreak.Services.BrowserExtensions;

public interface IBrowserExtension
{
string ExtensionId { get; }
Task CheckAndUpdate(string browserVersion);
Task<string> GetExtensionPath();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using Microsoft.Web.WebView2.Core;
using System.Threading.Tasks;

namespace Daybreak.Services.BrowserExtensions;

public interface IBrowserExtensionsManager
{
Task InitializeBrowserEnvironment(CoreWebView2Profile coreWebView2Profile, string browserVersion);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace Daybreak.Services.BrowserExtensions;
public interface IBrowserExtensionsProducer
{
void RegisterExtension<T>()
where T : class, IBrowserExtension;
}
2 changes: 1 addition & 1 deletion Daybreak/Services/Downloads/DownloadService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public async Task<bool> DownloadFile(string downloadUri, string destinationPath,
var fileInfo = new FileInfo(destinationPath);
fileInfo.Directory?.Create();
var fileStream = File.Open(destinationPath, FileMode.Create, FileAccess.Write);
var downloadSize = (double)response.Content!.Headers!.ContentLength!;
var downloadSize = response.Content?.Headers?.ContentLength ?? double.MaxValue;
var buffer = new byte[1024];
var length = 0;
var downloaded = 0d;
Expand Down
Loading

0 comments on commit 5765c27

Please sign in to comment.