Fix localStorage crash
## Ticket 1572 Always check for availability before use. ## Changes - Consolidated the keys into one place for easier tracking. - It'll also be easier to code using constant autocomplete. - Cleaned up the wrapper to be as close as the original. - Updated existing code to use the wrapper (even if they already handled the availability) to encourage future code to just use the wrapper.
This commit is contained in:
parent
3ed05e62a5
commit
a73694deb4
9 changed files with 67 additions and 46 deletions
|
@ -46,8 +46,6 @@ export const GA_DIMENSIONS = {
|
|||
const isProduction = process.env.NODE_ENV === 'production';
|
||||
const devInternalApis = process.env.LBRY_API_URL && process.env.LBRY_API_URL.includes('dev');
|
||||
|
||||
export const SHARE_INTERNAL = 'shareInternal';
|
||||
|
||||
const WATCHMAN_BACKEND_ENDPOINT = 'https://watchman.na-backend.odysee.com/reports/playback';
|
||||
const SEND_DATA_TO_WATCHMAN_INTERVAL = 10; // in seconds
|
||||
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
// Local Storage keys
|
||||
export const TUS_LOCKED_UPLOADS = 'tusLockedUploads';
|
||||
export const TUS_REMOVED_UPLOADS = 'tusRemovedUploads';
|
||||
export const TUS_REFRESH_LOCK = 'tusRefreshLock';
|
|
@ -45,8 +45,9 @@ import { selectUser, selectUserVerifiedEmail } from 'redux/selectors/user';
|
|||
import { doSetPrefsReady, doPreferenceGet, doPopulateSharedUserState, syncInvalidated } from 'redux/actions/sync';
|
||||
import { doAuthenticate } from 'redux/actions/user';
|
||||
import { lbrySettings as config, version as appVersion } from 'package.json';
|
||||
import analytics, { SHARE_INTERNAL } from 'analytics';
|
||||
import analytics from 'analytics';
|
||||
import { doSignOutCleanup } from 'util/saved-passwords';
|
||||
import { LocalStorage, LS } from 'util/storage';
|
||||
import { doNotificationSocketConnect } from 'redux/actions/websocket';
|
||||
import { stringifyServerParam, shouldSetSetting } from 'util/sync-settings';
|
||||
|
||||
|
@ -348,7 +349,7 @@ export function doDaemonReady() {
|
|||
const state = getState();
|
||||
|
||||
// TODO: call doFetchDaemonSettings, then get usage data, and call doAuthenticate once they are loaded into the store
|
||||
const shareUsageData = IS_WEB || window.localStorage.getItem(SHARE_INTERNAL) === 'true';
|
||||
const shareUsageData = IS_WEB || LocalStorage.getItem(LS.SHARE_INTERNAL) === 'true';
|
||||
|
||||
dispatch(
|
||||
doAuthenticate(
|
||||
|
|
|
@ -10,11 +10,9 @@ import {
|
|||
filterUpcomingLiveStreamClaims,
|
||||
} from 'util/livestream';
|
||||
import moment from 'moment';
|
||||
import { isLocalStorageAvailable } from 'util/storage';
|
||||
import { LocalStorage, LS } from 'util/storage';
|
||||
import { isEmpty } from 'util/object';
|
||||
|
||||
const localStorageAvailable = isLocalStorageAvailable();
|
||||
|
||||
export const doFetchNoSourceClaims = (channelId: string) => async (dispatch: Dispatch, getState: GetState) => {
|
||||
dispatch({
|
||||
type: ACTIONS.FETCH_NO_SOURCE_CLAIMS_STARTED,
|
||||
|
@ -118,20 +116,20 @@ const findActiveStreams = async (
|
|||
};
|
||||
|
||||
export const doFetchChannelLiveStatus = (channelId: string) => async (dispatch: Dispatch) => {
|
||||
const statusForId = `channel-live-status`;
|
||||
const localStatus = localStorageAvailable && window.localStorage.getItem(statusForId);
|
||||
const statusForId = LS.CHANNEL_LIVE_STATUS;
|
||||
const localStatus = LocalStorage.getItem(statusForId);
|
||||
|
||||
try {
|
||||
const { channelStatus, channelData } = await fetchLiveChannel(channelId);
|
||||
// store live state locally, and force 2 non-live statuses before returninig NOT LIVE. This allows for the stream to finish before disposing player.
|
||||
if (localStatus === LiveStatus.LIVE && channelStatus === LiveStatus.NOT_LIVE) {
|
||||
localStorageAvailable && window.localStorage.removeItem(statusForId);
|
||||
LocalStorage.removeItem(statusForId);
|
||||
return;
|
||||
}
|
||||
|
||||
if (channelStatus === LiveStatus.NOT_LIVE && !localStatus) {
|
||||
dispatch({ type: ACTIONS.REMOVE_CHANNEL_FROM_ACTIVE_LIVESTREAMS, data: { channelId } });
|
||||
localStorageAvailable && window.localStorage.removeItem(statusForId);
|
||||
LocalStorage.removeItem(statusForId);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -148,10 +146,10 @@ export const doFetchChannelLiveStatus = (channelId: string) => async (dispatch:
|
|||
dispatch({ type: ACTIONS.ADD_CHANNEL_TO_ACTIVE_LIVESTREAMS, data: { ...channelData } });
|
||||
}
|
||||
|
||||
localStorageAvailable && window.localStorage.setItem(statusForId, channelStatus);
|
||||
LocalStorage.setItem(statusForId, channelStatus);
|
||||
} catch (err) {
|
||||
dispatch({ type: ACTIONS.REMOVE_CHANNEL_FROM_ACTIVE_LIVESTREAMS, data: { channelId } });
|
||||
localStorageAvailable && window.localStorage.removeItem(statusForId);
|
||||
LocalStorage.removeItem(statusForId);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -15,8 +15,8 @@ import rewards from 'rewards';
|
|||
import { Lbryio } from 'lbryinc';
|
||||
import { DOMAIN, LOCALE_API } from 'config';
|
||||
import { getDefaultLanguage } from 'util/default-languages';
|
||||
import { LocalStorage, LS } from 'util/storage';
|
||||
|
||||
const AUTH_IN_PROGRESS = 'authInProgress';
|
||||
export let sessionStorageAvailable = false;
|
||||
const CHECK_INTERVAL = 200;
|
||||
const AUTH_WAIT_TIMEOUT = 10000;
|
||||
|
@ -91,9 +91,9 @@ function checkAuthBusy() {
|
|||
if (!IS_WEB || !sessionStorageAvailable) {
|
||||
return resolve();
|
||||
}
|
||||
const inProgress = window.sessionStorage.getItem(AUTH_IN_PROGRESS);
|
||||
const inProgress = LocalStorage.getItem(LS.AUTH_IN_PROGRESS);
|
||||
if (!inProgress) {
|
||||
window.sessionStorage.setItem(AUTH_IN_PROGRESS, 'true');
|
||||
LocalStorage.setItem(LS.AUTH_IN_PROGRESS, 'true');
|
||||
return resolve();
|
||||
} else {
|
||||
if (Date.now() - time < AUTH_WAIT_TIMEOUT) {
|
||||
|
@ -175,7 +175,7 @@ export function doAuthenticate(
|
|||
return Lbryio.authenticate(DOMAIN, getDefaultLanguage());
|
||||
})
|
||||
.then((user) => {
|
||||
if (sessionStorageAvailable) window.sessionStorage.removeItem(AUTH_IN_PROGRESS);
|
||||
LocalStorage.removeItem(LS.AUTH_IN_PROGRESS);
|
||||
Lbryio.getAuthToken().then((token) => {
|
||||
dispatch({
|
||||
type: ACTIONS.AUTHENTICATION_SUCCESS,
|
||||
|
@ -199,7 +199,7 @@ export function doAuthenticate(
|
|||
});
|
||||
})
|
||||
.catch((error) => {
|
||||
if (sessionStorageAvailable) window.sessionStorage.removeItem(AUTH_IN_PROGRESS);
|
||||
LocalStorage.removeItem(LS.AUTH_IN_PROGRESS);
|
||||
|
||||
dispatch({
|
||||
type: ACTIONS.AUTHENTICATION_FAILURE,
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { createSelector } from 'reselect';
|
||||
import { LocalStorage } from 'util/storage';
|
||||
|
||||
export const selectState = (state) => state.user || {};
|
||||
|
||||
|
@ -126,7 +127,7 @@ export const selectOdyseeMembershipIsPremiumPlus = (state) => {
|
|||
*/
|
||||
export const selectHasOdyseeMembership = (state) => {
|
||||
// @if process.env.NODE_ENV!='production'
|
||||
const override = window.localStorage.getItem('hasMembershipOverride');
|
||||
const override = LocalStorage.getItem('hasMembershipOverride');
|
||||
if (override) return override === 'true';
|
||||
// @endif
|
||||
|
||||
|
|
|
@ -1,3 +1,21 @@
|
|||
// @flow
|
||||
|
||||
// ****************************************************************************
|
||||
// ****************************************************************************
|
||||
|
||||
export const LS = Object.freeze({
|
||||
AUTH_IN_PROGRESS: 'authInProgress',
|
||||
CHANNEL_LIVE_STATUS: 'channel-live-status',
|
||||
GDPR_REQUIRED: 'gdprRequired', // <-- should be using 'locale/get', right?
|
||||
SHARE_INTERNAL: 'shareInternal',
|
||||
TUS_LOCKED_UPLOADS: 'tusLockedUploads',
|
||||
TUS_REFRESH_LOCK: 'tusRefreshLock',
|
||||
TUS_REMOVED_UPLOADS: 'tusRemovedUploads',
|
||||
});
|
||||
|
||||
// ****************************************************************************
|
||||
// ****************************************************************************
|
||||
|
||||
export function isLocalStorageAvailable() {
|
||||
try {
|
||||
return Boolean(window.localStorage);
|
||||
|
@ -24,14 +42,23 @@ export function getLocalStorageSummary() {
|
|||
}
|
||||
}
|
||||
|
||||
// ****************************************************************************
|
||||
// LocalStorage (wrapper for 'window.localStorage')
|
||||
// ****************************************************************************
|
||||
|
||||
// This assumes that local storage availability never changes after boot.
|
||||
const localStorageAvailable = isLocalStorageAvailable();
|
||||
|
||||
export function getLocalStorageItem(key) {
|
||||
return localStorageAvailable ? window.localStorage.getItem(key) : undefined;
|
||||
}
|
||||
export const LocalStorage = {
|
||||
setItem: (key: string, value: string) => {
|
||||
if (localStorageAvailable) window.localStorage.setItem(key, value);
|
||||
},
|
||||
|
||||
export function setLocalStorageItem(key, value) {
|
||||
if (localStorageAvailable) {
|
||||
window.localStorage.setItem(key, value);
|
||||
}
|
||||
}
|
||||
getItem: (key: string) => {
|
||||
return localStorageAvailable ? window.localStorage.getItem(key) : undefined;
|
||||
},
|
||||
|
||||
removeItem: (key: string) => {
|
||||
if (localStorageAvailable) window.localStorage.removeItem(key);
|
||||
},
|
||||
};
|
||||
|
|
|
@ -9,8 +9,7 @@
|
|||
*/
|
||||
|
||||
import { v4 as uuid } from 'uuid';
|
||||
import { TUS_LOCKED_UPLOADS, TUS_REFRESH_LOCK, TUS_REMOVED_UPLOADS } from 'constants/storage';
|
||||
import { isLocalStorageAvailable } from 'util/storage';
|
||||
import { isLocalStorageAvailable, LocalStorage, LS } from 'util/storage';
|
||||
import { doUpdateUploadRemove, doUpdateUploadProgress } from 'redux/actions/publish';
|
||||
|
||||
const localStorageAvailable = isLocalStorageAvailable();
|
||||
|
@ -32,7 +31,7 @@ function getTabId() {
|
|||
|
||||
function getLockedUploads() {
|
||||
if (localStorageAvailable) {
|
||||
const storedValue = window.localStorage.getItem(TUS_LOCKED_UPLOADS);
|
||||
const storedValue = LocalStorage.getItem(LS.TUS_LOCKED_UPLOADS);
|
||||
return storedValue ? JSON.parse(storedValue) : {};
|
||||
}
|
||||
return {};
|
||||
|
@ -47,7 +46,7 @@ export function tusLockAndNotify(guid: string) {
|
|||
const lockedUploads = getLockedUploads();
|
||||
if (!lockedUploads[guid] && localStorageAvailable) {
|
||||
lockedUploads[guid] = getTabId();
|
||||
window.localStorage.setItem(TUS_LOCKED_UPLOADS, JSON.stringify(lockedUploads));
|
||||
LocalStorage.setItem(LS.TUS_LOCKED_UPLOADS, JSON.stringify(lockedUploads));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -75,9 +74,9 @@ export function tusUnlockAndNotify(guid?: string) {
|
|||
}
|
||||
|
||||
if (Object.keys(lockedUploads).length > 0) {
|
||||
window.localStorage.setItem(TUS_LOCKED_UPLOADS, JSON.stringify(lockedUploads));
|
||||
LocalStorage.setItem(LS.TUS_LOCKED_UPLOADS, JSON.stringify(lockedUploads));
|
||||
} else {
|
||||
window.localStorage.removeItem(TUS_LOCKED_UPLOADS);
|
||||
LocalStorage.removeItem(LS.TUS_LOCKED_UPLOADS);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -87,7 +86,7 @@ export function tusUnlockAndNotify(guid?: string) {
|
|||
|
||||
function getRemovedUploads() {
|
||||
if (localStorageAvailable) {
|
||||
const storedValue = window.localStorage.getItem(TUS_REMOVED_UPLOADS);
|
||||
const storedValue = LocalStorage.getItem(LS.TUS_REMOVED_UPLOADS);
|
||||
return storedValue ? storedValue.split(',') : [];
|
||||
}
|
||||
return [];
|
||||
|
@ -97,18 +96,18 @@ export function tusRemoveAndNotify(guid: string) {
|
|||
if (!localStorageAvailable) return;
|
||||
const removedUploads = getRemovedUploads();
|
||||
removedUploads.push(guid);
|
||||
window.localStorage.setItem(TUS_REMOVED_UPLOADS, removedUploads.join(','));
|
||||
LocalStorage.setItem(LS.TUS_REMOVED_UPLOADS, removedUploads.join(','));
|
||||
}
|
||||
|
||||
export function tusClearRemovedUploads() {
|
||||
if (!localStorageAvailable) return;
|
||||
window.localStorage.removeItem(TUS_REMOVED_UPLOADS);
|
||||
LocalStorage.removeItem(LS.TUS_REMOVED_UPLOADS);
|
||||
}
|
||||
|
||||
export function tusClearLockedUploads() {
|
||||
if (!localStorageAvailable) return;
|
||||
window.localStorage.removeItem(TUS_LOCKED_UPLOADS);
|
||||
window.localStorage.setItem(TUS_REFRESH_LOCK, Math.random());
|
||||
LocalStorage.removeItem(LS.TUS_LOCKED_UPLOADS);
|
||||
LocalStorage.setItem(LS.TUS_REFRESH_LOCK, String(Math.random()));
|
||||
}
|
||||
|
||||
// ****************************************************************************
|
||||
|
@ -117,17 +116,17 @@ export function tusClearLockedUploads() {
|
|||
|
||||
export function tusHandleTabUpdates(storageKey: string) {
|
||||
switch (storageKey) {
|
||||
case TUS_LOCKED_UPLOADS:
|
||||
case LS.TUS_LOCKED_UPLOADS:
|
||||
// The locked IDs are in localStorage, but related GUI is unaware.
|
||||
// Send a redux update to force an update.
|
||||
window.store.dispatch(doUpdateUploadProgress({ guid: 'force--update' }));
|
||||
break;
|
||||
|
||||
case TUS_REFRESH_LOCK:
|
||||
case LS.TUS_REFRESH_LOCK:
|
||||
window.store.dispatch(doUpdateUploadProgress({ guid: 'refresh--lock' }));
|
||||
break;
|
||||
|
||||
case TUS_REMOVED_UPLOADS:
|
||||
case LS.TUS_REMOVED_UPLOADS:
|
||||
// The other tab's store has removed this upload, so it's safe to do the
|
||||
// same without affecting rehydration.
|
||||
if (localStorageAvailable) {
|
||||
|
|
|
@ -9,6 +9,7 @@ import classnames from 'classnames';
|
|||
import { platform } from 'util/platform';
|
||||
import Icon from 'component/common/icon';
|
||||
import * as ICONS from 'constants/icons';
|
||||
import { LocalStorage, LS } from 'util/storage';
|
||||
|
||||
// prettier-ignore
|
||||
const AD_CONFIGS = Object.freeze({
|
||||
|
@ -64,7 +65,7 @@ function Ads(props: Props) {
|
|||
const mobileAds = platform.isAndroid() || platform.isIOS();
|
||||
|
||||
// this is populated from app based on location
|
||||
const isInEu = localStorage.getItem('gdprRequired') === 'true';
|
||||
const isInEu = LocalStorage.getItem(LS.GDPR_REQUIRED) === 'true';
|
||||
const adConfig = isInEu ? AD_CONFIGS.EU : mobileAds ? AD_CONFIGS.MOBILE : AD_CONFIGS.DEFAULT;
|
||||
|
||||
function resolveAdVisibility() {
|
||||
|
|
Loading…
Reference in a new issue