ServiceController.cs 6.7 KB

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