Files
flipper/iOS/FlipperKit/FlipperClient.mm
Lorenzo Blasa 3dacf5a7c9 WebSocket as default socket provider
Summary:
This change makes WebSockets the default for Flipper on iOS.

Having said that, we are introducing some logic to deal with clients connecting to older Flipper Desktop versions.

The mobile client will first attempt to connect via WebSocket with the Desktop. This connection can either be secure or insecure. If that fails, it will attempt to connect via RSocket.

Connection failure logic:
The mobile client will attempt to connect up-to 3 times via a WebSocket. If it fails to connect, then the socket provider is switched to RSocket.

As before, the mobile client will attempt to connect up-to 3 times via a RSocket. If it fails to connect, then the socket provider is switched back to WebSocket.

Process repeats until a successful connection is established.

Some logs that can be seen from iOS:

   2021-09-15 14:31:51.193503+0100 Sample[92026:92107440] [] nw_protocol_get_quic_image_block_invoke dlopen libquic failed
   2021-09-15 14:31:51.878257+0100 Sample[92026:92107440] [connection] nw_socket_handle_socket_event [C1.1:1] Socket SO_ERROR [61: Connection refused]
   2021-09-15 14:31:52.553729+0100 Sample[92026:92107440] [connection] nw_socket_handle_socket_event [C1.2:1] Socket SO_ERROR [61: Connection refused]
   2021-09-15 14:31:52.899511+0100 Sample[92026:92107442] [connection] nw_connection_get_connected_socket [C1] Client called nw_connection_get_connected_socket on unconnected nw_connection
   2021-09-15 14:31:52.899664+0100 Sample[92026:92107442] TCP Conn 0x600001d384d0 Failed : error 0:61 [61]
   2021-09-15 14:31:57.120120+0100 Sample[92026:92107439] [connection] nw_socket_handle_socket_event [C2.1:1] Socket SO_ERROR [61: Connection refused]
   2021-09-15 14:31:57.141785+0100 Sample[92026:92107439] [connection] nw_socket_handle_socket_event [C2.2:1] Socket SO_ERROR [61: Connection refused]
   2021-09-15 14:31:57.151604+0100 Sample[92026:92107483] [connection] nw_connection_get_connected_socket [C2] Client called nw_connection_get_connected_socket on unconnected nw_connection
   2021-09-15 14:31:57.154312+0100 Sample[92026:92107483] TCP Conn 0x600001d7c0b0 Failed : error 0:61 [61]
   2021-09-15 14:31:59.206079+0100 Sample[92026:92107483] [connection] nw_socket_handle_socket_event [C3.1:1] Socket SO_ERROR [61: Connection refused]
   2021-09-15 14:31:59.236824+0100 Sample[92026:92107483] [connection] nw_socket_handle_socket_event [C3.2:1] Socket SO_ERROR [61: Connection refused]
   2021-09-15 14:31:59.251927+0100 Sample[92026:92107439] [connection] nw_connection_get_connected_socket [C3] Client called nw_connection_get_connected_socket on unconnected nw_connection
   2021-09-15 14:31:59.255963+0100 Sample[92026:92107439] TCP Conn 0x600001d1c210 Failed : error 0:61 [61]
   2021-09-15 14:32:01.291303+0100 Sample[92026:92107439] [connection] nw_socket_handle_socket_event [C4.1:1] Socket SO_ERROR [61: Connection refused]
   2021-09-15 14:32:01.312406+0100 Sample[92026:92107439] [connection] nw_socket_handle_socket_event [C4.2:1] Socket SO_ERROR [61: Connection refused]
   2021-09-15 14:32:01.323099+0100 Sample[92026:92107483] [connection] nw_connection_get_connected_socket [C4] Client called nw_connection_get_connected_socket on unconnected nw_connection
   2021-09-15 14:32:01.326028+0100 Sample[92026:92107483] TCP Conn 0x600001d7c0b0 Failed : error 0:61 [61]
   flipper: Failed to connect with the current socket provider
   flipper: Use legacy socket provider
   flipper: FlipperClient::onConnected

Reviewed By: passy

Differential Revision: D30900471

fbshipit-source-id: 7c242ad71306803b050d0174fc22696bb74fdba5
2021-09-23 05:22:23 -07:00

232 lines
6.7 KiB
Plaintext

/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#if FB_SONARKIT_ENABLED
#import "FlipperClient.h"
#import <Flipper/FlipperCertificateProvider.h>
#import <Flipper/FlipperClient.h>
#import <Flipper/FlipperSocketProvider.h>
#include <folly/io/async/EventBase.h>
#include <folly/io/async/ScopedEventBaseThread.h>
#include <memory>
#import "FlipperClient+Testing.h"
#import "FlipperCppWrapperPlugin.h"
#import "FlipperKitCertificateProvider.h"
#import "FlipperWebSocket.h"
#import "SKEnvironmentVariables.h"
#include "SKStateUpdateCPPWrapper.h"
#if !TARGET_OS_OSX
#import <UIKit/UIKit.h>
#if !TARGET_OS_SIMULATOR
#import <FKPortForwarding/FKPortForwardingServer.h>
#endif
#endif
using WrapperPlugin = facebook::flipper::FlipperCppWrapperPlugin;
@implementation FlipperClient {
facebook::flipper::FlipperClient* _cppClient;
folly::ScopedEventBaseThread sonarThread;
folly::ScopedEventBaseThread connectionThread;
id<FlipperKitCertificateProvider> _certProvider;
#if !TARGET_OS_OSX && !TARGET_OS_SIMULATOR
FKPortForwardingServer* _secureServer;
FKPortForwardingServer* _insecureServer;
#endif
}
+ (instancetype)sharedClient {
static FlipperClient* sharedClient = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
try {
sharedClient = [[self alloc] init];
} catch (const std::exception& e) {
// fail.
sharedClient = nil;
}
});
return sharedClient;
}
- (instancetype)init {
if (self = [super init]) {
NSBundle* bundle = [NSBundle mainBundle];
NSString* appName =
[bundle objectForInfoDictionaryKey:(NSString*)kCFBundleNameKey];
NSString* appId = [bundle bundleIdentifier];
NSString* privateAppDirectory = NSSearchPathForDirectoriesInDomains(
NSApplicationSupportDirectory, NSUserDomainMask, YES)[0];
NSFileManager* manager = [NSFileManager defaultManager];
if ([manager fileExistsAtPath:privateAppDirectory isDirectory:NULL] == NO &&
![manager createDirectoryAtPath:privateAppDirectory
withIntermediateDirectories:YES
attributes:nil
error:nil]) {
return nil;
}
NSString* deviceOS;
NSString* deviceName;
#if !TARGET_OS_OSX
deviceOS = @"iOS";
deviceName = [[UIDevice currentDevice] name];
#if TARGET_OS_SIMULATOR
deviceName = [NSString stringWithFormat:@"%@ %@",
[[UIDevice currentDevice] model],
@"Simulator"];
#endif
#else
deviceOS = @"MacOS";
deviceName = [[NSHost currentHost] localizedName];
#endif
static const std::string UNKNOWN = std::string("unknown");
try {
facebook::flipper::FlipperClient::init(
{{
"localhost",
[deviceOS UTF8String],
[deviceName UTF8String],
UNKNOWN,
[appName UTF8String] ?: UNKNOWN,
[appId UTF8String] ?: UNKNOWN,
[privateAppDirectory UTF8String],
},
sonarThread.getEventBase(),
connectionThread.getEventBase(),
[SKEnvironmentVariables getInsecurePort],
[SKEnvironmentVariables getSecurePort],
[SKEnvironmentVariables getAltInsecurePort],
[SKEnvironmentVariables getAltSecurePort]});
_cppClient = facebook::flipper::FlipperClient::instance();
// To switch to a websocket provider, uncomment the line below.
facebook::flipper::FlipperSocketProvider::setDefaultProvider(
std::make_unique<facebook::flipper::FlipperWebSocketProvider>());
} catch (const std::system_error& e) {
// Probably ran out of disk space.
return nil;
}
}
return self;
}
- (void)setCertificateProvider:(id<FlipperKitCertificateProvider>)provider {
_certProvider = provider;
std::shared_ptr<facebook::flipper::FlipperCertificateProvider>* prov =
static_cast<
std::shared_ptr<facebook::flipper::FlipperCertificateProvider>*>(
[provider getCPPCertificateProvider]);
_cppClient->setCertificateProvider(*prov);
}
- (id<FlipperKitCertificateProvider>)getCertificateProvider {
return _certProvider;
}
- (void)refreshPlugins {
_cppClient->refreshPlugins();
}
- (void)addPlugin:(NSObject<FlipperPlugin>*)plugin {
_cppClient->addPlugin(std::make_shared<WrapperPlugin>(plugin));
}
- (void)removePlugin:(NSObject<FlipperPlugin>*)plugin {
_cppClient->removePlugin(std::make_shared<WrapperPlugin>(plugin));
}
- (NSObject<FlipperPlugin>*)pluginWithIdentifier:(NSString*)identifier {
auto cppPlugin = _cppClient->getPlugin([identifier UTF8String]);
if (auto wrapper = dynamic_cast<WrapperPlugin*>(cppPlugin.get())) {
return wrapper->getObjCPlugin();
}
return nil;
}
- (void)start {
#if !TARGET_OS_OSX && !TARGET_OS_SIMULATOR
_secureServer = [FKPortForwardingServer new];
[_secureServer forwardConnectionsFromPort:8088];
[_secureServer listenForMultiplexingChannelOnPort:8078];
_insecureServer = [FKPortForwardingServer new];
[_insecureServer forwardConnectionsFromPort:8089];
[_insecureServer listenForMultiplexingChannelOnPort:8079];
#endif
_cppClient->start();
}
- (void)stop {
_cppClient->stop();
#if !TARGET_OS_OSX && !TARGET_OS_SIMULATOR
[_secureServer close];
_secureServer = nil;
[_insecureServer close];
_insecureServer = nil;
#endif
}
- (NSString*)getState {
return @(_cppClient->getState().c_str());
}
- (NSArray*)getStateElements {
NSMutableArray<NSDictionary<NSString*, NSString*>*>* const array =
[NSMutableArray array];
for (facebook::flipper::StateElement element :
_cppClient->getStateElements()) {
facebook::flipper::State state = element.state_;
NSString* stateString;
switch (state) {
case facebook::flipper::in_progress:
stateString = @"⏳ ";
break;
case facebook::flipper::success:
stateString = @"✅ ";
break;
case facebook::flipper::failed:
stateString = @"❌ ";
break;
default:
stateString = @"❓ ";
break;
}
[array addObject:@{
@"name" : [NSString stringWithUTF8String:element.name_.c_str()],
@"state" : stateString
}];
}
return array;
}
- (void)subscribeForUpdates:(id<FlipperStateUpdateListener>)controller {
auto stateListener = std::make_shared<SKStateUpdateCPPWrapper>(controller);
_cppClient->setStateListener(stateListener);
}
@end
@implementation FlipperClient (Testing)
- (instancetype)initWithCppClient:(facebook::flipper::FlipperClient*)cppClient {
if (self = [super init]) {
_cppClient = cppClient;
}
return self;
}
@end
#endif