diff --git a/nodecg-io-core/dashboard/crypto.ts b/nodecg-io-core/dashboard/crypto.ts index 1c2b421c7..11047fc30 100644 --- a/nodecg-io-core/dashboard/crypto.ts +++ b/nodecg-io-core/dashboard/crypto.ts @@ -4,7 +4,7 @@ import { ObjectMap, ServiceInstance, ServiceDependency, Service } from "nodecg-i import { isLoaded } from "./authentication"; import { PasswordMessage } from "nodecg-io-core/extension/messageManager"; -export const encryptedData = nodecg.Replicant("encryptedConfig"); +const encryptedData = nodecg.Replicant("encryptedConfig"); let services: Service[] | undefined; let password: string | undefined; diff --git a/nodecg-io-core/extension/persistenceManager.ts b/nodecg-io-core/extension/persistenceManager.ts index 2519d5247..34c8f3a3d 100644 --- a/nodecg-io-core/extension/persistenceManager.ts +++ b/nodecg-io-core/extension/persistenceManager.ts @@ -122,8 +122,9 @@ export class PersistenceManager { // Load config into the respecting manager // Instances first as the bundle dependency depend upon the existing instances. - this.loadServiceInstances(data.result.instances); + const promises = this.loadServiceInstances(data.result.instances); this.loadBundleDependencies(data.result.bundleDependencies); + this.saveAfterServiceInstancesLoaded(promises); } // Save password, used in save() function @@ -141,14 +142,11 @@ export class PersistenceManager { * and then setting the config of the passed object. * @param instances the service instances that should be loaded. */ - private loadServiceInstances(instances: ObjectMap>) { - for (const instanceName in instances) { - if (!Object.prototype.hasOwnProperty.call(instances, instanceName)) { - continue; - } + private loadServiceInstances(instances: ObjectMap>): Promise[] { + return Object.keys(instances).map((instanceName) => { const inst = instances[instanceName]; if (inst === undefined) { - continue; + return Promise.resolve(); } // Re-create service instance. @@ -157,19 +155,19 @@ export class PersistenceManager { this.nodecg.log.info( `Couldn't load instance "${instanceName}" from saved configuration: ${result.errorMessage}`, ); - continue; + return Promise.resolve(); } const svc = this.services.getService(inst.serviceType); if (!svc.failed && svc.result.requiresNoConfig) { - continue; + return Promise.resolve(); } // Re-set config of this instance. // We can skip the validation here because the config was already validated when it was initially set, // before getting saved to disk. // This results in faster loading when the validation takes time, e.g. makes HTTP requests. - this.instances + return this.instances .updateInstanceConfig(instanceName, inst.config, false) .then((result) => { if (result.failed) { @@ -183,7 +181,7 @@ export class PersistenceManager { `Couldn't load config of instance "${instanceName}" from saved configuration: ${reason}.`, ); }); - } + }); } /** @@ -191,9 +189,9 @@ export class PersistenceManager { * @param bundles the bundle dependencies that should be set. */ private loadBundleDependencies(bundles: ObjectMap[]>): void { - for (const bundleName in bundles) { + Object.keys(bundles).forEach((bundleName) => { if (!Object.prototype.hasOwnProperty.call(bundles, bundleName)) { - continue; + return; } const deps = bundles[bundleName]; @@ -209,7 +207,7 @@ export class PersistenceManager { } } }); - } + }); } /** @@ -257,4 +255,19 @@ export class PersistenceManager { return copy; } + + /** + * Saves the current configuration after all service instances have loaded. + * @param promises the promises of the service instances + */ + private async saveAfterServiceInstancesLoaded(promises: Promise[]) { + // We want to ignore errors because if a client in one instance cannot be created we still want to save the current state. + const promisesWithoutErrs = promises.map((prom) => new Promise((resolve) => prom.then(resolve).catch(resolve))); + + // Wait till all promises either are done or have failed. + await Promise.all(promisesWithoutErrs); + + this.nodecg.log.info("Finished creating service instances from stored configuration."); + this.save(); + } }