Example #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(false);

                m_Logger.LogInformation("OpenMod v{Version} is starting...", Version);

                if (parameters.PackageManager is not NuGetPackageManager nugetPackageManager)
                {
                    var packagesDirectory = Path.Combine(WorkingDirectory, "packages");
                    nugetPackageManager = new NuGetPackageManager(packagesDirectory);
                }

                nugetPackageManager.Logger = new OpenModNuGetLogger(m_LoggerFactory !.CreateLogger("NuGet"));

                await nugetPackageManager.RemoveOutdatedPackagesAsync();

                nugetPackageManager.InstallAssemblyResolver();
                nugetPackageManager.SetAssemblyLoader((NuGetPackageManager.AssemblyLoader)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: {UnparsedConfig}",
                                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: {UnparsedConfig}",
                                    unparsed);
                                break;
                            }
                        }
                    }

                    PluginAssemblyStore.TryInstallMissingDependencies = tryInstallMissingDependencies;
                }

                await nugetPackageManager.InstallMissingPackagesAsync(updateExisting : true);

                await startup.LoadPluginAssembliesAsync();

                SetupSerilog(true);

                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();
                }

                PerformFileSystemWatcherPatch();

                return(Host);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
                throw;
            }
        }