@openhps/core
Version:
Open Hybrid Positioning System - Core component
195 lines • 7.25 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.LocationBasedService = void 0;
const data_1 = require("../data");
const utils_1 = require("../utils");
const Service_1 = require("./Service");
const TimeService_1 = require("./TimeService");
/**
* Location-Based Service
*
* ## Usage
*
* ### Creation
* ```typescript
* const service = new LocationBasedService<
* DataObject,
* GeographicalPosition
* >();
*
* ModelBuilder.create()
* .addService(service)
* .from()
* .to().build();
* ```
*
* ### Getting the current position
*
* ### Setting the current position
*
* ### Watching the position of an object
*/
class LocationBasedService extends Service_1.Service {
constructor(options) {
super();
this.watchers = new Map();
this.watchedObjects = new Map();
this.watchIndex = 1;
this.options = options || {};
this.addDependency(TimeService_1.TimeService);
this.once('build', this._initLBS.bind(this));
this.once('destroy', this._destroy.bind(this));
}
_initLBS() {
// Default options
this.options.pullNode = this.options.pullNode || this.model.internalSink.uid;
this.options.dataService = this.options.dataService || data_1.DataObject;
this.service = this.model.findDataService(this.options.dataService);
this.service.on('insert', (uid, storedObject) => {
const watchIds = this.watchedObjects.get(uid);
if (watchIds) {
const position = storedObject.position;
watchIds.forEach((watchId) => {
const watcher = this.watchers.get(watchId);
if (position) {
watcher.callback(position);
}
});
}
});
}
_destroy() {
Array.from(this.watchers.keys()).forEach((watcher) => {
this.clearWatch(watcher);
});
}
/**
* Set the current position of an object
* @param {DataObject | string} object Data object to get the current position of or uid
* @param {AbsolutePosition} position Position to update
* @returns {Promise<void>} Promise of updating
*/
setCurrentPosition(object, position) {
return new Promise((resolve, reject) => {
const uid = object instanceof data_1.DataObject ? object.uid : object;
this.service
.findByUID(uid)
.then((storedObj) => {
storedObj.setPosition(position);
return this.service.insertObject(storedObj);
})
.then(() => {
resolve();
})
.catch(reject);
});
}
/**
* Get the current position of a specific data object.
* @param {DataObject | string} object Data object to get the current position of or uid
* @param {GeoOptions} [options] Current position options
* @returns {Promise<AbsolutePosition>} Promise of latest absolute position
*/
getCurrentPosition(object, options = {}) {
return new Promise((resolve, reject) => {
const maximumAge = options.maximumAge || Infinity;
options.timeout = options.timeout || 10000;
const uid = object instanceof data_1.DataObject ? object.uid : object;
// Force update
if (options.forceUpdate) {
this.model.findNodeByUID(this.options.pullNode).pull({
requestedObjects: [uid],
});
const timeout = setTimeout(() => {
this.clearWatch(watchId);
reject(new Error('Timeout error for getting current position!'));
}, options.timeout);
const watchId = this.watchPosition(object, (pos, err) => {
this.clearWatch(watchId);
clearTimeout(timeout);
if (err) {
return reject(err);
}
resolve(pos);
}, Object.assign(Object.assign({}, options), { interval: -1, forceUpdate: false }));
}
else {
this.service
.findByUID(uid)
.then((storedObj) => {
const position = storedObj.position;
const time = TimeService_1.TimeService.getUnit().convert(TimeService_1.TimeService.now(), utils_1.TimeUnit.MILLISECOND);
if (position && position.timestamp >= time - maximumAge) {
// Stored position satisfies maximum age
resolve(position);
}
else {
return this.getCurrentPosition(object, Object.assign(Object.assign({}, options), { forceUpdate: true }));
}
})
.then(resolve)
.catch(reject);
}
});
}
/**
* Watch for position changes
* @param {DataObject | string} object Data object to watch for position changes for
* @param {(position: AbsolutePosition, err?: Error) => void} callback Callback function
* @param {GeoWatchOptions} [options] Watch options
* @returns {number} Watch number
*/
watchPosition(object, callback, options = {}) {
var _a;
const uid = object instanceof data_1.DataObject ? object.uid : object;
const watchId = this.watchIndex++;
const interval = (_a = options.interval) !== null && _a !== void 0 ? _a : 1000;
const timer = interval !== -1
? setInterval(() => {
this.getCurrentPosition(object, options)
.then(callback)
.catch((ex) => {
callback(undefined, ex);
});
}, interval)
: undefined;
this.watchers.set(watchId, {
timer,
uid,
callback,
});
this.watchObject(uid, watchId);
return watchId;
}
watchObject(uid, watchId) {
var _a;
const existingIds = (_a = this.watchedObjects.get(uid)) !== null && _a !== void 0 ? _a : [];
existingIds.push(watchId);
this.watchedObjects.set(uid, existingIds);
}
unwatchObject(uid, watchId) {
var _a;
const existingIds = (_a = this.watchedObjects.get(uid)) !== null && _a !== void 0 ? _a : [];
existingIds.splice(existingIds.indexOf(watchId), 1);
if (existingIds.length === 0) {
this.watchedObjects.delete(uid);
}
else {
this.watchedObjects.set(uid, existingIds);
}
}
/**
* Clear a running position watch
* @param {number} watchId Watch identifier
*/
clearWatch(watchId) {
const watcher = this.watchers.get(watchId);
if (watcher.timer !== undefined) {
clearInterval(watcher.timer);
}
this.watchers.delete(watchId);
this.unwatchObject(watcher.uid, watchId);
}
}
exports.LocationBasedService = LocationBasedService;
//# sourceMappingURL=LocationBasedService.js.map