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