raspi-io-server-utils
Version:
Utilities for interacting with Raspberry IOs and Raspbian
147 lines • 11.5 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const EventEmitter = require('events');
const check = require('check-types');
/**
* Simple implementation of a vector clock.
*
* Events:
* - `new-time` when the time of any member changed
* - `time` when the time of the owner was changed by a client (may be renamed in future)
*/
class VectorClock extends EventEmitter {
constructor(data) {
super();
this._clock = new Map();
if (check.not.object(data))
throw new Error('Must pass either an ID (string) or an object to construct a vector clock');
if (check.not.string(data.owner))
throw new Error('owner is required when constructing from object');
const ownId = data.owner;
if (check.array(data.time)) {
data.time.forEach(t => {
if (check.not.string(t.id))
throw new Error(`time vector IDs must be strings: {id:string,t:number}[]. Received ${JSON.stringify(t)}`);
if (check.not.number(t.time))
throw new Error(`time vector times must be numbers: {id:string,t:number}[]. Received ${JSON.stringify(t)}`);
this.updateOther(t.id, t.time);
});
}
this._ownId = ownId;
if (!this._clock.has(ownId)) {
this._clock.set(ownId, 0);
}
}
get id() {
return this._ownId;
}
get time() {
return this._clock.get(this._ownId);
}
set time(time) {
this._clock.set(this._ownId, time);
}
get timestamps() {
const timestamps = [];
this._clock.forEach((v, k) => timestamps.push({ id: k, time: v }));
return timestamps;
}
get json() {
return {
owner: this._ownId,
time: this.timestamps,
};
}
nextTick() {
this._clock.set(this._ownId, this._clock.get(this._ownId) + 1);
this._newTime();
return this;
}
newerThan(other) {
let newer = 0;
let newerOrEqual = 0;
this._clock.forEach((v, k) => {
newer += Number(v > other.timeOf(k));
newerOrEqual += Number(v >= other.timeOf(k));
});
const knowsAll = other.timestamps.every(timestamp => this._clock.has(timestamp.id));
return knowsAll && newerOrEqual > 0 && newer > 0;
}
/**
* @param otherClock
* @returns true, if this clock holds information about the owner of another clock.
*/
knowsOwnerOf(otherClock) {
return this._clock.has(otherClock.id);
}
/**
* Only checks the timestamp of this clock's owner, ignores all other timestamps
*/
ownTimestampNewerThan(other) {
return this.time > other.time;
}
/**
* Integrate vector time of other into own time (update timestamps of all clients)
* @param other
* @param canUpdateMyTime Set to true if other clocks can update the time of this clock.
* This is useful e.g. if the owner of this clock could go offline and lose the current time, so it is recovered.
*/
syncFrom(other, canUpdateMyTime = false) {
let changes = 0;
const errors = [];
other.timestamps.forEach(time => {
if (time.id !== this._ownId) {
let changed = this.updateOther(time.id, time.time);
if (changed)
changes++;
}
else {
if (time.time > this.time) {
if (canUpdateMyTime) {
this.time = time.time;
changes++;
this._ownClockUpdated();
}
else {
errors.push('Client thinks my time is newer');
}
}
}
});
if (errors.length > 0) {
throw new Error(errors.join(','));
}
if (changes) {
this._newTime();
}
return this;
}
timeOf(id) {
return this._clock.get(id);
}
toString() {
const times = [`{Vector Clock for ${this._ownId}}`];
this._clock.forEach((v, k) => times.push(` ${v} : ${k}${k === this._ownId ? ' (self)' : ''}`));
return times.join('\n');
}
updateOther(id, time) {
if (id === this._ownId)
throw new Error('Other client has same ID: ' + id);
if (check.not.string(id))
throw new Error('Client ID must be a string. Received: ' + id);
if (check.not.greaterOrEqual(time, 0))
throw new Error(`Time for client ${id} must be a number > 0`);
const currentTime = this._clock.get(id) || 0;
const changed = currentTime !== time;
this._clock.set(id, Math.max(currentTime, time));
return changed;
}
_ownClockUpdated() {
setImmediate(() => this.emit('time'));
}
_newTime() {
setImmediate(() => this.emit('new-time'));
}
}
exports.VectorClock = VectorClock;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmVjdG9yLWNsb2NrLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3ZlY3Rvci1jbG9jay92ZWN0b3ItY2xvY2sudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFBQSxNQUFNLFlBQVksR0FBRyxPQUFPLENBQUUsUUFBUSxDQUFFLENBQUM7QUFDekMsTUFBTSxLQUFLLEdBQUcsT0FBTyxDQUFFLGFBQWEsQ0FBRSxDQUFDO0FBRXZDOzs7Ozs7R0FNRztBQUNILE1BQWEsV0FBWSxTQUFRLFlBQVk7SUFLekMsWUFBYSxJQUF3QztRQUNqRCxLQUFLLEVBQUUsQ0FBQztRQUVSLElBQUksQ0FBQyxNQUFNLEdBQUcsSUFBSSxHQUFHLEVBQUUsQ0FBQztRQUV4QixJQUFLLEtBQUssQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFFLElBQUksQ0FBRTtZQUFHLE1BQU0sSUFBSSxLQUFLLENBQUUsMEVBQTBFLENBQUUsQ0FBQztRQUM5SCxJQUFLLEtBQUssQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFFLElBQUksQ0FBQyxLQUFLLENBQUU7WUFBRyxNQUFNLElBQUksS0FBSyxDQUFFLGlEQUFpRCxDQUFFLENBQUM7UUFFM0csTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQztRQUV6QixJQUFLLEtBQUssQ0FBQyxLQUFLLENBQUUsSUFBSSxDQUFDLElBQUksQ0FBRSxFQUFHO1lBQzVCLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFFLENBQUMsQ0FBQyxFQUFFO2dCQUNuQixJQUFLLEtBQUssQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFFLENBQUMsQ0FBQyxFQUFFLENBQUU7b0JBQUcsTUFBTSxJQUFJLEtBQUssQ0FBRSxxRUFBcUUsSUFBSSxDQUFDLFNBQVMsQ0FBRSxDQUFDLENBQUUsRUFBRSxDQUFFLENBQUM7Z0JBQzlJLElBQUssS0FBSyxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUUsQ0FBQyxDQUFDLElBQUksQ0FBRTtvQkFB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