UNPKG

raspi-io-server-utils

Version:

Utilities for interacting with Raspberry IOs and Raspbian

147 lines 11.5 kB
"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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