using System; using System.Collections.Generic; using System.Reflection; using GameServiceWarden.Core.Games.Modules.Exceptions; using GameServiceWarden.API.Module; namespace GameServiceWarden.Core.Games.Modules { public class ServiceModuleLoader //Gateway { /// /// Loads an extension module. /// /// The path to the module. /// An from the given module. /// When the module requested to be loaded does not contain any public classes. public IEnumerable LoadModules(string path) { return instantiateServiceable(loadAssembly(path)); } /// /// Loads all module for each given path to modules file. /// /// The paths to load modules for. /// A where the key is a that is the associated path. public Dictionary> LoadAllModules(IEnumerable paths) { Dictionary> res = new Dictionary>(); foreach (string path in paths) { res.Add(path, LoadModules(path)); } return res; } private Assembly loadAssembly(string path) { ModuleLoadContext moduleLoadContext = new ModuleLoadContext(path); return moduleLoadContext.LoadFromAssemblyPath(path); } private IEnumerable instantiateServiceable(Assembly assembly) { int serviceableCount = 0; foreach (Type type in assembly.GetExportedTypes()) { if (typeof(IServiceModule).IsAssignableFrom(type)) { IServiceModule res = Activator.CreateInstance(type) as IServiceModule; if (res != null) { serviceableCount++; yield return res; } } } if (serviceableCount == 0) { List typeNames = new List(); foreach (Type type in assembly.GetExportedTypes()) { typeNames.Add(type.FullName); } string types = String.Join(',', typeNames); throw new ModuleLoadException( $"No public classes in {assembly} from {assembly.Location} implemented {typeof(IService).FullName}." + $"Detected types: {types}"); } } } }