ServiceController.cs 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. #pragma warning disable CS1591
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Threading.Tasks;
  5. using Emby.Server.Implementations.HttpServer;
  6. using MediaBrowser.Model.Services;
  7. using Microsoft.Extensions.Logging;
  8. namespace Emby.Server.Implementations.Services
  9. {
  10. public delegate object ActionInvokerFn(object intance, object request);
  11. public delegate void VoidActionInvokerFn(object intance, object request);
  12. public class ServiceController
  13. {
  14. private readonly ILogger<ServiceController> _logger;
  15. /// <summary>
  16. /// Initializes a new instance of the <see cref="ServiceController"/> class.
  17. /// </summary>
  18. /// <param name="logger">The <see cref="ServiceController"/> logger.</param>
  19. public ServiceController(ILogger<ServiceController> logger)
  20. {
  21. _logger = logger;
  22. }
  23. public void Init(HttpListenerHost appHost, IEnumerable<Type> serviceTypes)
  24. {
  25. foreach (var serviceType in serviceTypes)
  26. {
  27. RegisterService(appHost, serviceType);
  28. }
  29. }
  30. public void RegisterService(HttpListenerHost appHost, Type serviceType)
  31. {
  32. // Make sure the provided type implements IService
  33. if (!typeof(IService).IsAssignableFrom(serviceType))
  34. {
  35. _logger.LogWarning("Tried to register a service that does not implement IService: {ServiceType}", serviceType);
  36. return;
  37. }
  38. var processedReqs = new HashSet<Type>();
  39. var actions = ServiceExecGeneral.Reset(serviceType);
  40. foreach (var mi in serviceType.GetActions())
  41. {
  42. var requestType = mi.GetParameters()[0].ParameterType;
  43. if (processedReqs.Contains(requestType))
  44. {
  45. continue;
  46. }
  47. processedReqs.Add(requestType);
  48. ServiceExecGeneral.CreateServiceRunnersFor(requestType, actions);
  49. //var returnMarker = GetTypeWithGenericTypeDefinitionOf(requestType, typeof(IReturn<>));
  50. //var responseType = returnMarker != null ?
  51. // GetGenericArguments(returnMarker)[0]
  52. // : mi.ReturnType != typeof(object) && mi.ReturnType != typeof(void) ?
  53. // mi.ReturnType
  54. // : Type.GetType(requestType.FullName + "Response");
  55. RegisterRestPaths(appHost, requestType, serviceType);
  56. appHost.AddServiceInfo(serviceType, requestType);
  57. }
  58. }
  59. public readonly RestPath.RestPathMap RestPathMap = new RestPath.RestPathMap();
  60. public void RegisterRestPaths(HttpListenerHost appHost, Type requestType, Type serviceType)
  61. {
  62. var attrs = appHost.GetRouteAttributes(requestType);
  63. foreach (var attr in attrs)
  64. {
  65. var restPath = new RestPath(appHost.CreateInstance, appHost.GetParseFn, requestType, serviceType, attr.Path, attr.Verbs, attr.IsHidden, attr.Summary, attr.Description);
  66. RegisterRestPath(restPath);
  67. }
  68. }
  69. private static readonly char[] InvalidRouteChars = new[] { '?', '&' };
  70. public void RegisterRestPath(RestPath restPath)
  71. {
  72. if (restPath.Path[0] != '/')
  73. {
  74. throw new ArgumentException(string.Format("Route '{0}' on '{1}' must start with a '/'", restPath.Path, restPath.RequestType.GetMethodName()));
  75. }
  76. if (restPath.Path.IndexOfAny(InvalidRouteChars) != -1)
  77. {
  78. throw new ArgumentException(string.Format("Route '{0}' on '{1}' contains invalid chars. ", restPath.Path, restPath.RequestType.GetMethodName()));
  79. }
  80. if (RestPathMap.TryGetValue(restPath.FirstMatchHashKey, out List<RestPath> pathsAtFirstMatch))
  81. {
  82. pathsAtFirstMatch.Add(restPath);
  83. }
  84. else
  85. {
  86. RestPathMap[restPath.FirstMatchHashKey] = new List<RestPath>() { restPath };
  87. }
  88. }
  89. public RestPath GetRestPathForRequest(string httpMethod, string pathInfo)
  90. {
  91. var matchUsingPathParts = RestPath.GetPathPartsForMatching(pathInfo);
  92. List<RestPath> firstMatches;
  93. var yieldedHashMatches = RestPath.GetFirstMatchHashKeys(matchUsingPathParts);
  94. foreach (var potentialHashMatch in yieldedHashMatches)
  95. {
  96. if (!this.RestPathMap.TryGetValue(potentialHashMatch, out firstMatches))
  97. {
  98. continue;
  99. }
  100. var bestScore = -1;
  101. RestPath bestMatch = null;
  102. foreach (var restPath in firstMatches)
  103. {
  104. var score = restPath.MatchScore(httpMethod, matchUsingPathParts);
  105. if (score > bestScore)
  106. {
  107. bestScore = score;
  108. bestMatch = restPath;
  109. }
  110. }
  111. if (bestScore > 0 && bestMatch != null)
  112. {
  113. return bestMatch;
  114. }
  115. }
  116. var yieldedWildcardMatches = RestPath.GetFirstMatchWildCardHashKeys(matchUsingPathParts);
  117. foreach (var potentialHashMatch in yieldedWildcardMatches)
  118. {
  119. if (!this.RestPathMap.TryGetValue(potentialHashMatch, out firstMatches)) continue;
  120. var bestScore = -1;
  121. RestPath bestMatch = null;
  122. foreach (var restPath in firstMatches)
  123. {
  124. var score = restPath.MatchScore(httpMethod, matchUsingPathParts);
  125. if (score > bestScore)
  126. {
  127. bestScore = score;
  128. bestMatch = restPath;
  129. }
  130. }
  131. if (bestScore > 0 && bestMatch != null)
  132. {
  133. return bestMatch;
  134. }
  135. }
  136. return null;
  137. }
  138. public Task<object> Execute(HttpListenerHost httpHost, object requestDto, IRequest req)
  139. {
  140. var requestType = requestDto.GetType();
  141. req.OperationName = requestType.Name;
  142. var serviceType = httpHost.GetServiceTypeByRequest(requestType);
  143. var service = httpHost.CreateInstance(serviceType);
  144. var serviceRequiresContext = service as IRequiresRequest;
  145. if (serviceRequiresContext != null)
  146. {
  147. serviceRequiresContext.Request = req;
  148. }
  149. //Executes the service and returns the result
  150. return ServiceExecGeneral.Execute(serviceType, req, service, requestDto, requestType.GetMethodName());
  151. }
  152. }
  153. }