Skip to content

Commit bffc03c

Browse files
committed
feat: create JsonCacheSecStorage
Closes #58
1 parent 01b09ed commit bffc03c

10 files changed

+321
-12
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Added
11+
12+
- JsonCacheSecStorage: an implementation on top of the flutter_secure_storage
13+
package — [58](https://github.com/dartoos-dev/json_cache/issues/58).
14+
1015
## [1.0.0] - 2022-01-08
1116

1217
### Added

README.md

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# json_cache
22

3-
<img width="406" hight="192" alt="json cache logo" src="https://user-images.githubusercontent.com/24878574/119276278-56ef4a80-bbf0-11eb-8701-53a94f24f75b.png" align="middle">
3+
<img width="406" hight="192" alt="json cache logo"
4+
src="https://user-images.githubusercontent.com/24878574/119276278-56ef4a80-bbf0-11eb-8701-53a94f24f75b.png"
5+
align="middle">
46

57
[![EO principles respected
68
here](https://www.elegantobjects.org/badge.svg)](https://www.elegantobjects.org)
@@ -25,6 +27,7 @@ Rultor.com](https://www.rultor.com/b/dartoos-dev/json_cache)](https://www.rultor
2527
- [JsonCacheMem — Thread-safe In-memory cache](#jsoncachemem)
2628
- [JsonCachePrefs — SharedPreferences](#jsoncacheprefs)
2729
- [JsonCacheEncPrefs — EncryptedSharedPreferences](#jsoncacheencprefs)
30+
- [JsonCacheSecStorage — FlutterSecureStorage](#jsoncachesecstorage)
2831
- [JsonCacheLocalStorage — LocalStorage](#jsoncachelocalstorage)
2932
- [JsonCacheCrossLocalStorage — CrossLocalStorage](#jsoncachecrosslocalstorage)
3033
- [Demo application](#demo-application)
@@ -33,7 +36,6 @@ Rultor.com](https://www.rultor.com/b/dartoos-dev/json_cache)](https://www.rultor
3336

3437
## Overview
3538

36-
3739
> Cache is a hardware or software component that stores data so that future
3840
> requests for that data can be served faster; the data stored in a cache might
3941
> be the result of an earlier computation or a copy of data stored elsewhere.
@@ -61,12 +63,13 @@ that can be selected and grouped in various combinations to meet specific cache
6163
requirements.
6264

6365
[JsonCache](https://pub.dev/documentation/json_cache/latest/json_cache/JsonCache-class.html)
64-
is the core interface of this package and represents the concept of cached data. It is defined as:
66+
is the core interface of this package and represents the concept of cached data.
67+
It is defined as:
6568

6669
```dart
6770
/// Represents cached data in json format.
6871
abstract class JsonCache {
69-
/// Frees up storage space.
72+
/// Frees up storage space — deletes all keys with associated values.
7073
Future<void> clear();
7174
7275
/// Removes cached data located at [key].
@@ -147,14 +150,14 @@ object. For example:
147150
}
148151
149152
/// Removes cached data related to a specific user.
150-
Future<void> signoutId(String userId) async {
153+
Future<void> signoutId(String userId) async
151154
await jsonCache.remove(userId);
152155
}
153156
```
154157

155158
#### Cache Initialization
156159

157-
[JsonCacheMem.init](https://pub.dev/documentation/json_cache/latest/json_cache/JsonCacheMem/JsonCacheMem.init.html)
160+
[JsonCacheMem.init](https://p.dev/documentatijson_cache/latest/json_cache/JsonCacheMem/JsonCacheMem.init.html)
158161
is the constructor whose purpose is to initialize the cache upon object
159162
instantiation. The data passed to the `init` parameter is deeply copied to both
160163
the internal in-memory cache and the level2 cache.
@@ -194,6 +197,26 @@ package.
194197
195198
```
196199

200+
### JsonCacheSecStorage
201+
202+
JsonCacheSecStorage
203+
is an implementation on top of the
204+
[flutter_secure_storage](https://pub.dev/packages/flutter_secure_storage) package.
205+
206+
```dart
207+
208+
final secStorage = FlutterSecureStorage(…);
209+
final JsonCache jsonCache = JsonCacheSecStorage(secStorage);
210+
// Write a simple string value defining it as a key of the literal map.
211+
final Map<String, dynamic> info = {'an secret info': true};
212+
jsonCache.refresh('secret', info);
213+
214+
// later on…
215+
216+
final mappedInfo = await jsonCache.value('secret')!;
217+
final originalInfo = mappedInfo.keys.first; // 'an secret info'
218+
```
219+
197220
### JsonCacheLocalStorage
198221

199222
[JsonCacheLocalStorage](https://pub.dev/documentation/json_cache/latest/json_cache/JsonCacheLocalStorage-class.html)

lib/json_cache.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,5 @@ export 'src/json_cache_hollow.dart';
99
export 'src/json_cache_local_storage.dart';
1010
export 'src/json_cache_mem.dart';
1111
export 'src/json_cache_prefs.dart';
12+
export 'src/json_cache_sec_storage.dart';
1213
export 'src/json_cache_wrap.dart';

lib/src/json_cache.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
///> elsewhere.
77
///> — [cache Wikipedia](https://en.wikipedia.org/wiki/Cache_(computing))
88
abstract class JsonCache {
9-
/// Frees up storage space.
9+
/// Frees up storage space — deletes all keys with associated values.
1010
Future<void> clear();
1111

1212
/// Removes cached data located at [key].

lib/src/json_cache_fake.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import 'package:json_cache/json_cache.dart';
44
///
55
/// It is intended for unit testing and prototyping.
66
///
7-
/// **Warning**: do not use it in production code. It is not thread safe.
7+
/// **Warning**: do not use it in production code. It is not thread-safe.
88
class JsonCacheFake implements JsonCache {
99
/// It will share a static memory with other instances.
1010
JsonCacheFake() : this.mem(_shrMem);
@@ -14,7 +14,7 @@ class JsonCacheFake implements JsonCache {
1414
: this.mem(Map<String, Map<String, dynamic>?>.of(init));
1515

1616
/// Cache with custom memory.
17-
JsonCacheFake.mem(this._memory);
17+
const JsonCacheFake.mem(this._memory);
1818

1919
/// in-memory storage.
2020
final Map<String, Map<String, dynamic>?> _memory;
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import 'dart:convert';
2+
3+
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
4+
import 'package:json_cache/json_cache.dart';
5+
6+
/// Stores data in secure storage.
7+
///
8+
/// See also:
9+
/// - [flutter_secure_storage](https://pub.dev/packages/flutter_secure_storage).
10+
class JsonCacheSecStorage implements JsonCache {
11+
/// Sets the [FlutterSecureStorage] instance.
12+
const JsonCacheSecStorage(this._storage);
13+
14+
// the encapsulated [FlutterSecureStorage] instance.
15+
final FlutterSecureStorage _storage;
16+
17+
@override
18+
Future<void> clear() async {
19+
await _storage.deleteAll();
20+
}
21+
22+
@override
23+
Future<void> refresh(String key, Map<String, dynamic> value) async {
24+
await _storage.write(key: key, value: json.encode(value));
25+
}
26+
27+
@override
28+
Future<void> remove(String key) async {
29+
await _storage.delete(key: key);
30+
}
31+
32+
@override
33+
Future<Map<String, dynamic>?> value(String key) async {
34+
final encrypted = await _storage.read(key: key);
35+
return encrypted == null
36+
? null
37+
: json.decode(encrypted) as Map<String, dynamic>;
38+
}
39+
}

pubspec.lock

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,48 @@ packages:
118118
description: flutter
119119
source: sdk
120120
version: "0.0.0"
121+
flutter_secure_storage:
122+
dependency: "direct main"
123+
description:
124+
name: flutter_secure_storage
125+
url: "https://pub.dartlang.org"
126+
source: hosted
127+
version: "5.0.2"
128+
flutter_secure_storage_linux:
129+
dependency: transitive
130+
description:
131+
name: flutter_secure_storage_linux
132+
url: "https://pub.dartlang.org"
133+
source: hosted
134+
version: "1.1.0"
135+
flutter_secure_storage_macos:
136+
dependency: transitive
137+
description:
138+
name: flutter_secure_storage_macos
139+
url: "https://pub.dartlang.org"
140+
source: hosted
141+
version: "1.1.0"
142+
flutter_secure_storage_platform_interface:
143+
dependency: transitive
144+
description:
145+
name: flutter_secure_storage_platform_interface
146+
url: "https://pub.dartlang.org"
147+
source: hosted
148+
version: "1.0.0"
149+
flutter_secure_storage_web:
150+
dependency: transitive
151+
description:
152+
name: flutter_secure_storage_web
153+
url: "https://pub.dartlang.org"
154+
source: hosted
155+
version: "1.0.2"
156+
flutter_secure_storage_windows:
157+
dependency: transitive
158+
description:
159+
name: flutter_secure_storage_windows
160+
url: "https://pub.dartlang.org"
161+
source: hosted
162+
version: "1.1.2"
121163
flutter_test:
122164
dependency: "direct dev"
123165
description: flutter
@@ -141,7 +183,7 @@ packages:
141183
name: lint
142184
url: "https://pub.dartlang.org"
143185
source: hosted
144-
version: "1.8.1"
186+
version: "1.8.2"
145187
localstorage:
146188
dependency: "direct main"
147189
description:

pubspec.yaml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: json_cache
2-
description: An object-oriented package for caching user data locally in json; a combinable layer on top of local storage packages that unifies them as an elegant caching API.
2+
description: An object-oriented package for caching user data locally in json; a combinable layer on top of local storage packages that unifies them with an elegant caching API.
33
version: 1.0.0
44
homepage: https://dartoos.dev
55
repository: https://github.com/dartoos-dev/json_cache
@@ -13,11 +13,12 @@ dependencies:
1313
encrypted_shared_preferences: ^3.0.0
1414
flutter:
1515
sdk: flutter
16+
flutter_secure_storage: ^5.0.2
1617
localstorage: ^4.0.0+1
1718
mutex: ^3.0.0
1819
shared_preferences: ^2.0.11
1920

2021
dev_dependencies:
2122
flutter_test:
2223
sdk: flutter
23-
lint: ^1.8.1
24+
lint: ^1.8.2
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
import 'dart:convert';
2+
3+
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
4+
import 'package:json_cache/json_cache.dart';
5+
6+
/// Unit-testing purposes implementation of the [FlutterSecureStorage] class.
7+
class FlutterSecureStorageMock implements FlutterSecureStorage {
8+
/// Uses a instance of [JsonCacheFake] as the internal in-memory cache.
9+
FlutterSecureStorageMock() : this.fake(JsonCacheFake());
10+
11+
/// Set the fake cache instance.
12+
FlutterSecureStorageMock.fake(this._fakeCache);
13+
14+
final JsonCache _fakeCache;
15+
16+
/// throws [UnimplementedError].
17+
@override
18+
AndroidOptions get aOptions => throw UnimplementedError();
19+
20+
/// Tells how many times [write] has been invoked.
21+
int writeInvokations = 0;
22+
23+
/// Tells how many times [read] has been invoked.
24+
int readInvokations = 0;
25+
26+
/// Tells how many times [delete] has been invoked.
27+
int deleteInvokations = 0;
28+
29+
/// Tells how many times [deleteAll] has been invoked.
30+
int deleteAllInvokations = 0;
31+
@override
32+
Future<bool> containsKey({
33+
required String key,
34+
IOSOptions? iOptions,
35+
AndroidOptions? aOptions,
36+
LinuxOptions? lOptions,
37+
WebOptions? webOptions,
38+
MacOsOptions? mOptions,
39+
WindowsOptions? wOptions,
40+
}) async {
41+
return (await _fakeCache.value(key)) != null;
42+
}
43+
44+
@override
45+
Future<void> delete({
46+
required String key,
47+
IOSOptions? iOptions,
48+
AndroidOptions? aOptions,
49+
LinuxOptions? lOptions,
50+
WebOptions? webOptions,
51+
MacOsOptions? mOptions,
52+
WindowsOptions? wOptions,
53+
}) async {
54+
++deleteInvokations;
55+
await _fakeCache.remove(key);
56+
}
57+
58+
@override
59+
Future<void> deleteAll({
60+
IOSOptions? iOptions,
61+
AndroidOptions? aOptions,
62+
LinuxOptions? lOptions,
63+
WebOptions? webOptions,
64+
MacOsOptions? mOptions,
65+
WindowsOptions? wOptions,
66+
}) async {
67+
++deleteAllInvokations;
68+
await _fakeCache.clear();
69+
}
70+
71+
/// throws [UnimplementedError].
72+
@override
73+
IOSOptions get iOptions => throw UnimplementedError();
74+
75+
/// throws [UnimplementedError].
76+
@override
77+
LinuxOptions get lOptions => throw UnimplementedError();
78+
79+
/// throws [UnimplementedError].
80+
@override
81+
MacOsOptions get mOptions => throw UnimplementedError();
82+
83+
@override
84+
Future<String?> read({
85+
required String key,
86+
IOSOptions? iOptions,
87+
AndroidOptions? aOptions,
88+
LinuxOptions? lOptions,
89+
WebOptions? webOptions,
90+
MacOsOptions? mOptions,
91+
WindowsOptions? wOptions,
92+
}) async {
93+
++readInvokations;
94+
final jsonObj = await _fakeCache.value(key);
95+
return jsonObj == null ? null : json.encode(jsonObj);
96+
}
97+
98+
/// throws [UnimplementedError].
99+
@override
100+
Future<Map<String, String>> readAll({
101+
IOSOptions? iOptions,
102+
AndroidOptions? aOptions,
103+
LinuxOptions? lOptions,
104+
WebOptions? webOptions,
105+
MacOsOptions? mOptions,
106+
WindowsOptions? wOptions,
107+
}) {
108+
// TODO: implement readAll
109+
throw UnimplementedError();
110+
}
111+
112+
/// throws [UnimplementedError].
113+
@override
114+
WindowsOptions get wOptions => throw UnimplementedError();
115+
116+
/// throws [UnimplementedError].
117+
@override
118+
WebOptions get webOptions => throw UnimplementedError();
119+
120+
@override
121+
Future<void> write({
122+
required String key,
123+
required String? value,
124+
IOSOptions? iOptions,
125+
AndroidOptions? aOptions,
126+
LinuxOptions? lOptions,
127+
WebOptions? webOptions,
128+
MacOsOptions? mOptions,
129+
WindowsOptions? wOptions,
130+
}) async {
131+
++writeInvokations;
132+
if (value != null) {
133+
await _fakeCache.refresh(key, json.decode(value) as Map<String, dynamic>);
134+
}
135+
}
136+
}

0 commit comments

Comments
 (0)