Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions Refresh.Core/Configuration/ConfigStore.cs
Original file line number Diff line number Diff line change
@@ -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 Database { 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<GameServerConfig>("refreshGameServer.json", logger);
this.Database = Config.LoadFromJsonFile<DatabaseConfig>("db.json", logger);

this.ContactInfo = Config.LoadFromJsonFile<ContactInfoConfig>("contactInfo.json", logger);
this.Integration = Config.LoadFromJsonFile<IntegrationConfig>("integrations.json", logger);
this.RichPresence = Config.LoadFromJsonFile<RichPresenceConfig>("rpc.json", logger);

this.DryArchive = Config.LoadFromJsonFile<DryArchiveConfig>("dry.json", logger);
}
}

public ConfigStore()
{
this.GameServer = new GameServerConfig();
this.Database = 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.Database);
server.AddConfig(this.ContactInfo);
server.AddConfig(this.Integration);
server.AddConfig(this.RichPresence);
server.AddConfig(this.DryArchive);
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using Bunkum.Core.Configuration;

namespace Refresh.Core.Storage;
namespace Refresh.Core.Configuration;

public class DryArchiveConfig : Config
{
Expand Down
1 change: 1 addition & 0 deletions Refresh.Core/Storage/DryDataStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
85 changes: 32 additions & 53 deletions Refresh.GameServer/RefreshGameServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -59,42 +55,30 @@ public RefreshGameServer(
dataStore ??= new FileSystemDataStore();
List<IDataStore> dataStores = [];

DryArchiveConfig? dryConfig = null;
try
{
dryConfig = Config.LoadFromJsonFile<DryArchiveConfig>("dry.json", this.Logger);
if (dryConfig.Enabled)
dataStores.Add(new DownloadingDataStore(dataStore, new DryDataStore(dryConfig)));
// ReSharper disable once VirtualMemberCallInConstructor (you can't stop me)
this._configStore = this.CreateConfigStore();
}
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<DatabaseConfig>("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.Database);

this._databaseProvider = databaseProvider.Invoke();
this._databaseProvider.Initialize();

// 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

Expand All @@ -110,12 +94,17 @@ public RefreshGameServer(

this.WorkerManager?.Stop();

authProvider ??= new GameAuthenticationProvider(this._config!);
authProvider ??= new GameAuthenticationProvider(this._configStore.GameServer);

this.InjectBaseServices(provider, authProvider, this._dataStore);
});
}

protected virtual ConfigStore CreateConfigStore()
{
return new ConfigStore(this.Logger);
}

private void InjectBaseServices(GameDatabaseProvider databaseProvider, IAuthenticationProvider<Token> authProvider, IDataStore dataStore)
{
this.Server.UseDatabaseProvider(databaseProvider);
Expand All @@ -135,51 +124,41 @@ protected override void Initialize()
protected override void SetupMiddlewares()
{
this.Server.AddMiddleware<WebsiteMiddleware>();
this.Server.AddMiddleware(new DeflateMiddleware(this._config!));
this.Server.AddMiddleware(new DeflateMiddleware(this._configStore.GameServer));
this.Server.AddMiddleware<LegacyAdapterMiddleware>();
// 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<CrossOriginMiddleware>();
this.Server.AddMiddleware<PspVersionMiddleware>();
this.Server.AddMiddleware(new PresenceAuthenticationMiddleware(this._integrationConfig!));
this.Server.AddMiddleware(new PresenceAuthenticationMiddleware(this._configStore.Integration!));
this.Server.AddMiddleware<RequestStatisticTrackingMiddleware>();
}

protected override void SetupConfiguration()
{
GameServerConfig config = Config.LoadFromJsonFile<GameServerConfig>("refreshGameServer.json", this.Server.Logger);
this._config = config;

IntegrationConfig integrationConfig = Config.LoadFromJsonFile<IntegrationConfig>("integrations.json", this.Server.Logger);
this._integrationConfig = integrationConfig;

this.Server.AddConfig(config);
this.Server.AddConfig(integrationConfig);
this.Server.AddConfigFromJsonFile<RichPresenceConfig>("rpc.json");
this.Server.AddConfigFromJsonFile<ContactInfoConfig>("contactInfo.json");
this._configStore.AddToBunkum(this.Server);
}

protected override void SetupServices()
{
this.Server.AddService<TimeProviderService>(this.GetTimeProvider());
this.Server.AddRateLimitService(new RateLimitSettings(60, 400, 30, "global"));
this.Server.AddService<CategoryService>();
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<ImportService>();
this.Server.AddService<DocumentationService>();
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

Expand All @@ -191,7 +170,7 @@ protected override void SetupServices()
this.Server.AddService<ChallengeGhostRateLimitService>();
this.Server.AddService<DiscordStaffService>();

if(this._integrationConfig!.AipiEnabled)
if(this._configStore.Integration!.AipiEnabled)
this.Server.AddService<AipiService>();

#if DEBUG
Expand All @@ -208,9 +187,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));
}
}

Expand All @@ -220,7 +199,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.");
Expand Down
6 changes: 5 additions & 1 deletion Refresh.WorkerManager/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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();
Expand Down
2 changes: 1 addition & 1 deletion Refresh.Workers/WorkerManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
11 changes: 4 additions & 7 deletions RefreshTests.GameServer/GameServer/TestRefreshGameServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,12 @@ public class TestRefreshGameServer : RefreshGameServer
public TestRefreshGameServer(BunkumHttpListener listener, Func<GameDatabaseProvider> provider, IDataStore? dataStore = null) : base(listener, provider, null, dataStore ?? new InMemoryDataStore())
{}

protected override void SetupConfiguration()
protected override ConfigStore CreateConfigStore()
{
this.Server.AddConfig(this._config = new GameServerConfig());
this.Server.AddConfig(new RichPresenceConfig());
this.Server.AddConfig(this._integrationConfig = new IntegrationConfig());
this.Server.AddConfig(new ContactInfoConfig());
return new ConfigStore();
}

public GameServerConfig GameServerConfig => this._config!;
public GameServerConfig GameServerConfig => this._configStore.GameServer;

public override void Start()
{
Expand Down Expand Up @@ -71,7 +68,7 @@ protected override void SetupServices()
this.Server.AddService<CategoryService>();
this.Server.AddService<MatchService>();
this.Server.AddService<ImportService>();
this.Server.AddService(new PresenceService(this.Logger, this._integrationConfig!));
this.Server.AddService(new PresenceService(this.Logger, this._configStore.Integration!));
this.Server.AddService<PlayNowService>();
this.Server.AddService<CommandService>();
this.Server.AddService<GuidCheckerService>();
Expand Down