@inworld/web-core
Version:
119 lines (118 loc) • 4.88 kB
JavaScript
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;
}
}