diff --git a/lib/bloc/crypto/crypto_bloc.dart b/lib/bloc/crypto/crypto_bloc.dart index 05e7a2197..105a37bad 100644 --- a/lib/bloc/crypto/crypto_bloc.dart +++ b/lib/bloc/crypto/crypto_bloc.dart @@ -17,6 +17,7 @@ import 'package:my_wit_wallet/bloc/crypto/api_crypto.dart'; import 'package:my_wit_wallet/bloc/explorer/api_explorer.dart'; import 'package:my_wit_wallet/shared/api_database.dart'; import 'package:my_wit_wallet/shared/locator.dart'; +import 'package:my_wit_wallet/util/storage/cache/read_through.dart'; import 'package:my_wit_wallet/util/storage/database/account.dart'; import 'package:my_wit_wallet/util/storage/database/balance_info.dart'; import 'package:my_wit_wallet/util/storage/database/encrypt/password.dart'; @@ -40,7 +41,18 @@ class CryptoBloc extends Bloc { ApiExplorer apiExplorer = Locator.instance.get(); ApiDatabase db = Locator.instance.get(); + // TODO: remove late because is always being defined in the constructor + // Map + late ReadThrough _vttGetThroughBlockExplorer; + CryptoBloc(initialState) : super(initialState) { + _vttGetThroughBlockExplorer = ReadThrough( + (String hash) async => await apiExplorer.hash(hash), + (ValueTransferInfo valueTransferInfo) async => + await db.addVtt(valueTransferInfo), + (String hash) async => await db.getVtt(hash), + ); + on(_cryptoInitializeWalletEvent); on(_cryptoInitWalletDoneEvent); on(_cryptoReadyEvent); @@ -49,7 +61,6 @@ class CryptoBloc extends Bloc { Future _cryptoInitializeWalletEvent( CryptoInitializeWalletEvent event, Emitter emit) async { - print("----------2-----------"); /// setup default default structure for database and unlock it emit( CryptoInitializingWalletState( @@ -237,7 +248,6 @@ class CryptoBloc extends Bloc { ApiDatabase db = Locator.instance(); String key = await db.getKeychain(); final masterKey = key != '' ? key : event.password; - print("----------1-----------"); apiCrypto.setInitialWalletData( event.walletName, event.keyData, @@ -292,10 +302,11 @@ class CryptoBloc extends Bloc { try { for (int i = 0; i < account.vttHashes.length; i++) { String _hash = account.vttHashes.elementAt(i); - var result = await apiExplorer.hash(_hash); - ValueTransferInfo valueTransferInfo = result as ValueTransferInfo; - account.vtts.add(valueTransferInfo); - await db.addVtt(valueTransferInfo); + ValueTransferInfo? valueTransferInfo = + await _vttGetThroughBlockExplorer.get(_hash); + if (valueTransferInfo != null) { + account.vtts.add(valueTransferInfo); + } } return account; } catch (e) { @@ -334,7 +345,9 @@ class CryptoBloc extends Bloc { } Future _syncAccount(Account account) async { + // In this function vttHashes are fullfilled try { + // Is not ignoring repeated value transfers final addressValueTransfers = await apiExplorer.address( value: account.address, tab: 'value_transfers') as AddressValueTransfers; diff --git a/lib/util/storage/cache/read_through.dart b/lib/util/storage/cache/read_through.dart new file mode 100644 index 000000000..452f8377d --- /dev/null +++ b/lib/util/storage/cache/read_through.dart @@ -0,0 +1,32 @@ +// Generic implementation of read throught cache pattern +class ReadThrough { + // Consume the value if it's not already stored + Future Function(String) _fetch; + // Save the value in cache + Future Function(T) _save; + // Read Value from Cache + Future Function(String) _read; + + ReadThrough(this._fetch, this._save, this._read); + + Future _insert(T value) async { + return await _save(value); + } + + // Check if value is stored and call the fetch function if it's not found + Future get(String key) async { + T? storedValue = await _read(key); + + if (storedValue != null) { + return storedValue; + } else { + T? value = await _fetch(key); + + if (value != null) { + await _insert(value); + } + + return value; + } + } +} diff --git a/test/storage/read_through_in_memory_cache_test.dart b/test/storage/read_through_in_memory_cache_test.dart deleted file mode 100644 index 35d9dc70b..000000000 --- a/test/storage/read_through_in_memory_cache_test.dart +++ /dev/null @@ -1,48 +0,0 @@ -import 'package:my_wit_wallet/util/storage/cache/read_through_in_memory_cache.dart'; -import 'package:test/test.dart'; - -void main() { - group('Storage implementation of read through cache pattern in memory', () { - test('Should call fetch callback if it\'s first time getting the value', - () async { - int timesCalled = 0; - String expectedValue = "Potato"; - - ReadThroughInMemoryCache cache = - ReadThroughInMemoryCache((p0) async { - timesCalled = timesCalled += 1; - - await Future.delayed(Duration(seconds: 0)); - - return expectedValue; - }); - - expect(await cache.get("whatever"), expectedValue); - expect(timesCalled, 1); - }); - - test('Should NOT call fetch callback if it\'s the second time getting the value', - () async { - int timesCalled = 0; - String expectedValue = "Potato"; - - ReadThroughInMemoryCache cache = - ReadThroughInMemoryCache((p0) async { - timesCalled = timesCalled += 1; - - await Future.delayed(Duration(seconds: 0)); - - return expectedValue; - }); - - - // call get multiple times - expect(await cache.get("whatever"), expectedValue); - expect(await cache.get("whatever"), expectedValue); - expect(await cache.get("whatever"), expectedValue); - expect(await cache.get("whatever"), expectedValue); - - expect(timesCalled, 1); - }); - }); -} diff --git a/test/storage/read_through_test.dart b/test/storage/read_through_test.dart new file mode 100644 index 000000000..79cdbf102 --- /dev/null +++ b/test/storage/read_through_test.dart @@ -0,0 +1,64 @@ +import 'package:my_wit_wallet/util/storage/cache/read_through.dart'; +import 'package:test/test.dart'; + +void main() { + group('Storage implementation of read through cache pattern in memory', () { + test('Should call fetch callback if it\'s first time getting the value', + () async { + int timesCalled = 0; + String expectedValue = "Potato"; + bool saveCalled = false; + + ReadThrough cache = ReadThrough((p0) async { + timesCalled = timesCalled += 1; + + await Future.delayed(Duration(seconds: 0)); + + return expectedValue; + }, (p1) async { + saveCalled = true; + return true; + }, (p0) async { + return null; + }); + + expect(await cache.get("whatever"), expectedValue); + expect(saveCalled, true); + expect(timesCalled, 1); + }); + + test( + 'Should NOT call fetch callback if it\'s the second time getting the value', + () async { + int timesCalled = 0; + String expectedValue = "Potato"; + bool saveCalled = false; + + ReadThrough cache = ReadThrough((p0) async { + timesCalled = timesCalled += 1; + + await Future.delayed(Duration(seconds: 0)); + + return expectedValue; + }, (p1) async { + saveCalled = true; + return true; + }, (p0) async { + if (timesCalled == 0) { + return null; + } else { + return expectedValue; + } + }); + + // call get multiple times + expect(await cache.get(expectedValue), expectedValue); + expect(await cache.get(expectedValue), expectedValue); + expect(await cache.get(expectedValue), expectedValue); + expect(await cache.get(expectedValue), expectedValue); + expect(saveCalled, true); + + expect(timesCalled, 1); + }); + }); +}