You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

217 lines
7.6 KiB

  1. using Microsoft.AspNetCore.Authentication;
  2. using Microsoft.AspNetCore.Builder;
  3. using Microsoft.AspNetCore.Mvc;
  4. using Microsoft.Extensions.Configuration;
  5. using Microsoft.Extensions.DependencyInjection;
  6. using Microsoft.Net.Http.Headers;
  7. using Microsoft.OpenApi.Models;
  8. using Microsoft.Scripting.Utils;
  9. using MQTTnet.Server.Configuration;
  10. using MQTTnet.Server.Logging;
  11. using MQTTnet.Server.Mqtt;
  12. using MQTTnet.Server.Scripting;
  13. using MQTTnet.Server.Scripting.DataSharing;
  14. using Newtonsoft.Json.Converters;
  15. using Swashbuckle.AspNetCore.SwaggerUI;
  16. using System;
  17. using System.Collections.Generic;
  18. using System.Linq;
  19. using System.Net;
  20. namespace MQTTnet.Server.Web
  21. {
  22. public class Startup
  23. {
  24. public Startup(IConfiguration configuration)
  25. {
  26. var builder = new ConfigurationBuilder()
  27. .AddJsonFile("appsettings.json")
  28. .AddEnvironmentVariables();
  29. Configuration = builder.Build();
  30. }
  31. public IConfigurationRoot Configuration { get; }
  32. public void Configure(
  33. IApplicationBuilder application,
  34. MqttServerService mqttServerService,
  35. PythonScriptHostService pythonScriptHostService,
  36. DataSharingService dataSharingService,
  37. MqttSettingsModel mqttSettings)
  38. {
  39. application.UseHsts();
  40. application.UseRouting();
  41. application.UseCors(x => x
  42. .AllowAnyOrigin()
  43. .AllowAnyMethod()
  44. .AllowAnyHeader());
  45. application.UseAuthentication();
  46. application.UseAuthorization();
  47. application.UseStaticFiles();
  48. application.UseEndpoints(endpoints =>
  49. {
  50. endpoints.MapControllers();
  51. });
  52. ConfigureWebSocketEndpoint(application, mqttServerService, mqttSettings);
  53. dataSharingService.Configure();
  54. pythonScriptHostService.Configure();
  55. mqttServerService.Configure();
  56. application.UseSwagger(o => o.RouteTemplate = "/api/{documentName}/swagger.json");
  57. application.UseSwaggerUI(o =>
  58. {
  59. o.RoutePrefix = "api";
  60. o.DocumentTitle = "MQTTnet.Server API";
  61. o.SwaggerEndpoint("/api/v1/swagger.json", "MQTTnet.Server API v1");
  62. o.DisplayRequestDuration();
  63. o.DocExpansion(DocExpansion.List);
  64. o.DefaultModelRendering(ModelRendering.Model);
  65. });
  66. }
  67. public void ConfigureServices(IServiceCollection services)
  68. {
  69. services.AddCors();
  70. services.AddControllers();
  71. services.AddMvc()
  72. .SetCompatibilityVersion(CompatibilityVersion.Version_3_0)
  73. .AddNewtonsoftJson(o =>
  74. {
  75. o.SerializerSettings.Converters.Add(new StringEnumConverter());
  76. });
  77. ReadMqttSettings(services);
  78. services.AddSingleton<PythonIOStream>();
  79. services.AddSingleton<PythonScriptHostService>();
  80. services.AddSingleton<DataSharingService>();
  81. services.AddSingleton<MqttNetLoggerWrapper>();
  82. services.AddSingleton<CustomMqttFactory>();
  83. services.AddSingleton<MqttServerService>();
  84. services.AddSingleton<MqttServerStorage>();
  85. services.AddSingleton<MqttClientConnectedHandler>();
  86. services.AddSingleton<MqttClientDisconnectedHandler>();
  87. services.AddSingleton<MqttClientSubscribedTopicHandler>();
  88. services.AddSingleton<MqttClientUnsubscribedTopicHandler>();
  89. services.AddSingleton<MqttServerConnectionValidator>();
  90. services.AddSingleton<MqttSubscriptionInterceptor>();
  91. services.AddSingleton<MqttUnsubscriptionInterceptor>();
  92. services.AddSingleton<MqttApplicationMessageInterceptor>();
  93. services.AddSwaggerGen(c =>
  94. {
  95. var securityScheme = new OpenApiSecurityScheme
  96. {
  97. Scheme = "Basic",
  98. Name = HeaderNames.Authorization,
  99. Type = SecuritySchemeType.Http,
  100. In = ParameterLocation.Header
  101. };
  102. c.AddSecurityDefinition("Swagger", securityScheme);
  103. c.AddSecurityRequirement(new OpenApiSecurityRequirement
  104. {
  105. [securityScheme] = new List<string>()
  106. });
  107. c.SwaggerDoc("v1", new OpenApiInfo
  108. {
  109. Title = "MQTTnet.Server API",
  110. Version = "v1",
  111. Description = "The public API for the MQTT broker MQTTnet.Server.",
  112. License = new OpenApiLicense
  113. {
  114. Name = "MIT",
  115. Url = new Uri("https://github.com/chkr1011/MQTTnet/blob/master/README.md")
  116. },
  117. Contact = new OpenApiContact
  118. {
  119. Name = "MQTTnet.Server",
  120. Email = string.Empty,
  121. Url = new Uri("https://github.com/chkr1011/MQTTnet")
  122. },
  123. });
  124. });
  125. services.AddAuthentication("Basic")
  126. .AddScheme<AuthenticationSchemeOptions, AuthenticationHandler>("Basic", null)
  127. .AddCookie();
  128. }
  129. private void ReadMqttSettings(IServiceCollection services)
  130. {
  131. var mqttSettings = new MqttSettingsModel();
  132. Configuration.Bind("MQTT", mqttSettings);
  133. services.AddSingleton(mqttSettings);
  134. var scriptingSettings = new ScriptingSettingsModel();
  135. Configuration.Bind("Scripting", scriptingSettings);
  136. services.AddSingleton(scriptingSettings);
  137. }
  138. private static void ConfigureWebSocketEndpoint(
  139. IApplicationBuilder application,
  140. MqttServerService mqttServerService,
  141. MqttSettingsModel mqttSettings)
  142. {
  143. if (mqttSettings?.WebSocketEndPoint?.Enabled != true)
  144. {
  145. return;
  146. }
  147. if (string.IsNullOrEmpty(mqttSettings.WebSocketEndPoint.Path))
  148. {
  149. return;
  150. }
  151. var webSocketOptions = new WebSocketOptions
  152. {
  153. KeepAliveInterval = TimeSpan.FromSeconds(mqttSettings.WebSocketEndPoint.KeepAliveInterval),
  154. ReceiveBufferSize = mqttSettings.WebSocketEndPoint.ReceiveBufferSize
  155. };
  156. if (mqttSettings.WebSocketEndPoint.AllowedOrigins?.Any() == true)
  157. {
  158. webSocketOptions.AllowedOrigins.AddRange(mqttSettings.WebSocketEndPoint.AllowedOrigins);
  159. }
  160. application.UseWebSockets(webSocketOptions);
  161. application.Use(async (context, next) =>
  162. {
  163. if (context.Request.Path == mqttSettings.WebSocketEndPoint.Path)
  164. {
  165. if (context.WebSockets.IsWebSocketRequest)
  166. {
  167. using (var webSocket = await context.WebSockets.AcceptWebSocketAsync().ConfigureAwait(false))
  168. {
  169. await mqttServerService.RunWebSocketConnectionAsync(webSocket, context).ConfigureAwait(false);
  170. }
  171. }
  172. else
  173. {
  174. context.Response.StatusCode = (int)HttpStatusCode.BadRequest;
  175. }
  176. }
  177. else
  178. {
  179. await next().ConfigureAwait(false);
  180. }
  181. });
  182. }
  183. }
  184. }