using System.Net; using System.Text.Json; using HermesSocketLibrary; using HermesSocketLibrary.db; using HermesSocketLibrary.Requests; using HermesSocketServer; using HermesSocketServer.Requests; using HermesSocketServer.Socket; using HermesSocketServer.Socket.Handlers; using Microsoft.AspNetCore.HttpOverrides; using Serilog; using Serilog.Events; using YamlDotNet.Serialization; using YamlDotNet.Serialization.NamingConventions; var deserializer = new DeserializerBuilder() .WithNamingConvention(HyphenatedNamingConvention.Instance) .Build(); var configFileName = "server.config.yml"; if (File.Exists("server.config." + Environment.GetEnvironmentVariable("TTS_ENV").ToLower() + ".yml")) configFileName = "server.config." + Environment.GetEnvironmentVariable("TTS_ENV").ToLower() + ".yml"; var configContent = File.ReadAllText(configFileName); var configuration = deserializer.Deserialize(configContent); if (configuration.Environment.ToUpper() != "QA" && configuration.Environment.ToUpper() != "PROD") throw new Exception("Invalid environment set."); var builder = WebApplication.CreateBuilder(args); builder.Logging.ClearProviders(); builder.Services.Configure(options => { options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto; }); builder.WebHost.UseUrls($"http://{configuration.WebsocketServer.Host}:{configuration.WebsocketServer.Port}"); var logger = new LoggerConfiguration() .MinimumLevel.Debug() .Enrich.FromLogContext() .WriteTo.File("logs/log.log", rollingInterval: RollingInterval.Day, retainedFileCountLimit: 7) .WriteTo.Console(restrictedToMinimumLevel: LogEventLevel.Information) .CreateLogger(); builder.Host.UseSerilog(logger); builder.Logging.AddSerilog(logger); var s = builder.Services; s.AddSerilog(); s.AddSingleton(configuration); s.AddSingleton(); // Socket message handlers s.AddSingleton(logger); s.AddKeyedSingleton("hermes-heartbeat"); s.AddKeyedSingleton("hermes-hermeslogin"); s.AddKeyedSingleton("hermes-request"); s.AddKeyedSingleton("hermes-error"); s.AddKeyedSingleton("hermes-chatter"); s.AddKeyedSingleton("hermes-emotedetails"); s.AddKeyedSingleton("hermes-emoteusage"); // Request handlers s.AddKeyedSingleton("BanTTSUser"); s.AddKeyedSingleton("GetTTSUsers"); s.AddKeyedSingleton("GetTTSVoices"); s.AddKeyedSingleton("GetTTSWordFilters"); s.AddKeyedSingleton("CreateTTSUser"); s.AddKeyedSingleton("CreateTTSVoice"); s.AddKeyedSingleton("DeleteTTSVoice"); s.AddKeyedSingleton("UpdateTTSUser"); s.AddKeyedSingleton("UpdateTTSVoice"); s.AddKeyedSingleton("GetChatterIds"); s.AddKeyedSingleton("GetEmotes"); s.AddKeyedSingleton("UpdateTTSVoiceState"); s.AddSingleton(); s.AddSingleton(); s.AddSingleton(); s.AddSingleton(new JsonSerializerOptions() { PropertyNameCaseInsensitive = false, PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower }); s.AddSingleton(); var app = builder.Build(); app.UseForwardedHeaders(); app.UseSerilogRequestLogging(); app.UseWebSockets(new WebSocketOptions() { KeepAliveInterval = TimeSpan.FromSeconds(30) }); var options = app.Services.GetRequiredService(); var server = app.Services.GetRequiredService(); app.Use(async (HttpContext context, RequestDelegate next) => { if (context.Request.Path != "/") { context.Response.StatusCode = StatusCodes.Status403Forbidden; return; } if (context.WebSockets.IsWebSocketRequest) { using var webSocket = await context.WebSockets.AcceptWebSocketAsync(); await server.Handle(new WebSocketUser(webSocket, IPAddress.Parse(context.Request.Headers["X-Forwarded-For"].ToString()), options, logger), context); } else { context.Response.StatusCode = StatusCodes.Status400BadRequest; } }); await app.RunAsync();