Skip to content

Commit ddc12b8

Browse files
GantManrozele
authored andcommitted
feat(portable): .NET46 Storage Module (microsoft#748)
* migrate .Net46 AsyncStorage to PCLStorage vs Windows.Storage * clean up migration comments * migrate AsycStorageErrorHelper.cs to shared * fixing small changes * project to match file rename * moved shared constants to shared folder * move methods over * fix botched merge * clean-up project to fit feedback
1 parent 168c8e4 commit ddc12b8

File tree

8 files changed

+558
-183
lines changed

8 files changed

+558
-183
lines changed
Lines changed: 367 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,367 @@
1+
using Newtonsoft.Json;
2+
using Newtonsoft.Json.Linq;
3+
using PCLStorage;
4+
using ReactNative.Bridge;
5+
using System.Threading;
6+
using System.Threading.Tasks;
7+
8+
namespace ReactNative.Modules.Storage
9+
{
10+
class AsyncStorageModule : NativeModuleBase, ILifecycleEventListener
11+
{
12+
private readonly SemaphoreSlim _mutex = new SemaphoreSlim(1, 1);
13+
14+
private IFolder _cachedFolder;
15+
16+
public override string Name
17+
{
18+
get
19+
{
20+
return "AsyncLocalStorage";
21+
}
22+
}
23+
24+
[ReactMethod]
25+
public async void multiGet(string[] keys, ICallback callback)
26+
{
27+
if (keys == null)
28+
{
29+
callback.Invoke(AsyncStorageHelpers.GetInvalidKeyError(null), null);
30+
return;
31+
}
32+
33+
var error = default(JObject);
34+
var data = new JArray();
35+
36+
await _mutex.WaitAsync().ConfigureAwait(false);
37+
try
38+
{
39+
foreach (var key in keys)
40+
{
41+
if (key == null)
42+
{
43+
error = AsyncStorageHelpers.GetInvalidKeyError(null);
44+
break;
45+
}
46+
47+
var value = await GetAsync(key).ConfigureAwait(false);
48+
data.Add(new JArray(key, value));
49+
}
50+
}
51+
finally
52+
{
53+
_mutex.Release();
54+
}
55+
56+
if (error != null)
57+
{
58+
callback.Invoke(error);
59+
}
60+
else
61+
{
62+
callback.Invoke(null, data);
63+
}
64+
}
65+
66+
[ReactMethod]
67+
public async void multiSet(string[][] keyValueArray, ICallback callback)
68+
{
69+
if (keyValueArray == null || keyValueArray.Length == 0)
70+
{
71+
callback.Invoke(AsyncStorageHelpers.GetInvalidKeyError(null));
72+
return;
73+
}
74+
75+
var error = default(JObject);
76+
77+
await _mutex.WaitAsync().ConfigureAwait(false);
78+
try
79+
{
80+
foreach (var pair in keyValueArray)
81+
{
82+
if (pair.Length != 2)
83+
{
84+
error = AsyncStorageHelpers.GetInvalidValueError(null);
85+
break;
86+
}
87+
88+
if (pair[0] == null)
89+
{
90+
error = AsyncStorageHelpers.GetInvalidKeyError(null);
91+
break;
92+
}
93+
94+
if (pair[1] == null)
95+
{
96+
error = AsyncStorageHelpers.GetInvalidValueError(pair[0]);
97+
break;
98+
}
99+
100+
error = await SetAsync(pair[0], pair[1]).ConfigureAwait(false);
101+
if (error != null)
102+
{
103+
break;
104+
}
105+
}
106+
}
107+
finally
108+
{
109+
_mutex.Release();
110+
}
111+
112+
if (error != null)
113+
{
114+
callback.Invoke(error);
115+
}
116+
else
117+
{
118+
callback.Invoke();
119+
}
120+
}
121+
122+
[ReactMethod]
123+
public async void multiRemove(string[] keys, ICallback callback)
124+
{
125+
if (keys == null || keys.Length == 0)
126+
{
127+
callback.Invoke(AsyncStorageHelpers.GetInvalidKeyError(null));
128+
return;
129+
}
130+
131+
var error = default(JObject);
132+
133+
await _mutex.WaitAsync().ConfigureAwait(false);
134+
try
135+
{
136+
foreach (var key in keys)
137+
{
138+
if (key == null)
139+
{
140+
error = AsyncStorageHelpers.GetInvalidKeyError(null);
141+
break;
142+
}
143+
144+
error = await RemoveAsync(key).ConfigureAwait(false);
145+
if (error != null)
146+
{
147+
break;
148+
}
149+
}
150+
}
151+
finally
152+
{
153+
_mutex.Release();
154+
}
155+
156+
if (error != null)
157+
{
158+
callback.Invoke(error);
159+
}
160+
else
161+
{
162+
callback.Invoke();
163+
}
164+
}
165+
166+
[ReactMethod]
167+
public async void multiMerge(string[][] keyValueArray, ICallback callback)
168+
{
169+
if (keyValueArray == null || keyValueArray.Length == 0)
170+
{
171+
callback.Invoke(AsyncStorageHelpers.GetInvalidKeyError(null));
172+
return;
173+
}
174+
175+
var error = default(JObject);
176+
177+
await _mutex.WaitAsync().ConfigureAwait(false);
178+
try
179+
{
180+
foreach (var pair in keyValueArray)
181+
{
182+
if (pair.Length != 2)
183+
{
184+
error = AsyncStorageHelpers.GetInvalidValueError(null);
185+
break;
186+
}
187+
188+
if (pair[0] == null)
189+
{
190+
error = AsyncStorageHelpers.GetInvalidKeyError(null);
191+
break;
192+
}
193+
194+
if (pair[1] == null)
195+
{
196+
error = AsyncStorageHelpers.GetInvalidValueError(pair[0]);
197+
break;
198+
}
199+
200+
error = await MergeAsync(pair[0], pair[1]).ConfigureAwait(false);
201+
if (error != null)
202+
{
203+
break;
204+
}
205+
}
206+
}
207+
finally
208+
{
209+
_mutex.Release();
210+
}
211+
212+
if (error != null)
213+
{
214+
callback.Invoke(error);
215+
}
216+
else
217+
{
218+
callback.Invoke();
219+
}
220+
}
221+
222+
[ReactMethod]
223+
public async void clear(ICallback callback)
224+
{
225+
await _mutex.WaitAsync().ConfigureAwait(false);
226+
try
227+
{
228+
var storageFolder = await GetAsyncStorageFolder(false).ConfigureAwait(false);
229+
if (storageFolder != null)
230+
{
231+
await storageFolder.DeleteAsync().ConfigureAwait(false);
232+
_cachedFolder = null;
233+
}
234+
}
235+
finally
236+
{
237+
_mutex.Release();
238+
}
239+
240+
callback.Invoke();
241+
}
242+
243+
[ReactMethod]
244+
public async void getAllKeys(ICallback callback)
245+
{
246+
var keys = new JArray();
247+
248+
await _mutex.WaitAsync().ConfigureAwait(false);
249+
try
250+
{
251+
var storageFolder = await GetAsyncStorageFolder(false).ConfigureAwait(false);
252+
if (storageFolder != null)
253+
{
254+
var items = await storageFolder.GetFilesAsync().ConfigureAwait(false);
255+
foreach (var item in items)
256+
{
257+
var itemName = item.Name;
258+
if (itemName.EndsWith(AsyncStorageHelpers.FileExtension))
259+
{
260+
keys.Add(AsyncStorageHelpers.GetKeyName(itemName));
261+
}
262+
}
263+
}
264+
}
265+
finally
266+
{
267+
_mutex.Release();
268+
}
269+
270+
callback.Invoke(null, keys);
271+
}
272+
273+
public void OnSuspend()
274+
{
275+
}
276+
277+
public void OnResume()
278+
{
279+
}
280+
281+
public void OnDestroy()
282+
{
283+
_mutex.Dispose();
284+
}
285+
286+
private async Task<string> GetAsync(string key)
287+
{
288+
var storageFolder = await GetAsyncStorageFolder(false).ConfigureAwait(false);
289+
if (storageFolder != null)
290+
{
291+
var fileName = AsyncStorageHelpers.GetFileName(key);
292+
var storageItem = await storageFolder.GetFileAsync(fileName).ConfigureAwait(false);
293+
if (storageItem != null)
294+
{
295+
var file = await storageFolder.GetFileAsync(fileName).ConfigureAwait(false);
296+
return await FileExtensions.ReadAllTextAsync(file).ConfigureAwait(false);
297+
}
298+
}
299+
300+
return null;
301+
}
302+
303+
private async Task<JObject> MergeAsync(string key, string value)
304+
{
305+
var oldValue = await GetAsync(key).ConfigureAwait(false);
306+
307+
var newValue = default(string);
308+
if (oldValue == null)
309+
{
310+
newValue = value;
311+
}
312+
else
313+
{
314+
var oldJson = JObject.Parse(oldValue);
315+
var newJson = JObject.Parse(value);
316+
AsyncStorageHelpers.DeepMergeInto(oldJson, newJson);
317+
newValue = oldJson.ToString(Formatting.None);
318+
}
319+
320+
return await SetAsync(key, newValue).ConfigureAwait(false);
321+
}
322+
323+
private async Task<JObject> RemoveAsync(string key)
324+
{
325+
var storageFolder = await GetAsyncStorageFolder(false).ConfigureAwait(false);
326+
if (storageFolder != null)
327+
{
328+
var fileName = AsyncStorageHelpers.GetFileName(key);
329+
var storageItem = await storageFolder.GetFileAsync(fileName).ConfigureAwait(false);
330+
if (storageItem != null)
331+
{
332+
await storageItem.DeleteAsync().ConfigureAwait(false);
333+
}
334+
}
335+
336+
return null;
337+
}
338+
339+
private async Task<JObject> SetAsync(string key, string value)
340+
{
341+
var storageFolder = await GetAsyncStorageFolder(true).ConfigureAwait(false);
342+
var file = await storageFolder.CreateFileAsync(AsyncStorageHelpers.GetFileName(key), CreationCollisionOption.ReplaceExisting).ConfigureAwait(false);
343+
await FileExtensions.WriteAllTextAsync(file, value).ConfigureAwait(false);
344+
return default(JObject);
345+
}
346+
347+
private async Task<IFolder> GetAsyncStorageFolder(bool createIfNotExists)
348+
{
349+
if (_cachedFolder == null)
350+
{
351+
var localFolder = FileSystem.Current.LocalStorage;
352+
353+
if (localFolder.CheckExistsAsync(AsyncStorageHelpers.DirectoryName).Result == ExistenceCheckResult.FolderExists)
354+
{
355+
_cachedFolder = localFolder;
356+
}
357+
else
358+
{
359+
_cachedFolder = await localFolder.CreateFolderAsync(AsyncStorageHelpers.DirectoryName, CreationCollisionOption.OpenIfExists);
360+
}
361+
}
362+
363+
return _cachedFolder;
364+
}
365+
366+
}
367+
}

0 commit comments

Comments
 (0)