Пример #1
0
        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;
            }
        }
Пример #2
0
        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
                });
            }
        }