AspNetCoreWebApiCommunicatorProvider.cs 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. using Edge.Core.UniversalApi;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Threading.Tasks;
  6. using Microsoft.AspNetCore.Hosting;
  7. using Microsoft.Extensions.DependencyInjection;
  8. using Microsoft.Extensions.Hosting;
  9. using Microsoft.AspNetCore;
  10. using MQTTnet.AspNetCore;
  11. using Edge.Core.Processor;
  12. using Edge.Core.Configuration;
  13. using Microsoft.Extensions.Logging;
  14. using Edge.Core;
  15. using Edge.Core.Processor.Dispatcher;
  16. namespace Edge.WebHost
  17. {
  18. public class AspNetCoreWebApiCommunicatorProvider : ICommunicationProvider
  19. {
  20. public static UniversalApiHub UniversalApiHub { get; private set; }
  21. private bool isWebHostStarted = false;
  22. private IHost webHost;
  23. private IServiceProvider appServices;
  24. private IEnumerable<IProcessor> processors;
  25. public AspNetCoreWebApiCommunicatorProvider(IServiceProvider appServices)
  26. {
  27. this.appServices = appServices;
  28. }
  29. public void Dispose()
  30. {
  31. this.webHost?.Dispose();
  32. this.webHost?.StopAsync().Wait();
  33. }
  34. public IEnumerable<UniversalApiInfoDoc> GetApiDocuments()
  35. {
  36. var pDescriptors = this.processors.Select(p => p.ProcessorDescriptor())
  37. .Where(d => d.UniversalApiInfos != null && d.UniversalApiInfos.Any());
  38. return pDescriptors.SelectMany(pd => pd.UniversalApiInfos).Select(apiInfo =>
  39. {
  40. var doc = new UniversalApiInfoDoc()
  41. {
  42. ProviderType = apiInfo.Processor.ProcessorDescriptor().DeviceHandlerOrApp.GetType().FullName
  43. //+ ", " + apiInfo.Processor.MetaConfigName
  44. ,
  45. BaseCategory = apiInfo.ServiceApiInfo == null ?
  46. (apiInfo.PropertyApiInfo == null ? "Event" : "Property") : "Service",
  47. ProviderConfigName = apiInfo.Processor.MetaConfigName,
  48. Description = apiInfo.ApiAttribute.Description,
  49. InputParametersExampleJson = apiInfo.ApiAttribute.InputParametersExampleJson,
  50. //InputParameters = apiInfo.ServiceApiInfo == null ?
  51. // // for event, providing the EventDataType
  52. // (apiInfo.PropertyApiInfo == null ?
  53. // (apiInfo.EventApiInfo?.EventDataType?.ToString() ?? "")
  54. // : apiInfo.PropertyApiInfo.PropertyType.ToString()) :
  55. // // for service, providing the parameter list
  56. // apiInfo.ServiceApiInfo.GetParameters()?.Select(p => p.ParameterType.Name + " " + (p.Name ?? ""))?.Aggregate("", (acc, n) => (string.IsNullOrEmpty(acc) ? "" : (acc + ", ")) + n) ?? "",
  57. };
  58. var rawTags = new Type[] { apiInfo.Processor.ProcessorDescriptor().DeviceHandlerOrApp.GetType() }.ExtractProcessorMetaDescriptor(true).FirstOrDefault()?.Tags;
  59. if (rawTags != null)
  60. {
  61. var localizedTags = new List<string>();
  62. foreach (var t in rawTags)
  63. localizedTags.Add(t.LocalizedContent("en"));
  64. doc.ProviderTags = localizedTags.ToArray();
  65. }
  66. string apiName = null;
  67. string path = null;
  68. string[] inputParametersJsonSchemaStrings = null;
  69. string outputParameterJsonSchema = null;
  70. if (apiInfo.ServiceApiInfo != null)
  71. {
  72. apiName = apiInfo.ServiceApiInfo.Name;
  73. path = $"/u/?apitype=service&an={apiName}&pn={apiInfo.Processor.MetaConfigName}&en={apiInfo.Processor.ProcessorDescriptor().DeviceHandlerOrApp.GetType().FullName}";
  74. inputParametersJsonSchemaStrings = apiInfo.ServiceApiInfo.ResolveParamsJsonSchemas().ToArray();
  75. outputParameterJsonSchema = apiInfo.ServiceApiInfo.ReturnType.GetGenericArguments().FirstOrDefault()?.ResolveParamsJsonSchema();
  76. }
  77. else if (apiInfo.PropertyApiInfo != null)
  78. {
  79. apiName = apiInfo.PropertyApiInfo.Name;
  80. path = $"/u/?apitype=property&an={apiName}&pn={apiInfo.Processor.MetaConfigName}&en={apiInfo.Processor.ProcessorDescriptor().DeviceHandlerOrApp.GetType().FullName}";
  81. if (!apiInfo.PropertyApiInfo.CanWrite
  82. || apiInfo.PropertyApiInfo.SetMethod == null
  83. || (apiInfo.PropertyApiInfo.SetMethod?.IsPrivate ?? false))
  84. {
  85. // indicates this Property is read-only
  86. inputParametersJsonSchemaStrings = null;
  87. }
  88. else
  89. inputParametersJsonSchemaStrings = new string[] { apiInfo.PropertyApiInfo.ResolveParamsJsonSchemas() };
  90. outputParameterJsonSchema = apiInfo.PropertyApiInfo.ResolveParamsJsonSchemas();
  91. }
  92. else if (apiInfo.EventApiInfo != null)
  93. {
  94. outputParameterJsonSchema = apiInfo.EventApiInfo.EventDataType?.ResolveParamsJsonSchema();
  95. }
  96. doc.ApiName = apiName;
  97. doc.Path = path;
  98. doc.InputParametersJsonSchemaStrings = inputParametersJsonSchemaStrings;
  99. doc.InputParametersExampleJson = doc.InputParametersExampleJson ?? inputParametersJsonSchemaStrings?.GenerateParametersJsonSample();
  100. doc.OutputParametersJsonSchema = outputParameterJsonSchema;
  101. doc.OutputParametersExampleJson = doc.OutputParametersExampleJson ?? outputParameterJsonSchema?.GenerateParameterJsonSample();
  102. return doc;
  103. });
  104. return Enumerable.Empty<UniversalApiInfoDoc>();
  105. //throw new NotImplementedException();
  106. }
  107. public Task<bool> RouteEventAsync(IProcessor eventSource, EventDescriptor eventDescriptor)
  108. {
  109. //does not support event yet.
  110. return Task.FromResult(false);
  111. }
  112. public async Task SetupAsync(IEnumerable<IProcessor> processors)
  113. {
  114. UniversalApiHub = this.appServices.GetRequiredService<UniversalApiHub>();
  115. this.processors = processors;
  116. if (this.isWebHostStarted) return;
  117. var configurator = this.appServices.GetService<Configurator>();
  118. var httpListeningIp = configurator.MetaConfiguration.Parameter?.FirstOrDefault(p => p.Name == "WebHostHttpListeningIp")?.Value ?? "*";
  119. var httpListeningPort = configurator.MetaConfiguration.Parameter?.FirstOrDefault(p => p.Name == "WebHostHttpListeningPort")?.Value ?? "8384";
  120. var mqttServerTcpListeningIp = configurator.MetaConfiguration.Parameter?.FirstOrDefault(p => p.Name == "MqttServerTcpListeningIp")?.Value ?? "*";
  121. var mqttServerTcpListeningPort = configurator.MetaConfiguration.Parameter?.FirstOrDefault(p => p.Name == "MqttServerTcpListeningPort")?.Value ?? "8388";
  122. this.webHost = CreateHostBuilder(
  123. new string[] { "%LAUNCHER_ARGS%" },
  124. httpListeningIp,
  125. int.Parse(httpListeningPort),
  126. mqttServerTcpListeningIp,
  127. int.Parse(mqttServerTcpListeningPort)).Build();
  128. await this.webHost.StartAsync();
  129. this.isWebHostStarted = true;
  130. }
  131. private IHostBuilder CreateHostBuilder(string[] args,
  132. string httpListeningIp, int httpListeningPort,
  133. string mqttServerTcpListeningIp,
  134. int mqttServerTcpListeningPort
  135. ) =>
  136. Host.CreateDefaultBuilder(args)
  137. .ConfigureServices((hostBuilderContext, aspNetCoreServices) =>
  138. {
  139. aspNetCoreServices.Configure<HostOptions>(option =>
  140. {
  141. option.ShutdownTimeout = TimeSpan.FromSeconds(60);
  142. });
  143. Func<IEnumerable<IProcessor>> pFactory = () => processors;
  144. aspNetCoreServices.AddSingleton(pFactory);
  145. aspNetCoreServices.AddSingleton(this.appServices.GetRequiredService<UniversalApiHub>());
  146. aspNetCoreServices.AddSingleton(this.appServices.GetRequiredService<UniversalApiInvoker>());
  147. aspNetCoreServices.AddSingleton(this.appServices.GetService<IProcessorMetaConfigAccessor>());
  148. })
  149. //.ConfigureLogging(logging => logging.SetMinimumLevel(LogLevel.Error))
  150. .ConfigureWebHostDefaults(webBuilder =>
  151. {
  152. webBuilder.ConfigureKestrel(o =>
  153. {
  154. if (mqttServerTcpListeningIp == "*")
  155. o.ListenAnyIP(mqttServerTcpListeningPort, l => l.UseMqtt()); // MQTT pipeline
  156. else
  157. o.Listen(System.Net.IPAddress.Parse(mqttServerTcpListeningIp), mqttServerTcpListeningPort, l => l.UseMqtt()); // MQTT pipeline
  158. if (httpListeningIp == "*")
  159. o.ListenAnyIP(httpListeningPort);// Default HTTP pipeline
  160. else
  161. o.Listen(System.Net.IPAddress.Parse(httpListeningIp), httpListeningPort);// Default HTTP pipeline
  162. });
  163. webBuilder.UseStartup<Startup>();
  164. //webBuilder.UseUrls(url);
  165. });
  166. }
  167. }