ng2-idle-timeout
Version:
Zoneless-friendly session timeout management for Angular 16-20.
266 lines • 32.1 kB
JavaScript
import { DestroyRef, Injectable, NgZone, computed, inject, signal } from '@angular/core';
import { toObservable } from '@angular/core/rxjs-interop';
import { SESSION_TIMEOUT_CONFIG } from '../tokens/config.token';
import * as i0 from "@angular/core";
const HEARTBEAT_INTERVAL_MS = 1500;
const LEADER_TTL_MS = HEARTBEAT_INTERVAL_MS * 3;
export class LeaderElectionService {
destroyRef = inject(DestroyRef);
zone = inject(NgZone);
providedConfig = inject(SESSION_TIMEOUT_CONFIG, { optional: true });
leaderSignal = signal(null);
tabId = generateLeaderId();
storageKey = null;
heartbeatTimer = null;
watchdogTimer = null;
storage = this.resolveStorage();
isDisposed = false;
leaderId = this.leaderSignal.asReadonly();
isLeader = computed(() => this.leaderSignal() === this.tabId);
leader$ = toObservable(this.leaderId);
isLeader$ = toObservable(this.isLeader);
constructor() {
this.applyConfig(this.providedConfig);
if (!this.storage || !this.storageKey) {
return;
}
this.initialize();
}
updateConfig(config) {
this.applyConfig(config);
if (!this.storage || !this.storageKey || this.isDisposed) {
return;
}
this.evaluateLeadership();
}
electLeader() {
this.evaluateLeadership();
}
stepDown() {
if (!this.storage || !this.storageKey) {
return;
}
if (this.leaderSignal() === this.tabId) {
try {
const record = this.readLeaderRecord();
if (record?.id === this.tabId) {
this.storage.removeItem(this.storageKey);
}
}
catch (error) {
console.warn('[ng2-idle-timeout] Unable to release leader record', error);
}
}
this.stopHeartbeat();
this.leaderSignal.set(null);
}
initialize() {
this.destroyRef.onDestroy(() => {
this.cleanup();
});
this.evaluateLeadership();
this.startWatchdog();
if (typeof window !== 'undefined') {
window.addEventListener('storage', this.handleStorageEvent);
window.addEventListener('beforeunload', this.handleBeforeUnload);
}
}
cleanup() {
if (this.isDisposed) {
return;
}
this.isDisposed = true;
this.stopHeartbeat();
this.stopWatchdog();
if (typeof window !== 'undefined') {
window.removeEventListener('storage', this.handleStorageEvent);
window.removeEventListener('beforeunload', this.handleBeforeUnload);
}
}
handleBeforeUnload = () => {
this.stepDown();
};
handleStorageEvent = (event) => {
if (!this.storageKey || event.key !== this.storageKey) {
return;
}
this.zone.run(() => {
if (event.newValue == null) {
if (this.leaderSignal() !== this.tabId) {
this.leaderSignal.set(null);
}
return;
}
try {
const record = JSON.parse(event.newValue);
if (record.id === this.tabId) {
this.ensureHeartbeat();
this.leaderSignal.set(this.tabId);
}
else {
const now = Date.now();
if (now - record.updatedAt > LEADER_TTL_MS) {
this.evaluateLeadership();
return;
}
this.stopHeartbeat();
this.leaderSignal.set(record.id);
}
}
catch (error) {
console.warn('[ng2-idle-timeout] Invalid leader record from storage', error);
}
});
};
applyConfig(config) {
const storageKeyPrefix = config?.storageKeyPrefix ?? 'ng2-idle-timeout';
const appInstanceId = config?.appInstanceId ?? 'ng2-idle-timeout';
const nextKey = `${appInstanceId}:${storageKeyPrefix}:leader`;
if (this.storageKey === nextKey) {
return;
}
this.storageKey = nextKey;
if (this.storage) {
this.evaluateLeadership();
}
}
resolveStorage() {
if (typeof window === 'undefined') {
return null;
}
try {
return window.localStorage;
}
catch (error) {
console.warn('[ng2-idle-timeout] Leader election storage unavailable', error);
return null;
}
}
evaluateLeadership() {
if (!this.storage || !this.storageKey || this.isDisposed) {
return;
}
const record = this.readLeaderRecord();
const now = Date.now();
if (record?.id === this.tabId) {
this.leaderSignal.set(this.tabId);
this.ensureHeartbeat();
return;
}
if (!record || now - record.updatedAt > LEADER_TTL_MS) {
this.claimLeadership();
return;
}
this.leaderSignal.set(record.id);
this.stopHeartbeat();
}
claimLeadership() {
if (!this.storage || !this.storageKey || this.isDisposed) {
return;
}
const record = {
id: this.tabId,
updatedAt: Date.now()
};
try {
this.storage.setItem(this.storageKey, JSON.stringify(record));
this.leaderSignal.set(this.tabId);
this.ensureHeartbeat();
}
catch (error) {
console.warn('[ng2-idle-timeout] Unable to persist leader record', error);
}
}
readLeaderRecord() {
if (!this.storage || !this.storageKey) {
return null;
}
try {
const raw = this.storage.getItem(this.storageKey);
if (!raw) {
return null;
}
return JSON.parse(raw);
}
catch (error) {
console.warn('[ng2-idle-timeout] Unable to read leader record', error);
return null;
}
}
startWatchdog() {
if (!this.storage || this.watchdogTimer != null || typeof window === 'undefined') {
return;
}
this.zone.runOutsideAngular(() => {
this.watchdogTimer = window.setInterval(() => {
this.zone.run(() => {
this.evaluateLeadership();
});
}, HEARTBEAT_INTERVAL_MS);
});
}
stopWatchdog() {
if (this.watchdogTimer != null && typeof window !== 'undefined') {
window.clearInterval(this.watchdogTimer);
}
this.watchdogTimer = null;
}
startHeartbeat() {
if (!this.storage || this.heartbeatTimer != null || typeof window === 'undefined') {
return;
}
if (!this.isLeader()) {
return;
}
this.zone.runOutsideAngular(() => {
this.heartbeatTimer = window.setInterval(() => {
this.zone.run(() => {
this.touchLeaderRecord();
});
}, HEARTBEAT_INTERVAL_MS);
});
}
ensureHeartbeat() {
if (this.heartbeatTimer == null) {
this.startHeartbeat();
}
}
stopHeartbeat() {
if (this.heartbeatTimer != null && typeof window !== 'undefined') {
window.clearInterval(this.heartbeatTimer);
}
this.heartbeatTimer = null;
}
touchLeaderRecord() {
if (!this.storage || !this.storageKey || this.isDisposed) {
return;
}
if (this.leaderSignal() !== this.tabId) {
this.stopHeartbeat();
return;
}
const record = {
id: this.tabId,
updatedAt: Date.now()
};
try {
this.storage.setItem(this.storageKey, JSON.stringify(record));
}
catch (error) {
console.warn('[ng2-idle-timeout] Unable to update leader heartbeat', error);
}
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.0", ngImport: i0, type: LeaderElectionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.0", ngImport: i0, type: LeaderElectionService, providedIn: 'root' });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.0", ngImport: i0, type: LeaderElectionService, decorators: [{
type: Injectable,
args: [{ providedIn: 'root' }]
}], ctorParameters: () => [] });
function generateLeaderId() {
if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {
return crypto.randomUUID();
}
return Math.random().toString(36).slice(2);
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibGVhZGVyLWVsZWN0aW9uLnNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvbGliL3NlcnZpY2VzL2xlYWRlci1lbGVjdGlvbi5zZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxVQUFVLEVBQUUsVUFBVSxFQUFFLE1BQU0sRUFBRSxRQUFRLEVBQUUsTUFBTSxFQUFFLE1BQU0sRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUN6RixPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFHMUQsT0FBTyxFQUFFLHNCQUFzQixFQUFFLE1BQU0sd0JBQXdCLENBQUM7O0FBT2hFLE1BQU0scUJBQXFCLEdBQUcsSUFBSSxDQUFDO0FBQ25DLE1BQU0sYUFBYSxHQUFHLHFCQUFxQixHQUFHLENBQUMsQ0FBQztBQUdoRCxNQUFNLE9BQU8scUJBQXFCO0lBQ2YsVUFBVSxHQUFHLE1BQU0sQ0FBQyxVQUFVLENBQUMsQ0FBQztJQUNoQyxJQUFJLEdBQUcsTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQ3RCLGNBQWMsR0FBRyxNQUFNLENBQUMsc0JBQXNCLEVBQUUsRUFBRSxRQUFRLEVBQUUsSUFBSSxFQUFFLENBRXRFLENBQUM7SUFDRyxZQUFZLEdBQUcsTUFBTSxDQUFnQixJQUFJLENBQUMsQ0FBQztJQUMzQyxLQUFLLEdBQUcsZ0JBQWdCLEVBQUUsQ0FBQztJQUNwQyxVQUFVLEdBQWtCLElBQUksQ0FBQztJQUNqQyxjQUFjLEdBQWtCLElBQUksQ0FBQztJQUNyQyxhQUFhLEdBQWtCLElBQUksQ0FBQztJQUNwQyxPQUFPLEdBQW1CLElBQUksQ0FBQyxjQUFjLEVBQUUsQ0FBQztJQUNoRCxVQUFVLEdBQUcsS0FBSyxDQUFDO0lBRWxCLFFBQVEsR0FBRyxJQUFJLENBQUMsWUFBWSxDQUFDLFVBQVUsRUFBRSxDQUFDO0lBQzFDLFFBQVEsR0FBRyxRQUFRLENBQUMsR0FBRyxFQUFF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QUksT0FBTyxNQUFNLEtBQUssV0FBVyxJQUFJLE9BQU8sTUFBTSxDQUFDLFVBQVUsS0FBSyxVQUFVLEVBQUUsQ0FBQztRQUM3RSxPQUFPLE1BQU0sQ0FBQyxVQUFVLEVBQUUsQ0FBQztJQUM3QixDQUFDO0lBQ0QsT0FBTyxJQUFJLENBQUMsTUFBTSxFQUFFLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQztBQUM3QyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgRGVzdHJveVJlZiwgSW5qZWN0YWJsZSwgTmdab25lLCBjb21wdXRlZCwgaW5qZWN0LCBzaWduYWwgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcclxuaW1wb3J0IHsgdG9PYnNlcnZhYmxlIH0gZnJvbSAnQGFuZ3VsYXIvY29yZS9yeGpzLWludGVyb3AnO1xyXG5cclxuaW1wb3J0IHR5cGUgeyBTZXNzaW9uVGltZW91dENvbmZpZyB9IGZyb20gJy4uL21vZGVscy9zZXNzaW9uLXRpbWVvdXQtY29uZmlnJztcclxuaW1wb3J0IHsgU0VTU0lPTl9USU1FT1VUX0NPTkZJRyB9IGZyb20gJy4uL3Rva2Vucy9jb25maWcudG9rZW4nO1xyXG5cclxuaW50ZXJmYWNlIExlYWRlclJlY29yZCB7XHJcbiAgaWQ6IHN0cmluZztcclxuICB1cGRhdGVkQXQ6IG51bWJlcjtcclxufVxyXG5cclxuY29uc3QgSEVBUlRCRUFUX0lOVEVSVkFMX01TID0gMTUwMDtcclxuY29uc3QgTEVBREVSX1RUTF9NUyA9IEhFQVJUQkVBVF9JTlRFUlZBTF9NUyAqIDM7XHJcblxyXG5ASW5qZWN0YWJsZSh7IHByb3ZpZGVkSW46ICdyb290JyB9KVxyXG5leHBvcnQgY2xhc3MgTGVhZGVyRWxlY3Rpb25TZXJ2aWNlIHtcclxuICBwcml2YXRlIHJlYWRvbmx5IGRlc3Ryb3lSZWYgPSBpbmplY3QoRGVzdHJveVJlZik7XHJcbiAgcHJpdmF0ZSByZWFkb25seSB6b25lID0gaW5qZWN0KE5nWm9uZSk7XHJcbiAgcHJpdmF0ZSByZWFkb25seSBwcm92aWRlZENvbmZpZyA9IGluamVjdChTRVNTSU9OX1RJTUVPVVRfQ09ORklHLCB7IG9wdGlvbmFsOiB0cnVlIH0pIGFzXHJcbiAgICB8IFNlc3Npb25UaW1lb3V0Q29uZmlnXHJcbiAgICB8IHVuZGVmaW5lZDtcclxuICBwcml2YXRlIHJlYWRvbmx5IGxlYWRlclNpZ25hbCA9IHNpZ25hbDxzdHJpbmcgfCBudWxsPihudWxsKTtcclxuICBwcml2YXRlIHJlYWRvbmx5IHRhYklkID0gZ2VuZXJhdGVMZWFkZXJJZCgpO1xyXG4gIHByaXZhdGUgc3RvcmFnZUtleTogc3RyaW5nIHwgbnVsbCA9IG51bGw7XHJcbiAgcHJpdmF0ZSBoZWFydGJlYXRUaW1lcjogbnVtYmVyIHwgbnVsbCA9IG51bGw7XHJcbiAgcHJpdmF0ZSB3YXRjaGRvZ1RpbWVyOiBudW1iZXIgfCBudWxsID0gbnVsbDtcclxuICBwcml2YXRlIHN0b3JhZ2U6IFN0b3JhZ2UgfCBudWxsID0gdGhpcy5yZXNvbHZlU3RvcmFnZSgpO1xyXG4gIHByaXZhdGUgaXNEaXNwb3NlZCA9IGZhbHNlO1xyXG5cclxuICByZWFkb25seSBsZWFkZXJJZCA9IHRoaXMubGVhZGVyU2lnbmFsLmFzUmVhZG9ubHkoKTtcclxuICByZWFkb25seSBpc0xlYWRlciA9IGNvbXB1dGVkKCgpID0+IHRoaXMubGVhZGVyU2lnbmFsKCkgPT09IHRoaXMudGFiSWQpO1xyXG4gIHJlYWRvbmx5IGxlYWRlciQgPSB0b09ic2VydmFibGUodGhpcy5sZWFkZXJJZCk7XHJcbiAgcmVhZG9ubHkgaXNMZWFkZXIkID0gdG9PYnNlcnZhYmxlKHRoaXMuaXNMZWFkZXIpO1xyXG5cclxuICBjb25zdHJ1Y3RvcigpIHtcclxuICAgIHRoaXMuYXBwbHlDb25maWcodGhpcy5wcm92aWRlZENvbmZpZyk7XHJcblxyXG4gICAgaWYgKCF0aGlzLnN0b3JhZ2UgfHwgIXRoaXMuc3RvcmFnZUtleSkge1xyXG4gICAgICByZXR1cm47XHJcbiAgICB9XHJcblxyXG4gICAgdGhpcy5pbml0aWFsaXplKCk7XHJcbiAgfVxyXG5cclxuICB1cGRhdGVDb25maWcoY29uZmlnOiBTZXNzaW9uVGltZW91dENvbmZpZyk6IHZvaWQge1xyXG4gICAgdGhpcy5hcHBseUNvbmZpZyhjb25maWcpO1xyXG4gICAgaWYgKCF0aGlzLnN0b3JhZ2UgfHwgIXRoaXMuc3RvcmFnZUtleSB8fCB0aGlzLmlzRGlzcG9zZWQpIHtcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG4gICAgdGhpcy5ldmFsdWF0ZUxlYWRlcnNoaXAoKTtcclxuICB9XHJcblxyXG4gIGVsZWN0TGVhZGVyKCk6IHZvaWQge1xyXG4gICAgdGhpcy5ldmFsdWF0ZUxlYWRlcnNoaXAoKTtcclxuICB9XHJcblxyXG4gIHN0ZXBEb3duKCk6IHZvaWQge1xyXG4gICAgaWYgKCF0aGlzLnN0b3JhZ2UgfHwgIXRoaXMuc3RvcmFnZUtleSkge1xyXG4gICAgICByZXR1cm47XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKHRoaXMubGVhZGVyU2lnbmFsKCkgPT09IHRoaXMudGFiSWQpIHtcclxuICAgICAgdHJ5IHtcclxuICAgICAgICBjb25zdCByZWNvcmQgPSB0aGlzLnJlYWRMZWFkZXJSZWNvcmQoKTtcclxuICAgICAgICBpZiAocmVjb3JkPy5pZCA9PT0gdGhpcy50YWJJZCkge1xyXG4gICAgICAgICAgdGhpcy5zdG9yYWdlLnJlbW92ZUl0ZW0odGhpcy5zdG9yYWdlS2V5KTtcclxuICAgICAgICB9XHJcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgY29uc29sZS53YXJuKCdbbmcyLWlkbGUtdGltZW91dF0gVW5hYmxlIHRvIHJlbGVhc2UgbGVhZGVyIHJlY29yZCcsIGVycm9yKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIHRoaXMuc3RvcEhlYXJ0YmVhdCgpO1xyXG4gICAgdGhpcy5sZWFkZXJTaWduYWwuc2V0KG51bGwpO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBpbml0aWFsaXplKCk6IHZvaWQge1xyXG4gICAgdGhpcy5kZXN0cm95UmVmLm9uRGVzdHJveSgoKSA9PiB7XHJcbiAgICAgIHRoaXMuY2xlYW51cCgpO1xyXG4gICAgfSk7XHJcblxyXG4gICAgdGhpcy5ldmFsdWF0ZUxlYWRlcnNoaXAoKTtcclxuICAgIHRoaXMuc3RhcnRXYXRjaGRvZygpO1xyXG5cclxuICAgIGlmICh0eXBlb2Ygd2luZG93ICE9PSAndW5kZWZpbmVkJykge1xyXG4gICAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcignc3RvcmFnZScsIHRoaXMuaGFuZGxlU3RvcmFnZUV2ZW50KTtcclxuICAgICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoJ2JlZm9yZXVubG9hZCcsIHRoaXMuaGFuZGxlQmVmb3JlVW5sb2FkKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIHByaXZhdGUgY2xlYW51cCgpOiB2b2lkIHtcclxuICAgIGlmICh0aGlzLmlzRGlzcG9zZWQpIHtcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG4gICAgdGhpcy5pc0Rpc3Bvc2VkID0gdHJ1ZTtcclxuICAgIHRoaXMuc3RvcEhlYXJ0YmVhdCgpO1xyXG4gICAgdGhpcy5zdG9wV2F0Y2hkb2coKTtcclxuICAgIGlmICh0eXBlb2Ygd2luZG93ICE9PSAndW5kZWZpbmVkJykge1xyXG4gICAgICB3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lcignc3RvcmFnZScsIHRoaXMuaGFuZGxlU3RvcmFnZUV2ZW50KTtcclxuICAgICAgd2luZG93LnJlbW92ZUV2ZW50TGlzdGVuZXIoJ2JlZm9yZXVubG9hZCcsIHRoaXMuaGFuZGxlQmVmb3JlVW5sb2FkKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIHByaXZhdGUgcmVhZG9ubHkgaGFuZGxlQmVmb3JlVW5sb2FkID0gKCk6IHZvaWQgPT4ge1xyXG4gICAgdGhpcy5zdGVwRG93bigpO1xyXG4gIH07XHJcblxyXG4gIHByaXZhdGUgcmVhZG9ubHkgaGFuZGxlU3RvcmFnZUV2ZW50ID0gKGV2ZW50OiBTdG9yYWdlRXZlbnQpOiB2b2lkID0+IHtcclxuICAgIGlmICghdGhpcy5zdG9yYWdlS2V5IHx8IGV2ZW50LmtleSAhPT0gdGhpcy5zdG9yYWdlS2V5KSB7XHJcbiAgICAgIHJldHVybjtcclxuICAgIH1cclxuXHJcbiAgICB0aGlzLnpvbmUucnVuKCgpID0+IHtcclxuICAgICAgaWYgKGV2ZW50Lm5ld1ZhbHVlID09IG51bGwpIHtcclxuICAgICAgICBpZiAodGhpcy5sZWFkZXJTaWduYWwoKSAhPT0gdGhpcy50YWJJZCkge1xyXG4gICAgICAgICAgdGhpcy5sZWFkZXJTaWduYWwuc2V0KG51bGwpO1xyXG4gICAgICAgIH1cclxuICAgICAgICByZXR1cm47XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgY29uc3QgcmVjb3JkID0gSlNPTi5wYXJzZShldmVudC5uZXdWYWx1ZSkgYXMgTGVhZGVyUmVjb3JkO1xyXG4gICAgICAgIGlmIChyZWNvcmQuaWQgPT09IHRoaXMudGFiSWQpIHtcclxuICAgICAgICAgIHRoaXMuZW5zdXJlSGVhcnRiZWF0KCk7XHJcbiAgICAgICAgICB0aGlzLmxlYWRlclNpZ25hbC5zZXQodGhpcy50YWJJZCk7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgIGNvbnN0IG5vdyA9IERhdGUubm93KCk7XHJcbiAgICAgICAgICBpZiAobm93IC0gcmVjb3JkLnVwZGF0ZWRBdCA+IExFQURFUl9UVExfTVMpIHtcclxuICAgICAgICAgICAgdGhpcy5ldmFsdWF0ZUxlYWRlcnNoaXAoKTtcclxuICAgICAgICAgICAgcmV0dXJuO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgICAgdGhpcy5zdG9wSGVhcnRiZWF0KCk7XHJcbiAgICAgICAgICB0aGlzLmxlYWRlclNpZ25hbC5zZXQocmVjb3JkLmlkKTtcclxuICAgICAgICB9XHJcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgY29uc29sZS53YXJuKCdbbmcyLWlkbGUtdGltZW91dF0gSW52YWxpZCBsZWFkZXIgcmVjb3JkIGZyb20gc3RvcmFnZScsIGVycm9yKTtcclxuICAgICAgfVxyXG4gICAgfSk7XHJcbiAgfTtcclxuXHJcbiAgcHJpdmF0ZSBhcHBseUNvbmZpZyhjb25maWc6IFNlc3Npb25UaW1lb3V0Q29uZmlnIHwgdW5kZWZpbmVkKTogdm9pZCB7XHJcbiAgICBjb25zdCBzdG9yYWdlS2V5UHJlZml4ID0gY29uZmlnPy5zdG9yYWdlS2V5UHJlZml4ID8/ICduZzItaWRsZS10aW1lb3V0JztcclxuICAgIGNvbnN0IGFwcEluc3RhbmNlSWQgPSBjb25maWc/LmFwcEluc3RhbmNlSWQgPz8gJ25nMi1pZGxlLXRpbWVvdXQnO1xyXG4gICAgY29uc3QgbmV4dEtleSA9IGAke2FwcEluc3RhbmNlSWR9OiR7c3RvcmFnZUtleVByZWZpeH06bGVhZGVyYDtcclxuXHJcbiAgICBpZiAodGhpcy5zdG9yYWdlS2V5ID09PSBuZXh0S2V5KSB7XHJcbiAgICAgIHJldHVybjtcclxuICAgIH1cclxuXHJcbiAgICB0aGlzLnN0b3JhZ2VLZXkgPSBuZXh0S2V5O1xyXG4gICAgaWYgKHRoaXMuc3RvcmFnZSkge1xyXG4gICAgICB0aGlzLmV2YWx1YXRlTGVhZGVyc2hpcCgpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSByZXNvbHZlU3RvcmFnZSgpOiBTdG9yYWdlIHwgbnVsbCB7XHJcbiAgICBpZiAodHlwZW9mIHdpbmRvdyA9PT0gJ3VuZGVmaW5lZCcpIHtcclxuICAgICAgcmV0dXJuIG51bGw7XHJcbiAgICB9XHJcblxyXG4gICAgdHJ5IHtcclxuICAgICAgcmV0dXJuIHdpbmRvdy5sb2NhbFN0b3JhZ2U7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICBjb25zb2xlLndhcm4oJ1tuZzItaWRsZS10aW1lb3V0XSBMZWFkZXIgZWxlY3Rpb24gc3RvcmFnZSB1bmF2YWlsYWJsZScsIGVycm9yKTtcclxuICAgICAgcmV0dXJuIG51bGw7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIGV2YWx1YXRlTGVhZGVyc2hpcCgpOiB2b2lkIHtcclxuICAgIGlmICghdGhpcy5zdG9yYWdlIHx8ICF0aGlzLnN0b3JhZ2VLZXkgfHwgdGhpcy5pc0Rpc3Bvc2VkKSB7XHJcbiAgICAgIHJldHVybjtcclxuICAgIH1cclxuXHJcbiAgICBjb25zdCByZWNvcmQgPSB0aGlzLnJlYWRMZWFkZXJSZWNvcmQoKTtcclxuICAgIGNvbnN0IG5vdyA9IERhdGUubm93KCk7XHJcblxyXG4gICAgaWYgKHJlY29yZD8uaWQgPT09IHRoaXMudGFiSWQpIHtcclxuICAgICAgdGhpcy5sZWFkZXJTaWduYWwuc2V0KHRoaXMudGFiSWQpO1xyXG4gICAgICB0aGlzLmVuc3VyZUhlYXJ0YmVhdCgpO1xyXG4gICAgICByZXR1cm47XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKCFyZWNvcmQgfHwgbm93IC0gcmVjb3JkLnVwZGF0ZWRBdCA+IExFQURFUl9UVExfTVMgKSB7XHJcbiAgICAgIHRoaXMuY2xhaW1MZWFkZXJzaGlwKCk7XHJcbiAgICAgIHJldHVybjtcclxuICAgIH1cclxuXHJcbiAgICB0aGlzLmxlYWRlclNpZ25hbC5zZXQocmVjb3JkLmlkKTtcclxuICAgIHRoaXMuc3RvcEhlYXJ0YmVhdCgpO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBjbGFpbUxlYWRlcnNoaXAoKTogdm9pZCB7XHJcbiAgICBpZiAoIXRoaXMuc3RvcmFnZSB8fCAhdGhpcy5zdG9yYWdlS2V5IHx8IHRoaXMuaXNEaXNwb3NlZCkge1xyXG4gICAgICByZXR1cm47XHJcbiAgICB9XHJcblxyXG4gICAgY29uc3QgcmVjb3JkOiBMZWFkZXJSZWNvcmQgPSB7XHJcbiAgICAgIGlkOiB0aGlzLnRhYklkLFxyXG4gICAgICB1cGRhdGVkQXQ6IERhdGUubm93KClcclxuICAgIH07XHJcblxyXG4gICAgdHJ5IHtcclxuICAgICAgdGhpcy5zdG9yYWdlLnNldEl0ZW0odGhpcy5zdG9yYWdlS2V5LCBKU09OLnN0cmluZ2lmeShyZWNvcmQpKTtcclxuICAgICAgdGhpcy5sZWFkZXJTaWduYWwuc2V0KHRoaXMudGFiSWQpO1xyXG4gICAgICB0aGlzLmVuc3VyZUhlYXJ0YmVhdCgpO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgY29uc29sZS53YXJuKCdbbmcyLWlkbGUtdGltZW91dF0gVW5hYmxlIHRvIHBlcnNpc3QgbGVhZGVyIHJlY29yZCcsIGVycm9yKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIHByaXZhdGUgcmVhZExlYWRlclJlY29yZCgpOiBMZWFkZXJSZWNvcmQgfCBudWxsIHtcclxuICAgIGlmICghdGhpcy5zdG9yYWdlIHx8ICF0aGlzLnN0b3JhZ2VLZXkpIHtcclxuICAgICAgcmV0dXJuIG51bGw7XHJcbiAgICB9XHJcblxyXG4gICAgdHJ5IHtcclxuICAgICAgY29uc3QgcmF3ID0gdGhpcy5zdG9yYWdlLmdldEl0ZW0odGhpcy5zdG9yYWdlS2V5KTtcclxuICAgICAgaWYgKCFyYXcpIHtcclxuICAgICAgICByZXR1cm4gbnVsbDtcclxuICAgICAgfVxyXG4gICAgICByZXR1cm4gSlNPTi5wYXJzZShyYXcpIGFzIExlYWRlclJlY29yZDtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIGNvbnNvbGUud2FybignW25nMi1pZGxlLXRpbWVvdXRdIFVuYWJsZSB0byByZWFkIGxlYWRlciByZWNvcmQnLCBlcnJvcik7XHJcbiAgICAgIHJldHVybiBudWxsO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBzdGFydFdhdGNoZG9nKCk6IHZvaWQge1xyXG4gICAgaWYgKCF0aGlzLnN0b3JhZ2UgfHwgdGhpcy53YXRjaGRvZ1RpbWVyICE9IG51bGwgfHwgdHlwZW9mIHdpbmRvdyA9PT0gJ3VuZGVmaW5lZCcpIHtcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG5cclxuICAgIHRoaXMuem9uZS5ydW5PdXRzaWRlQW5ndWxhcigoKSA9PiB7XHJcbiAgICAgIHRoaXMud2F0Y2hkb2dUaW1lciA9IHdpbmRvdy5zZXRJbnRlcnZhbCgoKSA9PiB7XHJcbiAgICAgICAgdGhpcy56b25lLnJ1bigoKSA9PiB7XHJcbiAgICAgICAgICB0aGlzLmV2YWx1YXRlTGVhZGVyc2hpcCgpO1xyXG4gICAgICAgIH0pO1xyXG4gICAgICB9LCBIRUFSVEJFQVRfSU5URVJWQUxfTVMpO1xyXG4gICAgfSk7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIHN0b3BXYXRjaGRvZygpOiB2b2lkIHtcclxuICAgIGlmICh0aGlzLndhdGNoZG9nVGltZXIgIT0gbnVsbCAmJiB0eXBlb2Ygd2luZG93ICE9PSAndW5kZWZpbmVkJykge1xyXG4gICAgICB3aW5kb3cuY2xlYXJJbnRlcnZhbCh0aGlzLndhdGNoZG9nVGltZXIpO1xyXG4gICAgfVxyXG4gICAgdGhpcy53YXRjaGRvZ1RpbWVyID0gbnVsbDtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgc3RhcnRIZWFydGJlYXQoKTogdm9pZCB7XHJcbiAgICBpZiAoIXRoaXMuc3RvcmFnZSB8fCB0aGlzLmhlYXJ0YmVhdFRpbWVyICE9IG51bGwgfHwgdHlwZW9mIHdpbmRvdyA9PT0gJ3VuZGVmaW5lZCcpIHtcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG5cclxuICAgIGlmICghdGhpcy5pc0xlYWRlcigpKSB7XHJcbiAgICAgIHJldHVybjtcclxuICAgIH1cclxuXHJcbiAgICB0aGlzLnpvbmUucnVuT3V0c2lkZUFuZ3VsYXIoKCkgPT4ge1xyXG4gICAgICB0aGlzLmhlYXJ0YmVhdFRpbWVyID0gd2luZG93LnNldEludGVydmFsKCgpID0+IHtcclxuICAgICAgICB0aGlzLnpvbmUucnVuKCgpID0+IHtcclxuICAgICAgICAgIHRoaXMudG91Y2hMZWFkZXJSZWNvcmQoKTtcclxuICAgICAgICB9KTtcclxuICAgICAgfSwgSEVBUlRCRUFUX0lOVEVSVkFMX01TKTtcclxuICAgIH0pO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBlbnN1cmVIZWFydGJlYXQoKTogdm9pZCB7XHJcbiAgICBpZiAodGhpcy5oZWFydGJlYXRUaW1lciA9PSBudWxsKSB7XHJcbiAgICAgIHRoaXMuc3RhcnRIZWFydGJlYXQoKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIHByaXZhdGUgc3RvcEhlYXJ0YmVhdCgpOiB2b2lkIHtcclxuICAgIGlmICh0aGlzLmhlYXJ0YmVhdFRpbWVyICE9IG51bGwgJiYgdHlwZW9mIHdpbmRvdyAhPT0gJ3VuZGVmaW5lZCcpIHtcclxuICAgICAgd2luZG93LmNsZWFySW50ZXJ2YWwodGhpcy5oZWFydGJlYXRUaW1lcik7XHJcbiAgICB9XHJcbiAgICB0aGlzLmhlYXJ0YmVhdFRpbWVyID0gbnVsbDtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgdG91Y2hMZWFkZXJSZWNvcmQoKTogdm9pZCB7XHJcbiAgICBpZiAoIXRoaXMuc3RvcmFnZSB8fCAhdGhpcy5zdG9yYWdlS2V5IHx8IHRoaXMuaXNEaXNwb3NlZCkge1xyXG4gICAgICByZXR1cm47XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKHRoaXMubGVhZGVyU2lnbmFsKCkgIT09IHRoaXMudGFiSWQpIHtcclxuICAgICAgdGhpcy5zdG9wSGVhcnRiZWF0KCk7XHJcbiAgICAgIHJldHVybjtcclxuICAgIH1cclxuXHJcbiAgICBjb25zdCByZWNvcmQ6IExlYWRlclJlY29yZCA9IHtcclxuICAgICAgaWQ6IHRoaXMudGFiSWQsXHJcbiAgICAgIHVwZGF0ZWRBdDogRGF0ZS5ub3coKVxyXG4gICAgfTtcclxuXHJcbiAgICB0cnkge1xyXG4gICAgICB0aGlzLnN0b3JhZ2Uuc2V0SXRlbSh0aGlzLnN0b3JhZ2VLZXksIEpTT04uc3RyaW5naWZ5KHJlY29yZCkpO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgY29uc29sZS53YXJuKCdbbmcyLWlkbGUtdGltZW91dF0gVW5hYmxlIHRvIHVwZGF0ZSBsZWFkZXIgaGVhcnRiZWF0JywgZXJyb3IpO1xyXG4gICAgfVxyXG4gIH1cclxufVxyXG5cclxuZnVuY3Rpb24gZ2VuZXJhdGVMZWFkZXJJZCgpOiBzdHJpbmcge1xyXG4gIGlmICh0eXBlb2YgY3J5cHRvICE9PSAndW5kZWZpbmVkJyAmJiB0eXBlb2YgY3J5cHRvLnJhbmRvbVVVSUQgPT09ICdmdW5jdGlvbicpIHtcclxuICAgIHJldHVybiBjcnlwdG8ucmFuZG9tVVVJRCgpO1xyXG4gIH1cclxuICByZXR1cm4gTWF0aC5yYW5kb20oKS50b1N0cmluZygzNikuc2xpY2UoMik7XHJcbn1cclxuIl19