UNPKG

lavva.exalushome

Version:

Library implementing communication and abstraction layers for ExalusHome system

123 lines 6.48 kB
import { LoggerService } from './Services/Logging/LoggerService'; import { TypedEvent } from './TypedEvent'; export class DependencyContainer { constructor() { this._services = new Map(); this._serviceRegistrationEvent = new TypedEvent(); this._pendingResolutions = new Map(); this._nextResolutionId = 1; } static get Timers() { return globalThis; } static get Instance() { const g = globalThis; if (g.__dc_instance) return g.__dc_instance; const inst = new DependencyContainer(); g.__dc_instance = inst; if (typeof window !== 'undefined' && !window.LavvaDI) window.appservices = inst; this.Log = new LoggerService(); this.Log.Warning(DependencyContainer.ServiceName, 'Initializing DependencyContainer'); inst.RegisterService(this.Log); this.IsInitialized = true; return inst; } RegisterService(srv) { var _a; const serviceName = srv.GetServiceName(); if (this._services.has(serviceName)) { (_a = DependencyContainer.Log) === null || _a === void 0 ? void 0 : _a.Warning(DependencyContainer.ServiceName, `Service "${serviceName}" is being re-registered and the previous instance will be overwritten.`); } this._services.set(serviceName, srv); this._serviceRegistrationEvent.Invoke(srv); } GetService(name) { return this._services.get(name); } GetServiceAsync(name, token) { var _a, _b; if (this._services.has(name)) { (_a = DependencyContainer.Log) === null || _a === void 0 ? void 0 : _a.Debug(DependencyContainer.ServiceName, `Resolved service "${name}" immediately.`); return Promise.resolve(this._services.get(name)); } const resolution = this.CreatePendingResolution(name); this._pendingResolutions.set(resolution.Id, resolution); (_b = DependencyContainer.Log) === null || _b === void 0 ? void 0 : _b.Debug(DependencyContainer.ServiceName, `Waiting for service "${name}" (request #${resolution.Id}). Registered services: ${this.GetRegisteredServiceNamesForLogs()}.`); return new Promise((resolve, reject) => { const h = (s) => { var _a; if (s.GetServiceName() === name && this.TryCompleteResolution(resolution.Id)) { this._serviceRegistrationEvent.Unsubscribe(h); token === null || token === void 0 ? void 0 : token.CancellationEvent.Unsubscribe(onCancel); const waitedMs = Date.now() - resolution.StartedAt; (_a = DependencyContainer.Log) === null || _a === void 0 ? void 0 : _a.Info(DependencyContainer.ServiceName, `Resolved service "${name}" after ${waitedMs}ms (request #${resolution.Id}).`); resolve(s); } }; const onCancel = () => { var _a; this._serviceRegistrationEvent.Unsubscribe(h); if (!this.TryCompleteResolution(resolution.Id)) return; const waitedMs = Date.now() - resolution.StartedAt; (_a = DependencyContainer.Log) === null || _a === void 0 ? void 0 : _a.Warning(DependencyContainer.ServiceName, `Cancelled waiting for service "${name}" after ${waitedMs}ms (request #${resolution.Id}).`); reject(new Error('cancelled')); }; token === null || token === void 0 ? void 0 : token.CancellationEvent.Subscribe(onCancel); this._serviceRegistrationEvent.Subscribe(h); }); } GetServiceWithTimeoutAsync(name, timeout) { var _a, _b; if (this._services.has(name)) { (_a = DependencyContainer.Log) === null || _a === void 0 ? void 0 : _a.Debug(DependencyContainer.ServiceName, `Resolved service "${name}" immediately.`); return Promise.resolve(this._services.get(name)); } const resolution = this.CreatePendingResolution(name); this._pendingResolutions.set(resolution.Id, resolution); (_b = DependencyContainer.Log) === null || _b === void 0 ? void 0 : _b.Debug(DependencyContainer.ServiceName, `Waiting for service "${name}" with timeout ${timeout}ms (request #${resolution.Id}). Registered services: ${this.GetRegisteredServiceNamesForLogs()}.`); return new Promise((resolve, reject) => { const h = (s) => { var _a; if (s.GetServiceName() === name && this.TryCompleteResolution(resolution.Id)) { DependencyContainer.Timers.clearTimeout(tid); this._serviceRegistrationEvent.Unsubscribe(h); const waitedMs = Date.now() - resolution.StartedAt; (_a = DependencyContainer.Log) === null || _a === void 0 ? void 0 : _a.Info(DependencyContainer.ServiceName, `Resolved service "${name}" after ${waitedMs}ms (request #${resolution.Id}).`); resolve(s); } }; const tid = DependencyContainer.Timers.setTimeout(() => { var _a; this._serviceRegistrationEvent.Unsubscribe(h); if (!this.TryCompleteResolution(resolution.Id)) return; const waitedMs = Date.now() - resolution.StartedAt; (_a = DependencyContainer.Log) === null || _a === void 0 ? void 0 : _a.Warning(DependencyContainer.ServiceName, `Timeout waiting for service "${name}" after ${waitedMs}ms (request #${resolution.Id}). Registered services: ${this.GetRegisteredServiceNamesForLogs()}.`); reject(new Error(`timeout waiting for "${name}"`)); }, timeout); this._serviceRegistrationEvent.Subscribe(h); }); } CreatePendingResolution(name) { return { Id: this._nextResolutionId++, ServiceName: name, StartedAt: Date.now(), }; } TryCompleteResolution(id) { return this._pendingResolutions.delete(id); } GetRegisteredServiceNamesForLogs() { const names = [...this._services.keys()].sort(); if (names.length === 0) return "<none>"; return names.join(", "); } } DependencyContainer.ServiceName = "DependencyContainer"; DependencyContainer.IsInitialized = false; //# sourceMappingURL=DependencyContainer.js.map