Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

hamed/refactor_ws_in_deriv_api #270

Open
wants to merge 1 commit into
base: flutter-version-3
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion binary-websocket-api
2 changes: 1 addition & 1 deletion example/ios/Flutter/AppFrameworkInfo.plist
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,6 @@
<key>CFBundleVersion</key>
<string>1.0</string>
<key>MinimumOSVersion</key>
<string>8.0</string>
<string>11.0</string>
</dict>
</plist>
12 changes: 6 additions & 6 deletions example/ios/Flutter/Flutter.podspec
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
#
# NOTE: This podspec is NOT to be published. It is only used as a local source!
# This is a generated file; do not edit or check into version control.
# This podspec is NOT to be published. It is only used as a local source!
# This is a generated file; do not edit or check into version control.
#

Pod::Spec.new do |s|
s.name = 'Flutter'
s.version = '1.0.0'
s.summary = 'High-performance, high-fidelity mobile apps.'
s.homepage = 'https://flutter.io'
s.license = { :type => 'MIT' }
s.summary = 'A UI toolkit for beautiful and fast apps.'
s.homepage = 'https://flutter.dev'
s.license = { :type => 'BSD' }
s.author = { 'Flutter Dev Team' => '[email protected]' }
s.source = { :git => 'https://github.com/flutter/engine', :tag => s.version.to_s }
s.ios.deployment_target = '8.0'
s.ios.deployment_target = '11.0'
# Framework linking is handled by Flutter tooling, not CocoaPods.
# Add a placeholder to satisfy `s.dependency 'Flutter'` plugin podspecs.
s.vendored_frameworks = 'path/to/nothing'
Expand Down
2 changes: 1 addition & 1 deletion example/ios/Podfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Uncomment this line to define a global platform for your project
# platform :ios, '9.0'
# platform :ios, '11.0'

# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
Expand Down
39 changes: 13 additions & 26 deletions example/ios/Podfile.lock
Original file line number Diff line number Diff line change
@@ -1,47 +1,34 @@
PODS:
- connectivity (0.0.1):
- Flutter
- Reachability
- device_info (0.0.1):
- device_info_plus (0.0.1):
- Flutter
- Flutter (1.0.0)
- flutter_deriv_api (0.0.1):
- Flutter
- package_info (0.0.1):
- package_info_plus (0.4.5):
- Flutter
- Reachability (3.2)

DEPENDENCIES:
- connectivity (from `.symlinks/plugins/connectivity/ios`)
- device_info (from `.symlinks/plugins/device_info/ios`)
- device_info_plus (from `.symlinks/plugins/device_info_plus/ios`)
- Flutter (from `Flutter`)
- flutter_deriv_api (from `.symlinks/plugins/flutter_deriv_api/ios`)
- package_info (from `.symlinks/plugins/package_info/ios`)

SPEC REPOS:
trunk:
- Reachability
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)

EXTERNAL SOURCES:
connectivity:
:path: ".symlinks/plugins/connectivity/ios"
device_info:
:path: ".symlinks/plugins/device_info/ios"
device_info_plus:
:path: ".symlinks/plugins/device_info_plus/ios"
Flutter:
:path: Flutter
flutter_deriv_api:
:path: ".symlinks/plugins/flutter_deriv_api/ios"
package_info:
:path: ".symlinks/plugins/package_info/ios"
package_info_plus:
:path: ".symlinks/plugins/package_info_plus/ios"

SPEC CHECKSUMS:
connectivity: c4130b2985d4ef6fd26f9702e886bd5260681467
device_info: d7d233b645a32c40dfdc212de5cf646ca482f175
Flutter: 434fef37c0980e73bb6479ef766c45957d4b510c
device_info_plus: e5c5da33f982a436e103237c0c85f9031142abed
Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854
flutter_deriv_api: 9e29abd7cc5091b72303f9c8be549618415f1437
package_info: 873975fc26034f0b863a300ad47e7f1ac6c7ec62
Reachability: 33e18b67625424e47b6cde6d202dce689ad7af96
package_info_plus: 6c92f08e1f853dc01228d6f553146438dafcd14e

PODFILE CHECKSUM: aafe91acc616949ddb318b77800a7f51bffa2a4c
PODFILE CHECKSUM: ef19549a9bc3046e7bb7d2fab4d021637c0c58a3

COCOAPODS: 1.10.1
COCOAPODS: 1.12.1
40 changes: 24 additions & 16 deletions example/ios/Runner.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objectVersion = 54;
objects = {

/* Begin PBXBuildFile section */
Expand Down Expand Up @@ -164,7 +164,7 @@
97C146E61CF9000F007C117D /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 1020;
LastUpgradeCheck = 1300;
ORGANIZATIONNAME = "The Chromium Authors";
TargetAttributes = {
97C146ED1CF9000F007C117D = {
Expand Down Expand Up @@ -213,19 +213,15 @@
);
inputPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh",
"${BUILT_PRODUCTS_DIR}/Reachability/Reachability.framework",
"${BUILT_PRODUCTS_DIR}/connectivity/connectivity.framework",
"${BUILT_PRODUCTS_DIR}/device_info/device_info.framework",
"${BUILT_PRODUCTS_DIR}/device_info_plus/device_info_plus.framework",
"${BUILT_PRODUCTS_DIR}/flutter_deriv_api/flutter_deriv_api.framework",
"${BUILT_PRODUCTS_DIR}/package_info/package_info.framework",
"${BUILT_PRODUCTS_DIR}/package_info_plus/package_info_plus.framework",
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Reachability.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/connectivity.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/device_info.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/device_info_plus.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_deriv_api.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/package_info.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/package_info_plus.framework",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
Expand All @@ -234,10 +230,12 @@
};
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
"${TARGET_BUILD_DIR}/${INFOPLIST_PATH}",
);
name = "Thin Binary";
outputPaths = (
Expand All @@ -248,6 +246,7 @@
};
9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
Expand Down Expand Up @@ -357,7 +356,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
Expand All @@ -379,7 +378,10 @@
"$(PROJECT_DIR)/Flutter",
);
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
Expand Down Expand Up @@ -439,7 +441,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
Expand Down Expand Up @@ -488,7 +490,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
Expand All @@ -511,7 +513,10 @@
"$(PROJECT_DIR)/Flutter",
);
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
Expand All @@ -538,7 +543,10 @@
"$(PROJECT_DIR)/Flutter",
);
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1020"
LastUpgradeVersion = "1300"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
Expand Down
4 changes: 4 additions & 0 deletions example/ios/Runner/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,9 @@
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
</dict>
</plist>
7 changes: 7 additions & 0 deletions lib/services/connection/api_manager/base_api.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import 'package:flutter_deriv_api/basic_api/generated/forget_receive.dart';
import 'package:flutter_deriv_api/basic_api/request.dart';
import 'package:flutter_deriv_api/basic_api/response.dart';
import 'package:flutter_deriv_api/services/connection/api_manager/connection_information.dart';
import 'package:flutter_deriv_api/services/connection/api_manager/enums.dart';
import 'package:flutter_deriv_api/services/connection/call_manager/base_call_manager.dart';

/// Callbacks for websocket connection.
Expand Down Expand Up @@ -50,4 +51,10 @@ abstract class BaseAPI {

/// Disconnects from API.
Future<void> disconnect();

/// Gets current websocket connection status.
APIStatus get currentConnectionStatus;

/// Gets websocket connection status.
Stream<APIStatus> get connectionStatus;
}
51 changes: 31 additions & 20 deletions lib/services/connection/api_manager/binary_api.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import 'dart:developer' as dev;
import 'dart:io';

import 'package:flutter/widgets.dart';
import 'package:web_socket_channel/io.dart';

import 'package:web_socket_client/web_socket_client.dart' as ws;

import 'package:flutter_deriv_api/api/models/enums.dart';
import 'package:flutter_deriv_api/basic_api/generated/forget_all_receive.dart';
Expand All @@ -14,6 +15,8 @@ import 'package:flutter_deriv_api/basic_api/response.dart';
import 'package:flutter_deriv_api/helpers/helpers.dart';
import 'package:flutter_deriv_api/services/connection/api_manager/base_api.dart';
import 'package:flutter_deriv_api/services/connection/api_manager/connection_information.dart';
import 'package:flutter_deriv_api/services/connection/api_manager/enums.dart';
import 'package:flutter_deriv_api/services/connection/api_manager/extensions.dart';
import 'package:flutter_deriv_api/services/connection/call_manager/base_call_manager.dart';
import 'package:flutter_deriv_api/services/connection/call_manager/call_history.dart';
import 'package:flutter_deriv_api/services/connection/call_manager/call_manager.dart';
Expand All @@ -26,13 +29,10 @@ class BinaryAPI extends BaseAPI {
BinaryAPI({String? key, bool enableDebug = false})
: super(key: key ?? '${UniqueKey()}', enableDebug: enableDebug);

static const Duration _disconnectTimeOut = Duration(seconds: 5);
static const Duration _websocketConnectTimeOut = Duration(seconds: 10);

/// Represents the active websocket connection.
///
/// This is used to send and receive data from the websocket server.
IOWebSocketChannel? _webSocketChannel;
ws.WebSocket? _webSocketChannel;

/// Stream subscription to API data.
StreamSubscription<Map<String, dynamic>?>? _webSocketListener;
Expand Down Expand Up @@ -76,12 +76,16 @@ class BinaryAPI extends BaseAPI {
await _setUserAgent();

// Initialize connection to websocket server.
_webSocketChannel = IOWebSocketChannel.connect(
'$uri',
pingInterval: _websocketConnectTimeOut,
_webSocketChannel = ws.WebSocket(
uri,
pingInterval: const Duration(seconds: 1),
backoff: const ws.ConstantBackoff(Duration(seconds: 1)),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about LinearBackoff ? Is it supported?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we are looking for a way to connect asap, so I suppose ConstantBackoff is better in our case.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ws.BinaryExponentialBackoff is the one should be used to avoid flooding the server.

);

_webSocketListener = _webSocketChannel?.stream
await connectionStatus
.firstWhere((APIStatus status) => status == APIStatus.connected);

_webSocketListener = _webSocketChannel?.messages
.map<Map<String, dynamic>?>((Object? result) => jsonDecode('$result'))
.listen(
(Map<String, dynamic>? message) {
Expand All @@ -91,10 +95,12 @@ class BinaryAPI extends BaseAPI {
_handleResponse(message, printResponse: printResponse);
}
},
onDone: () async {
onDone: () {
_logDebugInfo('the websocket is closed.');

onDone?.call(key);

disconnect();
},
onError: (Object error) {
_logDebugInfo(
Expand All @@ -103,6 +109,8 @@ class BinaryAPI extends BaseAPI {
);

onError?.call(key);

disconnect();
},
);

Expand All @@ -117,10 +125,9 @@ class BinaryAPI extends BaseAPI {
@override
void addToChannel(Map<String, dynamic> request) {
try {
_webSocketChannel?.sink.add(utf8.encode(jsonEncode(request)));
// ignore: avoid_catches_without_on_clauses
} catch (error) {
_logDebugInfo('error while adding to channel.', error: error);
_webSocketChannel?.send(utf8.encode(jsonEncode(request)));
} on Exception catch (error) {
_logDebugInfo('error sending message to websocket.', error: error);
}
}

Expand Down Expand Up @@ -167,19 +174,23 @@ class BinaryAPI extends BaseAPI {
try {
await _webSocketListener?.cancel();

await _webSocketChannel?.sink.close().timeout(
_disconnectTimeOut,
onTimeout: () => throw TimeoutException('Could not close sink.'),
);
// ignore: avoid_catches_without_on_clauses
} catch (e) {
_webSocketChannel?.close();
} on Exception catch (e) {
_logDebugInfo('disconnect error.', error: e);
} finally {
_webSocketListener = null;
_webSocketChannel = null;
}
}

@override
APIStatus get currentConnectionStatus =>
_webSocketChannel!.connection.state.apiStatus;

@override
Stream<APIStatus> get connectionStatus => _webSocketChannel!.connection
.map<APIStatus>((ws.ConnectionState state) => state.apiStatus);

/// Handles responses that come from server, by using its reqId,
/// and completes caller's Future or add the response to caller's stream if it was a subscription call.
void _handleResponse(
Expand Down
7 changes: 7 additions & 0 deletions lib/services/connection/api_manager/enums.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// ignore_for_file: public_member_api_docs

enum APIStatus {
connecting,
connected,
disconnected,
}
Loading