UNPKG

@inworld/web-core

Version:
119 lines (118 loc) 4.88 kB
import { DEFAULT_SESSION_STATE_ATTEMPTS_INTERVAL, DEFAULT_SESSION_STATE_INTERVAL, DEFAULT_SESSION_STATE_KEY, DEFAULT_SESSION_STATE_MAX_ATTEMPTS, } from '../common/constants.js'; import { CHAT_HISTORY_TYPE } from '../common/data_structures/history.js'; import { safeJSONParse } from '../common/helpers.js'; export class SessionStateService { constructor(connection, stateSerialization) { this.maxAttempts = DEFAULT_SESSION_STATE_MAX_ATTEMPTS; this.isBlurred = false; this.isSaving = false; this.doNotSave = false; this.connection = connection; this.stateSerialization = stateSerialization; window.addEventListener('blur', this.onWindowBlur.bind(this)); window.addEventListener('focus', this.onWindowFocus.bind(this)); this.setAutoSaveInterval(); } clear() { sessionStorage.removeItem(DEFAULT_SESSION_STATE_KEY); } destroy() { this.clear(); this.clearAutoSaveInterval(); this.clearInteractionEndTimeout(); window.removeEventListener('blur', this.onWindowBlur.bind(this)); window.removeEventListener('focus', this.onWindowFocus.bind(this)); } static loadSessionState() { return sessionStorage.getItem(DEFAULT_SESSION_STATE_KEY); } onWindowBlur() { this.isBlurred = true; this.clearAutoSaveInterval(); this.clearInteractionEndTimeout(); this.tryToSaveState(); } onWindowFocus() { this.isBlurred = false; this.setAutoSaveInterval(); } tryToSaveState() { var _a; const newSessionId = this.connection.getSessionId(); if (this.sessionId !== newSessionId) { this.sessionId = newSessionId; this.doNotSave = false; } if (this.isSaving || this.doNotSave) { return; } this.isSaving = true; const history = this.connection .getHistory() .filter((item) => !item.fromHistory); const lastItem = history[history.length - 1]; const saved = SessionStateService.loadSessionState(); const sessionState = saved ? safeJSONParse(saved) : undefined; // Don't save session state if it's already saved. if (!lastItem || (lastItem.interactionId && lastItem.interactionId === ((_a = sessionState === null || sessionState === void 0 ? void 0 : sessionState.version) === null || _a === void 0 ? void 0 : _a.interactionId))) { this.isSaving = false; return; } let attempts = 0; const save = () => { this.interactionEndTimeout = setTimeout(async () => { this.clearInteractionEndTimeout(); attempts++; const history = this.connection .getHistory() .filter((item) => !item.fromHistory); const lastItem = history[history.length - 1]; // Try to wait for interaction end event before saving session state. // If all attempts are failed, just save session state here. // Or save session state if last item in history is interaction end event. if (attempts > this.maxAttempts || (lastItem === null || lastItem === void 0 ? void 0 : lastItem.type) === CHAT_HISTORY_TYPE.INTERACTION_END) { await this.saveSessionState(); this.isSaving = false; return; } else if (attempts <= this.maxAttempts) { save(); } }, DEFAULT_SESSION_STATE_ATTEMPTS_INTERVAL * (attempts + 1) + DEFAULT_SESSION_STATE_ATTEMPTS_INTERVAL * Math.pow(2, attempts) * attempts); }; save(); } async saveSessionState() { try { const sessionState = await this.stateSerialization.get(); if (sessionState === null || sessionState === void 0 ? void 0 : sessionState.state) { sessionStorage.setItem(DEFAULT_SESSION_STATE_KEY, JSON.stringify(sessionState)); return; } } catch (e) { } this.doNotSave = true; } setAutoSaveInterval() { this.clearAutoSaveInterval(); this.autoSaveIntervalId = setInterval(() => { if (!this.isBlurred && !this.connection.isConnecting()) { this.tryToSaveState(); } }, DEFAULT_SESSION_STATE_INTERVAL); } clearAutoSaveInterval() { clearInterval(this.autoSaveIntervalId); this.autoSaveIntervalId = undefined; } clearInteractionEndTimeout() { clearTimeout(this.interactionEndTimeout); this.interactionEndTimeout = undefined; } }