浏览代码

[RN] Prepare to polyfill sessionStorage

master
Lyubo Marinov 8 年前
父节点
当前提交
bf523711df

+ 0
- 112
react/features/base/lib-jitsi-meet/native/LocalStorage.js 查看文件

1
-import { AsyncStorage } from 'react-native';
2
-
3
-/**
4
- * Prefix used to mark keys stored by our app in the global React Native
5
- * storage.
6
- */
7
-const JITSI_KEY_PREFIX = '@jitsi/';
8
-
9
-/**
10
- * Web Sorage API compatible object used for polyfilling window.localStorage.
11
- * The Web Storage API is synchronous, whereas AsyncStorage, the builtin generic
12
- * storage API in React Native, is asynchronous, so this object is optimistic:
13
- * it will first store the value locally (in memory) so results can be served
14
- * synchronously, and then save the value asynchronously.
15
- *
16
- * If any of the asynchronous operations produces an error, it's ignored.
17
- */
18
-export default class LocalStorage {
19
-    /**
20
-     * Loads all keys from React Native's AsyncStorage.
21
-     */
22
-    constructor() {
23
-        AsyncStorage.getAllKeys()
24
-            .then(keys => {
25
-                const jitsiKeys
26
-                    = keys.filter(key => key.startsWith(JITSI_KEY_PREFIX));
27
-
28
-                AsyncStorage.multiGet(jitsiKeys)
29
-                    .then(items => {
30
-                        for (const item of items) {
31
-                            const key = item[0].slice(JITSI_KEY_PREFIX.length);
32
-                            const value = item[1];
33
-
34
-                            this[key] = value;
35
-                        }
36
-                    });
37
-            });
38
-    }
39
-
40
-    /**
41
-     * Gets the number of items stored.
42
-     *
43
-     * @returns {number}
44
-     */
45
-    get length() {
46
-        return Object.keys(this).length;
47
-    }
48
-
49
-    /**
50
-     * Removes all keys from the storage.
51
-     *
52
-     * @returns {void}
53
-     */
54
-    clear() {
55
-        const keys = Object.keys(this);
56
-
57
-        for (const key of keys) {
58
-            delete this[key];
59
-            AsyncStorage.removeItem(`${JITSI_KEY_PREFIX}${key}`);
60
-        }
61
-    }
62
-
63
-    /**
64
-     * Gets the element that was stored for the given `key`.
65
-     *
66
-     * @param {string} key - The requested `key`.
67
-     * @returns {string|null}
68
-     */
69
-    getItem(key) {
70
-        if (this.hasOwnProperty(key)) {
71
-            return this[key];
72
-        }
73
-
74
-        return null;
75
-    }
76
-
77
-    /**
78
-     * Gets the nth element in the storage.
79
-     *
80
-     * @param {number} n - The element number that is requested.
81
-     * @returns {string}
82
-     */
83
-    key(n) {
84
-        return Object.keys(this)[n || 0];
85
-    }
86
-
87
-    /**
88
-     * Removes the given `key` from the storage.
89
-     *
90
-     * @param {string} key - The `key` which will be removed.
91
-     * @returns {void}
92
-     */
93
-    removeItem(key) {
94
-        delete this[key];
95
-        AsyncStorage.removeItem(`${JITSI_KEY_PREFIX}${key}`);
96
-    }
97
-
98
-    /**
99
-     * Stores the given `value` for the given `key`. If a value or ready exists
100
-     * for that key, it's updated.
101
-     *
102
-     * @param {string} key - The key for the value which will be stored.
103
-     * @param {string} value - The value which will be stored.
104
-     * @returns {void}
105
-     */
106
-    setItem(key, value) {
107
-        // eslint-disable-next-line no-param-reassign
108
-        value = String(value);
109
-        this[key] = value;
110
-        AsyncStorage.setItem(`${JITSI_KEY_PREFIX}${key}`, value);
111
-    }
112
-}

+ 158
- 0
react/features/base/lib-jitsi-meet/native/Storage.js 查看文件

1
+/* @flow */
2
+
3
+import { AsyncStorage } from 'react-native';
4
+
5
+/**
6
+ * A Web Sorage API implementation used for polyfilling
7
+ * <tt>window.localStorage</tt> and/or <tt>window.sessionStorage</tt>.
8
+ * <p>
9
+ * The Web Storage API is synchronous whereas React Native's builtin generic
10
+ * storage API <tt>AsyncStorage</tt> is asynchronous so the implementation with
11
+ * persistence is optimistic: it will first store the value locally in memory so
12
+ * that results can be served synchronously and then persist the value
13
+ * asynchronously. If an asynchronous operation produces an error, it's ignored.
14
+ */
15
+export default class Storage {
16
+    _items: Map<string, string>;
17
+
18
+    _keyPrefix: ?string;
19
+
20
+    /**
21
+     * Initializes a new <tt>Storage</tt> instance. Loads all previously
22
+     * persisted data items from React Native's <tt>AsyncStorage</tt> if
23
+     * necessary.
24
+     *
25
+     * @param {string|undefined} keyPrefix - The prefix of the
26
+     * <tt>AsyncStorage</tt> keys to be persisted by this storage.
27
+     */
28
+    constructor(keyPrefix: ?string) {
29
+        /**
30
+         * The data items stored in this storage.
31
+         *
32
+         * @private
33
+         * @type {Map}
34
+         */
35
+        this._items = new Map();
36
+
37
+        /**
38
+         * The prefix of the <tt>AsyncStorage</tt> keys persisted by this
39
+         * storage. If <tt>undefined</tt>, then the data items stored in this
40
+         * storage will not be persisted.
41
+         *
42
+         * @private
43
+         * @type {string}
44
+         */
45
+        this._keyPrefix = keyPrefix;
46
+
47
+        if (typeof this._keyPrefix !== 'undefined') {
48
+            // Load all previously persisted data items from React Native's
49
+            // AsyncStorage.
50
+            AsyncStorage.getAllKeys().then((...getAllKeysCallbackArgs) => {
51
+                // XXX The keys argument of getAllKeys' callback may or may not
52
+                // be preceded by an error argument.
53
+                const keys
54
+                    = getAllKeysCallbackArgs[getAllKeysCallbackArgs.length - 1]
55
+                        .filter(key => key.startsWith(this._keyPrefix));
56
+
57
+                AsyncStorage.multiGet(keys).then((...multiGetCallbackArgs) => {
58
+                    // XXX The result argument of multiGet may or may not be
59
+                    // preceded by an errors argument.
60
+                    const result
61
+                        = multiGetCallbackArgs[multiGetCallbackArgs.length - 1];
62
+                    const keyPrefixLength
63
+                        = this._keyPrefix && this._keyPrefix.length;
64
+
65
+                    // eslint-disable-next-line prefer-const
66
+                    for (let [ key, value ] of result) {
67
+                        key = key.substring(keyPrefixLength);
68
+
69
+                        // XXX The loading of the previously persisted data
70
+                        // items from AsyncStorage is asynchronous which means
71
+                        // that it is technically possible to invoke setItem
72
+                        // with a key before the key is loaded from
73
+                        // AsyncStorage.
74
+                        if (!this._items.has(key)) {
75
+                            this._items.set(key, value);
76
+                        }
77
+                    }
78
+                });
79
+            });
80
+        }
81
+    }
82
+
83
+    /**
84
+     * Removes all keys from this storage.
85
+     *
86
+     * @returns {void}
87
+     */
88
+    clear() {
89
+        for (const key of this._items.keys()) {
90
+            this.removeItem(key);
91
+        }
92
+    }
93
+
94
+    /**
95
+     * Returns the value associated with a specific key in this storage.
96
+     *
97
+     * @param {string} key - The name of the key to retrieve the value of.
98
+     * @returns {string|null} The value associated with <tt>key</tt> or
99
+     * <tt>null</tt>.
100
+     */
101
+    getItem(key: string) {
102
+        return this._items.has(key) ? this._items.get(key) : null;
103
+    }
104
+
105
+    /**
106
+     * Returns the name of the nth key in this storage.
107
+     *
108
+     * @param {number} n - The zero-based integer index of the key to get the
109
+     * name of.
110
+     * @returns {string} The name of the nth key in this storage.
111
+     */
112
+    key(n: number) {
113
+        let i = 0;
114
+
115
+        for (const key in this._items.keys()) {
116
+            if (i++ === n) {
117
+                return key;
118
+            }
119
+        }
120
+    }
121
+
122
+    /**
123
+     * Returns an integer representing the number of data items stored in this
124
+     * storage.
125
+     *
126
+     * @returns {number}
127
+     */
128
+    get length(): number {
129
+        return this._items.size;
130
+    }
131
+
132
+    /**
133
+     * Removes a specific key from this storage.
134
+     *
135
+     * @param {string} key - The name of the key to remove.
136
+     * @returns {void}
137
+     */
138
+    removeItem(key: string) {
139
+        this._items.delete(key);
140
+        typeof this._keyPrefix === 'undefined'
141
+            || AsyncStorage.removeItem(`${String(this._keyPrefix)}${key}`);
142
+    }
143
+
144
+    /**
145
+     * Adds a specific key to this storage and associates it with a specific
146
+     * value. If the key exists already, updates its value.
147
+     *
148
+     * @param {string} key - The name of the key to add/update.
149
+     * @param {string} value - The value to associate with <tt>key</tt>.
150
+     * @returns {void}
151
+     */
152
+    setItem(key: string, value: string) {
153
+        value = String(value); // eslint-disable-line no-param-reassign
154
+        this._items.set(key, value);
155
+        typeof this._keyPrefix === 'undefined'
156
+            || AsyncStorage.setItem(`${String(this._keyPrefix)}${key}`, value);
157
+    }
158
+}

+ 4
- 2
react/features/base/lib-jitsi-meet/native/polyfills-browser.js 查看文件

2
 import BackgroundTimer from 'react-native-background-timer';
2
 import BackgroundTimer from 'react-native-background-timer';
3
 import 'url-polyfill'; // Polyfill for URL constructor
3
 import 'url-polyfill'; // Polyfill for URL constructor
4
 
4
 
5
-import LocalStorage from './LocalStorage';
5
+import Storage from './Storage';
6
 
6
 
7
 /**
7
 /**
8
  * Gets the first common prototype of two specified Objects (treating the
8
  * Gets the first common prototype of two specified Objects (treating the
267
     }
267
     }
268
 
268
 
269
     // localStorage
269
     // localStorage
270
-    global.localStorage = new LocalStorage();
270
+    if (typeof global.localStorage === 'undefined') {
271
+        global.localStorage = new Storage('@jitsi-meet/');
272
+    }
271
 
273
 
272
     // location
274
     // location
273
     if (typeof global.location === 'undefined') {
275
     if (typeof global.location === 'undefined') {

正在加载...
取消
保存