Proxify local storage and handle if it is unavailable
authorChocobozzz <me@florianbigard.com>
Fri, 23 Mar 2018 13:26:20 +0000 (14:26 +0100)
committerChocobozzz <me@florianbigard.com>
Fri, 23 Mar 2018 13:26:20 +0000 (14:26 +0100)
client/src/app/+admin/jobs/jobs-list/jobs-list.component.ts
client/src/app/core/auth/auth-user.model.ts
client/src/app/core/server/server.service.ts
client/src/app/shared/misc/peertube-local-storage.ts [new file with mode: 0644]
client/src/app/shared/rest/rest-table.ts
client/src/app/videos/+video-watch/video-watch.component.ts

index e3f317e6de940f3e231a7f8134d47613239b8df2..ad2f05c6bea8447e56d1b15a5504737058f2a7d9 100644 (file)
@@ -1,12 +1,12 @@
 import { Component, OnInit } from '@angular/core'
+import { peertubeLocalStorage } from '@app/shared/misc/peertube-local-storage'
 import { NotificationsService } from 'angular2-notifications'
 import { SortMeta } from 'primeng/primeng'
 import { Job } from '../../../../../../shared/index'
 import { JobState } from '../../../../../../shared/models'
 import { RestPagination, RestTable } from '../../../shared'
-import { viewportHeight } from '../../../shared/misc/utils'
-import { JobService } from '../shared'
 import { RestExtractor } from '../../../shared/rest/rest-extractor.service'
+import { JobService } from '../shared'
 
 @Component({
   selector: 'my-jobs-list',
@@ -56,12 +56,12 @@ export class JobsListComponent extends RestTable implements OnInit {
   }
 
   private loadJobState () {
-    const result = localStorage.getItem(JobsListComponent.JOB_STATE_LOCAL_STORAGE_STATE)
+    const result = peertubeLocalStorage.getItem(JobsListComponent.JOB_STATE_LOCAL_STORAGE_STATE)
 
     if (result) this.jobState = result as JobState
   }
 
   private saveJobState () {
-    localStorage.setItem(JobsListComponent.JOB_STATE_LOCAL_STORAGE_STATE, this.jobState)
+    peertubeLocalStorage.setItem(JobsListComponent.JOB_STATE_LOCAL_STORAGE_STATE, this.jobState)
   }
 }
index 9ad275392e359739cd59593d0ddbb1d4ec028563..366eea110bb0657a714d1126275796adaa0e28b5 100644 (file)
@@ -1,7 +1,8 @@
+import { peertubeLocalStorage } from '@app/shared/misc/peertube-local-storage'
+import { UserRight } from '../../../../../shared/models/users/user-right.enum'
 // Do not use the barrel (dependency loop)
 import { hasUserRight, UserRole } from '../../../../../shared/models/users/user-role'
 import { User, UserConstructorHash } from '../../shared/users/user.model'
-import { UserRight } from '../../../../../shared/models/users/user-right.enum'
 
 export type TokenOptions = {
   accessToken: string
@@ -22,9 +23,9 @@ class Tokens {
   tokenType: string
 
   static load () {
-    const accessTokenLocalStorage = localStorage.getItem(this.KEYS.ACCESS_TOKEN)
-    const refreshTokenLocalStorage = localStorage.getItem(this.KEYS.REFRESH_TOKEN)
-    const tokenTypeLocalStorage = localStorage.getItem(this.KEYS.TOKEN_TYPE)
+    const accessTokenLocalStorage = peertubeLocalStorage.getItem(this.KEYS.ACCESS_TOKEN)
+    const refreshTokenLocalStorage = peertubeLocalStorage.getItem(this.KEYS.REFRESH_TOKEN)
+    const tokenTypeLocalStorage = peertubeLocalStorage.getItem(this.KEYS.TOKEN_TYPE)
 
     if (accessTokenLocalStorage && refreshTokenLocalStorage && tokenTypeLocalStorage) {
       return new Tokens({
@@ -38,9 +39,9 @@ class Tokens {
   }
 
   static flush () {
-    localStorage.removeItem(this.KEYS.ACCESS_TOKEN)
-    localStorage.removeItem(this.KEYS.REFRESH_TOKEN)
-    localStorage.removeItem(this.KEYS.TOKEN_TYPE)
+    peertubeLocalStorage.removeItem(this.KEYS.ACCESS_TOKEN)
+    peertubeLocalStorage.removeItem(this.KEYS.REFRESH_TOKEN)
+    peertubeLocalStorage.removeItem(this.KEYS.TOKEN_TYPE)
   }
 
   constructor (hash?: TokenOptions) {
@@ -57,9 +58,9 @@ class Tokens {
   }
 
   save () {
-    localStorage.setItem(Tokens.KEYS.ACCESS_TOKEN, this.accessToken)
-    localStorage.setItem(Tokens.KEYS.REFRESH_TOKEN, this.refreshToken)
-    localStorage.setItem(Tokens.KEYS.TOKEN_TYPE, this.tokenType)
+    peertubeLocalStorage.setItem(Tokens.KEYS.ACCESS_TOKEN, this.accessToken)
+    peertubeLocalStorage.setItem(Tokens.KEYS.REFRESH_TOKEN, this.refreshToken)
+    peertubeLocalStorage.setItem(Tokens.KEYS.TOKEN_TYPE, this.tokenType)
   }
 }
 
@@ -76,16 +77,16 @@ export class AuthUser extends User {
   tokens: Tokens
 
   static load () {
-    const usernameLocalStorage = localStorage.getItem(this.KEYS.USERNAME)
+    const usernameLocalStorage = peertubeLocalStorage.getItem(this.KEYS.USERNAME)
     if (usernameLocalStorage) {
       return new AuthUser(
         {
-          id: parseInt(localStorage.getItem(this.KEYS.ID), 10),
-          username: localStorage.getItem(this.KEYS.USERNAME),
-          email: localStorage.getItem(this.KEYS.EMAIL),
-          role: parseInt(localStorage.getItem(this.KEYS.ROLE), 10) as UserRole,
-          displayNSFW: localStorage.getItem(this.KEYS.DISPLAY_NSFW) === 'true',
-          autoPlayVideo: localStorage.getItem(this.KEYS.AUTO_PLAY_VIDEO) === 'true'
+          id: parseInt(peertubeLocalStorage.getItem(this.KEYS.ID), 10),
+          username: peertubeLocalStorage.getItem(this.KEYS.USERNAME),
+          email: peertubeLocalStorage.getItem(this.KEYS.EMAIL),
+          role: parseInt(peertubeLocalStorage.getItem(this.KEYS.ROLE), 10) as UserRole,
+          displayNSFW: peertubeLocalStorage.getItem(this.KEYS.DISPLAY_NSFW) === 'true',
+          autoPlayVideo: peertubeLocalStorage.getItem(this.KEYS.AUTO_PLAY_VIDEO) === 'true'
         },
         Tokens.load()
       )
@@ -95,12 +96,12 @@ export class AuthUser extends User {
   }
 
   static flush () {
-    localStorage.removeItem(this.KEYS.USERNAME)
-    localStorage.removeItem(this.KEYS.ID)
-    localStorage.removeItem(this.KEYS.ROLE)
-    localStorage.removeItem(this.KEYS.DISPLAY_NSFW)
-    localStorage.removeItem(this.KEYS.AUTO_PLAY_VIDEO)
-    localStorage.removeItem(this.KEYS.EMAIL)
+    peertubeLocalStorage.removeItem(this.KEYS.USERNAME)
+    peertubeLocalStorage.removeItem(this.KEYS.ID)
+    peertubeLocalStorage.removeItem(this.KEYS.ROLE)
+    peertubeLocalStorage.removeItem(this.KEYS.DISPLAY_NSFW)
+    peertubeLocalStorage.removeItem(this.KEYS.AUTO_PLAY_VIDEO)
+    peertubeLocalStorage.removeItem(this.KEYS.EMAIL)
     Tokens.flush()
   }
 
@@ -131,12 +132,12 @@ export class AuthUser extends User {
   }
 
   save () {
-    localStorage.setItem(AuthUser.KEYS.ID, this.id.toString())
-    localStorage.setItem(AuthUser.KEYS.USERNAME, this.username)
-    localStorage.setItem(AuthUser.KEYS.EMAIL, this.email)
-    localStorage.setItem(AuthUser.KEYS.ROLE, this.role.toString())
-    localStorage.setItem(AuthUser.KEYS.DISPLAY_NSFW, JSON.stringify(this.displayNSFW))
-    localStorage.setItem(AuthUser.KEYS.AUTO_PLAY_VIDEO, JSON.stringify(this.autoPlayVideo))
+    peertubeLocalStorage.setItem(AuthUser.KEYS.ID, this.id.toString())
+    peertubeLocalStorage.setItem(AuthUser.KEYS.USERNAME, this.username)
+    peertubeLocalStorage.setItem(AuthUser.KEYS.EMAIL, this.email)
+    peertubeLocalStorage.setItem(AuthUser.KEYS.ROLE, this.role.toString())
+    peertubeLocalStorage.setItem(AuthUser.KEYS.DISPLAY_NSFW, JSON.stringify(this.displayNSFW))
+    peertubeLocalStorage.setItem(AuthUser.KEYS.AUTO_PLAY_VIDEO, JSON.stringify(this.autoPlayVideo))
     this.tokens.save()
   }
 }
index 0b63ef5be2fd47e2ce3d978fb46c9c5f8b3467e1..206ec7bcd9ec446414272e1f5e3147ed5eaed79f 100644 (file)
@@ -1,5 +1,6 @@
 import { HttpClient } from '@angular/common/http'
 import { Injectable } from '@angular/core'
+import { peertubeLocalStorage } from '@app/shared/misc/peertube-local-storage'
 import 'rxjs/add/operator/do'
 import { ReplaySubject } from 'rxjs/ReplaySubject'
 import { ServerConfig } from '../../../../../shared'
@@ -140,11 +141,11 @@ export class ServerService {
   }
 
   private saveConfigLocally (config: ServerConfig) {
-    localStorage.setItem(ServerService.CONFIG_LOCAL_STORAGE_KEY, JSON.stringify(config))
+    peertubeLocalStorage.setItem(ServerService.CONFIG_LOCAL_STORAGE_KEY, JSON.stringify(config))
   }
 
   private loadConfigLocally () {
-    const configString = localStorage.getItem(ServerService.CONFIG_LOCAL_STORAGE_KEY)
+    const configString = peertubeLocalStorage.getItem(ServerService.CONFIG_LOCAL_STORAGE_KEY)
 
     if (configString) {
       try {
diff --git a/client/src/app/shared/misc/peertube-local-storage.ts b/client/src/app/shared/misc/peertube-local-storage.ts
new file mode 100644 (file)
index 0000000..ad761c8
--- /dev/null
@@ -0,0 +1,70 @@
+// Thanks: https://github.com/capaj/localstorage-polyfill
+
+const valuesMap = new Map()
+
+class MemoryStorage {
+  [key: string]: any
+  [index: number]: string
+
+  getItem (key) {
+    const stringKey = String(key)
+    if (valuesMap.has(key)) {
+      return String(valuesMap.get(stringKey))
+    }
+
+    return null
+  }
+
+  setItem (key, val) {
+    valuesMap.set(String(key), String(val))
+  }
+
+  removeItem (key) {
+    valuesMap.delete(key)
+  }
+
+  clear () {
+    valuesMap.clear()
+  }
+
+  key (i: any) {
+    if (arguments.length === 0) {
+      throw new TypeError('Failed to execute "key" on "Storage": 1 argument required, but only 0 present.')
+    }
+
+    const arr = Array.from(valuesMap.keys())
+    return arr[i]
+  }
+
+  get length () {
+    return valuesMap.size
+  }
+}
+
+let peertubeLocalStorage: Storage
+try {
+  peertubeLocalStorage = localStorage
+} catch (err) {
+  const instance = new MemoryStorage()
+
+  peertubeLocalStorage = new Proxy(instance, {
+    set: function (obj, prop, value) {
+      if (MemoryStorage.prototype.hasOwnProperty(prop)) {
+        instance[prop] = value
+      } else {
+        instance.setItem(prop, value)
+      }
+      return true
+    },
+    get: function (target, name) {
+      if (MemoryStorage.prototype.hasOwnProperty(name)) {
+        return instance[name]
+      }
+      if (valuesMap.has(name)) {
+        return instance.getItem(name)
+      }
+    }
+  })
+}
+
+export { peertubeLocalStorage }
index 165fc4e45959fffe364ac23ced8e032476528494..fe1a91d2d6e8bcd6479841e50a2a69be33d18a5b 100644 (file)
@@ -1,3 +1,4 @@
+import { peertubeLocalStorage } from '@app/shared/misc/peertube-local-storage'
 import { LazyLoadEvent } from 'primeng/components/common/lazyloadevent'
 import { SortMeta } from 'primeng/components/common/sortmeta'
 
@@ -15,7 +16,7 @@ export abstract class RestTable {
   protected abstract loadData (): void
 
   loadSort () {
-    const result = localStorage.getItem(this.sortLocalStorageKey)
+    const result = peertubeLocalStorage.getItem(this.sortLocalStorageKey)
 
     if (result) {
       try {
@@ -42,7 +43,7 @@ export abstract class RestTable {
   }
 
   saveSort () {
-    localStorage.setItem(this.sortLocalStorageKey, JSON.stringify(this.sort))
+    peertubeLocalStorage.setItem(this.sortLocalStorageKey, JSON.stringify(this.sort))
   }
 
 }
index b60e58fb09521d1b0371e31f6450a16609f04fe9..fda69efab6ff40afbb04ea1f254a0592036f8768 100644 (file)
@@ -1,6 +1,7 @@
 import { Component, ElementRef, NgZone, OnDestroy, OnInit, ViewChild } from '@angular/core'
 import { ActivatedRoute, Router } from '@angular/router'
 import { RedirectService } from '@app/core/routing/redirect.service'
+import { peertubeLocalStorage } from '@app/shared/misc/peertube-local-storage'
 import { VideoSupportComponent } from '@app/videos/+video-watch/modal/video-support.component'
 import { MetaService } from '@ngx-meta/core'
 import { NotificationsService } from 'angular2-notifications'
@@ -75,7 +76,10 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
   }
 
   ngOnInit () {
-    if (WebTorrent.WEBRTC_SUPPORT === false || localStorage.getItem(VideoWatchComponent.LOCAL_STORAGE_PRIVACY_CONCERN_KEY) === 'true') {
+    if (
+      WebTorrent.WEBRTC_SUPPORT === false ||
+      peertubeLocalStorage.getItem(VideoWatchComponent.LOCAL_STORAGE_PRIVACY_CONCERN_KEY) === 'true'
+    ) {
       this.hasAlreadyAcceptedPrivacyConcern = true
     }
 
@@ -262,7 +266,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
   }
 
   acceptedPrivacyConcern () {
-    localStorage.setItem(VideoWatchComponent.LOCAL_STORAGE_PRIVACY_CONCERN_KEY, 'true')
+    peertubeLocalStorage.setItem(VideoWatchComponent.LOCAL_STORAGE_PRIVACY_CONCERN_KEY, 'true')
     this.hasAlreadyAcceptedPrivacyConcern = true
   }