diff options
| author | Henry Jameson <me@hjkos.com> | 2022-08-04 22:09:42 +0300 |
|---|---|---|
| committer | Henry Jameson <me@hjkos.com> | 2022-08-04 22:09:42 +0300 |
| commit | 8c59bad3c2444e7deea20f9d301b675d2ef51016 (patch) | |
| tree | 334591c1a764cd76a6d8f4f0a1045e4c2a6edcef /src/modules/serverSideStorage.js | |
| parent | 9c00610d0031969cce4d50c0f947098a632ca712 (diff) | |
unit test + some refactoring
Diffstat (limited to 'src/modules/serverSideStorage.js')
| -rw-r--r-- | src/modules/serverSideStorage.js | 159 |
1 files changed, 86 insertions, 73 deletions
diff --git a/src/modules/serverSideStorage.js b/src/modules/serverSideStorage.js index da908728..fd3fe781 100644 --- a/src/modules/serverSideStorage.js +++ b/src/modules/serverSideStorage.js @@ -1,13 +1,14 @@ import { toRaw } from 'vue' -import { isEqual } from 'lodash' +import { isEqual, cloneDeep } from 'lodash' +import { CURRENT_UPDATE_COUNTER } from 'src/components/update_notification/update_notification.js' export const VERSION = 1 -export const NEW_USER_DATE = new Date('04-08-2022') // date of writing this, basically +export const NEW_USER_DATE = new Date('2022-08-04') // date of writing this, basically export const COMMAND_TRIM_FLAGS = 1000 export const COMMAND_TRIM_FLAGS_AND_RESET = 1001 -const defaultState = { +export const defaultState = { // do we need to update data on server? dirty: false, // storage of flags - stuff that can only be set and incremented @@ -27,9 +28,9 @@ const defaultState = { cache: null } -const newUserFlags = { +export const newUserFlags = { ...defaultState.flagStorage, - updateCounter: 1 // new users don't need to see update notification + updateCounter: CURRENT_UPDATE_COUNTER // new users don't need to see update notification } const _wrapData = (data) => ({ @@ -38,24 +39,23 @@ const _wrapData = (data) => ({ _version: VERSION }) -export const _checkValidity = (data) => data._timestamp > 0 && data._version > 0 +const _checkValidity = (data) => data._timestamp > 0 && data._version > 0 export const _getRecentData = (cache, live) => { const result = { recent: null, stale: null, needUpload: false } const cacheValid = _checkValidity(cache || {}) const liveValid = _checkValidity(live || {}) - if (!liveValid) { + if (!liveValid && cacheValid) { result.needUpload = true console.debug('Nothing valid stored on server, assuming cache to be source of truth') result.recent = cache result.stale = live - } else if (!cacheValid) { + } else if (!cacheValid && liveValid) { console.debug('Valid storage on server found, no local cache found, using live as source of truth') result.recent = live result.stale = cache - } else { + } else if (cacheValid && liveValid) { console.debug('Both sources have valid data, figuring things out...') - console.log(live._timestamp, cache._timestamp) if (live._timestamp === cache._timestamp && live._version === cache._version) { console.debug('Same version/timestamp on both source, source of truth irrelevant') result.recent = cache @@ -70,14 +70,17 @@ export const _getRecentData = (cache, live) => { result.stale = cache } } + } else { + console.debug('Both sources are invalid, start from scratch') + result.needUpload = true } return result } -export const _getAllFlags = (recent = {}, stale = {}) => { +export const _getAllFlags = (recent, stale) => { return Array.from(new Set([ - ...Object.keys(toRaw(recent.flagStorage || {})), - ...Object.keys(toRaw(stale.flagStorage || {})) + ...Object.keys(toRaw((recent || {}).flagStorage || {})), + ...Object.keys(toRaw((stale || {}).flagStorage || {})) ])) } @@ -86,37 +89,43 @@ export const _mergeFlags = (recent, stale, allFlagKeys) => { const recentFlag = recent.flagStorage[flag] const staleFlag = stale.flagStorage[flag] // use flag that is of higher value - return [flag, recentFlag > staleFlag ? recentFlag : staleFlag] + return [flag, Number((recentFlag > staleFlag ? recentFlag : staleFlag) || 0)] })) } -export const _resetFlags = (totalFlags, allFlagKeys) => { +export const _resetFlags = (totalFlags, knownKeys = defaultState.flagStorage) => { + let result = { ...totalFlags } + const allFlagKeys = Object.keys(totalFlags) // flag reset functionality if (totalFlags.reset >= COMMAND_TRIM_FLAGS && totalFlags.reset <= COMMAND_TRIM_FLAGS_AND_RESET) { console.debug('Received command to trim the flags') - const knownKeys = new Set(Object.keys(defaultState.flagStorage)) + const knownKeysSet = new Set(Object.keys(knownKeys)) + + // Trim + result = {} allFlagKeys.forEach(flag => { - if (!knownKeys.has(flag)) { - delete totalFlags[flag] + if (knownKeysSet.has(flag)) { + result[flag] = totalFlags[flag] } }) + + // Reset if (totalFlags.reset === COMMAND_TRIM_FLAGS_AND_RESET) { // 1001 - and reset everything to 0 console.debug('Received command to reset the flags') - allFlagKeys.forEach(flag => { totalFlags[flag] = 0 }) - } else { - // reset the reset 0 - totalFlags.reset = 0 + Object.keys(knownKeys).forEach(flag => { result[flag] = 0 }) } } else if (totalFlags.reset > 0 && totalFlags.reset < 9000) { console.debug('Received command to reset the flags') - allFlagKeys.forEach(flag => { totalFlags[flag] = 0 }) - // for good luck - totalFlags.reset = 0 + allFlagKeys.forEach(flag => { result[flag] = 0 }) } + result.reset = 0 + return result } export const _doMigrations = (cache) => { + if (!cache) return cache + if (cache._version < VERSION) { console.debug('Local cached data has older version, seeing if there any migrations that can be applied') @@ -139,65 +148,69 @@ export const _doMigrations = (cache) => { return cache } -const serverSideStorage = { - state: { - ...defaultState - }, - mutations: { - setServerSideStorage (state, userData) { - const live = userData.storage - state.raw = live - let cache = state.cache +export const mutations = { + setServerSideStorage (state, userData) { + const live = userData.storage + state.raw = live + let cache = state.cache - cache = _doMigrations(cache) + cache = _doMigrations(cache) - let { recent, stale, needsUpload } = _getRecentData(cache, live) + let { recent, stale, needsUpload } = _getRecentData(cache, live) - const userNew = userData.created_at > NEW_USER_DATE - const flagsTemplate = userNew ? newUserFlags : defaultState.defaultState - let dirty = false + const userNew = userData.created_at > NEW_USER_DATE + const flagsTemplate = userNew ? newUserFlags : defaultState.flagStorage + let dirty = false - if (recent === null) { - console.debug(`Data is empty, initializing for ${userNew ? 'new' : 'existing'} user`) - recent = _wrapData({ - flagStorage: { ...flagsTemplate } - }) - } + if (recent === null) { + console.debug(`Data is empty, initializing for ${userNew ? 'new' : 'existing'} user`) + recent = _wrapData({ + flagStorage: { ...flagsTemplate } + }) + } - if (!needsUpload && recent && stale) { - console.debug('Checking if data needs merging...') - // discarding timestamps and versions - const { _timestamp: _0, _version: _1, ...recentData } = recent - const { _timestamp: _2, _version: _3, ...staleData } = stale - dirty = !isEqual(recentData, staleData) - console.debug(`Data ${dirty ? 'needs' : 'doesn\'t need'} merging`) - } + if (!needsUpload && recent && stale) { + console.debug('Checking if data needs merging...') + // discarding timestamps and versions + const { _timestamp: _0, _version: _1, ...recentData } = recent + const { _timestamp: _2, _version: _3, ...staleData } = stale + dirty = !isEqual(recentData, staleData) + console.debug(`Data ${dirty ? 'needs' : 'doesn\'t need'} merging`) + } - const allFlagKeys = _getAllFlags(recent, stale) - let totalFlags - if (dirty) { - // Merge the flags - console.debug('Merging the flags...') - totalFlags = _mergeFlags(recent, stale, allFlagKeys) - } else { - totalFlags = recent.flagStorage - } + const allFlagKeys = _getAllFlags(recent, stale) + let totalFlags + if (dirty) { + // Merge the flags + console.debug('Merging the flags...') + totalFlags = _mergeFlags(recent, stale, allFlagKeys) + } else { + totalFlags = recent.flagStorage + } - // This does side effects on totalFlags !!! - // only resets if needed (checks are inside) - _resetFlags(totalFlags, allFlagKeys) + totalFlags = _resetFlags(totalFlags) - recent.flagStorage = totalFlags + recent.flagStorage = totalFlags - state.dirty = dirty || needsUpload - state.cache = recent - state.flagStorage = state.cache.flagStorage - }, - setFlag (state, { flag, value }) { - state.flagStorage[flag] = value - state.dirty = true + state.dirty = dirty || needsUpload + state.cache = recent + // set local timestamp to smaller one if we don't have any changes + if (stale && recent && !state.dirty) { + state.cache._timestamp = Math.min(stale._timestamp, recent._timestamp) } + state.flagStorage = state.cache.flagStorage + }, + setFlag (state, { flag, value }) { + state.flagStorage[flag] = value + state.dirty = true + } +} + +const serverSideStorage = { + state: { + ...cloneDeep(defaultState) }, + mutations, actions: { pushServerSideStorage ({ state, rootState, commit }, { force = false } = {}) { const needPush = state.dirty || force |
