Startup.cs 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. using System;
  2. using System.Net.WebSockets;
  3. using BubbleSocketCore.Handlers;
  4. using Microsoft.AspNetCore.Builder;
  5. using Microsoft.AspNetCore.Hosting;
  6. using Microsoft.Extensions.Configuration;
  7. using Microsoft.Extensions.DependencyInjection;
  8. using Microsoft.Extensions.Logging;
  9. using Microsoft.AspNetCore.Authentication.JwtBearer;
  10. using Microsoft.IdentityModel.Tokens;
  11. using System.Text;
  12. using System.IO;
  13. using Microsoft.Extensions.FileProviders;
  14. using Microsoft.AspNetCore.Cors.Infrastructure;
  15. using Microsoft.AspNetCore.Http;
  16. using Microsoft.Extensions.Hosting;
  17. using System.Threading;
  18. using BubbleSocketCore.Simulation;
  19. namespace BubbleSocketCore
  20. {
  21. public class Startup
  22. {
  23. public IConfiguration Configuration { get; }
  24. public CancellationTokenSource serverShutdown;
  25. public Startup(IConfiguration configuration)
  26. {
  27. Configuration = configuration;
  28. serverShutdown = new CancellationTokenSource();
  29. }
  30. public void ConfigureServices(IServiceCollection services)
  31. {
  32. services.AddHostedService<TickService>();
  33. services.AddControllers();
  34. services.AddAuthentication(options =>
  35. {
  36. options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
  37. options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
  38. options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
  39. }).AddJwtBearer(options =>
  40. {
  41. options.RequireHttpsMetadata = false;
  42. options.SaveToken = true;
  43. options.TokenValidationParameters = new TokenValidationParameters()
  44. {
  45. ValidateIssuerSigningKey = true,
  46. IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["JwtSettings:SecretKey"])),
  47. ValidateIssuer = true,
  48. ValidIssuer = Configuration["JwtSettings:Issuer"],
  49. ValidateAudience = true,
  50. ValidAudience = Configuration["JwtSettings:Audience"],
  51. ValidateLifetime = true,
  52. ClockSkew = TimeSpan.FromMinutes(Configuration.GetValue<int>("JwtSettings:ExpirationInHours"))
  53. };
  54. });
  55. services.AddMvc();
  56. services.AddCors(options =>
  57. {
  58. options.AddPolicy(name: "bubblesocket_corspolicy",
  59. policy =>
  60. {
  61. policy.AllowAnyOrigin();
  62. policy.AllowAnyMethod();
  63. policy.AllowAnyHeader();
  64. });
  65. });
  66. }
  67. public void Configure(
  68. IApplicationBuilder app,
  69. IWebHostEnvironment env,
  70. ILogger<Startup> logger,
  71. ICorsService corsService,
  72. ICorsPolicyProvider corsPolicyProvider
  73. )
  74. {
  75. string errorPath = Path.Combine(Directory.GetCurrentDirectory(), Configuration.GetValue<string>("RelativeErrorFilePath"));
  76. logger.LogInformation($"Loading static error pages from {errorPath}");
  77. app.UseStatusCodePages(new StatusCodePagesOptions()
  78. {
  79. HandleAsync = async (context) =>
  80. {
  81. var filePath = Path.Combine(errorPath, context.HttpContext.Response.StatusCode + ".html");
  82. var responseMessage = $"Error {context.HttpContext.Response.StatusCode}";
  83. if (System.IO.File.Exists(filePath))
  84. {
  85. responseMessage = System.IO.File.ReadAllText(filePath);
  86. }
  87. await context.HttpContext.Response.WriteAsync(responseMessage);
  88. }
  89. });
  90. string staticPath = Path.Combine(Directory.GetCurrentDirectory(), Configuration.GetValue<string>("RelativeStaticFilePath"));
  91. logger.LogInformation($"Loading static files from {staticPath}");
  92. PhysicalFileProvider staticFileProvider = new PhysicalFileProvider(staticPath);
  93. app.UseDefaultFiles(new DefaultFilesOptions()
  94. {
  95. FileProvider = staticFileProvider,
  96. DefaultFileNames = new string[] { "index.html" }
  97. });
  98. app.UseStaticFiles(new StaticFileOptions()
  99. {
  100. FileProvider = staticFileProvider,
  101. ServeUnknownFileTypes = true,
  102. OnPrepareResponse = (ctx) =>
  103. {
  104. var policy = corsPolicyProvider.GetPolicyAsync(ctx.Context, "bubblesocket_corspolicy")
  105. .ConfigureAwait(false)
  106. .GetAwaiter().GetResult();
  107. var corsResult = corsService.EvaluatePolicy(ctx.Context, policy);
  108. corsService.ApplyResult(corsResult, ctx.Context.Response);
  109. }
  110. });
  111. app.UseRouting();
  112. app.UseCors("bubblesocket_corspolicy");
  113. app.UseAuthentication();
  114. app.UseAuthorization();
  115. app.UseEndpoints(endpoints =>
  116. {
  117. endpoints.MapControllers();
  118. });
  119. app.UseWebSockets(new WebSocketOptions()
  120. {
  121. KeepAliveInterval = TimeSpan.FromSeconds(120)
  122. });
  123. app.Use(async (context, next) =>
  124. {
  125. try
  126. {
  127. IHandler handler = new HandlerFactory(Configuration, app.ApplicationServices.GetService<ILoggerFactory>()).Get(context.Request);
  128. if (context.WebSockets.IsWebSocketRequest)
  129. {
  130. using (WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync())
  131. {
  132. handler.AddSocket(webSocket);
  133. try
  134. {
  135. await handler.Listen(context, webSocket, serverShutdown.Token);
  136. }
  137. catch (WebSocketException)
  138. {
  139. //unhandled socket exception!
  140. }
  141. }
  142. }
  143. else
  144. {
  145. await next();
  146. }
  147. }
  148. catch (HandlerNotFoundException)
  149. {
  150. // await webSocket.CloseOutputAsync(WebSocketCloseStatus.EndpointUnavailable, $"Websocket protocol not found: {e.Message}", CancellationToken.None);
  151. }
  152. catch (Exception e)
  153. {
  154. logger.LogError($"Unexpected Error: {e.Message}");
  155. }
  156. });
  157. app.ApplicationServices.GetRequiredService<IHostApplicationLifetime>().ApplicationStopping.Register(() => {
  158. serverShutdown.Cancel();
  159. });
  160. }
  161. //frame
  162. //frame id (int counting up? deterministic uuid?)
  163. //ms it started
  164. //inputs pressed
  165. //each frame is 16ms (Time % 16) //need synchronize step for setInterval
  166. //last frame id seen
  167. //simulation
  168. //keeps position of all entities each frame for 10 seconds (160 frames stored)
  169. //if player gives a frameid that's too old, player gets force-updated simulation
  170. //sort list of inputs based on ms & adjust game state
  171. //game
  172. //3 frame input delay (48ms) //maybe determine based on latency of players in sector?
  173. }
  174. }