@openhps/core
Version:
Open Hybrid Positioning System - Core component
296 lines • 10.6 kB
JavaScript
;
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