2020-12-24 16:33:17 -06:00
using System ;
using System.Collections.Generic ;
using System.Reflection ;
2021-04-19 01:34:45 -05:00
using GameServiceWarden.Core.Module.Exceptions ;
2021-04-22 16:03:09 -05:00
using GameServiceWarden.ModuleFramework ;
2020-12-24 16:33:17 -06:00
2021-04-19 01:34:45 -05:00
namespace GameServiceWarden.Core.Module
2020-12-24 16:33:17 -06:00
{
2021-04-19 01:34:45 -05:00
public class ModuleLoader //Gateway
2020-12-24 16:33:17 -06:00
{
/// <summary>
/// Loads an extension module.
/// </summary>
/// <param name="path">The path to the module.</param>
2021-04-08 21:36:08 -05:00
/// <returns>An </<see cref="IEnumerable{IServiceModule}"/> from the given module.</returns>
/// <exception cref="NoServiceableFoundException">When the module requested to be loaded does not contain any public <see cref="IService"/> classes.</exception>
public IEnumerable < IServiceModule > LoadModules ( string path )
2020-12-24 16:33:17 -06:00
{
return instantiateServiceable ( loadAssembly ( path ) ) ;
}
/// <summary>
/// Loads all module for each given path to modules file.
/// </summary>
/// <param name="paths">The paths to load modules for.</param>
2021-04-08 21:36:08 -05:00
/// <returns>A <see cref="Dictionary{string, IEnumerable{IServiceModule}}"/> where the key is a <see cref="string"/> that is the associated path.</returns>
public Dictionary < string , IEnumerable < IServiceModule > > LoadAllModules ( IEnumerable < string > paths )
2020-12-24 16:33:17 -06:00
{
2021-04-08 21:36:08 -05:00
Dictionary < string , IEnumerable < IServiceModule > > res = new Dictionary < string , IEnumerable < IServiceModule > > ( ) ;
2020-12-24 16:33:17 -06:00
foreach ( string path in paths )
{
res . Add ( path , LoadModules ( path ) ) ;
}
return res ;
}
private Assembly loadAssembly ( string path )
{
2021-04-08 21:36:08 -05:00
ModuleLoadContext moduleLoadContext = new ModuleLoadContext ( path ) ;
2020-12-24 16:33:17 -06:00
return moduleLoadContext . LoadFromAssemblyPath ( path ) ;
}
2021-04-08 21:36:08 -05:00
private IEnumerable < IServiceModule > instantiateServiceable ( Assembly assembly )
2020-12-24 16:33:17 -06:00
{
int serviceableCount = 0 ;
foreach ( Type type in assembly . GetExportedTypes ( ) )
{
2021-04-08 21:36:08 -05:00
if ( typeof ( IServiceModule ) . IsAssignableFrom ( type ) )
2020-12-24 16:33:17 -06:00
{
2021-04-08 21:36:08 -05:00
IServiceModule res = Activator . CreateInstance ( type ) as IServiceModule ;
2020-12-24 16:33:17 -06:00
if ( res ! = null )
{
serviceableCount + + ;
yield return res ;
}
}
}
if ( serviceableCount = = 0 )
{
List < string > typeNames = new List < string > ( ) ;
foreach ( Type type in assembly . GetExportedTypes ( ) )
{
typeNames . Add ( type . FullName ) ;
}
string types = String . Join ( ',' , typeNames ) ;
2020-12-28 00:43:02 -06:00
throw new ModuleLoadException (
2021-04-08 21:36:08 -05:00
$"No public classes in {assembly} from {assembly.Location} implemented {typeof(IService).FullName}." +
2020-12-24 16:33:17 -06:00
$"Detected types: {types}" ) ;
}
}
}
}