This commit is contained in:
M 2020-08-29 13:19:27 +03:00
parent 6aaac93fa8
commit 24d139e540
11 changed files with 114 additions and 31 deletions

View file

@ -373,7 +373,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = 9;
CURRENT_PROJECT_VERSION = 12;
DEVELOPMENT_TEAM = 32J6BB6VUS;
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
@ -509,7 +509,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = 9;
CURRENT_PROJECT_VERSION = 12;
DEVELOPMENT_TEAM = 32J6BB6VUS;
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
@ -540,7 +540,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = 9;
CURRENT_PROJECT_VERSION = 12;
DEVELOPMENT_TEAM = 32J6BB6VUS;
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (

View file

@ -16,12 +16,13 @@ class BitcoinTransactionInfo extends TransactionInfo {
@required TransactionDirection direction,
@required bool isPending,
@required DateTime date,
@required this.confirmations}) {
@required int confirmations}) {
this.height = height;
this.amount = amount;
this.direction = direction;
this.date = date;
this.isPending = isPending;
this.confirmations = confirmations;
}
factory BitcoinTransactionInfo.fromElectrumVerbose(Map<String, Object> obj,
@ -119,7 +120,6 @@ class BitcoinTransactionInfo extends TransactionInfo {
}
final String id;
int confirmations;
String _fiatAmount;

View file

@ -1,3 +1,4 @@
import 'dart:async';
import 'dart:typed_data';
import 'dart:convert';
import 'package:cake_wallet/bitcoin/bitcoin_transaction_credentials.dart';
@ -31,9 +32,12 @@ import 'package:cake_wallet/src/domain/common/node.dart';
import 'package:cake_wallet/core/wallet_base.dart';
import 'package:rxdart/rxdart.dart';
import 'package:hex/hex.dart';
import 'package:cake_wallet/di.dart';
import 'package:shared_preferences/shared_preferences.dart';
part 'bitcoin_wallet.g.dart';
class BitcoinWallet = BitcoinWalletBase with _$BitcoinWallet;
abstract class BitcoinWalletBase extends WalletBase<BitcoinBalance> with Store {
@ -217,6 +221,11 @@ abstract class BitcoinWalletBase extends WalletBase<BitcoinBalance> with Store {
try {
syncStatus = ConnectingSyncStatus();
await eclient.connectToUri(node.uri);
eclient.onConnectionStatusChange = (bool isConnected) {
if (!isConnected) {
syncStatus = LostConnectionSyncStatus();
}
};
syncStatus = ConnectedSyncStatus();
} catch (e) {
print(e.toString());
@ -331,7 +340,6 @@ abstract class BitcoinWalletBase extends WalletBase<BitcoinBalance> with Store {
await _scripthashesUpdateSubject[sh]?.close();
_scripthashesUpdateSubject[sh] = eclient.scripthashUpdate(sh);
_scripthashesUpdateSubject[sh].listen((event) async {
print('event $event');
transactionHistory.updateAsync();
await _updateBalance();
});

View file

@ -32,6 +32,7 @@ class ElectrumClient {
bool get isConnected => _isConnected;
Socket socket;
void Function(bool) onConnectionStatusChange;
int _id;
final Map<String, SocketTask> _tasks;
bool _isConnected;
@ -45,50 +46,49 @@ class ElectrumClient {
}
Future<void> connect({@required String host, @required int port}) async {
await socket?.close();
final start = DateTime.now();
try {
await socket?.close();
} catch (_) {}
socket = await SecureSocket.connect(host, port, timeout: connectionTimeout);
_isConnected = true;
_setIsConnected(true);
socket.listen((List<int> event) {
try {
final jsoned = json.decode(utf8.decode(event)) as Map<String, Object>;
// print(jsoned);
print(jsoned);
final method = jsoned['method'];
final id = jsoned['id'] as String;
final params = jsoned['result'];
if (method is String) {
_methodHandler(method: method, request: jsoned);
return;
}
final id = jsoned['id'] as String;
final params = jsoned['result'];
_finish(id, params);
} catch (e) {
print(e);
}
}, onError: (Object error) {
print('ElectrumClient error: ${error.toString()}');
}, onDone: () {
final end = DateTime.now();
final diff = end.millisecondsSinceEpoch - start.millisecondsSinceEpoch;
print('On done: $diff');
});
print('Connected to ${socket.remoteAddress}');
},
onError: (_) => _setIsConnected(false),
onDone: () => _setIsConnected(false));
keepAlive();
}
void keepAlive() {
_aliveTimer?.cancel();
// FIXME: Unnamed constant.
_aliveTimer = Timer.periodic(Duration(seconds: 30), (_) async => ping());
_aliveTimer = Timer.periodic(Duration(seconds: 2), (_) async => ping());
}
Future<void> ping() => call(method: 'server.ping');
Future<void> ping() async {
try {
await callWithTimeout(method: 'server.ping');
_setIsConnected(true);
} on RequestFailedTimeoutException catch (_) {
_setIsConnected(false);
}
}
Future<List<String>> version() =>
call(method: 'server.version').then((dynamic result) {
@ -205,7 +205,6 @@ class ElectrumClient {
{@required String transactionRaw}) async =>
call(method: 'blockchain.transaction.broadcast', params: [transactionRaw])
.then((dynamic result) {
print('result $result');
if (result is String) {
return result;
}
@ -264,6 +263,25 @@ class ElectrumClient {
return completer.future;
}
Future<dynamic> callWithTimeout(
{String method,
List<Object> params = const [],
int timeout = 2000}) async {
final completer = Completer<dynamic>();
_id += 1;
final id = _id;
_regisryTask(id, completer);
socket.write(jsonrpc(method: method, id: _id, params: params));
Timer(Duration(milliseconds: timeout), () {
if (!completer.isCompleted) {
completer.completeError(RequestFailedTimeoutException(method, _id));
}
});
return completer.future;
}
void request({String method, List<Object> params = const []}) {
_id += 1;
socket.write(jsonrpc(method: method, id: _id, params: params));
@ -280,7 +298,9 @@ class ElectrumClient {
return;
}
_tasks[id]?.completer?.complete(data);
if (!(_tasks[id]?.completer?.isCompleted ?? false)) {
_tasks[id]?.completer?.complete(data);
}
if (!(_tasks[id]?.isSubscription ?? false)) {
_tasks[id] = null;
@ -303,4 +323,19 @@ class ElectrumClient {
break;
}
}
void _setIsConnected(bool isConnected) {
if (_isConnected != isConnected) {
onConnectionStatusChange?.call(isConnected);
}
_isConnected = isConnected;
}
}
class RequestFailedTimeoutException implements Exception {
RequestFailedTimeoutException(this.method, this.id);
final String method;
final int id;
}

View file

@ -1,3 +1,5 @@
import 'dart:async';
import 'package:cake_wallet/core/key_service.dart';
import 'package:cake_wallet/src/domain/common/sync_status.dart';
import 'package:mobx/mobx.dart';
@ -49,6 +51,7 @@ ReactionDisposer _initialAuthReaction;
ReactionDisposer _onCurrentWalletChangeReaction;
ReactionDisposer _onWalletSyncStatusChangeReaction;
ReactionDisposer _onCurrentFiatCurrencyChangeDisposer;
Timer _reconnectionTimer;
Future<void> bootstrap(
{FiatConvertationService fiatConvertationService}) async {
@ -74,10 +77,21 @@ Future<void> bootstrap(
_onCurrentWalletChangeReaction ??=
reaction((_) => getIt.get<AppStore>().wallet, (WalletBase wallet) async {
_onWalletSyncStatusChangeReaction?.reaction?.dispose();
_reconnectionTimer?.cancel();
_onWalletSyncStatusChangeReaction = reaction(
(_) => wallet.syncStatus is ConnectedSyncStatus,
(_) async => await wallet.startSync());
_reconnectionTimer = Timer.periodic(Duration(seconds: 5), (_) async {
if (wallet.syncStatus is LostConnectionSyncStatus ||
wallet.syncStatus is FailedSyncStatus) {
try {
await wallet.connectToNode(
node: settingsStore.getCurrentNode(wallet.type));
} catch (_) {}
}
});
await getIt
.get<SharedPreferences>()
.setString('current_wallet_name', wallet.name);

View file

@ -73,3 +73,11 @@ class ConnectedSyncStatus extends SyncStatus {
@override
String title() => S.current.sync_status_connected;
}
class LostConnectionSyncStatus extends SyncStatus {
@override
double progress() => 1.0;
@override
String title() => S.current.sync_status_failed_connect;
}

View file

@ -7,6 +7,7 @@ abstract class TransactionInfo extends Object {
bool isPending;
DateTime date;
int height;
int confirmations;
String amountFormatted();
String fiatAmount();
void changeFiatAmount(String amount);

View file

@ -159,7 +159,8 @@ class SendFormState extends State<SendForm> {
decoration: InputDecoration(
prefixIcon: Padding(
padding: EdgeInsets.only(top: 12),
child: Text('${widget.sendViewModel.currency.toString()}:',
child: Text(
'${widget.sendViewModel.currency.toString()}:',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
@ -213,7 +214,14 @@ class SendFormState extends State<SendForm> {
borderSide: BorderSide(
color: Theme.of(context).dividerColor,
width: 1.0))),
validator: widget.sendViewModel.amountValidator),
validator: (String value) {
if (widget.sendViewModel.all) {
return null;
}
return widget.sendViewModel.amountValidator
.call(value);
}),
),
Padding(
padding: const EdgeInsets.only(top: 20),

View file

@ -1,3 +1,4 @@
import 'package:intl/intl.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
@ -48,6 +49,9 @@ class TransactionDetailsPage extends BasePage {
StandartListItem(
title: S.current.transaction_details_date,
value: dateFormat.format(tx.date)),
StandartListItem(
title: 'Confirmations',
value: tx.confirmations?.toString()),
StandartListItem(
title: S.current.transaction_details_height, value: '${tx.height}'),
StandartListItem(

View file

@ -86,7 +86,7 @@ abstract class DashboardViewModelBase with Store {
statusText = S.current.Blocks_remaining(status.toString());
}
if (status is FailedSyncStatus) {
if (status is FailedSyncStatus || status is LostConnectionSyncStatus) {
statusText = S.current.please_try_to_connect_to_another_node;
}

View file

@ -116,6 +116,11 @@ abstract class SendViewModelBase with Store {
@action
void setCryptoAmount(String amount) {
// FIXME: hardcoded value.
if (amount.toUpperCase() != 'ALL') {
all = false;
}
cryptoAmount = amount;
_updateFiatAmount();
}