public async Task <IHost> InitAsync( List <Assembly> openModHostAssemblies, RuntimeInitParameters parameters, Func <IHostBuilder>?hostBuilderFunc = null) { if (parameters == null) { throw new ArgumentNullException(nameof(parameters)); } HostAssemblies = openModHostAssemblies ?? throw new ArgumentNullException(nameof(openModHostAssemblies)); try { IsDisposing = false; var openModCoreAssembly = typeof(AsyncHelper).Assembly; if (!openModHostAssemblies.Contains(openModCoreAssembly)) { openModHostAssemblies.Insert(0, openModCoreAssembly); } var hostInformationType = openModHostAssemblies .Select(asm => AssemblyExtensions.GetLoadableTypes(asm) .FirstOrDefault(t => typeof(IHostInformation).IsAssignableFrom(t))) .LastOrDefault(d => d != null); if (hostInformationType == null) { throw new Exception("Failed to find IHostInformation in host assemblies."); } HostInformation = (IHostInformation)Activator.CreateInstance(hostInformationType); m_OpenModHostAssemblies = openModHostAssemblies; m_HostBuilderFunc = hostBuilderFunc; m_RuntimeInitParameters = parameters; var hostBuilder = hostBuilderFunc == null ? new HostBuilder() : hostBuilderFunc(); if (!Directory.Exists(parameters.WorkingDirectory)) { Directory.CreateDirectory(parameters.WorkingDirectory); } Status = RuntimeStatus.Initializing; WorkingDirectory = parameters.WorkingDirectory; CommandlineArgs = parameters.CommandlineArgs; SetupSerilog(); m_Logger.LogInformation($"OpenMod v{Version} is starting..."); if (parameters.PackageManager is not NuGetPackageManager nugetPackageManager) { var packagesDirectory = Path.Combine(WorkingDirectory, "packages"); nugetPackageManager = new NuGetPackageManager(packagesDirectory) { Logger = new OpenModNuGetLogger(m_LoggerFactory !.CreateLogger("NuGet")) }; } nugetPackageManager.Logger = new OpenModNuGetLogger(m_LoggerFactory !.CreateLogger("NuGet")); await nugetPackageManager.RemoveOutdatedPackagesAsync(); nugetPackageManager.InstallAssemblyResolver(); nugetPackageManager.SetAssemblyLoader(Hotloader.LoadAssembly); var startupContext = new OpenModStartupContext { Runtime = this, LoggerFactory = m_LoggerFactory !, NuGetPackageManager = nugetPackageManager, DataStore = new Dictionary <string, object>() }; var startup = new OpenModStartup(startupContext); startupContext.OpenModStartup = startup; foreach (var assembly in openModHostAssemblies) { startup.RegisterIocAssemblyAndCopyResources(assembly, string.Empty); } var configFile = Path.Combine(WorkingDirectory, "openmod.yaml"); if (File.Exists(configFile)) { var yaml = File.ReadAllText(configFile); var deserializer = new DeserializerBuilder() .WithTypeConverter(new YamlNullableEnumTypeConverter()) .WithNamingConvention(CamelCaseNamingConvention.Instance) .Build(); var config = deserializer.Deserialize <Dictionary <string, object> >(yaml); var hotReloadingEnabled = true; if (config.TryGetValue("hotreloading", out var unparsed)) { switch (unparsed) { case bool value: hotReloadingEnabled = value; break; case string strValue when bool.TryParse(strValue, out var parsed): hotReloadingEnabled = parsed; break; default: m_Logger.LogWarning("Unknown config for 'hotreloading' in OpenMod configuration: " + unparsed); break; } } Hotloader.Enabled = hotReloadingEnabled; var tryInstallMissingDependencies = false; if (config.TryGetValue("nuget", out unparsed) && unparsed is Dictionary <object, object> nugetConfig) { if (nugetConfig.TryGetValue("tryAutoInstallMissingDependencies", out unparsed)) { switch (unparsed) { case bool value: tryInstallMissingDependencies = value; break; case string strValue when bool.TryParse(strValue, out var parsed): tryInstallMissingDependencies = parsed; break; default: m_Logger.LogWarning("Unknown config for 'tryAutoInstallMissingDependencies' in OpenMod configuration: " + unparsed); break; } } } PluginAssemblyStore.TryInstallMissingDependencies = tryInstallMissingDependencies; } await nugetPackageManager.InstallMissingPackagesAsync(updateExisting : true); await startup.LoadPluginAssembliesAsync(); hostBuilder .UseContentRoot(parameters.WorkingDirectory) .UseServiceProviderFactory(new AutofacServiceProviderFactory()) .ConfigureHostConfiguration(builder => { ConfigureConfiguration(builder, startup); ((OpenModStartupContext)startup.Context).Configuration = builder.Build(); }) .ConfigureAppConfiguration(builder => ConfigureConfiguration(builder, startup)) .ConfigureContainer <ContainerBuilder>(builder => SetupContainer(builder, startup)) .ConfigureServices(services => SetupServices(services, startup)) .UseSerilog(); Host = hostBuilder.Build(); m_AppLifeTime = Host.Services.GetRequiredService <IHostApplicationLifetime>(); m_AppLifeTime.ApplicationStopping.Register(() => { AsyncHelper.RunSync(ShutdownAsync); }); Status = RuntimeStatus.Initialized; LifetimeScope = Host.Services.GetRequiredService <ILifetimeScope>().BeginLifetimeScopeEx( containerBuilder => { containerBuilder.Register(_ => this) .As <IOpenModComponent>() .SingleInstance() .ExternallyOwned(); containerBuilder.RegisterType <ScopedPermissionChecker>() .As <IPermissionChecker>() .InstancePerLifetimeScope() .OwnedByLifetimeScope(); }); DataStore = Host.Services.GetRequiredService <IDataStoreFactory>().CreateDataStore( new DataStoreCreationParameters { Component = this, Prefix = "openmod", Suffix = null, WorkingDirectory = WorkingDirectory }); try { await Host.StartAsync(); } catch (Exception ex) { Status = RuntimeStatus.Crashed; m_Logger.LogCritical(ex, "OpenMod has crashed."); Log.CloseAndFlush(); } return(Host); } catch (Exception ex) { Console.WriteLine(ex); throw; } }
public static IEnumerable <ServiceRegistration> FindFromAssembly <T>(Assembly assembly, ILogger?logger = null) where T : ServiceImplementationAttribute { List <Type> types; try { types = AssemblyExtensions.GetLoadableTypes(assembly) .Where(d => d.IsClass && !d.IsInterface && !d.IsAbstract) .ToList(); } catch (ReflectionTypeLoadException ex) //this ignores missing optional dependencies { logger?.LogTrace(ex, $"Some optional dependencies are missing for \"{assembly}\""); if (ex.LoaderExceptions != null && ex.LoaderExceptions.Length > 0) { foreach (var loaderException in ex.LoaderExceptions) { logger?.LogTrace(loaderException, "Loader Exception: "); } } types = ex.Types.Where(tp => tp != null && tp.IsClass && !tp.IsInterface && !tp.IsAbstract) .ToList(); } foreach (var type in types) { T attribute; Type[] interfaces; try { attribute = type.GetCustomAttribute <T>(inherit: false); if (attribute == null) { continue; } interfaces = type.GetInterfaces() .Where(d => d.GetCustomAttribute <ServiceAttribute>() != null) .ToArray(); if (interfaces.Length == 0) { logger?.LogWarning( $"Type {type.FullName} in assembly {assembly.FullName} has been marked as ServiceImplementation but does not inherit any services!\nDid you forget to add [Service] to your interfaces?"); continue; } } catch (Exception ex) { logger?.LogWarning($"FindFromAssembly has failed for type: {type.FullName} while searching for {typeof(T).FullName}", ex); continue; } yield return(new ServiceRegistration { Priority = attribute.Priority, ServiceImplementationType = type, ServiceTypes = interfaces, Lifetime = attribute.Lifetime }); } }