UNPKG

@bbc/sofie-server-core-integration

Version:
139 lines 5.67 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.TimeSync = void 0; const tslib_1 = require("tslib"); const underscore_1 = tslib_1.__importDefault(require("underscore")); class TimeSync { // public serverDelayTime: number = 0.0008 // the minimum time we think the server needs to process our request _options; _invalidationCallback; _timeSource; _syncDiff; // difference local time vs server time _syncQuality; // how good the synced time probably is (in ms) _lastSyncTime; // timestamp (in local time) _timeInterval = undefined; constructor(options, timeSource, invalidationCallback) { this._timeSource = timeSource; this._options = { syncPeriod: options.syncPeriod || 1000 * 60 * 10, minSyncQuality: options.minSyncQuality || 1000 / 50, minTryCount: options.minTryCount || 3, maxTryCount: options.maxTryCount || 10, retryWaitTime: options.retryWaitTime || 300, serverDelayTime: options.serverDelayTime || 0, }; this._syncDiff = 0; this._lastSyncTime = 0; this._syncQuality = null; this._invalidationCallback = invalidationCallback; } localTime() { return Date.now(); } currentTime() { return this.localTime() + this._syncDiff; } get quality() { return this._syncQuality; } get diff() { return this._syncDiff; } isGood() { return !!(this.quality && this.quality < this._options.minSyncQuality); } async init() { this._timeInterval = setInterval(() => { this.maybeTriggerSync(); }, this._options.syncPeriod / 2); return this.syncTime(); } stop() { if (this._timeInterval) { clearInterval(this._timeInterval); } } maybeTriggerSync() { if (this.localTime() - this._lastSyncTime > this._options.syncPeriod) { // It's time to do a sync // log.verbose('triggerSync ' + (this.localTime() - this._lastSyncTime)) this._lastSyncTime = this.localTime(); setTimeout(() => { this.syncTime().catch((err) => { console.log(err); }); }, 1); } } async syncTime() { const syncResults = []; let selectedSyncResult = null; let haveGoodSyncResult = false; const doSync = async () => { const startTime = this.localTime(); // Local time at the start of the query const serverTime = await this._timeSource(); // Server time at some point during the query if (serverTime) { const endTime = this.localTime(); // Local time at the end of the query const transportDuration = endTime - startTime; const calcLocalTime = startTime + transportDuration / 2 + this._options.serverDelayTime; // Our best guess of the point in time the server probably calculated serverTime const quality = transportDuration / 2; // The estimated quality of our estimate const diff = serverTime - calcLocalTime; return { diff: diff, quality: quality, }; } return { diff: 0, quality: null, }; }; for (let tryCount = 0; tryCount < this._options.maxTryCount; tryCount++) { const syncResult = await doSync(); if (!underscore_1.default.isNull(syncResult.quality)) { syncResults.push(syncResult); } if (tryCount >= this._options.minTryCount) { // Evaluate our progress: // The best result is the one earliest in time, since the best quality is // caused by the lowest delay: let bestResult = underscore_1.default.min(syncResults, (r) => { return !underscore_1.default.isNull(r.quality) ? r.quality : 999999; }); if (!bestResult) bestResult = { diff: 0, quality: null }; if (!underscore_1.default.isNull(bestResult.quality) && bestResult.quality < this._options.minSyncQuality) { // Our result is good enough selectedSyncResult = bestResult; haveGoodSyncResult = true; break; } } } if (!selectedSyncResult) { // We don't have a good sync result. const bestResult = underscore_1.default.min(syncResults, (r) => { return !underscore_1.default.isNull(r.quality) ? r.quality : 999999; }); if (!underscore_1.default.isNull(bestResult.quality) && bestResult.quality < (this._syncQuality || 99990)) { // It's not a good result, but it's better than what we currently have selectedSyncResult = bestResult; } } if (selectedSyncResult) { // we've got a sync result this._syncDiff = selectedSyncResult.diff; this._syncQuality = selectedSyncResult.quality; this._lastSyncTime = this.localTime(); if (this._invalidationCallback) this._invalidationCallback(); return haveGoodSyncResult; } else { // we never got a result that was good enough return false; } } } exports.TimeSync = TimeSync; //# sourceMappingURL=timeSync.js.map