jellyfin-server/Emby.Server.Implementations/Services/ServiceController.cs

203 lines
7.1 KiB
C#
Raw Normal View History

#pragma warning disable CS1591
2016-11-11 19:55:12 +00:00
using System;
using System.Collections.Generic;
2020-07-24 14:37:54 +00:00
using System.Globalization;
2016-11-11 19:55:12 +00:00
using System.Threading.Tasks;
2017-02-13 01:07:48 +00:00
using Emby.Server.Implementations.HttpServer;
2016-11-11 19:55:12 +00:00
using MediaBrowser.Model.Services;
using Microsoft.Extensions.Logging;
2016-11-11 19:55:12 +00:00
2017-02-13 01:07:48 +00:00
namespace Emby.Server.Implementations.Services
2016-11-11 19:55:12 +00:00
{
public delegate object ActionInvokerFn(object intance, object request);
2016-11-11 19:55:12 +00:00
public delegate void VoidActionInvokerFn(object intance, object request);
public class ServiceController
{
2020-06-06 00:15:56 +00:00
private readonly ILogger<ServiceController> _logger;
/// <summary>
/// Initializes a new instance of the <see cref="ServiceController"/> class.
/// </summary>
2020-04-02 13:32:43 +00:00
/// <param name="logger">The <see cref="ServiceController"/> logger.</param>
public ServiceController(ILogger<ServiceController> logger)
{
2020-04-02 13:32:43 +00:00
_logger = logger;
}
2019-03-26 18:20:40 +00:00
public void Init(HttpListenerHost appHost, IEnumerable<Type> serviceTypes)
2016-11-11 19:55:12 +00:00
{
foreach (var serviceType in serviceTypes)
2016-11-11 19:55:12 +00:00
{
2017-02-13 01:07:48 +00:00
RegisterService(appHost, serviceType);
2016-11-11 19:55:12 +00:00
}
}
2017-02-13 01:07:48 +00:00
public void RegisterService(HttpListenerHost appHost, Type serviceType)
2016-11-11 19:55:12 +00:00
{
// Make sure the provided type implements IService
if (!typeof(IService).IsAssignableFrom(serviceType))
{
2020-04-02 13:32:43 +00:00
_logger.LogWarning("Tried to register a service that does not implement IService: {ServiceType}", serviceType);
return;
}
2016-11-11 19:55:12 +00:00
var processedReqs = new HashSet<Type>();
var actions = ServiceExecGeneral.Reset(serviceType);
foreach (var mi in serviceType.GetActions())
{
var requestType = mi.GetParameters()[0].ParameterType;
2019-03-26 18:20:40 +00:00
if (processedReqs.Contains(requestType))
{
continue;
}
2016-11-11 19:55:12 +00:00
processedReqs.Add(requestType);
ServiceExecGeneral.CreateServiceRunnersFor(requestType, actions);
2020-06-14 09:11:11 +00:00
// var returnMarker = GetTypeWithGenericTypeDefinitionOf(requestType, typeof(IReturn<>));
// var responseType = returnMarker != null ?
2017-08-19 19:43:35 +00:00
// GetGenericArguments(returnMarker)[0]
// : mi.ReturnType != typeof(object) && mi.ReturnType != typeof(void) ?
// mi.ReturnType
// : Type.GetType(requestType.FullName + "Response");
2016-11-11 19:55:12 +00:00
2018-09-12 17:26:21 +00:00
RegisterRestPaths(appHost, requestType, serviceType);
2016-11-11 19:55:12 +00:00
2017-08-19 19:43:35 +00:00
appHost.AddServiceInfo(serviceType, requestType);
2017-02-13 02:06:54 +00:00
}
}
2018-09-12 17:26:21 +00:00
public readonly RestPath.RestPathMap RestPathMap = new RestPath.RestPathMap();
2016-11-11 19:55:12 +00:00
2018-09-12 17:26:21 +00:00
public void RegisterRestPaths(HttpListenerHost appHost, Type requestType, Type serviceType)
2016-11-11 19:55:12 +00:00
{
var attrs = appHost.GetRouteAttributes(requestType);
2019-01-13 20:37:13 +00:00
foreach (var attr in attrs)
2016-11-11 19:55:12 +00:00
{
2018-09-12 17:26:21 +00:00
var restPath = new RestPath(appHost.CreateInstance, appHost.GetParseFn, requestType, serviceType, attr.Path, attr.Verbs, attr.IsHidden, attr.Summary, attr.Description);
2016-11-11 19:55:12 +00:00
RegisterRestPath(restPath);
}
}
private static readonly char[] InvalidRouteChars = new[] { '?', '&' };
public void RegisterRestPath(RestPath restPath)
{
2019-03-26 18:20:40 +00:00
if (restPath.Path[0] != '/')
{
2020-07-24 14:37:54 +00:00
throw new ArgumentException(
string.Format(
CultureInfo.InvariantCulture,
"Route '{0}' on '{1}' must start with a '/'",
restPath.Path,
restPath.RequestType.GetMethodName()));
2019-03-26 18:20:40 +00:00
}
2016-11-11 19:55:12 +00:00
if (restPath.Path.IndexOfAny(InvalidRouteChars) != -1)
2019-03-26 18:20:40 +00:00
{
2020-07-24 14:37:54 +00:00
throw new ArgumentException(
string.Format(
CultureInfo.InvariantCulture,
"Route '{0}' on '{1}' contains invalid chars. ",
restPath.Path,
restPath.RequestType.GetMethodName()));
2019-03-26 18:20:40 +00:00
}
2016-11-11 19:55:12 +00:00
2019-03-26 18:20:40 +00:00
if (RestPathMap.TryGetValue(restPath.FirstMatchHashKey, out List<RestPath> pathsAtFirstMatch))
2016-11-11 19:55:12 +00:00
{
2019-03-26 18:20:40 +00:00
pathsAtFirstMatch.Add(restPath);
}
else
{
RestPathMap[restPath.FirstMatchHashKey] = new List<RestPath>() { restPath };
2016-11-11 19:55:12 +00:00
}
}
2018-12-14 19:17:29 +00:00
public RestPath GetRestPathForRequest(string httpMethod, string pathInfo)
2016-11-11 19:55:12 +00:00
{
var matchUsingPathParts = RestPath.GetPathPartsForMatching(pathInfo);
List<RestPath> firstMatches;
var yieldedHashMatches = RestPath.GetFirstMatchHashKeys(matchUsingPathParts);
foreach (var potentialHashMatch in yieldedHashMatches)
{
if (!this.RestPathMap.TryGetValue(potentialHashMatch, out firstMatches))
{
continue;
}
2016-11-11 19:55:12 +00:00
var bestScore = -1;
2018-09-12 17:26:21 +00:00
RestPath bestMatch = null;
2016-11-11 19:55:12 +00:00
foreach (var restPath in firstMatches)
{
2018-12-14 19:17:29 +00:00
var score = restPath.MatchScore(httpMethod, matchUsingPathParts);
2018-09-12 17:26:21 +00:00
if (score > bestScore)
{
bestScore = score;
bestMatch = restPath;
}
2016-11-11 19:55:12 +00:00
}
2018-09-12 17:26:21 +00:00
if (bestScore > 0 && bestMatch != null)
2016-11-11 19:55:12 +00:00
{
2018-09-12 17:26:21 +00:00
return bestMatch;
2016-11-11 19:55:12 +00:00
}
}
var yieldedWildcardMatches = RestPath.GetFirstMatchWildCardHashKeys(matchUsingPathParts);
foreach (var potentialHashMatch in yieldedWildcardMatches)
{
2020-06-20 08:35:29 +00:00
if (!this.RestPathMap.TryGetValue(potentialHashMatch, out firstMatches))
{
continue;
}
2016-11-11 19:55:12 +00:00
var bestScore = -1;
2018-09-12 17:26:21 +00:00
RestPath bestMatch = null;
2016-11-11 19:55:12 +00:00
foreach (var restPath in firstMatches)
{
2018-12-14 19:17:29 +00:00
var score = restPath.MatchScore(httpMethod, matchUsingPathParts);
2018-09-12 17:26:21 +00:00
if (score > bestScore)
2016-11-11 19:55:12 +00:00
{
2018-09-12 17:26:21 +00:00
bestScore = score;
bestMatch = restPath;
2016-11-11 19:55:12 +00:00
}
}
2018-09-12 17:26:21 +00:00
if (bestScore > 0 && bestMatch != null)
{
return bestMatch;
}
2016-11-11 19:55:12 +00:00
}
return null;
}
2019-03-26 18:20:40 +00:00
public Task<object> Execute(HttpListenerHost httpHost, object requestDto, IRequest req)
2016-11-11 19:55:12 +00:00
{
var requestType = requestDto.GetType();
req.OperationName = requestType.Name;
2019-03-26 18:20:40 +00:00
var serviceType = httpHost.GetServiceTypeByRequest(requestType);
2016-11-11 19:55:12 +00:00
2020-07-17 11:54:28 +00:00
var service = httpHost.CreateInstance(serviceType);
2020-07-24 14:37:54 +00:00
if (service is IRequiresRequest serviceRequiresContext)
2016-11-11 19:55:12 +00:00
{
serviceRequiresContext.Request = req;
}
2020-06-14 09:11:11 +00:00
// Executes the service and returns the result
2017-05-26 06:48:54 +00:00
return ServiceExecGeneral.Execute(serviceType, req, service, requestDto, requestType.GetMethodName());
2016-11-11 19:55:12 +00:00
}
}
}