Skip to content

Commit

Permalink
Merge tag 'v1.13.5' into f-droid
Browse files Browse the repository at this point in the history
  • Loading branch information
clangenb committed Mar 26, 2024
2 parents b63fed6 + b015527 commit dbd74e7
Show file tree
Hide file tree
Showing 15 changed files with 94 additions and 95 deletions.
7 changes: 4 additions & 3 deletions .github/workflows/ios_integration_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,10 @@ jobs:
record_video: true
# With this flag we can run the CI against different node versions to check compatibility.
docker_tag: "1.5.4"
- device: "iPhone 8 Plus"
record_video: false
docker_tag: "1.5.4"
# IPhone 8 is broken currently.
# - device: "iPhone 8 Plus"
# record_video: false
# docker_tag: "1.5.4"
- device: "iPad Pro (12.9-inch) (6th generation)"
record_video: false
docker_tag: "1.5.4"
Expand Down
2 changes: 0 additions & 2 deletions app/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import 'package:encointer_wallet/utils/repository_provider.dart';
import 'package:encointer_wallet/modules/modules.dart';
import 'package:encointer_wallet/service/notification/lib/notification.dart';
import 'package:encointer_wallet/store/connectivity/connectivity_store.dart';
import 'package:encointer_wallet/service/substrate_api/core/dart_api.dart';
import 'package:encointer_wallet/service/http_overrides.dart';
import 'package:encointer_wallet/store/app.dart';
import 'package:encointer_wallet/utils/local_storage.dart' as util;
Expand All @@ -36,7 +35,6 @@ Future<void> main({AppConfig? appConfig, AppSettings? settings}) async {
providers: [
RepositoryProvider(create: (context) => EwHttp()),
RepositoryProvider(create: (context) => appConfig ?? const AppConfig()),
RepositoryProvider(create: (context) => SubstrateDartApi()),
],
child: MultiProvider(
providers: [
Expand Down
1 change: 0 additions & 1 deletion app/lib/page/assets/index.dart
Original file line number Diff line number Diff line change
Expand Up @@ -400,7 +400,6 @@ class _AssetsViewState extends State<AssetsView> {
void _connectNodeAll() {
// if network connected failed, reconnect
if (!widget.store.settings.loading) {
widget.store.settings.setNetworkLoading(true);
webApi.init();
}
}
Expand Down
4 changes: 1 addition & 3 deletions app/lib/service/init_web_api/init_web_api.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import 'package:encointer_wallet/config.dart';
import 'package:encointer_wallet/service/log/log_service.dart';
import 'package:encointer_wallet/service/substrate_api/api.dart';
import 'package:encointer_wallet/service/substrate_api/core/dart_api.dart';
import 'package:encointer_wallet/store/app.dart';
import 'package:encointer_wallet/utils/repository_provider.dart';
import 'package:ew_http/ew_http.dart';
Expand All @@ -14,8 +13,7 @@ import 'package:flutter/material.dart';
Future<void> initWebApi(BuildContext context, AppStore store) async {
final ewHttp = RepositoryProvider.of<EwHttp>(context);
final appConfig = RepositoryProvider.of<AppConfig>(context);
final dartApi = RepositoryProvider.of<SubstrateDartApi>(context);
webApi = Api.create(store, dartApi, ewHttp, isIntegrationTest: appConfig.isIntegrationTest);
webApi = Api.create(store, ewHttp, isIntegrationTest: appConfig.isIntegrationTest);

await webApi.init().timeout(
const Duration(seconds: 20),
Expand Down
82 changes: 61 additions & 21 deletions app/lib/service/substrate_api/api.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,9 @@ import 'package:encointer_wallet/service/log/log_service.dart';
late Api webApi;

class Api {
const Api(
Api(
this.store,
this.provider,
this.dartApi,
this.account,
this.assets,
this.chain,
Expand All @@ -32,40 +31,75 @@ class Api {

factory Api.create(
AppStore store,
SubstrateDartApi dartApi,
EwHttp ewHttp, {
bool isIntegrationTest = false,
}) {
final provider = ReconnectingWsProvider(Uri.parse(store.settings.endpoint.value!), autoConnect: false);
return Api(
store,
provider,
dartApi,
AccountApi(store, provider),
AssetsApi(store, EncointerKusama(provider)),
ChainApi(store, provider),
EncointerApi(store, dartApi, ewHttp, EncointerKusama(provider)),
EncointerApi(store, SubstrateDartApi(provider), ewHttp, EncointerKusama(provider)),
isIntegrationTest ? MockIpfsApi(ewHttp) : IpfsApi(ewHttp, gateway: store.settings.ipfsGateway),
);
}

final AppStore store;

final ReconnectingWsProvider provider;
final SubstrateDartApi dartApi;
final AccountApi account;
final AssetsApi assets;
final ChainApi chain;
final EncointerApi encointer;
final IpfsApi ipfsApi;

Future<void>? _connecting;

/// Timer to regularly check for network connections. This periodic timer will be
/// paused when the app goes into background, and resumes when the app comes into
/// the foreground again.
Timer? _timer;

Future<void> init() async {
await Future.wait([
dartApi.connect(store.settings.endpoint.value!),
provider.connectToNewEndpoint(Uri.parse(store.settings.endpoint.value!)),
]);
await close();
_connecting = _connect();

_timer = Timer.periodic(const Duration(seconds: 10), (timer) async {
if (!provider.isConnected()) {
if (_connecting == null) {
Log.p('[webApi] provider is disconnected. Trying to connect again...');
await close();
_connecting = _connect();
} else {
Log.p('[webApi] still trying to connect..');
}
}
});
}

Log.d('Connected to endpoint: ${store.settings.endpoint.value!}', 'Api');
Future<void> _connect() {
Log.d('[webApi] Connecting to endpoint: ${store.settings.endpoint.value!}', 'Api');

store.settings.setNetworkLoading(true);

final endpoint = store.settings.endpoint.value!;
return provider.connectToNewEndpoint(Uri.parse(endpoint)).then((voidValue) async {
Log.p('[webApi] channel is ready...');
if (await isConnected()) {
return _onConnected();
} else {
Log.p('[webApi] connection failed will try again...');
}
}).catchError((dynamic error) {
// mostly timeouts if the endpoint is not available
Log.e('[webApi] error during connection: $error}');
}).whenComplete(() => _connecting == null);
}

Future<void> _onConnected() async {
Log.d('[webApi] Connected to endpoint: ${store.settings.endpoint.value!}', 'Api');

if (store.account.currentAddress.isNotEmpty) {
await store.encointer.initializeUninitializedStores(store.account.currentAddress);
Expand All @@ -84,7 +118,7 @@ class Api {

store.settings.setNetworkLoading(false);

Log.d('Obtained basic network data: ${store.settings.endpoint.value!}', 'Api');
Log.d('[webApi] Obtained basic network data: ${store.settings.endpoint.value!}');

// need to do this from here as we can't access instance fields in constructor.
account.setFetchAccountData(fetchAccountData);
Expand All @@ -93,13 +127,21 @@ class Api {
}

Future<void> close() async {
_timer?.cancel();
_timer = null;
_connecting = null;

final futures = [
stopSubscriptions(),
encointer.close(),
provider.disconnect(),
stopSubscriptions()
.timeout(const Duration(seconds: 5), onTimeout: () => Log.e('[webApi] stopping subscriptions timeout')),
provider
.disconnect()
.timeout(const Duration(seconds: 5), onTimeout: () => Log.e('[webApi] provider disconnect timeout')),
];

await Future.wait(futures);

Log.d('[webApi] Closed webApi connections');
}

void fetchAccountData() {
Expand All @@ -115,21 +157,19 @@ class Api {
]);
}

Future<void> stopSubscriptions() {
return Future.wait([
Future<void> stopSubscriptions() async {
await Future.wait([
encointer.stopSubscriptions(),
chain.stopSubscriptions(),
assets.stopSubscriptions(),
]);
}

Future<bool> isConnected() async {
final dartConnected = dartApi.isConnected();
final providerConnected = provider.isConnected();

Log.d('Dart Rpc Api is connected: $dartConnected', 'Api');
Log.d('Provider is connected: $providerConnected', 'Api');
Log.d('[webApi] Provider is connected: $providerConnected');

return dartConnected && providerConnected;
return providerConnected;
}
}
46 changes: 7 additions & 39 deletions app/lib/service/substrate_api/core/dart_api.dart
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import 'dart:async';

import 'package:encointer_wallet/service/substrate_api/core/reconnecting_ws_provider.dart';
import 'package:encointer_wallet/models/index.dart';
import 'package:encointer_wallet/service/log/log_service.dart';
import 'package:ew_polkadart/ew_polkadart.dart';

/// Api to talk to an substrate node via the websocket protocol.
///
/// Once connected, a websocket channel is maintained until closed by either side.
class SubstrateDartApi {
SubstrateDartApi(this._provider);

/// Websocket client used to connect to the node.
ReconnectingWsProvider? _provider;
final Provider _provider;

/// The rpc methods exposed by the connected node.
RpcMethods? _rpc;
Expand All @@ -18,16 +20,14 @@ class SubstrateDartApi {
String? _endpoint;

/// Returns the rpc nodes of the connected node or an empty list otherwise.
List<String>? get rpcMethods {
return _rpc != null ? _rpc!.methods : <String>[];
Future<RpcMethods> rpcMethods() async {
return rpc<Map<String, dynamic>>('rpc_methods', []).then(RpcMethods.fromJson);
}

/// Gets address of the node we connect to including ws(s).
String? get endpoint => _endpoint;

Future<void> connect(String endpoint) async {
_connectAndListen(endpoint);

try {
_rpc = await rpc<Map<String, dynamic>>('rpc_methods', []).then(RpcMethods.fromJson);

Expand All @@ -44,48 +44,16 @@ class SubstrateDartApi {
}
}

/// Closes the websocket connection.
Future<void> close() async {
if (_provider != null) {
await _provider!.disconnect();
} else {
Log.d('no connection to be closed.', 'SubstrateDartApi');
}
}

/// Queries the rpc of the node.
///
/// Hints:
/// * account ids must be passed as SS58.
Future<T> rpc<T>(String method, List<dynamic> params) async {
if (_provider == null) {
throw Exception("[dartApi] Can't call an rpc method because we are not connected to an endpoint");
}
if (!_provider!.isConnected()) {
Log.d('[dartApi] not connected. trying to reconnect to $endpoint', 'SubstrateDartApi');
reconnect();
Log.d('[dartApi] connection status: isConnected? ${_provider?.isConnected()}', 'SubstrateDartApi');
}
final response = await _provider!.send(method, params);
final response = await _provider.send(method, params);

if (response.error != null) throw Exception(response.error);

final data = response.result! as T;
return data;
}

bool isConnected() {
return _provider!.isConnected();
}

/// Reconnect to the same endpoint if the connection was closed.
void reconnect() {
if (endpoint != null) _connectAndListen(endpoint!);
}

/// Connects to and endpoint and starts listening on the input stream.
void _connectAndListen(String endpoint) {
_endpoint = endpoint;
_provider = ReconnectingWsProvider(Uri.parse(endpoint));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ class ReconnectingWsProvider extends Provider {
Future<void> connectToNewEndpoint(Uri url) async {
await disconnect();
provider = WsProvider(url);
await provider.ready();
}

@override
Expand All @@ -39,7 +40,9 @@ class ReconnectingWsProvider extends Provider {
return Future.value();
} else {
try {
await provider.disconnect();
// Disconnect runs into a timeout if our endpoint doesn't exist for some reason.
await provider.disconnect().timeout(const Duration(seconds: 3),
onTimeout: () => Log.e('Timeout in disconnecting', 'ReconnectingWsProvider'));
} catch (e) {
Log.e('Error disconnecting websocket: $e', 'ReconnectingWsProvider');
return Future.value();
Expand Down
5 changes: 0 additions & 5 deletions app/lib/service/substrate_api/encointer/encointer_api.dart
Original file line number Diff line number Diff line change
Expand Up @@ -84,11 +84,6 @@ class EncointerApi {
await _businessRegistry?.cancel();
}

Future<void> close() async {
Log.d('[EncointerApi: closing', 'EncointerApi');
return _dartApi.close();
}

void getCommunityData() {
getBusinesses();
getCommunityMetadata();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,6 @@ class EncointerDartApi {

final SubstrateDartApi _dartApi;

Future<void> close() async {
Log.d('[EncointerDartApi: closing', 'EncointerDartApi');
return _dartApi.close();
}

/// Queries the rpc 'encointer_getAggregatedAccountData'.
///
Future<AggregatedAccountData> getAggregatedAccountData(CommunityIdentifier cid, String account, {BlockHash? at}) {
Expand Down
2 changes: 0 additions & 2 deletions app/lib/store/settings.dart
Original file line number Diff line number Diff line change
Expand Up @@ -169,8 +169,6 @@ abstract class _SettingsStore with Store {
}

Future<void> reloadNetwork(EndpointData network) async {
setNetworkLoading(true);

// Stop networking before loading cache
await webApi.close();

Expand Down
2 changes: 1 addition & 1 deletion app/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ description: EncointerWallet made with Flutter.

# bump version already while working on new release, bumping build number at the same time
# bump build number even more, if needed to clarify what's deployed
version: 1.13.4+884
version: 1.13.5+885

publish_to: none

Expand Down
7 changes: 3 additions & 4 deletions app/test/mock/api/mock_api.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,18 @@ import 'mock_polkadart_provider.dart';
import 'mock_substrate_dart_api.dart';

MockApi getMockApi(AppStore store) {
return MockApi(store, MockSubstrateDartApi(), EwHttp());
return MockApi(store, EwHttp());
}

class MockApi extends Api {
MockApi(AppStore store, MockSubstrateDartApi dartApi, EwHttp ewHttp)
MockApi(AppStore store, EwHttp ewHttp)
: super(
store,
MockPolkadartProvider(),
dartApi,
MockAccountApi(store, MockPolkadartProvider()),
MockAssetsApi(store, MockEncointerKusamaApi()),
MockChainApi(store, MockPolkadartProvider()),
MockEncointerApi(store, dartApi, ewHttp, MockEncointerKusamaApi()),
MockEncointerApi(store, MockSubstrateDartApi(MockPolkadartProvider()), ewHttp, MockEncointerKusamaApi()),
MockIpfsApi(ewHttp),
);

Expand Down
4 changes: 3 additions & 1 deletion app/test/mock/api/mock_substrate_dart_api.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import 'package:encointer_wallet/service/substrate_api/core/dart_api.dart';

class MockSubstrateDartApi extends SubstrateDartApi {}
class MockSubstrateDartApi extends SubstrateDartApi {
MockSubstrateDartApi(super.provider);
}
Loading

0 comments on commit dbd74e7

Please sign in to comment.