1
0
mirror of https://github.com/mxpv/podsync.git synced 2024-05-11 05:55:04 +00:00

Detect RSS builders automatically via reflection

This commit is contained in:
Maksym Pavlenko
2017-01-05 17:25:17 -08:00
parent f7e1e388fa
commit c9124cd25e
3 changed files with 69 additions and 11 deletions

View File

@@ -1,4 +1,8 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using Podsync.Services.Feed;
using Podsync.Services.Links;
@@ -10,13 +14,15 @@ namespace Podsync.Services.Builder
// ReSharper disable once ClassNeverInstantiated.Global
public class CompositeRssBuilder : RssBuilderBase
{
private readonly YouTubeRssBuilder _youTubeBuilder;
private readonly VimeoRssBuilder _vimeoBuilder;
private readonly IDictionary<Provider, IRssBuilder> _builders;
public CompositeRssBuilder(IServiceProvider serviceProvider, IStorageService storageService) : base(storageService)
{
_youTubeBuilder = serviceProvider.CreateInstance<YouTubeRssBuilder>();
_vimeoBuilder = serviceProvider.CreateInstance<VimeoRssBuilder>();
// Find all RSS builders (all implementations of IRssBuilder), create instances and make dictionary for fast search by Provider type
var buildTypes = serviceProvider.FindAllImplementationsOf<IRssBuilder>(Assembly.GetEntryAssembly()).Where(x => x != typeof(CompositeRssBuilder));
var builders = buildTypes.Select(builderType => (IRssBuilder)serviceProvider.CreateInstance(builderType)).ToDictionary(builder => builder.Provider);
_builders = new ReadOnlyDictionary<Provider, IRssBuilder>(builders);
}
public override Provider Provider
@@ -26,14 +32,10 @@ namespace Podsync.Services.Builder
public override Task<Rss> Query(Uri baseUrl, string feedId, FeedMetadata feed)
{
if (feed.Provider == Provider.YouTube)
IRssBuilder builder;
if (_builders.TryGetValue(feed.Provider, out builder))
{
return _youTubeBuilder.Query(baseUrl, feedId, feed);
}
if (feed.Provider == Provider.Vimeo)
{
return _vimeoBuilder.Query(baseUrl, feedId, feed);
return builder.Query(baseUrl, feedId, feed);
}
throw new NotSupportedException("Not supported provider");

View File

@@ -1,11 +1,17 @@
using System;
using System.Threading.Tasks;
using Podsync.Services.Feed;
using Podsync.Services.Links;
using Podsync.Services.Storage;
namespace Podsync.Services.Builder
{
public interface IRssBuilder
{
Provider Provider { get; }
Task<Rss> Query(Uri baseUrl, string feedId);
Task<Rss> Query(Uri baseUrl, string feedId, FeedMetadata metadata);
}
}

View File

@@ -1,4 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Microsoft.Extensions.DependencyInjection;
namespace Shared
@@ -19,5 +22,52 @@ namespace Shared
{
return ActivatorUtilities.CreateInstance(serviceProvider, type);
}
public static IEnumerable<Type> FindAllImplementationsOf(this IServiceProvider serviceProvider, Type interfaceType, Assembly assembly)
{
if (!interfaceType.GetTypeInfo().IsInterface)
{
throw new ArgumentException("T should be an interface");
}
return GetLoadableTypes(assembly).Where(type => IsAssignableFrom(interfaceType, type));
}
public static IEnumerable<Type> FindAllImplementationsOf<T>(this IServiceProvider serviceProvider, Assembly assembly)
{
return serviceProvider.FindAllImplementationsOf(typeof(T), assembly);
}
private static bool IsAssignableFrom(Type interfaceType, Type serviceType)
{
var serviceTypeInfo = serviceType.GetTypeInfo();
if (serviceTypeInfo.IsInterface || serviceTypeInfo.IsAbstract)
{
return false;
}
var interfaceTypeInfo = interfaceType.GetTypeInfo();
if (!interfaceTypeInfo.IsGenericType)
{
return interfaceType.IsAssignableFrom(serviceType);
}
return serviceType
.GetInterfaces()
.Where(type => type.GetTypeInfo().IsGenericType)
.Any(type => type.GetGenericTypeDefinition() == interfaceType);
}
private static IEnumerable<Type> GetLoadableTypes(Assembly assembly)
{
try
{
return assembly.GetTypes();
}
catch (ReflectionTypeLoadException e)
{
return e.Types.Where(x => x != null);
}
}
}
}