UNPKG

wingbot

Version:

Enterprise Messaging Bot Conversation Engine

160 lines (135 loc) 4.2 kB
/* * @author David Menger */ 'use strict'; /** * @typedef {object} State * @prop {string} senderId * @prop {string} pageId * @prop {object} state */ /** * @typedef {object} StateCondition * @prop {string} [search] */ /** * Memory conversation state storage for testing purposes * * @class */ class MemoryStateStorage { constructor () { this.store = new Map(); } _key (senderId, pageId) { return `${senderId}|${pageId}`; } getStateSync (senderId, pageId) { const key = this._key(senderId, pageId); if (this.store.has(key)) { return this.store.get(key); } return null; } getOrCreateStateSync (senderId, pageId, defaultState = {}) { let state = this.getStateSync(senderId, pageId); if (!state) { state = { senderId, pageId, state: defaultState }; this.saveState(state); } return state; } /** * * @param {string} senderId * @param {string} pageId * @returns {Promise<State|null>} */ async getState (senderId, pageId) { return this.getStateSync(senderId, pageId); } /** * * @param {string} senderId - sender identifier * @param {string} pageId - page or channel identifier * @param {object} defaultState - default state of the conversation * @param {number} lockTimeout - duration of lock * @returns {Promise.<State>} - conversation state */ async getOrCreateAndLock (senderId, pageId, defaultState = {}, lockTimeout = 300) { // eslint-disable-line no-unused-vars,max-len return this.getOrCreateStateSync(senderId, pageId, defaultState); } /** * * @param {object} state - conversation state * @returns {Promise} */ saveState (state) { const { senderId, pageId } = state; const stateCopy = JSON.parse(JSON.stringify(state)); this.store.set(this._key(senderId, pageId), stateCopy); return Promise.resolve(state); } /** * * @param {StateCondition} condition * @param {number} limit * @param {string} lastKey * @returns {Promise<{data:State[],lastKey:string}>} */ getStates (condition = {}, limit = 20, lastKey = null) { let reachedKey = lastKey === null; let filtered = 0; let hasNext = false; const key = lastKey !== null ? JSON.parse(Buffer.from(lastKey, 'base64').toString('utf8')) : null; const data = Array.from(this.store.values()) .sort((a, b) => { if (a.lastInteraction === b.lastInteraction) { return 0; } return a.lastInteraction > b.lastInteraction ? -1 : 1; }) .filter((state) => { // const matches = conditionKeys // .every(k => state[k] === condition[k]); const matches = !condition.search || condition.search === state.senderId; if (!matches) { return false; } if (limit !== null && filtered >= limit) { hasNext = true; return false; } if (reachedKey) { filtered++; return true; } reachedKey = key.senderId === state.senderId && key.pageId === state.pageId; return false; }) .map((e) => ({ ...e, lastInteraction: new Date(e.lastInteraction) })); let nextLastKey = null; if (limit && hasNext) { const last = data[data.length - 1]; nextLastKey = Buffer.from(JSON.stringify({ senderId: last.senderId, pageId: last.pageId })).toString('base64'); } return Promise.resolve({ data, lastKey: nextLastKey }); } } module.exports = MemoryStateStorage;