-
Notifications
You must be signed in to change notification settings - Fork 4
Clearing expired local storage items on initialization #98
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,5 @@ | ||
| import { log } from "./log"; | ||
|
|
||
| const maxExpiryDays = 365; | ||
|
|
||
| const isPersistingSessionLocalStoreName = "gist.web.isPersistingSession"; | ||
|
|
@@ -21,32 +23,20 @@ export function setKeyToLocalStore(key, value, ttl = null) { | |
| } | ||
|
|
||
| export function getKeyFromLocalStore(key) { | ||
| const itemStr = getStorage().getItem(key); | ||
| if (!itemStr) return null; | ||
|
|
||
| const item = JSON.parse(itemStr); | ||
| const now = new Date(); | ||
| const expiryTime = new Date(item.expiry); | ||
|
|
||
| // Retroactive bugfix: remove old cache entries with long expiry times | ||
| const isBroadcastOrUserKey = (key.startsWith("gist.web.message.broadcasts") && !key.endsWith("shouldShow") && !key.endsWith("numberOfTimesShown")) || (key.startsWith("gist.web.message.user") && !key.endsWith("seen")); | ||
| const sixtyMinutesFromNow = new Date(now.getTime() + 61 * 60 * 1000); | ||
| if (isBroadcastOrUserKey && expiryTime.getTime() > sixtyMinutesFromNow.getTime()) { | ||
| clearKeyFromLocalStore(key); | ||
| return null; | ||
| } | ||
|
|
||
| if (now.getTime() > expiryTime.getTime()) { | ||
| clearKeyFromLocalStore(key); | ||
| return null; | ||
| } | ||
| return item.value; | ||
| return checkKeyForExpiry(key); | ||
| } | ||
|
|
||
| export function clearKeyFromLocalStore(key) { | ||
| getStorage().removeItem(key); | ||
| } | ||
|
|
||
| export function clearExpiredFromLocalStore() { | ||
| const storage = getStorage(); | ||
| for (let i = storage.length - 1; i >= 0; i--) { | ||
| checkKeyForExpiry(storage.key(i)); | ||
| } | ||
| } | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Bug: Storage Cleanup Fails on Malformed EntriesThe There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is something we should look at as well, we're sharing the local store with the entire app. |
||
|
|
||
| export function isSessionBeingPersisted() { | ||
| const currentValue = sessionStorage.getItem(isPersistingSessionLocalStoreName); | ||
| if (currentValue === null) { | ||
|
|
@@ -59,4 +49,38 @@ export function isSessionBeingPersisted() { | |
| // Helper function to select the correct storage based on the session flag | ||
| function getStorage() { | ||
| return isSessionBeingPersisted() ? localStorage : sessionStorage; | ||
| } | ||
|
|
||
| function checkKeyForExpiry(key) { | ||
| if (!key) return null; | ||
|
|
||
| try { | ||
| const itemStr = getStorage().getItem(key); | ||
| if (!itemStr) return null; | ||
|
|
||
| const item = JSON.parse(itemStr); | ||
| if (!item.expiry) return item.value; | ||
|
|
||
| const now = new Date(); | ||
| const expiryTime = new Date(item.expiry); | ||
|
|
||
| // remove old cache entries with long expiry times | ||
| const isBroadcastOrUserKey = (key.startsWith("gist.web.message.broadcasts") && !key.endsWith("shouldShow") && !key.endsWith("numberOfTimesShown")) || (key.startsWith("gist.web.message.user") && !key.endsWith("seen")); | ||
| const sixtyMinutesFromNow = new Date(now.getTime() + 61 * 60 * 1000); | ||
| if (isBroadcastOrUserKey && expiryTime.getTime() > sixtyMinutesFromNow.getTime()) { | ||
| clearKeyFromLocalStore(key); | ||
| return null; | ||
| } | ||
|
|
||
| if (now.getTime() > expiryTime.getTime()) { | ||
| clearKeyFromLocalStore(key); | ||
| return null; | ||
| } | ||
|
|
||
| return item.value; | ||
| } catch (e) { | ||
| log(`Error checking key ${key} for expiry: ${e}`); | ||
| } | ||
|
|
||
| return null; | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bug: Storage Iteration Bug Causes Item Skipping
The
clearExpiredFromLocalStorefunction modifies storage during iteration. WhencheckKeyForExpiryremoves an expired item, subsequent items shift indices, causing the loop to skip keys. This means some expired items may not be cleared as intended.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice catch Cursor, I think this can be an issue @djanhjo
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be outdated since I reversed the for loop.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we, just out of safety, check the name and if it starts with gist.web we delete it? I'm just worried we might delete something else. All keys should start with that as far as I know.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In its current form, it'll only potentially delete
gist.web.message.broadcastsandgist.web.message.useritems based on:Is this fine or should the logic be changed to review all
gist.webitems in local storage and not justgist.web.message.broadcasts/gist.web.message.user?Also if it helps, I also prompted a review on other storage items in the repo:
From my minimal knowledge, it doesn't seem like the other keys are worth cleaning up as they seem to just re-populate, but I might be missing context!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No you're right, those are the worst offenders. Approving! Thank you for this 🙏