From f303ec8a0ea7b5baa825be46292fc02714e6c555 Mon Sep 17 00:00:00 2001 From: jvyden Date: Tue, 22 Jul 2025 00:01:07 -0400 Subject: [PATCH 1/3] Move config loading to ConfigStore --- Refresh.Core/Configuration/ConfigStore.cs | 55 +++++++++++++ .../DryArchiveConfig.cs | 2 +- Refresh.Core/Storage/DryDataStore.cs | 1 + Refresh.GameServer/RefreshGameServer.cs | 79 ++++++------------- .../GameServer/TestRefreshGameServer.cs | 9 +-- 5 files changed, 86 insertions(+), 60 deletions(-) create mode 100644 Refresh.Core/Configuration/ConfigStore.cs rename Refresh.Core/{Storage => Configuration}/DryArchiveConfig.cs (93%) diff --git a/Refresh.Core/Configuration/ConfigStore.cs b/Refresh.Core/Configuration/ConfigStore.cs new file mode 100644 index 000000000..568a46e7f --- /dev/null +++ b/Refresh.Core/Configuration/ConfigStore.cs @@ -0,0 +1,55 @@ +using Bunkum.Core; +using Bunkum.Core.Configuration; +using NotEnoughLogs; + +namespace Refresh.Core.Configuration; + +public class ConfigStore +{ + public GameServerConfig GameServer { get; } + public DatabaseConfig DatabaseConfig { get; } + + public ContactInfoConfig ContactInfo { get; } + public IntegrationConfig Integration { get; } + public RichPresenceConfig RichPresence { get; } + + public DryArchiveConfig DryArchive { get; } + + private static readonly Lock ConfigLock = new(); + public ConfigStore(Logger logger) + { + lock (ConfigLock) + { + this.GameServer = Config.LoadFromJsonFile("refreshGameServer.json", logger); + this.DatabaseConfig = Config.LoadFromJsonFile("db.json", logger); + + this.ContactInfo = Config.LoadFromJsonFile("contactInfo.json", logger); + this.Integration = Config.LoadFromJsonFile("integrations.json", logger); + this.RichPresence = Config.LoadFromJsonFile("rpc.json", logger); + + this.DryArchive = Config.LoadFromJsonFile("dry.json", logger); + } + } + + public ConfigStore() + { + this.GameServer = new GameServerConfig(); + this.DatabaseConfig = new DatabaseConfig(); + + this.ContactInfo = new ContactInfoConfig(); + this.Integration = new IntegrationConfig(); + this.RichPresence = new RichPresenceConfig(); + + this.DryArchive = new DryArchiveConfig(); + } + + public void AddToBunkum(BunkumServer server) + { + server.AddConfig(this.GameServer); + server.AddConfig(this.DatabaseConfig); + server.AddConfig(this.ContactInfo); + server.AddConfig(this.Integration); + server.AddConfig(this.RichPresence); + server.AddConfig(this.DryArchive); + } +} \ No newline at end of file diff --git a/Refresh.Core/Storage/DryArchiveConfig.cs b/Refresh.Core/Configuration/DryArchiveConfig.cs similarity index 93% rename from Refresh.Core/Storage/DryArchiveConfig.cs rename to Refresh.Core/Configuration/DryArchiveConfig.cs index c79fbe801..8dd7f3550 100644 --- a/Refresh.Core/Storage/DryArchiveConfig.cs +++ b/Refresh.Core/Configuration/DryArchiveConfig.cs @@ -1,6 +1,6 @@ using Bunkum.Core.Configuration; -namespace Refresh.Core.Storage; +namespace Refresh.Core.Configuration; public class DryArchiveConfig : Config { diff --git a/Refresh.Core/Storage/DryDataStore.cs b/Refresh.Core/Storage/DryDataStore.cs index 9c00cb1a4..5b3ea1585 100644 --- a/Refresh.Core/Storage/DryDataStore.cs +++ b/Refresh.Core/Storage/DryDataStore.cs @@ -3,6 +3,7 @@ using Bunkum.Core.Storage; using JetBrains.Annotations; using Refresh.Common.Verification; +using Refresh.Core.Configuration; using Refresh.Core.Metrics; namespace Refresh.Core.Storage; diff --git a/Refresh.GameServer/RefreshGameServer.cs b/Refresh.GameServer/RefreshGameServer.cs index 3af37fba7..c8492958f 100644 --- a/Refresh.GameServer/RefreshGameServer.cs +++ b/Refresh.GameServer/RefreshGameServer.cs @@ -43,11 +43,7 @@ public class RefreshGameServer : RefreshServer protected readonly GameDatabaseProvider _databaseProvider; protected readonly IDataStore _dataStore; - protected MatchService _matchService = null!; - protected GuidCheckerService _guidCheckerService = null!; - - protected GameServerConfig? _config; - protected IntegrationConfig? _integrationConfig; + protected readonly ConfigStore _configStore; public RefreshGameServer( BunkumHttpListener? listener = null, @@ -59,34 +55,21 @@ public RefreshGameServer( dataStore ??= new FileSystemDataStore(); List dataStores = []; - DryArchiveConfig? dryConfig = null; try { - dryConfig = Config.LoadFromJsonFile("dry.json", this.Logger); - if (dryConfig.Enabled) - dataStores.Add(new DownloadingDataStore(dataStore, new DryDataStore(dryConfig))); + this._configStore = new ConfigStore(this.Logger); } catch (Exception ex) { - this.Logger.LogWarning(BunkumCategory.Configuration, "Failed to read dry.json: " + ex); + this.Logger.LogCritical(RefreshContext.Database, "Failed to read the configuration files: " + ex); + this.Logger.Dispose(); + Environment.Exit(1); } + + if (this._configStore.DryArchive.Enabled) + dataStores.Add(new DownloadingDataStore(dataStore, new DryDataStore(this._configStore.DryArchive))); - if (databaseProvider == null) - { - DatabaseConfig? dbConfig = null; - try - { - dbConfig = Config.LoadFromJsonFile("db.json", this.Logger); - } - catch (Exception ex) - { - this.Logger.LogCritical(RefreshContext.Database, "Failed to read the database configuration file: " + ex); - this.Logger.Dispose(); - Environment.Exit(1); - } - - databaseProvider = () => new GameDatabaseProvider(this.Logger, dbConfig); - } + databaseProvider ??= () => new GameDatabaseProvider(this.Logger, this._configStore.DatabaseConfig); this._databaseProvider = databaseProvider.Invoke(); this._databaseProvider.Initialize(); @@ -94,7 +77,7 @@ public RefreshGameServer( // Uncomment if you want to use production refresh as a source for assets // TODO: remove config option when test.lbpbonsai.com instance no longer needs prod assets #if DEBUG - if (dryConfig?.TemporaryWillBeRemoved_UseProductionRefreshData ?? false) + if (this._configStore.DryArchive?.TemporaryWillBeRemoved_UseProductionRefreshData ?? false) dataStores.Add(new DownloadingDataStore(dataStore, new RemoteRefreshDataStore())); #endif @@ -110,7 +93,7 @@ public RefreshGameServer( this.WorkerManager?.Stop(); - authProvider ??= new GameAuthenticationProvider(this._config!); + authProvider ??= new GameAuthenticationProvider(this._configStore.GameServer); this.InjectBaseServices(provider, authProvider, this._dataStore); }); @@ -135,28 +118,19 @@ protected override void Initialize() protected override void SetupMiddlewares() { this.Server.AddMiddleware(); - this.Server.AddMiddleware(new DeflateMiddleware(this._config!)); + this.Server.AddMiddleware(new DeflateMiddleware(this._configStore.GameServer)); this.Server.AddMiddleware(); // Digest middleware must be run before LegacyAdapterMiddleware, because digest is based on the raw route, not the fixed route - this.Server.AddMiddleware(new DigestMiddleware(this._config!)); + this.Server.AddMiddleware(new DigestMiddleware(this._configStore.GameServer)); this.Server.AddMiddleware(); this.Server.AddMiddleware(); - this.Server.AddMiddleware(new PresenceAuthenticationMiddleware(this._integrationConfig!)); + this.Server.AddMiddleware(new PresenceAuthenticationMiddleware(this._configStore.Integration!)); this.Server.AddMiddleware(); } protected override void SetupConfiguration() { - GameServerConfig config = Config.LoadFromJsonFile("refreshGameServer.json", this.Server.Logger); - this._config = config; - - IntegrationConfig integrationConfig = Config.LoadFromJsonFile("integrations.json", this.Server.Logger); - this._integrationConfig = integrationConfig; - - this.Server.AddConfig(config); - this.Server.AddConfig(integrationConfig); - this.Server.AddConfigFromJsonFile("rpc.json"); - this.Server.AddConfigFromJsonFile("contactInfo.json"); + this._configStore.AddToBunkum(this.Server); } protected override void SetupServices() @@ -164,22 +138,21 @@ protected override void SetupServices() this.Server.AddService(this.GetTimeProvider()); this.Server.AddRateLimitService(new RateLimitSettings(60, 400, 30, "global")); this.Server.AddService(); - this.Server.AddService(this._matchService = new MatchService(this.Server.Logger, this._config!)); + this.Server.AddService(new MatchService(this.Server.Logger, this._configStore.GameServer)); this.Server.AddService(); this.Server.AddService(); - this.Server.AddService(this._guidCheckerService = new GuidCheckerService(this._config!, this.Server.Logger)); - this.Server.AddAutoDiscover(serverBrand: $"{this._config!.InstanceName} (Refresh)", - baseEndpoint: GameEndpointAttribute.BaseRoute.Substring(0, GameEndpointAttribute.BaseRoute.Length - 1), + this.Server.AddService(new GuidCheckerService(this._configStore.GameServer, this.Server.Logger)); + this.Server.AddAutoDiscover(serverBrand: $"{this._configStore.GameServer.InstanceName} (Refresh)", + baseEndpoint: GameEndpointAttribute.BaseRoute[..^1], usesCustomDigestKey: true, - serverDescription: this._config.InstanceDescription, + serverDescription: this._configStore.GameServer.InstanceDescription, bannerImageUrl: "https://github.com/LittleBigRefresh/Branding/blob/main/logos/refresh_type.png?raw=true"); #pragma warning disable CA1825 #pragma warning disable CA1861 - this.Server.AddHealthCheckService(this._databaseProvider, new Type[] - { + this.Server.AddHealthCheckService(this._databaseProvider, [ // TODO: add postgres health check - }); + ]); #pragma warning restore CA1861 #pragma warning restore CA1825 @@ -191,7 +164,7 @@ protected override void SetupServices() this.Server.AddService(); this.Server.AddService(); - if(this._integrationConfig!.AipiEnabled) + if(this._configStore.Integration!.AipiEnabled) this.Server.AddService(); #if DEBUG @@ -208,9 +181,9 @@ protected virtual void SetupWorkers() { this.WorkerManager = RefreshWorkerManager.Create(this.Logger, this._dataStore, this._databaseProvider); - if ((this._integrationConfig?.DiscordWebhookEnabled ?? false) && this._config != null && this._config.PermitShowingOnlineUsers) + if (this._configStore.Integration.DiscordWebhookEnabled && this._configStore.GameServer.PermitShowingOnlineUsers) { - this.WorkerManager.AddJob(new DiscordIntegrationJob(this._integrationConfig, this._config)); + this.WorkerManager.AddJob(new DiscordIntegrationJob(this._configStore.Integration, this._configStore.GameServer)); } } @@ -220,7 +193,7 @@ public override void Start() this.Server.Start(); this.WorkerManager?.Start(); - if (this._config!.MaintenanceMode) + if (this._configStore.GameServer.MaintenanceMode) { this.Logger.LogWarning(RefreshContext.Startup, "The server is currently in maintenance mode! " + "Only administrators will be able to log in and interact with the server."); diff --git a/RefreshTests.GameServer/GameServer/TestRefreshGameServer.cs b/RefreshTests.GameServer/GameServer/TestRefreshGameServer.cs index 0fa4a5573..f3b5e6154 100644 --- a/RefreshTests.GameServer/GameServer/TestRefreshGameServer.cs +++ b/RefreshTests.GameServer/GameServer/TestRefreshGameServer.cs @@ -26,13 +26,10 @@ public class TestRefreshGameServer : RefreshGameServer protected override void SetupConfiguration() { - this.Server.AddConfig(this._config = new GameServerConfig()); - this.Server.AddConfig(new RichPresenceConfig()); - this.Server.AddConfig(this._integrationConfig = new IntegrationConfig()); - this.Server.AddConfig(new ContactInfoConfig()); + new ConfigStore().AddToBunkum(this.Server); } - public GameServerConfig GameServerConfig => this._config!; + public GameServerConfig GameServerConfig => this._configStore.GameServer; public override void Start() { @@ -71,7 +68,7 @@ protected override void SetupServices() this.Server.AddService(); this.Server.AddService(); this.Server.AddService(); - this.Server.AddService(new PresenceService(this.Logger, this._integrationConfig!)); + this.Server.AddService(new PresenceService(this.Logger, this._configStore.Integration!)); this.Server.AddService(); this.Server.AddService(); this.Server.AddService(); From 1af94e825745bf733b0376f108388abbab30fb9b Mon Sep 17 00:00:00 2001 From: jvyden Date: Tue, 22 Jul 2025 00:09:14 -0400 Subject: [PATCH 2/3] Make Refresh.WorkerManager use ConfigStore --- Refresh.Core/Configuration/ConfigStore.cs | 8 ++++---- Refresh.GameServer/RefreshGameServer.cs | 2 +- Refresh.WorkerManager/Program.cs | 6 +++++- Refresh.Workers/WorkerManager.cs | 2 +- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/Refresh.Core/Configuration/ConfigStore.cs b/Refresh.Core/Configuration/ConfigStore.cs index 568a46e7f..82c65e5f2 100644 --- a/Refresh.Core/Configuration/ConfigStore.cs +++ b/Refresh.Core/Configuration/ConfigStore.cs @@ -7,7 +7,7 @@ namespace Refresh.Core.Configuration; public class ConfigStore { public GameServerConfig GameServer { get; } - public DatabaseConfig DatabaseConfig { get; } + public DatabaseConfig Database { get; } public ContactInfoConfig ContactInfo { get; } public IntegrationConfig Integration { get; } @@ -21,7 +21,7 @@ public ConfigStore(Logger logger) lock (ConfigLock) { this.GameServer = Config.LoadFromJsonFile("refreshGameServer.json", logger); - this.DatabaseConfig = Config.LoadFromJsonFile("db.json", logger); + this.Database = Config.LoadFromJsonFile("db.json", logger); this.ContactInfo = Config.LoadFromJsonFile("contactInfo.json", logger); this.Integration = Config.LoadFromJsonFile("integrations.json", logger); @@ -34,7 +34,7 @@ public ConfigStore(Logger logger) public ConfigStore() { this.GameServer = new GameServerConfig(); - this.DatabaseConfig = new DatabaseConfig(); + this.Database = new DatabaseConfig(); this.ContactInfo = new ContactInfoConfig(); this.Integration = new IntegrationConfig(); @@ -46,7 +46,7 @@ public ConfigStore() public void AddToBunkum(BunkumServer server) { server.AddConfig(this.GameServer); - server.AddConfig(this.DatabaseConfig); + server.AddConfig(this.Database); server.AddConfig(this.ContactInfo); server.AddConfig(this.Integration); server.AddConfig(this.RichPresence); diff --git a/Refresh.GameServer/RefreshGameServer.cs b/Refresh.GameServer/RefreshGameServer.cs index c8492958f..9ab5dbca9 100644 --- a/Refresh.GameServer/RefreshGameServer.cs +++ b/Refresh.GameServer/RefreshGameServer.cs @@ -69,7 +69,7 @@ public RefreshGameServer( if (this._configStore.DryArchive.Enabled) dataStores.Add(new DownloadingDataStore(dataStore, new DryDataStore(this._configStore.DryArchive))); - databaseProvider ??= () => new GameDatabaseProvider(this.Logger, this._configStore.DatabaseConfig); + databaseProvider ??= () => new GameDatabaseProvider(this.Logger, this._configStore.Database); this._databaseProvider = databaseProvider.Invoke(); this._databaseProvider.Initialize(); diff --git a/Refresh.WorkerManager/Program.cs b/Refresh.WorkerManager/Program.cs index bcf158956..c458fa38c 100644 --- a/Refresh.WorkerManager/Program.cs +++ b/Refresh.WorkerManager/Program.cs @@ -2,6 +2,7 @@ using Bunkum.Core.Storage; using NotEnoughLogs; using NotEnoughLogs.Behaviour; +using Refresh.Core.Configuration; using Refresh.Database; using Refresh.Database.Configuration; using Refresh.Interfaces.Workers; @@ -22,8 +23,11 @@ logger.LogInfo(BunkumCategory.Startup, "Starting up worker manager..."); logger.LogCritical(BunkumCategory.Startup, "The dedicated worker manager isn't complete yet! It will work in a debug setting, but do not use this in production yet."); -using GameDatabaseProvider database = new(logger, new EmptyDatabaseConfig()); +logger.LogInfo(BunkumCategory.Startup, "Initializing configs..."); +ConfigStore configStore = new(logger); + logger.LogInfo(BunkumCategory.Startup, "Initializing database..."); +using GameDatabaseProvider database = new(logger, configStore.Database); database.Initialize(); logger.LogInfo(BunkumCategory.Startup, "Warming up database..."); database.Warmup(); diff --git a/Refresh.Workers/WorkerManager.cs b/Refresh.Workers/WorkerManager.cs index 5e79d614a..cfcab9a8c 100644 --- a/Refresh.Workers/WorkerManager.cs +++ b/Refresh.Workers/WorkerManager.cs @@ -54,7 +54,7 @@ private void RunWorkCycle() if (!job.CanExecute()) continue; - this._logger.LogDebug(RefreshContext.Worker, $"Running work cycle for {job.GetType().Name}"); + this._logger.LogTrace(RefreshContext.Worker, $"Running work cycle for {job.GetType().Name}"); try { job.ExecuteJob(context); From a442eae7a2ef7049b4572554a071c6249db17526 Mon Sep 17 00:00:00 2001 From: jvyden Date: Tue, 22 Jul 2025 00:15:08 -0400 Subject: [PATCH 3/3] Fix ConfigStore in tests --- Refresh.GameServer/RefreshGameServer.cs | 8 +++++++- .../GameServer/TestRefreshGameServer.cs | 4 ++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/Refresh.GameServer/RefreshGameServer.cs b/Refresh.GameServer/RefreshGameServer.cs index 9ab5dbca9..8f6fba5be 100644 --- a/Refresh.GameServer/RefreshGameServer.cs +++ b/Refresh.GameServer/RefreshGameServer.cs @@ -57,7 +57,8 @@ public RefreshGameServer( try { - this._configStore = new ConfigStore(this.Logger); + // ReSharper disable once VirtualMemberCallInConstructor (you can't stop me) + this._configStore = this.CreateConfigStore(); } catch (Exception ex) { @@ -99,6 +100,11 @@ public RefreshGameServer( }); } + protected virtual ConfigStore CreateConfigStore() + { + return new ConfigStore(this.Logger); + } + private void InjectBaseServices(GameDatabaseProvider databaseProvider, IAuthenticationProvider authProvider, IDataStore dataStore) { this.Server.UseDatabaseProvider(databaseProvider); diff --git a/RefreshTests.GameServer/GameServer/TestRefreshGameServer.cs b/RefreshTests.GameServer/GameServer/TestRefreshGameServer.cs index f3b5e6154..824e93ab8 100644 --- a/RefreshTests.GameServer/GameServer/TestRefreshGameServer.cs +++ b/RefreshTests.GameServer/GameServer/TestRefreshGameServer.cs @@ -24,9 +24,9 @@ public class TestRefreshGameServer : RefreshGameServer public TestRefreshGameServer(BunkumHttpListener listener, Func provider, IDataStore? dataStore = null) : base(listener, provider, null, dataStore ?? new InMemoryDataStore()) {} - protected override void SetupConfiguration() + protected override ConfigStore CreateConfigStore() { - new ConfigStore().AddToBunkum(this.Server); + return new ConfigStore(); } public GameServerConfig GameServerConfig => this._configStore.GameServer;