using System.Core.Extensions; using System.Extensions; using System.Reflection; using Daybreak.Configuration.Options; using Daybreak.Extensions; using Daybreak.Services.Api; using Daybreak.Services.ApplicationArguments; using Daybreak.Services.ApplicationArguments.ArgumentHandling; using Daybreak.Services.ApplicationLauncher; using Daybreak.Services.BuildTemplates; using Daybreak.Services.Credentials; using Daybreak.Services.DirectSong; using Daybreak.Services.Downloads; using Daybreak.Services.Events; using Daybreak.Services.ExceptionHandling; using Daybreak.Services.ExecutableManagement; using Daybreak.Services.Experience; using Daybreak.Services.FileProviders; using Daybreak.Services.Github; using Daybreak.Services.Graph.Models; using Daybreak.Services.Guildwars; using Daybreak.Services.GuildWars; using Daybreak.Services.Injection; using Daybreak.Services.InternetChecker; using Daybreak.Services.LaunchConfigurations; using Daybreak.Services.Logging; using Daybreak.Services.Metrics; using Daybreak.Services.Mods; using Daybreak.Services.Monitoring; using Daybreak.Services.Notifications; using Daybreak.Services.Notifications.Handlers; using Daybreak.Services.Onboarding; using Daybreak.Services.Options; using Daybreak.Services.Plugins; using Daybreak.Services.Privilege; using Daybreak.Services.ReShade; using Daybreak.Services.Screenshots; using Daybreak.Services.Startup; using Daybreak.Services.Startup.Actions; using Daybreak.Services.TarGz; using Daybreak.Services.Telemetry; using Daybreak.Services.Themes; using Daybreak.Services.Toolbox; using Daybreak.Services.Toolbox.Notifications; using Daybreak.Services.Toolbox.Utilities; using Daybreak.Services.TradeChat; using Daybreak.Services.TradeChat.Models; using Daybreak.Services.TradeChat.Notifications; using Daybreak.Services.UMod; using Daybreak.Services.Updater; using Daybreak.Services.Wiki; using Daybreak.Shared.Models.Plugins; using Daybreak.Shared.Services.Api; using Daybreak.Shared.Services.ApplicationArguments; using Daybreak.Shared.Services.ApplicationLauncher; using Daybreak.Shared.Services.BuildTemplates; using Daybreak.Shared.Services.Credentials; using Daybreak.Shared.Services.DirectSong; using Daybreak.Shared.Services.Downloads; using Daybreak.Shared.Services.Events; using Daybreak.Shared.Services.ExecutableManagement; using Daybreak.Shared.Services.Experience; using Daybreak.Shared.Services.FileProviders; using Daybreak.Shared.Services.Github; using Daybreak.Shared.Services.Guildwars; using Daybreak.Shared.Services.Initialization; using Daybreak.Shared.Services.Injection; using Daybreak.Shared.Services.InternetChecker; using Daybreak.Shared.Services.LaunchConfigurations; using Daybreak.Shared.Services.Menu; using Daybreak.Shared.Services.Metrics; using Daybreak.Shared.Services.Mods; using Daybreak.Shared.Services.Notifications; using Daybreak.Shared.Services.Onboarding; using Daybreak.Shared.Services.Options; using Daybreak.Shared.Services.Plugins; using Daybreak.Shared.Services.Screenshots; using Daybreak.Shared.Services.TarGz; using Daybreak.Shared.Services.Themes; using Daybreak.Shared.Services.Toolbox; using Daybreak.Shared.Services.TradeChat; using Daybreak.Shared.Services.UMod; using Daybreak.Shared.Services.Updater; using Daybreak.Shared.Services.Wiki; using Daybreak.Services.Graph; using Daybreak.Themes; using Daybreak.Views; using Daybreak.Views.Copy; using Daybreak.Views.Installation; using Daybreak.Views.Mods; using Daybreak.Views.Trade; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.FileProviders; using Microsoft.Extensions.Logging; using Microsoft.FluentUI.AspNetCore.Components; using Microsoft.Identity.Client; using OpenTelemetry.Resources; using TrailBlazr.Extensions; using TrailBlazr.Services; using IMenuService = Daybreak.Shared.Services.Menu.IMenuService; using MenuService = Daybreak.Services.Menu.MenuService; using LogLevel = Microsoft.Extensions.Logging.LogLevel; namespace Daybreak.Configuration; public class ProjectConfiguration : PluginConfigurationBase { public static readonly Version CurrentVersion = Version.Parse( Assembly.GetExecutingAssembly().GetName().Version?.ToString() ?? throw new InvalidOperationException("Unable to get current version") ); public override void RegisterServices(IServiceCollection services) { services.ThrowIfNull(); services.AddFluentUIComponents(); services.AddTrailBlazr(); services.AddSingleton(); RegisterHttpClients(services); services.RegisterClientWebSocket>().Build(); services.RegisterClientWebSocket>().Build(); services.AddSingleton(_ => { var resourceBuilder = ResourceBuilder .CreateDefault() .AddService("Daybreak", serviceVersion: CurrentVersion.ToString()); var attributes = new List>(); #if DEBUG attributes.Add(new KeyValuePair("deployment.environment", "debug")); #else attributes.Add( new KeyValuePair("deployment.environment", "production") ); #endif resourceBuilder.AddAttributes(attributes); return resourceBuilder; }); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(sp => sp.GetRequiredService().Cast() ); services.AddSingleton(sp => sp.GetRequiredService().Cast() ); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(sp => sp.GetRequiredService().Cast() ); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(sp => sp.GetRequiredService() ); services.AddSingleton(); // Register MSAL IPublicClientApplication for cross-platform OAuth services.AddSingleton(sp => { var logger = sp.GetRequiredService>(); try { var clientId = SecretManager.GetSecret(SecretKeys.AadApplicationId); if (string.IsNullOrWhiteSpace(clientId)) { logger.LogWarning("AAD Application ID not configured. OneDrive sync will not be available."); return new DummyPublicClientApplication(); } var builder = PublicClientApplicationBuilder.Create(clientId) .WithLogging((logLevel, message, containsPii) => { if (containsPii && logLevel > Microsoft.Identity.Client.LogLevel.Info) { message = "[REDACTED]"; } var equivalentLogLevel = logLevel switch { Microsoft.Identity.Client.LogLevel.Error => LogLevel.Error, Microsoft.Identity.Client.LogLevel.Warning => LogLevel.Warning, Microsoft.Identity.Client.LogLevel.Info => LogLevel.Information, Microsoft.Identity.Client.LogLevel.Verbose => LogLevel.Debug, _ => LogLevel.None }; logger.Log(equivalentLogLevel, message); }, enablePiiLogging: true, enableDefaultPlatformLogging: true) .WithCacheOptions(new CacheOptions { UseSharedCache = true }) .WithRedirectUri(GraphClient.RedirectUri) .WithHttpClientFactory(new DaybreakMsalHttpClientProvider(sp.GetRequiredService>())); return builder.Build(); } catch (Exception e) { logger.LogError(e, "Failed to create PublicClientApplication, using dummy implementation"); return new DummyPublicClientApplication(); } }); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped< ITradeChatService, TradeChatService >(); services.AddScoped< ITradeChatService, TradeChatService >(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddSingleton(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddHostedSingleton(); services.AddHostedSingleton(); services.AddHostedSingleton(); services.AddHostedSingleton(); services.AddHostedSingleton(); services.AddHostedSingleton(); services.AddHostedSingleton(); services.AddHostedSingleton(); services.AddHostedService(); services.AddHostedService(); services.AddHostedService(); } public override void RegisterViews(IViewProducer viewProducer) { viewProducer.ThrowIfNull(); viewProducer.RegisterView(isSingleton: true); viewProducer.RegisterView(); viewProducer.RegisterView(); viewProducer.RegisterView(); viewProducer.RegisterView(); viewProducer.RegisterView(); viewProducer.RegisterView(); viewProducer.RegisterView(); viewProducer.RegisterView(); viewProducer.RegisterView(); viewProducer.RegisterView(); viewProducer.RegisterView(); viewProducer.RegisterView(); viewProducer.RegisterView(); viewProducer.RegisterView(); viewProducer.RegisterView(); viewProducer.RegisterView(); viewProducer.RegisterView(); viewProducer.RegisterView(); viewProducer.RegisterView(); viewProducer.RegisterView(); viewProducer.RegisterView(); viewProducer.RegisterView(); viewProducer.RegisterView(); viewProducer.RegisterView(); viewProducer.RegisterView(); viewProducer.RegisterView(); viewProducer.RegisterView(); viewProducer.RegisterView(); viewProducer.RegisterView(); viewProducer.RegisterView(); viewProducer.RegisterView< ModInstallationConfirmationView, ModInstallationConfirmationViewModel >(); viewProducer.RegisterView(); viewProducer.RegisterView(); viewProducer.RegisterView(); viewProducer.RegisterView(); viewProducer.RegisterView(); viewProducer.RegisterView(); } public override void RegisterStartupActions(IStartupActionProducer startupActionProducer) { startupActionProducer.ThrowIfNull(); startupActionProducer.RegisterAction(); startupActionProducer.RegisterAction(); startupActionProducer.RegisterAction(); startupActionProducer.RegisterAction(); startupActionProducer.RegisterAction(); startupActionProducer.RegisterAction(); startupActionProducer.RegisterAction(); } public override void RegisterPostUpdateActions( IPostUpdateActionProducer postUpdateActionProducer ) { postUpdateActionProducer.ThrowIfNull(); } public override void RegisterOptions(IOptionsProducer optionsProducer) { optionsProducer.ThrowIfNull(); optionsProducer.RegisterOptions(); optionsProducer.RegisterOptions(); optionsProducer.RegisterOptions(); optionsProducer.RegisterOptions(); optionsProducer.RegisterOptions(); optionsProducer.RegisterOptions(); optionsProducer.RegisterOptions(); optionsProducer.RegisterOptions(); optionsProducer.RegisterOptions(); optionsProducer.RegisterOptions(); optionsProducer.RegisterOptions(); optionsProducer.RegisterOptions(); optionsProducer.RegisterOptions(); optionsProducer.RegisterOptions(); optionsProducer.RegisterOptions(); optionsProducer.RegisterOptions(); optionsProducer.RegisterOptions(); optionsProducer.RegisterOptions(); optionsProducer.RegisterOptions(); optionsProducer.RegisterOptions(); optionsProducer.RegisterOptions(); optionsProducer.RegisterOptions(); optionsProducer.RegisterOptions(); optionsProducer.RegisterOptions(); } public override void RegisterNotificationHandlers( INotificationHandlerProducer notificationHandlerProducer ) { notificationHandlerProducer.RegisterNotificationHandler(); notificationHandlerProducer.RegisterNotificationHandler(); notificationHandlerProducer.RegisterNotificationHandler(); notificationHandlerProducer.RegisterNotificationHandler(); notificationHandlerProducer.RegisterNotificationHandler(); notificationHandlerProducer.RegisterNotificationHandler(); notificationHandlerProducer.RegisterNotificationHandler(); notificationHandlerProducer.RegisterNotificationHandler(); } public override void RegisterMods(IModsProducer modsManager) { modsManager.RegisterMod(); modsManager.RegisterMod(); modsManager.RegisterMod(); modsManager.RegisterMod(); modsManager.RegisterMod(singleton: true); } public override void RegisterLaunchArgumentHandlers( IArgumentHandlerProducer argumentHandlerProducer ) { argumentHandlerProducer.ThrowIfNull(); argumentHandlerProducer.RegisterArgumentHandler(); argumentHandlerProducer.RegisterArgumentHandler(); } public override void RegisterMenuButtons(IMenuServiceProducer menuServiceProducer) { menuServiceProducer.ThrowIfNull(); menuServiceProducer .CreateIfNotExistCategory("Guild Wars") .RegisterButton( "Game Companion", "Open game companion", sp => sp.GetRequiredService().ShowView() ) .RegisterButton( "Manage Builds", "Open builds manager", sp => sp.GetRequiredService().ShowView() ) .RegisterButton( "Manage Mods", "Open Guild Wars mods manager", sp => sp.GetRequiredService().ShowView() ) .RegisterButton( "Download Guild Wars", "Download Guild Wars installer", sp => sp.GetRequiredService().ShowView() ) .RegisterButton( "Copy Guild Wars", "Copy Guild Wars from an existing installation", sp => sp.GetRequiredService().ShowView() ); menuServiceProducer .CreateIfNotExistCategory("Daybreak") //TODO: Implement Notifications view //.RegisterButton("Notifications", "Open notifications view", sp => { }) .RegisterButton( "Manage Plugins", "Open plugins view", sp => sp.GetRequiredService().ShowView() ) .RegisterButton( "Manage version", "Open version manager", sp => sp.GetRequiredService().ShowView() ) .RegisterButton( "Help", "Open Daybreak wiki", sp => sp.GetRequiredService() .ShowView((nameof(WikiView.Page), "Home")) ); menuServiceProducer .CreateIfNotExistCategory("Services") .RegisterButton( "Alerts", "Open trade alerts manager", sp => sp.GetRequiredService().ShowView() ) .RegisterButton( "Kamadan", "Open kamadan trade chat", sp => sp.GetRequiredService() .ShowView( (nameof(TradeChatView.Source), nameof(TraderSource.Kamadan)) ) ) .RegisterButton( "Ascalon", "Open ascalon trade chat", sp => sp.GetRequiredService() .ShowView( (nameof(TradeChatView.Source), nameof(TraderSource.Ascalon)) ) ) .RegisterButton( "Guild Wars Party Search", "Show party search broadcasts", sp => sp.GetRequiredService().ShowView() ) .RegisterButton( "Guild Wars Marketplace", "Show guild wars marketplace", sp => sp.GetRequiredService().ShowView() ) .RegisterButton( "Event Calendar", "Show current and upcoming events", sp => sp.GetRequiredService().ShowView() ); menuServiceProducer .CreateIfNotExistCategory("Settings") .RegisterButton( "Accounts", "Accounts Settings", sp => sp.GetRequiredService().ShowView() ) .RegisterButton( "Executables", "Executables Settings", sp => sp.GetRequiredService().ShowView() ) .RegisterButton( "Launch configurations", "Launch configurations settings", sp => sp.GetRequiredService().ShowView() ); menuServiceProducer .CreateIfNotExistCategory("Diagnostics") .RegisterButton( "Telemetry", "Open telemetry view", sp => sp.GetRequiredService().ShowView() ) .RegisterButton( "Logs", "Open logs view", sp => sp.GetRequiredService().ShowView() ); } public override void RegisterThemes(IThemeProducer themeProducer) { themeProducer.ThrowIfNull(); var themes = CoreThemes.Themes.Concat(HeroThemes.Themes).Concat(LiveThemes.Themes); foreach (var theme in themes) { themeProducer.RegisterTheme(theme); } } public override void RegisterProviderAssemblies(IFileProviderProducer fileProviderProducer) { fileProviderProducer.RegisterAssembly(typeof(ProjectConfiguration).Assembly); } private static IServiceCollection RegisterHttpClients(IServiceCollection services) { return services .ThrowIfNull() .RegisterHttpClient() .WithMessageHandler(SetupLoggingAndMetrics) .WithDefaultRequestHeadersSetup(SetupDaybreakUserAgent) .Build() .RegisterHttpClient>() .WithMessageHandler(SetupLoggingAndMetrics>) .WithDefaultRequestHeadersSetup(SetupDaybreakUserAgent) .Build() .RegisterHttpClient>() .WithMessageHandler(SetupLoggingAndMetrics>) .WithDefaultRequestHeadersSetup(SetupDaybreakUserAgent) .Build() .RegisterHttpClient() .WithMessageHandler(SetupLoggingAndMetrics) .WithDefaultRequestHeadersSetup(SetupDaybreakUserAgent) .Build() .RegisterHttpClient() .WithMessageHandler(SetupLoggingAndMetrics) .WithDefaultRequestHeadersSetup(SetupDaybreakUserAgent) .Build() .RegisterHttpClient() .WithMessageHandler(SetupLoggingAndMetrics) .WithDefaultRequestHeadersSetup(SetupDaybreakUserAgent) .Build() .RegisterHttpClient() .WithMessageHandler(SetupLoggingAndMetrics) .WithDefaultRequestHeadersSetup(SetupDaybreakUserAgent) .Build() .RegisterHttpClient() .WithMessageHandler(SetupLoggingAndMetrics) .WithDefaultRequestHeadersSetup(SetupDaybreakUserAgent) .Build() .RegisterHttpClient() .WithMessageHandler(SetupLoggingAndMetrics) .WithDefaultRequestHeadersSetup(SetupDaybreakUserAgent) .Build() .RegisterHttpClient() .WithMessageHandler(SetupLoggingAndMetrics) .WithDefaultRequestHeadersSetup(SetupDaybreakUserAgent) .Build(); } }