HomeController.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  1. using Edge.Core.Processor;
  2. using Edge.Core.UniversalApi;
  3. using Microsoft.AspNetCore.Mvc;
  4. using Microsoft.Extensions.Logging;
  5. using Microsoft.Net.Http.Headers;
  6. using System;
  7. using System.Collections.Generic;
  8. using System.Diagnostics;
  9. using System.Linq;
  10. using System.Reflection;
  11. using System.Text.Json;
  12. using System.Text.Json.Serialization;
  13. using System.Threading.Tasks;
  14. using Microsoft.Extensions.DependencyInjection;
  15. using Edge.WebHost.Models;
  16. using Edge.Core.Processor.Dispatcher;
  17. using System.Diagnostics.CodeAnalysis;
  18. using Edge.Core.UniversalApi.Auditing;
  19. using Edge.Core.Processor.Dispatcher.Attributes;
  20. using Edge.Core;
  21. namespace Edge.WebHost.Controllers
  22. {
  23. public class HomeController : Controller
  24. {
  25. public const string UniversalWebApiHandlerRoute = "u";
  26. //private readonly ILogger<HomeController> _logger;
  27. private readonly Func<IEnumerable<IProcessor>> processorFactory;
  28. private UniversalApiHub universalApiHub;
  29. private UniversalApiInvoker universalApiInvoker;
  30. private IProcessorMetaConfigAccessor processorMetaConfigAccessor;
  31. private static JsonSerializerOptions jsonSerializerOptions;
  32. static HomeController()
  33. {
  34. jsonSerializerOptions = new JsonSerializerOptions()
  35. {
  36. WriteIndented = true,
  37. PropertyNameCaseInsensitive = true,
  38. };
  39. jsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
  40. }
  41. public HomeController(
  42. Func<IEnumerable<IProcessor>> processorFactory,
  43. UniversalApiHub universalApiHub, UniversalApiInvoker universalApiInvoker,
  44. IProcessorMetaConfigAccessor processorMetaConfigAccessor)
  45. {
  46. this.processorFactory = processorFactory;
  47. this.universalApiHub = universalApiHub;
  48. this.universalApiInvoker = universalApiInvoker;
  49. this.processorMetaConfigAccessor = processorMetaConfigAccessor;
  50. }
  51. [HttpGet]
  52. public IActionResult Index()
  53. {
  54. var clientAcceptFormatStr = Request.Headers[HeaderNames.Accept].FirstOrDefault();
  55. var processorCompoundInfos = this.processorFactory().Select(p =>
  56. {
  57. var pDesc = p.ProcessorDescriptor();
  58. return new Tuple<ProcessorDescriptor, MetaPartsDescriptor>(pDesc,
  59. pDesc.DeviceHandlerOrApp.GetType().GetCustomAttributes<MetaPartsDescriptor>().FirstOrDefault());
  60. });
  61. if (string.IsNullOrEmpty(clientAcceptFormatStr))
  62. return View("~/Views/Home/Index.cshtml", processorCompoundInfos);
  63. else if (clientAcceptFormatStr.Contains("text/html"))
  64. return View("~/Views/Home/Index.cshtml", processorCompoundInfos);
  65. else if (clientAcceptFormatStr.Contains("application/json"))
  66. return Ok(processorCompoundInfos);
  67. else if (clientAcceptFormatStr.Contains("application/xml"))
  68. return Ok(processorCompoundInfos);
  69. return View("~/Views/Home/Index.cshtml", processorCompoundInfos);
  70. }
  71. [HttpGet]
  72. public async Task<IActionResult> GetProcessorMetaConfigSchema(string simpleSourceEndpointTypeStr, string configSubSection, string format)
  73. {
  74. if (this.processorMetaConfigAccessor == null) return Content("");
  75. var metaConfigs = await this.processorMetaConfigAccessor.GetMetaConfigAsync(null);
  76. var configs = metaConfigs.Where(c => c.SourceEndpointFullTypeStr.Contains(simpleSourceEndpointTypeStr));
  77. if (!(configs?.Any() ?? false)) return Content("");
  78. //sample: en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7
  79. var clientAcceptLanguageStr = Request.Headers[HeaderNames.AcceptLanguage].FirstOrDefault()?.Split(',')[0] ?? "en-us";
  80. #region FdcServerHostApp
  81. if (simpleSourceEndpointTypeStr.Contains("FdcServerHostApp", StringComparison.OrdinalIgnoreCase))
  82. {
  83. if (configSubSection == "Pump")
  84. {
  85. var pumpJsElements = JsonDocument.Parse(configs.FirstOrDefault().Parts.FirstOrDefault().ParametersJsonArrayStr).RootElement.EnumerateArray().First().GetProperty("PumpConfigs").EnumerateArray().ToArray();
  86. var productElements = JsonDocument.Parse(configs.FirstOrDefault().Parts.FirstOrDefault().ParametersJsonArrayStr).RootElement.EnumerateArray().First().GetProperty("ProductConfigs").EnumerateArray().ToArray();
  87. var siteLevelNozzleIds = new List<int>();
  88. var siteLevelNozzleDisplayStrings = new List<string>();
  89. foreach (var pumpJsEle in pumpJsElements)
  90. {
  91. var pumpId = pumpJsEle.GetProperty("PumpId").GetInt32();
  92. var nzJsEles = pumpJsEle.GetProperty("NozzleConfigs").EnumerateArray().ToArray();
  93. foreach (var nzJsEle in nzJsEles)
  94. {
  95. int nozzleLogicalId;
  96. if (!nzJsEle.GetProperty("NozzleLogicalId").TryGetInt32(out nozzleLogicalId))
  97. nozzleLogicalId = -1;
  98. int siteLvlNozzleId;
  99. if (!nzJsEle.GetProperty("SiteLevelNozzleId").TryGetInt32(out siteLvlNozzleId))
  100. siteLvlNozzleId = -1;
  101. int tankNumber;
  102. if (!nzJsEle.GetProperty("TankNumber").TryGetInt32(out tankNumber))
  103. tankNumber = -1;
  104. var productCode = nzJsEle.GetProperty("ProductCode").GetInt32();
  105. var productName = productElements.Where(p => p.GetProperty("ProductCode").GetInt32() == productCode).FirstOrDefault().GetProperty("ProductName").GetString();
  106. siteLevelNozzleIds.Add(siteLvlNozzleId);
  107. if (string.IsNullOrEmpty(format))
  108. siteLevelNozzleDisplayStrings.Add(
  109. $"lang-en-us:SiteLevelNozzleId: {siteLvlNozzleId}, pumpId: {pumpId}, nozzleLogicalId: {nozzleLogicalId}, productName: {productName}(code: {productCode }), tankNo.:{ tankNumber}lang-zh-cn:站级枪号: {siteLvlNozzleId}, 加油点号: {pumpId}, 逻辑枪号: {nozzleLogicalId}, 油品名: {productName}(代码: {productCode }), 油罐号.: { tankNumber}"
  110. .LocalizedContent(clientAcceptLanguageStr));
  111. else if (format == "simple")
  112. {
  113. siteLevelNozzleDisplayStrings.Add(
  114. $"lang-en-us:SiteLevelNozzleId: {siteLvlNozzleId}, productName: {productName}(code: {productCode })lang-zh-cn:站级枪号: {siteLvlNozzleId}, 油品名: {productName}(代码: {productCode })"
  115. .LocalizedContent(clientAcceptLanguageStr));
  116. }
  117. }
  118. }
  119. var dynamicPumpSchema = "{" +
  120. "\"$schema\": \"http://json-schema.org/draft-04/schema\"," +
  121. "\"type\": \"integer\"," +
  122. "\"enum\": [ " +
  123. siteLevelNozzleIds.Select(i => i.ToString()).Aggregate((acc, n) => acc + "," + n) + " ]," +
  124. " \"options\": {" +
  125. " \"enum_titles\": [ " +
  126. siteLevelNozzleDisplayStrings.Select(s => "\"" + s + "\"").Aggregate((acc, n) => acc + "," + n) + " ]" +
  127. " }" +
  128. "}";
  129. return Content(dynamicPumpSchema);
  130. }
  131. }
  132. #endregion
  133. return Content("");
  134. }
  135. /// <summary>
  136. ///
  137. /// </summary>
  138. /// <param name="apiType">localmqtt, remotemqtt, webapi</param>
  139. /// <param name="tags">, split tag string</param>
  140. /// <param name="format"></param>
  141. /// <returns></returns>
  142. [HttpGet]
  143. public IActionResult ShowMeApi(string apiType, string tags, string format)
  144. {
  145. var communicationProvider =
  146. this.universalApiHub.CommunicationProviders?.Where(p => p.GetType().Name.Contains(apiType, StringComparison.OrdinalIgnoreCase))?.FirstOrDefault();
  147. var docs = communicationProvider?.GetApiDocuments()?.FilterByTags(tags?.Replace(" ", "")?.Split(",")) ?? Enumerable.Empty<UniversalApiInfoDoc>();
  148. if (format == "data")
  149. return Ok(docs);
  150. else if (format == "pretty")
  151. return View("~/Views/Home/MqttApiDocPretty.cshtml", docs);
  152. return Redirect("/swagger");
  153. }
  154. public async Task<IActionResult> ProcessorMetaDescriptor(int startIndex = 0, int count = 10, string q = "")
  155. {
  156. var clientAcceptFormatStr = Request.Headers[HeaderNames.Accept].FirstOrDefault();
  157. //sample: en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7
  158. var clientAcceptLanguageStr = Request.Headers[HeaderNames.AcceptLanguage].FirstOrDefault()?.Split(',')[0] ?? "en-us";
  159. IEnumerable<ProcessorMetaDescriptor> pMetaDescriptors = null;
  160. if (!string.IsNullOrEmpty(q))
  161. {
  162. pMetaDescriptors = ObjectInstanceCreator.CurrentDomainProcessorEndPointTypes.ExtractProcessorMetaDescriptor()
  163. .Where(d => d.SourceEndpointFullTypeStr.Contains(q.Trim(), StringComparison.OrdinalIgnoreCase));
  164. }
  165. else
  166. {
  167. pMetaDescriptors = ObjectInstanceCreator.CurrentDomainProcessorEndPointTypes.ExtractProcessorMetaDescriptor().Skip(startIndex).Take(count);
  168. }
  169. ReplaceWithLocalizedContent(pMetaDescriptors, clientAcceptLanguageStr);
  170. if (string.IsNullOrEmpty(clientAcceptFormatStr))
  171. return View(pMetaDescriptors);
  172. else if (clientAcceptFormatStr.Contains("text/html"))
  173. return View(pMetaDescriptors);
  174. else if (clientAcceptFormatStr.Contains("application/json"))
  175. return Ok(pMetaDescriptors);
  176. else if (clientAcceptFormatStr.Contains("application/xml"))
  177. return Ok(pMetaDescriptors);
  178. return View(pMetaDescriptors);
  179. }
  180. /// <summary>
  181. ///
  182. /// </summary>
  183. /// <param name="source"></param>
  184. /// <param name="clientAcceptLanguageStr">sample: en-US or zh-CN</param>
  185. static void ReplaceWithLocalizedContent(IEnumerable<ProcessorMetaDescriptor> source, string clientAcceptLanguageStr)
  186. {
  187. foreach (var pDescriptor in source)
  188. {
  189. pDescriptor.Description = pDescriptor?.Description?.LocalizedContent(clientAcceptLanguageStr);
  190. if (pDescriptor.Tags != null)
  191. {
  192. var localizedTags = new List<string>();
  193. foreach (var t in pDescriptor.Tags)
  194. {
  195. var compoundTag = new
  196. {
  197. TagKey = t.LocalizedContent("en"),
  198. LocalizedTagName = t.LocalizedContent(clientAcceptLanguageStr)
  199. };
  200. localizedTags.Add(System.Text.Json.JsonSerializer.Serialize(compoundTag));
  201. }
  202. pDescriptor.Tags = localizedTags.ToArray();
  203. }
  204. if (string.IsNullOrEmpty(pDescriptor.DisplayName))
  205. {
  206. //SourceEndpointFullTypeStr sample: Edge.Core.Processor.Dispatcher.DefaultDispatcher, Edge.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
  207. pDescriptor.DisplayName = pDescriptor.SourceEndpointFullTypeStr.Substring(0, pDescriptor.SourceEndpointFullTypeStr.IndexOf(", Version="));
  208. }
  209. else
  210. pDescriptor.DisplayName = pDescriptor.DisplayName.LocalizedContent(clientAcceptLanguageStr);
  211. foreach (var mpGroup in pDescriptor.MetaPartsGroupDescriptors)
  212. {
  213. foreach (var mpDescriptor in mpGroup.MetaPartsDescriptors)
  214. {
  215. mpDescriptor.Description = mpDescriptor?.Description?.LocalizedContent(clientAcceptLanguageStr);
  216. if (string.IsNullOrEmpty(mpDescriptor.DisplayName))
  217. {
  218. mpDescriptor.DisplayName = mpDescriptor.TypeString;
  219. }
  220. else
  221. mpDescriptor.DisplayName = mpDescriptor.DisplayName.LocalizedContent(clientAcceptLanguageStr);
  222. foreach (var pJsons in mpDescriptor.ParametersJsonSchemaStrings)
  223. {
  224. for (int i = 0; i < pJsons.Count; i++)
  225. {
  226. pJsons[i] = pJsons[i].LocalizedJsonSchema(clientAcceptLanguageStr);
  227. }
  228. }
  229. }
  230. }
  231. }
  232. }
  233. [HttpGet]
  234. [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
  235. public IActionResult Error()
  236. {
  237. return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
  238. }
  239. //public async Task<IActionResult> Processors()
  240. //{
  241. // return View(this.processors);
  242. //}
  243. /// <summary>
  244. /// all calls to every single processor will be routed here
  245. /// </summary>
  246. /// <param name="apiType">service, or property</param>
  247. /// <param name="targetApiName">service, or property name</param>
  248. /// <param name="targetProcessorName"></param>
  249. /// <param name="endpointName"></param>
  250. /// <param name="inputParameter"></param>
  251. /// <returns></returns>
  252. //[ApiExplorerSettings(IgnoreApi = true)]
  253. [HttpPost]
  254. [Route(UniversalWebApiHandlerRoute)]
  255. public async Task<IActionResult> UniversalWebApiHandler(
  256. [FromQuery(Name = "apitype")] string apiType,
  257. [FromQuery(Name = "an")] string targetApiName,
  258. [FromQuery(Name = "pn")] string targetProcessorName,
  259. [FromQuery(Name = "en")] string endpointName,
  260. [FromBody] JsonElement inputParameter)
  261. {
  262. try
  263. {
  264. /* empty post body will treat inputParameters==null, no content json array '[]' will treat inputParameters.Length==0*/
  265. JsonElement[] inputParameters = null;
  266. if (inputParameter.ValueKind == JsonValueKind.Array)
  267. inputParameters = inputParameter.EnumerateArray().ToArray();
  268. else if (inputParameter.ValueKind == JsonValueKind.Object)
  269. inputParameters = new JsonElement[] { inputParameter };
  270. else if (inputParameter.ValueKind == JsonValueKind.Undefined)
  271. { }
  272. else
  273. inputParameters = new JsonElement[] { inputParameter };
  274. var p = this.processorFactory().FirstOrDefault(p => p.MetaConfigName == targetProcessorName);
  275. if (p == null) return BadRequest("Could not find processor with name: " + targetProcessorName);
  276. if (string.IsNullOrEmpty(apiType) || string.IsNullOrEmpty(targetApiName))
  277. return BadRequest("Must provide apiType and targetApiName in query");
  278. var requestContext = new RequestContext(Request);
  279. if (apiType.ToLower() == "service")
  280. {
  281. var apiCallResult = await this.universalApiInvoker.InvokeUniversalApiServiceAsync(p, targetApiName, inputParameters, requestContext);
  282. return Json(apiCallResult, jsonSerializerOptions);
  283. }
  284. else if (apiType.ToLower() == "property")
  285. {
  286. object apiCallResult;
  287. if (inputParameters == null)
  288. {
  289. /*call 'get'*/
  290. apiCallResult = this.universalApiInvoker.InvokeUniversalApiPropertyGet(p, targetApiName, requestContext);
  291. }
  292. else
  293. {
  294. /*call 'set'*/
  295. JsonElement? setValue = null;
  296. if (inputParameters.Length == 0)
  297. {
  298. }
  299. else if (inputParameters.Length >= 2)
  300. {
  301. return BadRequest("Unexpected too many parameters passed in. when calling for set value for a Property, Either post a single JsonObject, or a JsonArray with single element of JsonObject");
  302. }
  303. else
  304. setValue = inputParameters[0];
  305. apiCallResult = this.universalApiInvoker.InvokeUniversalApiPropertySet(p, targetApiName, setValue, requestContext);
  306. }
  307. return Json(apiCallResult, jsonSerializerOptions);
  308. }
  309. return BadRequest();
  310. }
  311. catch (Exception exx)
  312. {
  313. return StatusCode(500, exx.ToString());
  314. }
  315. }
  316. public IActionResult Configure()
  317. {
  318. //return all descriptor
  319. IEnumerable<ProcessorMetaDescriptor> descriptors = null;
  320. descriptors = ObjectInstanceCreator.CurrentDomainProcessorEndPointTypes.ExtractProcessorMetaDescriptor().Skip(0);
  321. //sample: en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7
  322. var clientAcceptLanguageStr = Request.Headers[HeaderNames.AcceptLanguage].FirstOrDefault()?.Split(',')[0] ?? "en-us";
  323. ReplaceWithLocalizedContent(descriptors, clientAcceptLanguageStr);
  324. return View(descriptors);
  325. }
  326. ///// <summary>
  327. /////
  328. ///// </summary>
  329. ///// <param name="appOrHandlerFullName">like Applications.FDC.FdcServerHostApp, or Wayne_Pump_Dart.PumpGroupHandler</param>
  330. ///// <param name="input"></param>
  331. ///// <returns></returns>
  332. //[HttpPost]
  333. //public async Task<IActionResult> UniversalWebConsoleHandler(
  334. // [FromQuery(Name = "epn")] string appOrHandlerFullName,
  335. // [FromBody]ApiData input)
  336. //{
  337. // return View("~/Home/WebConsoles/VeederRoot_ATG_Console_Handler");
  338. //}
  339. }
  340. }