UNPKG

@openhps/core

Version:

Open Hybrid Positioning System - Core component

296 lines 10.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ModelGraph = void 0; const tslib_1 = require("tslib"); const object_1 = require("../../../data/object"); const Service_1 = require("../../../service/Service"); const DataService_1 = require("../../../service/DataService"); const GraphShape_1 = require("./GraphShape"); const ServiceProxy_1 = require("../../../service/_internal/ServiceProxy"); const decorators_1 = require("../../../data/decorators"); const _internal_1 = require("../../../service/_internal"); const PushPromise_1 = require("../../PushPromise"); /** * [[Model]] implementation */ let ModelGraph = class ModelGraph extends GraphShape_1.GraphShape { /** * Create a new OpenHPS model * @param {string} name Model name */ constructor(name = 'model') { super(); this._services = new Map(); this._dataServices = new Map(); this.name = name; this.referenceSpace = new object_1.ReferenceSpace(undefined); this.removeAllListeners('build'); this.removeAllListeners('destroy'); this.once('build', this._onModelBuild.bind(this)); this.once('destroy', this._onModelDestroy.bind(this)); } _onModelBuild(_) { return new Promise((resolve, reject) => { this.emit('prebuild', _); // First resolve the building of services this._buildServices() .then(() => { for (const service of this.findAllServices()) { if (!service.isReady()) { service.emit('ready'); } } // Build nodes return this._buildNodes(_); }) .then(() => { for (const node of this.nodes) { if (!node.isReady()) { node.emit('ready'); } } this.emit('ready'); this.emit('postbuild', this); resolve(); }) .catch(reject); }); } _buildServices() { return new Promise((resolve, reject) => { const buildPromises = []; const loadService = (service) => tslib_1.__awaiter(this, void 0, void 0, function* () { if (service.isReady()) { return Promise.resolve(true); } const dependencies = service.dependencies || []; const dependencyPromises = dependencies.map((dep) => { const depService = this.findService(dep); if (depService) { return loadService(depService); } else { return Promise.resolve(true); } }); yield Promise.all(dependencyPromises); const result = yield service.emitAsync('build'); service.emit('ready'); return result; }); this._services.forEach((service) => { buildPromises.push(loadService(service)); }); this._dataServices.forEach((service) => { buildPromises.push(loadService(service)); }); Promise.all(buildPromises) .then(() => resolve()) .catch(reject); }); } _buildNodes(_) { return new Promise((resolve, reject) => { const buildPromises = []; this.nodes.forEach((node) => { if (!node.isReady()) { buildPromises.push(node.emitAsync('build', _)); } }); Promise.all(buildPromises) .then(() => resolve()) .catch(reject); }); } _onModelDestroy(_) { return new Promise((resolve, reject) => { const destroyPromises = []; this._services.forEach((service) => { destroyPromises.push(service.emitAsync('destroy', _)); }); this._dataServices.forEach((service) => { destroyPromises.push(service.emitAsync('destroy', _)); }); this.nodes.forEach((node) => { destroyPromises.push(node.emitAsync('destroy', _)); }); Promise.all(destroyPromises) .then(() => { resolve(); }) .catch(reject); }); } findService(q) { let result = undefined; if (!q) { return undefined; } else if (typeof q === 'string') { result = this._services.get(q); } else { result = Array.from(this._services.values()).filter((s) => s instanceof q)[0]; } if (!result) { result = this.findDataService(q); } return result; } findDataService(q) { let result; if (q === undefined) { result = undefined; } else if (typeof q === 'string') { // Find by name result = this._findDataServiceByUID(q); } else if (q.prototype instanceof DataService_1.DataService) { // Find by data service class result = this.findAllServices(q)[0]; } else if (q instanceof Function) { // Find by constructor result = this.findAllDataServices(q)[0]; } else { // Find by instance result = this.findDataService(q.constructor); } return result; } _findDataServiceByUID(uid) { return Array.from(this._dataServices.values()).filter((s) => s.uid === uid)[0]; } /** * Find all services and data services * @param {typeof Service} [q] Service class * @returns {Service[]} Array of all services */ findAllServices(q) { if (q !== undefined) { return this.findAllServices().filter((s) => s instanceof q) || []; } else { return Array.from(this._services.values()).concat(Array.from(this._dataServices.values())) || []; } } /** * Find all data services by data type * @param {typeof Service} [q] data type class * @returns {Service[]} Array of all services */ findAllDataServices(q) { if (q !== undefined) { return (this.findAllDataServices() .map((s) => [s, ...this._instanceofPriority(q, s['target'].dataType)]) .filter((s) => s[1]) .sort((a, b) => (a[2] === b[2] ? b[0].priority - a[0].priority : a[2] - b[2])) .map((s) => s[0]) || []); } else { return Array.from(this._dataServices.values()) || []; } } _instanceofPriority(obj, constr) { if (obj === constr) { return [true, 0]; } let level = 1; while ((obj = Object.getPrototypeOf(obj))) { if (obj === constr) { return [true, level]; } level++; } return [false, undefined]; } /** * Add service to model * @param {Service} service Service to add * @param {ProxyHandler} [proxy] Proxy handler */ addService(service, proxy) { service.model = this.graph === undefined ? this : this.model; if (service instanceof DataService_1.DataService) { // Data service this._dataServices.set(service.uid, new Proxy(service, proxy || new _internal_1.DataServiceProxy())); } else { // Normal service this._services.set(service.uid, new Proxy(service, proxy || new ServiceProxy_1.ServiceProxy())); } } push(frame, options) { return new PushPromise_1.PushPromise((resolve, reject, completed) => { const servicePromises = []; // Merge the changes in the frame service const frameService = this.findDataService(frame.constructor.name); if (frameService) { if (Array.isArray(frame)) { frame.forEach((f) => { // Update the frame servicePromises.push(frameService.insert(f.uid, frame)); }); } else { // Update the frame servicePromises.push(frameService.insert(frame.uid, frame)); } } Promise.all(servicePromises) .then(() => { const completedFrames = new Set(); this.once('completed', (e) => { if (Array.isArray(frame)) { frame.forEach((f) => { if (e.frameUID === f.uid) { completedFrames.add(f.uid); } }); if (completedFrames.size === frame.length) { completed(); } } else { if (e.frameUID === frame.uid) { completed(); } } }); const promise = this.internalSource.push(frame, options); return promise; }) .then(() => { resolve(); }) .catch(reject); }); } destroy() { return this.emitAsync('destroy'); } }; exports.ModelGraph = ModelGraph; tslib_1.__decorate([ (0, decorators_1.SerializableMapMember)(String, Service_1.Service, { name: 'services', }), tslib_1.__metadata("design:type", Map) ], ModelGraph.prototype, "_services", void 0); tslib_1.__decorate([ (0, decorators_1.SerializableMapMember)(String, DataService_1.DataService, { name: 'dataServices', }), tslib_1.__metadata("design:type", Map) ], ModelGraph.prototype, "_dataServices", void 0); tslib_1.__decorate([ (0, decorators_1.SerializableMember)(), tslib_1.__metadata("design:type", object_1.ReferenceSpace) ], ModelGraph.prototype, "referenceSpace", void 0); exports.ModelGraph = ModelGraph = tslib_1.__decorate([ (0, decorators_1.SerializableObject)(), tslib_1.__metadata("design:paramtypes", [Object]) ], ModelGraph); //# sourceMappingURL=ModelGraph.js.map