mirror of
https://github.com/jcwimer/wrestlingApp
synced 2026-04-19 05:43:17 +00:00
New stats page, scoreboard, and live scores pages.
This commit is contained in:
116
app/assets/javascripts/lib/match_state/transport.js
Normal file
116
app/assets/javascripts/lib/match_state/transport.js
Normal file
@@ -0,0 +1,116 @@
|
||||
export const MATCH_DATA_TTL_MS = 48 * 60 * 60 * 1000
|
||||
export const SHORT_LIVED_TTL_MS = 4 * 60 * 60 * 1000
|
||||
|
||||
const STORAGE_MARKER = "__wrestlingAppStorage"
|
||||
|
||||
export function loadJson(storage, key) {
|
||||
try {
|
||||
const rawValue = storage.getItem(key)
|
||||
if (!rawValue) return null
|
||||
const parsed = JSON.parse(rawValue)
|
||||
if (!isExpiringStorageValue(parsed)) return parsed
|
||||
if (isExpired(parsed)) {
|
||||
storage.removeItem(key)
|
||||
return null
|
||||
}
|
||||
return parsed.value
|
||||
} catch (_error) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
export function saveJson(storage, key, value, options = {}) {
|
||||
try {
|
||||
const valueToStore = options.ttlMs
|
||||
? expiringStorageValue(value, options.ttlMs)
|
||||
: value
|
||||
storage.setItem(key, JSON.stringify(valueToStore))
|
||||
return true
|
||||
} catch (_error) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
export function removeKey(storage, key) {
|
||||
try {
|
||||
storage.removeItem(key)
|
||||
return true
|
||||
} catch (_error) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
export function performIfChanged(subscription, action, payload, lastSerializedPayload) {
|
||||
if (!subscription) return lastSerializedPayload
|
||||
|
||||
const serializedPayload = JSON.stringify(payload)
|
||||
if (serializedPayload === lastSerializedPayload) {
|
||||
return lastSerializedPayload
|
||||
}
|
||||
|
||||
subscription.perform(action, payload)
|
||||
return serializedPayload
|
||||
}
|
||||
|
||||
export function cleanupExpiredLocalStorage(storage, now = Date.now()) {
|
||||
try {
|
||||
const keys = []
|
||||
for (let index = 0; index < storage.length; index += 1) {
|
||||
const key = storage.key(index)
|
||||
if (key && ttlForStorageKey(key)) keys.push(key)
|
||||
}
|
||||
|
||||
keys.forEach((key) => cleanupStorageKey(storage, key, now))
|
||||
} catch (_error) {
|
||||
}
|
||||
}
|
||||
|
||||
function cleanupStorageKey(storage, key, now) {
|
||||
const ttlMs = ttlForStorageKey(key)
|
||||
if (!ttlMs) return
|
||||
|
||||
const rawValue = storage.getItem(key)
|
||||
if (!rawValue) return
|
||||
|
||||
try {
|
||||
const parsed = JSON.parse(rawValue)
|
||||
if (isExpiringStorageValue(parsed)) {
|
||||
if (isExpired(parsed, now)) storage.removeItem(key)
|
||||
return
|
||||
}
|
||||
|
||||
const legacyUpdatedAt = Date.parse(parsed?.updated_at)
|
||||
if (legacyUpdatedAt && now - legacyUpdatedAt > ttlMs) {
|
||||
storage.removeItem(key)
|
||||
return
|
||||
}
|
||||
|
||||
storage.setItem(key, JSON.stringify(expiringStorageValue(parsed, ttlMs, legacyUpdatedAt || now)))
|
||||
} catch (_error) {
|
||||
storage.removeItem(key)
|
||||
}
|
||||
}
|
||||
|
||||
function expiringStorageValue(value, ttlMs, storedAt = Date.now()) {
|
||||
return {
|
||||
[STORAGE_MARKER]: true,
|
||||
expiresAt: storedAt + ttlMs,
|
||||
value
|
||||
}
|
||||
}
|
||||
|
||||
function isExpiringStorageValue(value) {
|
||||
return value && typeof value === "object" && value[STORAGE_MARKER] === true
|
||||
}
|
||||
|
||||
function isExpired(value, now = Date.now()) {
|
||||
return Number(value.expiresAt) <= now
|
||||
}
|
||||
|
||||
function ttlForStorageKey(key) {
|
||||
if (key.startsWith("match-state:")) return MATCH_DATA_TTL_MS
|
||||
if (/^w[12]-\d+-\d+$/.test(key)) return MATCH_DATA_TTL_MS
|
||||
if (key.startsWith("mat-selected-bout:")) return SHORT_LIVED_TTL_MS
|
||||
if (key.startsWith("mat-last-match-result:")) return SHORT_LIVED_TTL_MS
|
||||
return null
|
||||
}
|
||||
Reference in New Issue
Block a user