diff --git a/Docker/run/compose/mare-sharded.yml b/Docker/run/compose/mare-sharded.yml index afe9527..12f4252 100644 --- a/Docker/run/compose/mare-sharded.yml +++ b/Docker/run/compose/mare-sharded.yml @@ -82,6 +82,7 @@ services: restart: on-failure environment: MareSynchronos__DiscordBotToken: "${DEV_MARE_DISCORDTOKEN}" + MareSynchronos__DiscordChannelForMessages: "${DEV_MARE_DISCORDCHANNEL}" volumes: - ../config/standalone/services-standalone.json:/opt/MareSynchronosServices/appsettings.json - ../log/services-standalone/:/opt/MareSynchronosServices/logs/:rw diff --git a/Docker/run/compose/mare-standalone.yml b/Docker/run/compose/mare-standalone.yml index 6add106..1843387 100644 --- a/Docker/run/compose/mare-standalone.yml +++ b/Docker/run/compose/mare-standalone.yml @@ -28,6 +28,7 @@ services: - 6000:6000/tcp environment: MareSynchronos__CdnFullUrl: "${DEV_MARE_CDNURL}" + DOTNET_USE_POLLING_FILE_WATCHER: 1 volumes: - ../config/standalone/server-standalone.json:/opt/MareSynchronosServer/appsettings.json - ../log/server-standalone/:/opt/MareSynchronosServer/logs/:rw @@ -46,11 +47,15 @@ services: restart: on-failure environment: MareSynchronos__DiscordBotToken: "${DEV_MARE_DISCORDTOKEN}" + MareSynchronos__DiscordChannelForMessages: "${DEV_MARE_DISCORDCHANNEL}" + DOTNET_USE_POLLING_FILE_WATCHER: 1 volumes: - ../config/standalone/services-standalone.json:/opt/MareSynchronosServices/appsettings.json - ../log/services-standalone/:/opt/MareSynchronosServices/logs/:rw - postgres_socket:/var/run/postgresql/:rw depends_on: + mare-server: + condition: service_healthy postgres: condition: service_healthy @@ -59,6 +64,8 @@ services: ports: - 6200:6200/tcp restart: on-failure + environment: + DOTNET_USE_POLLING_FILE_WATCHER: 1 volumes: - ../config/standalone/files-standalone.json:/opt/MareSynchronosStaticFilesServer/appsettings.json - ../log/files-standalone/:/opt/MareSynchronosStaticFilesServer/logs/:rw diff --git a/Docker/run/config/sharded/files-shard-1.json b/Docker/run/config/sharded/files-shard-1.json index 26b6549..2b36db7 100644 --- a/Docker/run/config/sharded/files-shard-1.json +++ b/Docker/run/config/sharded/files-shard-1.json @@ -28,17 +28,17 @@ "DbContextPoolSize": 512, "ShardName": "Files Shard 1", "MetricsPort": 6250, - "FileServerGrpcAddress": "http://mare-files:6205", "ForcedDeletionOfFilesAfterHours": 2, "CacheSizeHardLimitInGiB": 5, "UnusedFileRetentionPeriodInDays": 14, "CacheDirectory": "/marecache/", - "RemoteCacheSourceUri": "http://mare-files:6200/", - "MainServerGrpcAddress": "http://mare-server:6005", "DownloadTimeoutSeconds": 30, "DownloadQueueSize": 50, "DownloadQueueReleaseSeconds": 15, - "RedisConnectionString": "redis,password=secretredispassword" + "RedisConnectionString": "redis,password=secretredispassword", + "Jwt": "teststringteststringteststringteststringteststringteststringteststringteststringteststringteststring", + "MainServerAddress": "http://mare-server:6000", + "MainFileServerAddress": "http://mare-files:6200" }, "AllowedHosts": "*", "Kestrel": { diff --git a/Docker/run/config/sharded/files-shard-2.json b/Docker/run/config/sharded/files-shard-2.json index a187ac1..50a9307 100644 --- a/Docker/run/config/sharded/files-shard-2.json +++ b/Docker/run/config/sharded/files-shard-2.json @@ -28,17 +28,17 @@ "DbContextPoolSize": 512, "ShardName": "Files Shard 2", "MetricsPort": 6250, - "FileServerGrpcAddress": "http://mare-files:6205", "ForcedDeletionOfFilesAfterHours": 2, "CacheSizeHardLimitInGiB": 5, "UnusedFileRetentionPeriodInDays": 14, "CacheDirectory": "/marecache/", - "RemoteCacheSourceUri": "http://mare-files:6200/", - "MainServerGrpcAddress": "http://mare-server:6005", "DownloadTimeoutSeconds": 30, "DownloadQueueSize": 50, "DownloadQueueReleaseSeconds": 15, - "RedisConnectionString": "redis,password=secretredispassword" + "RedisConnectionString": "redis,password=secretredispassword", + "Jwt": "teststringteststringteststringteststringteststringteststringteststringteststringteststringteststring", + "MainServerAddress": "http://mare-server:6000", + "MainFileServerAddress": "http://mare-files:6200" }, "AllowedHosts": "*", "Kestrel": { diff --git a/Docker/run/config/sharded/files-shard-main.json b/Docker/run/config/sharded/files-shard-main.json index 222a6d1..d481e10 100644 --- a/Docker/run/config/sharded/files-shard-main.json +++ b/Docker/run/config/sharded/files-shard-main.json @@ -34,8 +34,10 @@ "UnusedFileRetentionPeriodInDays": 14, "CacheDirectory": "/marecache/", "RemoteCacheSourceUri": "", - "MainServerGrpcAddress": "http://mare-server:6005", - "RedisConnectionString": "redis,password=secretredispassword" + "RedisConnectionString": "redis,password=secretredispassword", + "Jwt": "teststringteststringteststringteststringteststringteststringteststringteststringteststringteststring", + "MainServerAddress": "http://mare-server:6000", + "MainFileServerAddress": "" }, "AllowedHosts": "*", "Kestrel": { diff --git a/Docker/run/config/sharded/server-shard-1.json b/Docker/run/config/sharded/server-shard-1.json index 1978f5f..402babe 100644 --- a/Docker/run/config/sharded/server-shard-1.json +++ b/Docker/run/config/sharded/server-shard-1.json @@ -28,8 +28,9 @@ "DbContextPoolSize": 512, "ShardName": "Shard 1", "MetricsPort": 6050, - "MainServerGrpcAddress": "http://mare-server:6005", - "RedisConnectionString": "redis,password=secretredispassword" + "MainServerAddress": "http://mare-server:6000", + "RedisConnectionString": "redis,password=secretredispassword", + "Jwt": "teststringteststringteststringteststringteststringteststringteststringteststringteststringteststring" }, "AllowedHosts": "*", "Kestrel": { diff --git a/Docker/run/config/sharded/server-shard-2.json b/Docker/run/config/sharded/server-shard-2.json index 698df5e..f8a3228 100644 --- a/Docker/run/config/sharded/server-shard-2.json +++ b/Docker/run/config/sharded/server-shard-2.json @@ -28,8 +28,9 @@ "DbContextPoolSize": 512, "ShardName": "Shard 2", "MetricsPort": 6050, - "MainServerGrpcAddress": "http://mare-server:6005", - "RedisConnectionString": "redis,password=secretredispassword" + "MainServerAddress": "http://mare-server:6000", + "RedisConnectionString": "redis,password=secretredispassword", + "Jwt": "teststringteststringteststringteststringteststringteststringteststringteststringteststringteststring" }, "AllowedHosts": "*", "Kestrel": { diff --git a/Docker/run/config/standalone/files-standalone.json b/Docker/run/config/standalone/files-standalone.json index 222a6d1..c61baf0 100644 --- a/Docker/run/config/standalone/files-standalone.json +++ b/Docker/run/config/standalone/files-standalone.json @@ -34,8 +34,10 @@ "UnusedFileRetentionPeriodInDays": 14, "CacheDirectory": "/marecache/", "RemoteCacheSourceUri": "", - "MainServerGrpcAddress": "http://mare-server:6005", - "RedisConnectionString": "redis,password=secretredispassword" + "MainServerAddress": "http://mare-server:6000/", + "RedisConnectionString": "redis,password=secretredispassword", + "MainFileServerAddress": "", + "Jwt": "teststringteststringteststringteststringteststringteststringteststringteststringteststringteststring" }, "AllowedHosts": "*", "Kestrel": { diff --git a/Docker/run/config/standalone/server-standalone.json b/Docker/run/config/standalone/server-standalone.json index 5ab764f..ddbc1cc 100644 --- a/Docker/run/config/standalone/server-standalone.json +++ b/Docker/run/config/standalone/server-standalone.json @@ -28,7 +28,7 @@ "DbContextPoolSize": 512, "ShardName": "Main", "MetricsPort": 6050, - "MainServerGrpcAddress": "", + "MainServerAddress": "", "FailedAuthForTempBan": 5, "TempBanDurationInMinutes": 5, "Jwt": "teststringteststringteststringteststringteststringteststringteststringteststringteststringteststring", diff --git a/Docker/run/config/standalone/services-standalone.json b/Docker/run/config/standalone/services-standalone.json index c943a86..8a07ba9 100644 --- a/Docker/run/config/standalone/services-standalone.json +++ b/Docker/run/config/standalone/services-standalone.json @@ -28,8 +28,11 @@ "DbContextPoolSize": 512, "ShardName": "Services", "MetricsPort": 6150, - "MainServerGrpcAddress": "http://mare-server:6005", + "MainServerAddress": "http://mare-server:6000/", + "MainServerGrpcAddress": "http://mare-server:6005/", "DiscordBotToken": "", + "DiscordChannelForMessages": "", + "Jwt": "teststringteststringteststringteststringteststringteststringteststringteststringteststringteststring", "RedisConnectionString": "redis,password=secretredispassword" }, "AllowedHosts": "*", diff --git a/MareSynchronosServer/MareSynchronosServer/Hubs/MareHub.User.cs b/MareSynchronosServer/MareSynchronosServer/Hubs/MareHub.User.cs index 9df9c46..e4cfcda 100644 --- a/MareSynchronosServer/MareSynchronosServer/Hubs/MareHub.User.cs +++ b/MareSynchronosServer/MareSynchronosServer/Hubs/MareHub.User.cs @@ -2,7 +2,6 @@ using MareSynchronos.API.Data; using MareSynchronos.API.Data.Enum; using MareSynchronos.API.Data.Extensions; -using MareSynchronos.API.Dto.Group; using MareSynchronos.API.Dto.User; using MareSynchronosServer.Utils; using MareSynchronosShared.Metrics; diff --git a/MareSynchronosServer/MareSynchronosServer/Program.cs b/MareSynchronosServer/MareSynchronosServer/Program.cs index 6d32264..d524a91 100644 --- a/MareSynchronosServer/MareSynchronosServer/Program.cs +++ b/MareSynchronosServer/MareSynchronosServer/Program.cs @@ -55,8 +55,15 @@ public class Program } } - public static IHostBuilder CreateHostBuilder(string[] args) => - Host.CreateDefaultBuilder(args) + public static IHostBuilder CreateHostBuilder(string[] args) + { + var loggerFactory = LoggerFactory.Create(builder => + { + builder.ClearProviders(); + builder.AddConsole(); + }); + var logger = loggerFactory.CreateLogger(); + return Host.CreateDefaultBuilder(args) .UseSystemd() .UseConsoleLifetime() .ConfigureWebHostDefaults(webBuilder => @@ -67,6 +74,7 @@ public class Program builder.AddConfiguration(ctx.Configuration.GetSection("Logging")); builder.AddFile(o => o.RootPath = AppContext.BaseDirectory); }); - webBuilder.UseStartup(); + webBuilder.UseStartup(ctx => new Startup(ctx.Configuration, logger)); }); + } } diff --git a/MareSynchronosServer/MareSynchronosServer/Startup.cs b/MareSynchronosServer/MareSynchronosServer/Startup.cs index cf020f4..d408311 100644 --- a/MareSynchronosServer/MareSynchronosServer/Startup.cs +++ b/MareSynchronosServer/MareSynchronosServer/Startup.cs @@ -13,8 +13,6 @@ using MareSynchronosServer.RequirementHandlers; using MareSynchronosShared.Utils; using MareSynchronosShared.Services; using Prometheus; -using Microsoft.Extensions.Options; -using Grpc.Net.ClientFactory; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.IdentityModel.Tokens; using System.Text; @@ -26,14 +24,19 @@ using StackExchange.Redis.Extensions.System.Text.Json; using MareSynchronos.API.SignalR; using MessagePack; using MessagePack.Resolvers; +using Microsoft.AspNetCore.Mvc.Controllers; +using MareSynchronosServer.Controllers; namespace MareSynchronosServer; public class Startup { - public Startup(IConfiguration configuration) + private readonly ILogger _logger; + + public Startup(IConfiguration configuration, ILogger logger) { Configuration = configuration; + _logger = logger; } public IConfiguration Configuration { get; } @@ -68,16 +71,27 @@ public class Startup ConfigureMareServices(services, mareConfig); services.AddHealthChecks(); - services.AddControllers(); + services.AddControllers().ConfigureApplicationPartManager(a => + { + a.FeatureProviders.Remove(a.FeatureProviders.OfType().First()); + if (mareConfig.GetValue(nameof(ServerConfiguration.MainServerAddress), defaultValue: null) == null) + { + a.FeatureProviders.Add(new AllowedControllersFeatureProvider(typeof(MareServerConfigurationController), typeof(MareAuthBaseConfigurationController), typeof(JwtController))); + } + else + { + a.FeatureProviders.Add(new AllowedControllersFeatureProvider()); + } + }); } - private static void ConfigureMareServices(IServiceCollection services, IConfigurationSection mareConfig) + private void ConfigureMareServices(IServiceCollection services, IConfigurationSection mareConfig) { - bool isMainServer = mareConfig.GetValue(nameof(ServerConfiguration.MainServerGrpcAddress), defaultValue: null) == null; + bool isMainServer = mareConfig.GetValue(nameof(ServerConfiguration.MainServerAddress), defaultValue: null) == null; - services.Configure(mareConfig); - services.Configure(mareConfig); - services.Configure(mareConfig); + services.Configure(Configuration.GetRequiredSection("MareSynchronos")); + services.Configure(Configuration.GetRequiredSection("MareSynchronos")); + services.Configure(Configuration.GetRequiredSection("MareSynchronos")); services.AddSingleton(); services.AddSingleton(); @@ -217,6 +231,7 @@ public class Startup { policy.AddRequirements(new UserRequirement(UserRequirements.Identified | UserRequirements.Moderator | UserRequirements.Administrator)); }); + options.AddPolicy("Internal", new AuthorizationPolicyBuilder().RequireClaim(MareClaimTypes.Internal, "true").Build()); }); } @@ -264,34 +279,9 @@ public class Startup { if (!isMainServer) { - var noRetryConfig = new MethodConfig - { - Names = { MethodName.Default }, - RetryPolicy = null, - }; + services.AddSingleton, MareConfigurationServiceClient>(); + services.AddSingleton, MareConfigurationServiceClient>(); - services.AddGrpcClient("MainServer", c => - { - c.Address = new Uri(mareConfig.GetValue(nameof(ServerConfiguration.MainServerGrpcAddress))); - }).ConfigureChannel(c => - { - c.ServiceConfig = new ServiceConfig { MethodConfigs = { noRetryConfig } }; - c.HttpHandler = new SocketsHttpHandler() - { - EnableMultipleHttp2Connections = true, - }; - }); - - services.AddSingleton>(c => new MareConfigurationServiceClient( - c.GetService>>(), - c.GetService>(), - c.GetService(), - "MainServer")); - services.AddSingleton>(c => new MareConfigurationServiceClient( - c.GetService>>(), - c.GetService>(), - c.GetService(), - "MainServer")); services.AddHostedService(p => (MareConfigurationServiceClient)p.GetService>()); services.AddHostedService(p => (MareConfigurationServiceClient)p.GetService>()); } @@ -358,12 +348,18 @@ public class Startup if (config.IsMain) { - endpoints.MapGrpcService>().AllowAnonymous(); endpoints.MapGrpcService().AllowAnonymous(); } endpoints.MapHealthChecks("/health").AllowAnonymous(); - endpoints.MapControllers().AllowAnonymous(); + endpoints.MapControllers(); + + foreach (var source in endpoints.DataSources.SelectMany(e => e.Endpoints).Cast()) + { + if (source == null) continue; + _logger.LogInformation("Endpoint: {url} ", source.RoutePattern.RawText); + } }); + } } diff --git a/MareSynchronosServer/MareSynchronosServices/Discord/MareModule.cs b/MareSynchronosServer/MareSynchronosServices/Discord/MareModule.cs index 78741b5..f2c2bae 100644 --- a/MareSynchronosServer/MareSynchronosServices/Discord/MareModule.cs +++ b/MareSynchronosServer/MareSynchronosServices/Discord/MareModule.cs @@ -29,18 +29,21 @@ public class MareModule : InteractionModuleBase private readonly IServiceProvider _services; private readonly DiscordBotServices _botServices; private readonly IConfigurationService _mareClientConfigurationService; + private readonly IConfigurationService _mareServicesConfiguration; private readonly GrpcClientFactory _grpcClientFactory; private readonly IConnectionMultiplexer _connectionMultiplexer; private Random random = new(); public MareModule(ILogger logger, IServiceProvider services, DiscordBotServices botServices, IConfigurationService mareClientConfigurationService, + IConfigurationService mareServicesConfiguration, GrpcClientFactory grpcClientFactory, IConnectionMultiplexer connectionMultiplexer) { _logger = logger; _services = services; _botServices = botServices; _mareClientConfigurationService = mareClientConfigurationService; + _mareServicesConfiguration = mareServicesConfiguration; _grpcClientFactory = grpcClientFactory; _connectionMultiplexer = connectionMultiplexer; } @@ -314,6 +317,29 @@ public class MareModule : InteractionModuleBase Uid = uid ?? string.Empty }); + var discordChannelForMessages = _mareServicesConfiguration.GetValueOrDefault(nameof(ServicesConfiguration.DiscordChannelForMessages), null); + if (uid == null && discordChannelForMessages != null) + { + var discordChannel = await Context.Guild.GetChannelAsync(discordChannelForMessages.Value) as IMessageChannel; + if (discordChannel != null) + { + var embedColor = messageType switch + { + MareSynchronosShared.Protos.MessageType.Info => Color.Blue, + MareSynchronosShared.Protos.MessageType.Warning => new Color(255, 255, 0), + MareSynchronosShared.Protos.MessageType.Error => Color.Red, + _ => Color.Blue + }; + + EmbedBuilder eb = new(); + eb.WithTitle(messageType + " server message"); + eb.WithColor(embedColor); + eb.WithDescription(message); + + await discordChannel.SendMessageAsync(embed: eb.Build()); + } + } + await RespondAsync("Message sent", ephemeral: true).ConfigureAwait(false); } catch (Exception ex) diff --git a/MareSynchronosServer/MareSynchronosServices/Program.cs b/MareSynchronosServer/MareSynchronosServices/Program.cs index 69302a2..ed66bdc 100644 --- a/MareSynchronosServer/MareSynchronosServices/Program.cs +++ b/MareSynchronosServer/MareSynchronosServices/Program.cs @@ -1,6 +1,5 @@ using MareSynchronosServices; using MareSynchronosShared.Data; -using MareSynchronosShared.Metrics; using MareSynchronosShared.Services; using MareSynchronosShared.Utils; diff --git a/MareSynchronosServer/MareSynchronosServices/Startup.cs b/MareSynchronosServer/MareSynchronosServices/Startup.cs index da4c063..e1336ea 100644 --- a/MareSynchronosServer/MareSynchronosServices/Startup.cs +++ b/MareSynchronosServer/MareSynchronosServices/Startup.cs @@ -7,9 +7,6 @@ using MareSynchronosShared.Utils; using Grpc.Net.Client.Configuration; using MareSynchronosShared.Protos; using MareSynchronosShared.Services; -using Grpc.Net.ClientFactory; -using Microsoft.Extensions.Options; -using Microsoft.Extensions.DependencyInjection; using StackExchange.Redis; namespace MareSynchronosServices; @@ -52,18 +49,6 @@ public class Startup ConnectionMultiplexer connectionMultiplexer = ConnectionMultiplexer.Connect(options); services.AddSingleton(connectionMultiplexer); - services.AddGrpcClient("MainServer", c => - { - c.Address = new Uri(mareConfig.GetValue(nameof(ServicesConfiguration.MainServerGrpcAddress))); - }).ConfigureChannel(c => - { - c.ServiceConfig = new ServiceConfig { MethodConfigs = { noRetryConfig } }; - c.HttpHandler = new SocketsHttpHandler() - { - EnableMultipleHttp2Connections = true - }; - }); - services.AddGrpcClient("MessageClient", c => { c.Address = new Uri(mareConfig.GetValue(nameof(ServicesConfiguration.MainServerGrpcAddress))); @@ -80,19 +65,12 @@ public class Startup services.Configure(Configuration.GetRequiredSection("MareSynchronos")); services.Configure(Configuration.GetRequiredSection("MareSynchronos")); services.AddSingleton(Configuration); + services.AddSingleton(); services.AddSingleton(); services.AddHostedService(); services.AddSingleton, MareConfigurationServiceServer>(); - services.AddSingleton>(c => new MareConfigurationServiceClient( - c.GetService>>(), - c.GetService>(), - c.GetService(), - "MainServer")); - services.AddSingleton>(c => new MareConfigurationServiceClient( - c.GetService>>(), - c.GetService>(), - c.GetService(), - "MainServer")); + services.AddSingleton, MareConfigurationServiceClient>(); + services.AddSingleton, MareConfigurationServiceClient>(); services.AddHostedService(p => (MareConfigurationServiceClient)p.GetService>()); services.AddHostedService(p => (MareConfigurationServiceClient)p.GetService>()); diff --git a/MareSynchronosServer/MareSynchronosServices/appsettings.json b/MareSynchronosServer/MareSynchronosServices/appsettings.json index 5d0ffbf..902d25f 100644 --- a/MareSynchronosServer/MareSynchronosServices/appsettings.json +++ b/MareSynchronosServer/MareSynchronosServices/appsettings.json @@ -19,6 +19,7 @@ "MareSynchronos": { "DbContextPoolSize": 1024, "DiscordBotToken": "", + "DiscordChannelForMessages": "", "PurgeUnusedAccounts": true, "PurgeUnusedAccountsPeriodInDays": 14, "FailedAuthForTempBan": 5, diff --git a/MareSynchronosServer/MareSynchronosShared/Protos/mareservices.proto b/MareSynchronosServer/MareSynchronosShared/Protos/mareservices.proto index a66d9e4..6b83f4b 100644 --- a/MareSynchronosServer/MareSynchronosShared/Protos/mareservices.proto +++ b/MareSynchronosServer/MareSynchronosShared/Protos/mareservices.proto @@ -9,10 +9,6 @@ service FileService { rpc DeleteFiles (DeleteFilesRequest) returns (Empty); } -service ConfigurationService { - rpc GetConfigurationEntry (KeyMessage) returns (ValueMessage); -} - service ClientMessageService { rpc SendClientMessage (ClientMessage) returns (Empty); } @@ -29,15 +25,6 @@ enum MessageType { ERROR = 2; } -message KeyMessage { - string key = 1; - string default = 2; -} - -message ValueMessage { - string value = 1; -} - message Empty { } message MultiUidMessage { diff --git a/MareSynchronosServer/MareSynchronosShared/Services/GrpcBaseService.cs b/MareSynchronosServer/MareSynchronosShared/Services/GrpcBaseService.cs deleted file mode 100644 index 9038eb7..0000000 --- a/MareSynchronosServer/MareSynchronosShared/Services/GrpcBaseService.cs +++ /dev/null @@ -1,132 +0,0 @@ -using Grpc.Core; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; - -namespace MareSynchronosShared.Services; - -public abstract class GrpcBaseService : IHostedService, IDisposable -{ - protected GrpcBaseService(ILogger logger) - { - _logger = logger; - } - - private CancellationTokenSource _faultCheckCts = new(); - private CancellationTokenSource _streamCts = new(); - private readonly ILogger _logger; - protected bool GrpcIsFaulty { get; private set; } - - protected abstract Task StartAsyncInternal(CancellationToken cancellationToken); - protected abstract Task StopAsyncInternal(CancellationToken cancellationToken); - protected abstract Task OnGrpcRestore(); - protected abstract Task PreStartStream(); - protected abstract Task StartStream(CancellationToken ct); - protected abstract Task PostStartStream(); - - public async Task StartAsync(CancellationToken cancellationToken) - { - _ = RestartStreams(); - _ = CheckGrpcFaults(_faultCheckCts.Token); - await StartAsyncInternal(cancellationToken).ConfigureAwait(false); - } - - public async Task StopAsync(CancellationToken cancellationToken) - { - _faultCheckCts.Cancel(); - _streamCts.Cancel(); - await StopAsyncInternal(cancellationToken).ConfigureAwait(false); - } - - private async Task RestartStreams() - { - if (!GrpcIsFaulty) - { - _streamCts?.Cancel(); - _streamCts?.Dispose(); - _streamCts = new(); - var token = _streamCts.Token; - try - { - await PreStartStream().ConfigureAwait(false); - await StartStream(token).ConfigureAwait(false); - await PostStartStream().ConfigureAwait(false); - } - catch - { - SetGrpcFaulty(); - } - } - } - - protected void SetGrpcFaulty() - { - if (!GrpcIsFaulty) - { - GrpcIsFaulty = true; - _logger.LogWarning("GRPC connection is faulty"); - } - } - - private async Task CheckGrpcFaults(CancellationToken ct) - { - while (!ct.IsCancellationRequested) - { - try - { - await CheckFaultStateAndRestore().ConfigureAwait(false); - } - catch - { - SetGrpcFaulty(); - await Task.Delay(5000, ct).ConfigureAwait(false); - } - await Task.Delay(250).ConfigureAwait(false); - } - } - - private async Task CheckFaultStateAndRestore() - { - if (GrpcIsFaulty) - { - GrpcIsFaulty = false; - await RestartStreams().ConfigureAwait(false); - await OnGrpcRestore().ConfigureAwait(false); - _logger.LogInformation("GRPC connection is restored"); - } - } - - protected async Task InvokeOnGrpc(AsyncUnaryCall toExecute) - { - try - { - var result = await toExecute.ConfigureAwait(false); - - return result; - } - catch - { - SetGrpcFaulty(); - - return default; - } - } - - protected async Task ExecuteOnGrpc(AsyncUnaryCall toExecute) - { - try - { - await toExecute.ConfigureAwait(false); - await CheckFaultStateAndRestore().ConfigureAwait(false); - } - catch - { - SetGrpcFaulty(); - } - } - - public void Dispose() - { - _streamCts?.Dispose(); - _faultCheckCts?.Dispose(); - } -} \ No newline at end of file diff --git a/MareSynchronosServer/MareSynchronosShared/Services/GrpcConfigurationService.cs b/MareSynchronosServer/MareSynchronosShared/Services/GrpcConfigurationService.cs deleted file mode 100644 index bb6da9d..0000000 --- a/MareSynchronosServer/MareSynchronosShared/Services/GrpcConfigurationService.cs +++ /dev/null @@ -1,30 +0,0 @@ -using Grpc.Core; -using MareSynchronosShared.Protos; -using MareSynchronosShared.Utils; -using Microsoft.AspNetCore.Authorization; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; - -namespace MareSynchronosShared.Services; - -[Authorize] -[AllowAnonymous] -public class GrpcConfigurationService : ConfigurationService.ConfigurationServiceBase where T : class, IMareConfiguration -{ - private readonly T _config; - private readonly ILogger> logger; - - public GrpcConfigurationService(IOptions config, ILogger> logger) - { - _config = config.Value; - this.logger = logger; - } - - [AllowAnonymous] - public override Task GetConfigurationEntry(KeyMessage request, ServerCallContext context) - { - logger.LogInformation("Remote requested {key}", request.Key); - var returnVal = _config.SerializeValue(request.Key, request.Default); - return Task.FromResult(new ValueMessage() { Value = returnVal }); - } -} \ No newline at end of file diff --git a/MareSynchronosServer/MareSynchronosShared/Services/MareConfigurationController.cs b/MareSynchronosServer/MareSynchronosShared/Services/MareConfigurationController.cs new file mode 100644 index 0000000..8f66f27 --- /dev/null +++ b/MareSynchronosServer/MareSynchronosShared/Services/MareConfigurationController.cs @@ -0,0 +1,61 @@ +using MareSynchronosShared.Utils; +using MareSynchronosStaticFilesServer; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; + +namespace MareSynchronosShared.Services; + +[Route("configuration/[controller]")] +[Authorize(Policy = "Internal")] +public class MareConfigurationController : Controller where T : class, IMareConfiguration +{ + private readonly ILogger> _logger; + private IOptionsMonitor _config; + + public MareConfigurationController(IOptionsMonitor config, ILogger> logger) + { + _config = config; + _logger = logger; + } + + [HttpGet("GetConfigurationEntry")] + [Authorize(Policy = "Internal")] + public IActionResult GetConfigurationEntry(string key, string defaultValue) + { + var result = _config.CurrentValue.SerializeValue(key, defaultValue); + _logger.LogInformation("Requested " + key + ", returning:" + result); + return Ok(result); + } +} + +#pragma warning disable MA0048 // File name must match type name +public class MareStaticFilesServerConfigurationController : MareConfigurationController +{ + public MareStaticFilesServerConfigurationController(IOptionsMonitor config, ILogger logger) : base(config, logger) + { + } +} + +public class MareAuthBaseConfigurationController : MareConfigurationController +{ + public MareAuthBaseConfigurationController(IOptionsMonitor config, ILogger logger) : base(config, logger) + { + } +} + +public class MareServerConfigurationController : MareConfigurationController +{ + public MareServerConfigurationController(IOptionsMonitor config, ILogger logger) : base(config, logger) + { + } +} + +public class MareServicesConfigurationController : MareConfigurationController +{ + public MareServicesConfigurationController(IOptionsMonitor config, ILogger logger) : base(config, logger) + { + } +} +#pragma warning restore MA0048 // File name must match type name diff --git a/MareSynchronosServer/MareSynchronosShared/Services/MareConfigurationServiceClient.cs b/MareSynchronosServer/MareSynchronosShared/Services/MareConfigurationServiceClient.cs index 68edefb..16fb54f 100644 --- a/MareSynchronosServer/MareSynchronosShared/Services/MareConfigurationServiceClient.cs +++ b/MareSynchronosServer/MareSynchronosShared/Services/MareConfigurationServiceClient.cs @@ -1,43 +1,55 @@ -using Grpc.Net.ClientFactory; -using MareSynchronosShared.Protos; -using MareSynchronosShared.Utils; +using MareSynchronosShared.Utils; +using MareSynchronosStaticFilesServer; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using System.Collections; using System.Collections.Concurrent; using System.Globalization; +using System.Net.Http.Headers; using System.Reflection; using System.Text; using System.Text.Json; -using static MareSynchronosShared.Protos.ConfigurationService; namespace MareSynchronosShared.Services; public class MareConfigurationServiceClient : IHostedService, IConfigurationService where T : class, IMareConfiguration { - private readonly T _config; + private readonly IOptionsMonitor _config; private readonly ConcurrentDictionary _cachedRemoteProperties = new(StringComparer.Ordinal); private readonly ILogger> _logger; - private readonly GrpcClientFactory _grpcClientFactory; - private readonly string _grpcClientName; + private readonly ServerTokenGenerator _serverTokenGenerator; private readonly CancellationTokenSource _updateTaskCts = new(); - private ConfigurationServiceClient _configurationServiceClient; private bool _initialized = false; + private readonly HttpClient _httpClient; - public MareConfigurationServiceClient(ILogger> logger, IOptions config, GrpcClientFactory grpcClientFactory, string grpcClientName) + private Uri GetRoute(string key, string value) { - _config = config.Value; + if (_config.CurrentValue.GetType() == typeof(ServerConfiguration)) + return new Uri((_config.CurrentValue as ServerConfiguration).MainServerAddress, $"configuration/MareServerConfiguration/{nameof(MareServerConfigurationController.GetConfigurationEntry)}?key={key}&defaultValue={value}"); + if (_config.CurrentValue.GetType() == typeof(MareConfigurationAuthBase)) + return new Uri((_config.CurrentValue as MareConfigurationAuthBase).MainServerAddress, $"configuration/MareAuthBaseConfiguration/{nameof(MareAuthBaseConfigurationController.GetConfigurationEntry)}?key={key}&defaultValue={value}"); + if (_config.CurrentValue.GetType() == typeof(ServicesConfiguration)) + return new Uri((_config.CurrentValue as ServicesConfiguration).MainServerAddress, $"configuration/MareServicesConfiguration/{nameof(MareServicesConfigurationController.GetConfigurationEntry)}?key={key}&defaultValue={value}"); + if (_config.CurrentValue.GetType() == typeof(StaticFilesServerConfiguration)) + return new Uri((_config.CurrentValue as StaticFilesServerConfiguration).MainFileServerAddress, $"configuration/MareStaticFilesServerConfiguration/{nameof(MareStaticFilesServerConfigurationController.GetConfigurationEntry)}?key={key}&defaultValue={value}"); + + throw new NotSupportedException("Config is not supported to be gotten remotely"); + } + + public MareConfigurationServiceClient(ILogger> logger, IOptionsMonitor config, ServerTokenGenerator serverTokenGenerator) + { + _config = config; _logger = logger; - _grpcClientFactory = grpcClientFactory; - _grpcClientName = grpcClientName; + _serverTokenGenerator = serverTokenGenerator; + _httpClient = new(); } public bool IsMain => false; public T1 GetValueOrDefault(string key, T1 defaultValue) { - var prop = _config.GetType().GetProperty(key); + var prop = _config.CurrentValue.GetType().GetProperty(key); if (prop == null) return defaultValue; if (prop.PropertyType != typeof(T1)) throw new InvalidCastException($"Invalid Cast: Property {key} is {prop.PropertyType}, wanted: {typeof(T1)}"); bool isRemote = prop.GetCustomAttributes(typeof(RemoteConfigurationAttribute), inherit: true).Any(); @@ -46,7 +58,7 @@ public class MareConfigurationServiceClient : IHostedService, IConfigurationS return (T1)remotevalue; } - var value = prop.GetValue(_config); + var value = prop.GetValue(_config.CurrentValue); var defaultPropValue = prop.PropertyType.IsValueType ? Activator.CreateInstance(prop.PropertyType) : null; if (value == defaultPropValue) return defaultValue; return (T1)value; @@ -54,7 +66,7 @@ public class MareConfigurationServiceClient : IHostedService, IConfigurationS public T1 GetValue(string key) { - var prop = _config.GetType().GetProperty(key); + var prop = _config.CurrentValue.GetType().GetProperty(key); if (prop == null) throw new KeyNotFoundException(key); if (prop.PropertyType != typeof(T1)) throw new InvalidCastException($"Invalid Cast: Property {key} is {prop.PropertyType}, wanted: {typeof(T1)}"); bool isRemote = prop.GetCustomAttributes(typeof(RemoteConfigurationAttribute), inherit: true).Any(); @@ -63,19 +75,19 @@ public class MareConfigurationServiceClient : IHostedService, IConfigurationS return (T1)remotevalue; } - var value = prop.GetValue(_config); + var value = prop.GetValue(_config.CurrentValue); return (T1)value; } public override string ToString() { - var props = _config.GetType().GetProperties(); + var props = _config.CurrentValue.GetType().GetProperties(); StringBuilder sb = new(); foreach (var prop in props) { var isRemote = prop.GetCustomAttributes(typeof(RemoteConfigurationAttribute), true).Any(); var getValueMethod = GetType().GetMethod(nameof(GetValue)).MakeGenericMethod(prop.PropertyType); - var value = isRemote ? getValueMethod.Invoke(this, new[] { prop.Name }) : prop.GetValue(_config); + var value = isRemote ? getValueMethod.Invoke(this, new[] { prop.Name }) : prop.GetValue(_config.CurrentValue); if (typeof(IEnumerable).IsAssignableFrom(prop.PropertyType) && !typeof(string).IsAssignableFrom(prop.PropertyType)) { var enumVal = (IEnumerable)value; @@ -90,15 +102,18 @@ public class MareConfigurationServiceClient : IHostedService, IConfigurationS return sb.ToString(); } - private async Task GetValueFromGrpc(ConfigurationServiceClient client, string key, object defaultValue) + private async Task GetValueFromRemote(string key, object defaultValue) { - // grab stuff from grpc try { - _logger.LogInformation("Getting {key} from Grpc", key); - var response = await client.GetConfigurationEntryAsync(new KeyMessage { Key = key, Default = Convert.ToString(defaultValue, CultureInfo.InvariantCulture) }).ConfigureAwait(false); - _logger.LogInformation("Grpc Response for {key} = {value}", key, response.Value); - return JsonSerializer.Deserialize(response.Value); + _logger.LogInformation("Getting {key} from Http", key); + HttpRequestMessage msg = new(HttpMethod.Get, GetRoute(key, Convert.ToString(defaultValue, CultureInfo.InvariantCulture))); + msg.Headers.Authorization = new AuthenticationHeaderValue("Bearer", _serverTokenGenerator.Token); + var response = await _httpClient.SendAsync(msg).ConfigureAwait(false); + response.EnsureSuccessStatusCode(); + var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + _logger.LogInformation("Http Response for {key} = {value}", key, content); + return JsonSerializer.Deserialize(content); } catch (Exception ex) { @@ -111,20 +126,19 @@ public class MareConfigurationServiceClient : IHostedService, IConfigurationS { while (!ct.IsCancellationRequested) { - _logger.LogInformation("Getting Properties from GRPC"); + _logger.LogInformation("Getting Properties from Remote for " + typeof(T)); try { - _configurationServiceClient = _grpcClientFactory.CreateClient(_grpcClientName); - var properties = _config.GetType().GetProperties(); + var properties = _config.CurrentValue.GetType().GetProperties(); foreach (var prop in properties) { try { if (!prop.GetCustomAttributes(typeof(RemoteConfigurationAttribute), true).Any()) continue; _logger.LogInformation("Checking Property " + prop.Name); - var mi = GetType().GetMethod(nameof(GetValueFromGrpc), BindingFlags.NonPublic | BindingFlags.Instance).MakeGenericMethod(prop.PropertyType); + var mi = GetType().GetMethod(nameof(GetValueFromRemote), BindingFlags.NonPublic | BindingFlags.Instance).MakeGenericMethod(prop.PropertyType); var defaultValue = prop.PropertyType.IsValueType ? Activator.CreateInstance(prop.PropertyType) : null; - var task = (Task)mi.Invoke(this, new[] { _configurationServiceClient, prop.Name, defaultValue }); + var task = (Task)mi.Invoke(this, new[] { prop.Name, defaultValue }); await task.ConfigureAwait(false); var resultProperty = task.GetType().GetProperty("Result"); @@ -147,12 +161,12 @@ public class MareConfigurationServiceClient : IHostedService, IConfigurationS _initialized = true; } - _logger.LogInformation("Saved properties from GRPC are now:"); + _logger.LogInformation("Saved properties from HTTP are now:"); _logger.LogInformation(ToString()); } catch (Exception ex) { - _logger.LogError(ex, "Failure getting or updating properties from GRPC, retrying in 30min"); + _logger.LogError(ex, "Failure getting or updating properties from HTTP, retrying in 30min"); } await Task.Delay(TimeSpan.FromMinutes(30), ct).ConfigureAwait(false); @@ -169,6 +183,7 @@ public class MareConfigurationServiceClient : IHostedService, IConfigurationS public Task StopAsync(CancellationToken cancellationToken) { _updateTaskCts.Cancel(); + _httpClient.Dispose(); return Task.CompletedTask; } } \ No newline at end of file diff --git a/MareSynchronosServer/MareSynchronosShared/Services/MareConfigurationServiceServer.cs b/MareSynchronosServer/MareSynchronosShared/Services/MareConfigurationServiceServer.cs index 2f15060..24c9522 100644 --- a/MareSynchronosServer/MareSynchronosShared/Services/MareConfigurationServiceServer.cs +++ b/MareSynchronosServer/MareSynchronosShared/Services/MareConfigurationServiceServer.cs @@ -6,31 +6,31 @@ namespace MareSynchronosShared.Services; public class MareConfigurationServiceServer : IConfigurationService where T : class, IMareConfiguration { - private readonly T _config; + private readonly IOptionsMonitor _config; public bool IsMain => true; - public MareConfigurationServiceServer(IOptions config) + public MareConfigurationServiceServer(IOptionsMonitor config) { - _config = config.Value; + _config = config; } public T1 GetValueOrDefault(string key, T1 defaultValue) { - return _config.GetValueOrDefault(key, defaultValue); + return _config.CurrentValue.GetValueOrDefault(key, defaultValue); } public T1 GetValue(string key) { - return _config.GetValue(key); + return _config.CurrentValue.GetValue(key); } public override string ToString() { - var props = _config.GetType().GetProperties(); + var props = _config.CurrentValue.GetType().GetProperties(); StringBuilder sb = new(); foreach (var prop in props) { - sb.AppendLine($"{prop.Name} (IsRemote: {prop.GetCustomAttributes(typeof(RemoteConfigurationAttribute), true).Any()}) => {prop.GetValue(_config)}"); + sb.AppendLine($"{prop.Name} (IsRemote: {prop.GetCustomAttributes(typeof(RemoteConfigurationAttribute), true).Any()}) => {prop.GetValue(_config.CurrentValue)}"); } sb.AppendLine(_config.ToString()); diff --git a/MareSynchronosServer/MareSynchronosShared/Utils/AllowedControllersFeatureProvider.cs b/MareSynchronosServer/MareSynchronosShared/Utils/AllowedControllersFeatureProvider.cs new file mode 100644 index 0000000..1001a3b --- /dev/null +++ b/MareSynchronosServer/MareSynchronosShared/Utils/AllowedControllersFeatureProvider.cs @@ -0,0 +1,22 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.AspNetCore.Mvc.Controllers; +using System.Reflection; +using Microsoft.Extensions.Logging; + +namespace MareSynchronosShared.Utils; + +public class AllowedControllersFeatureProvider : ControllerFeatureProvider +{ + private readonly ILogger _logger; + private readonly Type[] _allowedTypes; + + public AllowedControllersFeatureProvider(params Type[] allowedTypes) + { + _allowedTypes = allowedTypes; + } + + protected override bool IsController(TypeInfo typeInfo) + { + return base.IsController(typeInfo) && _allowedTypes.Contains(typeInfo.AsType()); + } +} diff --git a/MareSynchronosServer/MareSynchronosShared/Utils/CdnShardConfiguration.cs b/MareSynchronosServer/MareSynchronosShared/Utils/CdnShardConfiguration.cs index 7805498..4b9d694 100644 --- a/MareSynchronosServer/MareSynchronosShared/Utils/CdnShardConfiguration.cs +++ b/MareSynchronosServer/MareSynchronosShared/Utils/CdnShardConfiguration.cs @@ -1,7 +1,4 @@ -using System.Text.Json.Serialization; -using System.Text.RegularExpressions; - -namespace MareSynchronosShared.Utils; +namespace MareSynchronosShared.Utils; public class CdnShardConfiguration { diff --git a/MareSynchronosServer/MareSynchronosShared/Utils/MareConfigurationAuthBase.cs b/MareSynchronosServer/MareSynchronosShared/Utils/MareConfigurationAuthBase.cs index b14c47e..966f956 100644 --- a/MareSynchronosServer/MareSynchronosShared/Utils/MareConfigurationAuthBase.cs +++ b/MareSynchronosServer/MareSynchronosShared/Utils/MareConfigurationAuthBase.cs @@ -4,21 +4,17 @@ namespace MareSynchronosShared.Utils; public class MareConfigurationAuthBase : MareConfigurationBase { - public Uri MainServerGrpcAddress { get; set; } = null; [RemoteConfiguration] public int FailedAuthForTempBan { get; set; } = 5; [RemoteConfiguration] public int TempBanDurationInMinutes { get; set; } = 5; [RemoteConfiguration] public List WhitelistedIps { get; set; } = new(); - [RemoteConfiguration] - public string Jwt { get; set; } = string.Empty; public override string ToString() { StringBuilder sb = new(); sb.AppendLine(base.ToString()); - sb.AppendLine($"{nameof(MainServerGrpcAddress)} => {MainServerGrpcAddress}"); sb.AppendLine($"{nameof(FailedAuthForTempBan)} => {FailedAuthForTempBan}"); sb.AppendLine($"{nameof(TempBanDurationInMinutes)} => {TempBanDurationInMinutes}"); sb.AppendLine($"{nameof(Jwt)} => {Jwt}"); diff --git a/MareSynchronosServer/MareSynchronosShared/Utils/MareConfigurationBase.cs b/MareSynchronosServer/MareSynchronosShared/Utils/MareConfigurationBase.cs index 993ba29..2f9f6f8 100644 --- a/MareSynchronosServer/MareSynchronosShared/Utils/MareConfigurationBase.cs +++ b/MareSynchronosServer/MareSynchronosShared/Utils/MareConfigurationBase.cs @@ -1,5 +1,4 @@ -using System.Globalization; -using System.Reflection; +using System.Reflection; using System.Text; using System.Text.Json; @@ -7,9 +6,11 @@ namespace MareSynchronosShared.Utils; public class MareConfigurationBase : IMareConfiguration { + public Uri MainServerAddress { get; set; } public int DbContextPoolSize { get; set; } = 100; public string ShardName { get; set; } = string.Empty; public int MetricsPort { get; set; } + public string Jwt { get; set; } = string.Empty; public T GetValue(string key) { @@ -39,6 +40,7 @@ public class MareConfigurationBase : IMareConfiguration { StringBuilder sb = new(); sb.AppendLine(base.ToString()); + sb.AppendLine($"{nameof(MainServerAddress)} => {MainServerAddress}"); sb.AppendLine($"{nameof(ShardName)} => {ShardName}"); sb.AppendLine($"{nameof(DbContextPoolSize)} => {DbContextPoolSize}"); return sb.ToString(); diff --git a/MareSynchronosServer/MareSynchronosShared/Utils/ServerConfiguration.cs b/MareSynchronosServer/MareSynchronosShared/Utils/ServerConfiguration.cs index 5a91b2c..33e2832 100644 --- a/MareSynchronosServer/MareSynchronosShared/Utils/ServerConfiguration.cs +++ b/MareSynchronosServer/MareSynchronosShared/Utils/ServerConfiguration.cs @@ -28,7 +28,6 @@ public class ServerConfiguration : MareConfigurationAuthBase { StringBuilder sb = new(); sb.AppendLine(base.ToString()); - sb.AppendLine($"{nameof(MainServerGrpcAddress)} => {MainServerGrpcAddress}"); sb.AppendLine($"{nameof(CdnFullUrl)} => {CdnFullUrl}"); sb.AppendLine($"{nameof(CdnShardConfiguration)} => {string.Join(", ", CdnShardConfiguration.Select(c => c.ToString()))}"); sb.AppendLine($"{nameof(StaticFileServiceAddress)} => {StaticFileServiceAddress}"); diff --git a/MareSynchronosServer/MareSynchronosShared/Utils/ServerTokenGenerator.cs b/MareSynchronosServer/MareSynchronosShared/Utils/ServerTokenGenerator.cs index 6080cd3..60df4c9 100644 --- a/MareSynchronosServer/MareSynchronosShared/Utils/ServerTokenGenerator.cs +++ b/MareSynchronosServer/MareSynchronosShared/Utils/ServerTokenGenerator.cs @@ -1,5 +1,5 @@ -using MareSynchronosShared.Services; -using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; using Microsoft.IdentityModel.Tokens; using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; @@ -9,7 +9,7 @@ namespace MareSynchronosShared.Utils; public class ServerTokenGenerator { - private readonly IConfigurationService _configuration; + private readonly IOptionsMonitor _configuration; private readonly ILogger _logger; private Dictionary _tokenDictionary { get; set; } = new(StringComparer.Ordinal); @@ -17,7 +17,7 @@ public class ServerTokenGenerator { get { - var currentJwt = _configuration.GetValue(nameof(MareConfigurationAuthBase.Jwt)); + var currentJwt = _configuration.CurrentValue.Jwt; if (_tokenDictionary.TryGetValue(currentJwt, out var token)) { return token; @@ -27,7 +27,7 @@ public class ServerTokenGenerator } } - public ServerTokenGenerator(IConfigurationService configuration, ILogger logger) + public ServerTokenGenerator(IOptionsMonitor configuration, ILogger logger) { _configuration = configuration; _logger = logger; @@ -35,14 +35,14 @@ public class ServerTokenGenerator private string GenerateToken() { - var signingKey = _configuration.GetValue(nameof(MareConfigurationAuthBase.Jwt)); + var signingKey = _configuration.CurrentValue.Jwt; var authSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(signingKey)); var token = new SecurityTokenDescriptor() { Subject = new ClaimsIdentity(new List() { - new Claim(MareClaimTypes.Uid, _configuration.GetValue(nameof(MareConfigurationBase.ShardName))), + new Claim(MareClaimTypes.Uid, _configuration.CurrentValue.ShardName), new Claim(MareClaimTypes.Internal, "true"), }), SigningCredentials = new SigningCredentials(authSigningKey, SecurityAlgorithms.HmacSha256Signature), diff --git a/MareSynchronosServer/MareSynchronosShared/Utils/ServicesConfiguration.cs b/MareSynchronosServer/MareSynchronosShared/Utils/ServicesConfiguration.cs index 6f8d18b..5768edc 100644 --- a/MareSynchronosServer/MareSynchronosShared/Utils/ServicesConfiguration.cs +++ b/MareSynchronosServer/MareSynchronosShared/Utils/ServicesConfiguration.cs @@ -6,6 +6,7 @@ public class ServicesConfiguration : MareConfigurationBase { public string DiscordBotToken { get; set; } = string.Empty; public Uri MainServerGrpcAddress { get; set; } = null; + public ulong? DiscordChannelForMessages { get; set; } = null; public override string ToString() { diff --git a/MareSynchronosServer/MareSynchronosShared/Utils/StaticFilesServerConfiguration.cs b/MareSynchronosServer/MareSynchronosShared/Utils/StaticFilesServerConfiguration.cs index eb781c5..f35e0fb 100644 --- a/MareSynchronosServer/MareSynchronosShared/Utils/StaticFilesServerConfiguration.cs +++ b/MareSynchronosServer/MareSynchronosShared/Utils/StaticFilesServerConfiguration.cs @@ -5,27 +5,24 @@ namespace MareSynchronosStaticFilesServer; public class StaticFilesServerConfiguration : MareConfigurationBase { - public Uri FileServerGrpcAddress { get; set; } = null; + public Uri? MainFileServerAddress { get; set; } = null; public int ForcedDeletionOfFilesAfterHours { get; set; } = -1; public double CacheSizeHardLimitInGiB { get; set; } = -1; public int UnusedFileRetentionPeriodInDays { get; set; } = 14; public string CacheDirectory { get; set; } - public Uri? RemoteCacheSourceUri { get; set; } = null; - public Uri MainServerGrpcAddress { get; set; } = null; public int DownloadQueueSize { get; set; } = 50; public int DownloadTimeoutSeconds { get; set; } = 5; public int DownloadQueueReleaseSeconds { get; set; } = 15; + public int DownloadQueueClearLimit { get; set; } = 15000; public override string ToString() { StringBuilder sb = new(); sb.AppendLine(base.ToString()); - sb.AppendLine($"{nameof(FileServerGrpcAddress)} => {FileServerGrpcAddress}"); - sb.AppendLine($"{nameof(MainServerGrpcAddress)} => {MainServerGrpcAddress}"); + sb.AppendLine($"{nameof(MainFileServerAddress)} => {MainFileServerAddress}"); sb.AppendLine($"{nameof(ForcedDeletionOfFilesAfterHours)} => {ForcedDeletionOfFilesAfterHours}"); sb.AppendLine($"{nameof(CacheSizeHardLimitInGiB)} => {CacheSizeHardLimitInGiB}"); sb.AppendLine($"{nameof(UnusedFileRetentionPeriodInDays)} => {UnusedFileRetentionPeriodInDays}"); sb.AppendLine($"{nameof(CacheDirectory)} => {CacheDirectory}"); - sb.AppendLine($"{nameof(RemoteCacheSourceUri)} => {RemoteCacheSourceUri}"); sb.AppendLine($"{nameof(DownloadQueueSize)} => {DownloadQueueSize}"); sb.AppendLine($"{nameof(DownloadQueueReleaseSeconds)} => {DownloadQueueReleaseSeconds}"); return sb.ToString(); diff --git a/MareSynchronosServer/MareSynchronosStaticFilesServer/Controllers/CacheController.cs b/MareSynchronosServer/MareSynchronosStaticFilesServer/Controllers/CacheController.cs index b058c1d..a81b3c5 100644 --- a/MareSynchronosServer/MareSynchronosStaticFilesServer/Controllers/CacheController.cs +++ b/MareSynchronosServer/MareSynchronosStaticFilesServer/Controllers/CacheController.cs @@ -1,5 +1,4 @@ using MareSynchronos.API.Routes; -using MareSynchronosShared.Utils; using MareSynchronosStaticFilesServer.Services; using MareSynchronosStaticFilesServer.Utils; using Microsoft.AspNetCore.Mvc; diff --git a/MareSynchronosServer/MareSynchronosStaticFilesServer/Controllers/RequestController.cs b/MareSynchronosServer/MareSynchronosStaticFilesServer/Controllers/RequestController.cs index 17b7f64..e4be17c 100644 --- a/MareSynchronosServer/MareSynchronosStaticFilesServer/Controllers/RequestController.cs +++ b/MareSynchronosServer/MareSynchronosStaticFilesServer/Controllers/RequestController.cs @@ -1,5 +1,4 @@ using MareSynchronos.API.Routes; -using MareSynchronosShared.Utils; using MareSynchronosStaticFilesServer.Services; using Microsoft.AspNetCore.Mvc; diff --git a/MareSynchronosServer/MareSynchronosStaticFilesServer/Controllers/ServerFilesController.cs b/MareSynchronosServer/MareSynchronosStaticFilesServer/Controllers/ServerFilesController.cs index 7d38da6..78e02e5 100644 --- a/MareSynchronosServer/MareSynchronosStaticFilesServer/Controllers/ServerFilesController.cs +++ b/MareSynchronosServer/MareSynchronosStaticFilesServer/Controllers/ServerFilesController.cs @@ -1,5 +1,4 @@ using MareSynchronos.API.Routes; -using MareSynchronosShared.Utils; using MareSynchronosStaticFilesServer.Services; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; diff --git a/MareSynchronosServer/MareSynchronosStaticFilesServer/Program.cs b/MareSynchronosServer/MareSynchronosStaticFilesServer/Program.cs index f0721d2..9b58f03 100644 --- a/MareSynchronosServer/MareSynchronosStaticFilesServer/Program.cs +++ b/MareSynchronosServer/MareSynchronosStaticFilesServer/Program.cs @@ -24,13 +24,21 @@ public class Program host.Run(); } - public static IHostBuilder CreateHostBuilder(string[] args) => - Host.CreateDefaultBuilder(args) + public static IHostBuilder CreateHostBuilder(string[] args) + { + var loggerFactory = LoggerFactory.Create(builder => + { + builder.ClearProviders(); + builder.AddConsole(); + }); + var logger = loggerFactory.CreateLogger(); + return Host.CreateDefaultBuilder(args) .UseSystemd() .UseConsoleLifetime() .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseContentRoot(AppContext.BaseDirectory); - webBuilder.UseStartup(); + webBuilder.UseStartup(ctx => new Startup(ctx.Configuration, logger)); }); + } } \ No newline at end of file diff --git a/MareSynchronosServer/MareSynchronosStaticFilesServer/Services/CachedFileProvider.cs b/MareSynchronosServer/MareSynchronosStaticFilesServer/Services/CachedFileProvider.cs index dbd7ac8..d3ba1d0 100644 --- a/MareSynchronosServer/MareSynchronosStaticFilesServer/Services/CachedFileProvider.cs +++ b/MareSynchronosServer/MareSynchronosStaticFilesServer/Services/CachedFileProvider.cs @@ -26,7 +26,7 @@ public class CachedFileProvider _fileStatisticsService = fileStatisticsService; _metrics = metrics; _generator = generator; - _remoteCacheSourceUri = configuration.GetValueOrDefault(nameof(StaticFilesServerConfiguration.RemoteCacheSourceUri), null); + _remoteCacheSourceUri = configuration.GetValueOrDefault(nameof(StaticFilesServerConfiguration.MainFileServerAddress), null); _basePath = configuration.GetValue(nameof(StaticFilesServerConfiguration.CacheDirectory)); _httpClient = new HttpClient(); } diff --git a/MareSynchronosServer/MareSynchronosStaticFilesServer/Services/RequestQueueService.cs b/MareSynchronosServer/MareSynchronosStaticFilesServer/Services/RequestQueueService.cs index d1ca796..76ea2ba 100644 --- a/MareSynchronosServer/MareSynchronosStaticFilesServer/Services/RequestQueueService.cs +++ b/MareSynchronosServer/MareSynchronosStaticFilesServer/Services/RequestQueueService.cs @@ -1,5 +1,4 @@ -using MareSynchronos.API.Routes; -using MareSynchronosShared.Metrics; +using MareSynchronosShared.Metrics; using MareSynchronosShared.Services; using MareSynchronosStaticFilesServer.Utils; using Microsoft.AspNetCore.SignalR; @@ -19,6 +18,7 @@ public class RequestQueueService : IHostedService private readonly int _queueExpirationSeconds; private readonly SemaphoreSlim _queueSemaphore = new(1); private readonly SemaphoreSlim _queueProcessingSemaphore = new(1); + private int _queueLimitForReset; private System.Timers.Timer _queueTimer; private readonly ConcurrentDictionary _queueRemoval = new(); @@ -26,6 +26,7 @@ public class RequestQueueService : IHostedService { _userQueueRequests = new UserQueueEntry[configurationService.GetValueOrDefault(nameof(StaticFilesServerConfiguration.DownloadQueueSize), 50)]; _queueExpirationSeconds = configurationService.GetValueOrDefault(nameof(StaticFilesServerConfiguration.DownloadTimeoutSeconds), 5); + _queueLimitForReset = configurationService.GetValueOrDefault(nameof(StaticFilesServerConfiguration.DownloadQueueClearLimit), 15000); _metrics = metrics; _logger = logger; _hubContext = hubContext; @@ -120,6 +121,12 @@ public class RequestQueueService : IHostedService try { + if (_queue.Count > _queueLimitForReset) + { + _queue.Clear(); + return; + } + Parallel.For(0, _userQueueRequests.Length, new ParallelOptions() { MaxDegreeOfParallelism = 10, diff --git a/MareSynchronosServer/MareSynchronosStaticFilesServer/Startup.cs b/MareSynchronosServer/MareSynchronosStaticFilesServer/Startup.cs index c471caf..89bfbe2 100644 --- a/MareSynchronosServer/MareSynchronosStaticFilesServer/Startup.cs +++ b/MareSynchronosServer/MareSynchronosStaticFilesServer/Startup.cs @@ -1,24 +1,21 @@ using Grpc.Net.Client.Configuration; -using Grpc.Net.ClientFactory; -using MareSynchronos.API; using MareSynchronosShared.Data; using MareSynchronosShared.Metrics; -using MareSynchronosShared.Protos; using MareSynchronosShared.Services; using MareSynchronosShared.Utils; +using MareSynchronosStaticFilesServer.Controllers; using MareSynchronosStaticFilesServer.Services; using MareSynchronosStaticFilesServer.Utils; using MessagePack; using MessagePack.Resolvers; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc.Controllers; using Microsoft.AspNetCore.Server.Kestrel.Core; using Microsoft.AspNetCore.SignalR; using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.Options; using Microsoft.IdentityModel.Tokens; using Prometheus; -using StackExchange.Redis; using System.Text; namespace MareSynchronosStaticFilesServer; @@ -26,11 +23,14 @@ namespace MareSynchronosStaticFilesServer; public class Startup { private bool _isMain; - public Startup(IConfiguration configuration) + private readonly ILogger _logger; + + public Startup(IConfiguration configuration, ILogger logger) { Configuration = configuration; + _logger = logger; var mareSettings = Configuration.GetRequiredSection("MareSynchronos"); - _isMain = string.IsNullOrEmpty(mareSettings.GetValue(nameof(StaticFilesServerConfiguration.RemoteCacheSourceUri), string.Empty)); + _isMain = string.IsNullOrEmpty(mareSettings.GetValue(nameof(StaticFilesServerConfiguration.MainFileServerAddress), string.Empty)); } public IConfiguration Configuration { get; } @@ -83,30 +83,6 @@ public class Startup RetryPolicy = null, }; - services.AddGrpcClient("FileServer", c => - { - c.Address = new Uri(mareConfig.GetValue(nameof(StaticFilesServerConfiguration.FileServerGrpcAddress))); - }).ConfigureChannel(c => - { - c.ServiceConfig = new ServiceConfig { MethodConfigs = { noRetryConfig } }; - c.HttpHandler = new SocketsHttpHandler() - { - EnableMultipleHttp2Connections = true, - }; - }); - - services.AddGrpcClient("MainServer", c => - { - c.Address = new Uri(mareConfig.GetValue(nameof(StaticFilesServerConfiguration.MainServerGrpcAddress))); - }).ConfigureChannel(c => - { - c.ServiceConfig = new ServiceConfig { MethodConfigs = { noRetryConfig } }; - c.HttpHandler = new SocketsHttpHandler() - { - EnableMultipleHttp2Connections = true, - }; - }); - services.AddOptions(JwtBearerDefaults.AuthenticationScheme) .Configure>((o, s) => { @@ -144,26 +120,27 @@ public class Startup } else { - services.AddSingleton>(p => new MareConfigurationServiceClient( - p.GetRequiredService>>(), - p.GetRequiredService>(), - p.GetRequiredService(), - "FileServer")); - + services.AddSingleton, MareConfigurationServiceClient>(); services.AddHostedService(p => (MareConfigurationServiceClient)p.GetService>()); } - services.AddSingleton>(p => - new MareConfigurationServiceClient( - p.GetRequiredService>>(), - p.GetService>(), - p.GetRequiredService(), "MainServer") - ); + services.AddSingleton, MareConfigurationServiceClient>(); services.AddSingleton(); services.AddSingleton(); services.AddHostedService(p => p.GetService()); - services.AddControllers(); + services.AddControllers().ConfigureApplicationPartManager(a => + { + a.FeatureProviders.Remove(a.FeatureProviders.OfType().First()); + if (_isMain) + { + a.FeatureProviders.Add(new AllowedControllersFeatureProvider(typeof(MareStaticFilesServerConfigurationController), typeof(CacheController), typeof(RequestController), typeof(ServerFilesController))); + } + else + { + a.FeatureProviders.Add(new AllowedControllersFeatureProvider(typeof(CacheController), typeof(RequestController))); + } + }); services.AddHostedService(p => (MareConfigurationServiceClient)p.GetService>()); @@ -198,7 +175,6 @@ public class Startup signalRServiceBuilder.AddStackExchangeRedis(redisConnection, options => { }); services.AddHealthChecks(); - services.AddControllers(); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env)