Swift support for NetworkPlugin (#201)

Summary:
Solves #173

- [x] Add plugins in the sonarkit xcodeproj so that its easy to debug
- [x] Get rid off the c++ in the headers
- [x] Add example to hit network requests and validate

Have a look at the screen shot below ️

<img width="1677" alt="screen shot 2018-08-02 at 12 46 07 pm" src="https://user-images.githubusercontent.com/3865908/43581809-22efe4fe-9652-11e8-9424-f279d07c5c81.png">
Pull Request resolved: https://github.com/facebook/flipper/pull/201

Reviewed By: danielbuechele

Differential Revision: D9132157

Pulled By: priteshrnandgaonkar

fbshipit-source-id: 2b425506961f02eb2bf629c2bcab0da6e7ce5bb0
This commit is contained in:
Pritesh Nandgaonkar
2018-08-06 12:34:08 -07:00
committed by Facebook Github Bot
parent 134a0d96c5
commit 0c60347593
20 changed files with 863 additions and 147 deletions

View File

@@ -116,13 +116,7 @@ NSString *const kFLEXNetworkRecorderResponseCacheLimitDefaultsKey = @"com.flex.r
}
dispatch_async(self.queue, ^{
RequestInfo info = {
.identifier = self.identifierDict[requestID].longLongValue,
.timestamp = [NSDate timestamp],
.request = request,
};
info.setBody(request.HTTPBody);
SKRequestInfo *info = [[SKRequestInfo alloc] initWithIdentifier:self.identifierDict[requestID].longLongValue timestamp:[NSDate timestamp] request:request data:request.HTTPBody];
[self.delegate didObserveRequest:info];
FLEXNetworkTransaction *transaction = [FLEXNetworkTransaction new];
@@ -176,13 +170,7 @@ NSString *const kFLEXNetworkRecorderResponseCacheLimitDefaultsKey = @"com.flex.r
}
transaction.transactionState = FLEXNetworkTransactionStateFinished;
transaction.duration = -[transaction.startTime timeIntervalSinceDate:finishedDate];
ResponseInfo responseInfo = {
.identifier = self.identifierDict[requestID].longLongValue,
.timestamp = [NSDate timestamp],
.response = transaction.response,
.body = nil,
};
responseInfo.setBody(responseBody);
SKResponseInfo *responseInfo = [[SKResponseInfo alloc] initWithIndentifier:self.identifierDict[requestID].longLongValue timestamp:[NSDate timestamp] response:transaction.response data:responseBody];
self.identifierDict[requestID] = nil; //Clear the entry
[self.delegate didObserveResponse:responseInfo];
@@ -207,12 +195,8 @@ NSString *const kFLEXNetworkRecorderResponseCacheLimitDefaultsKey = @"com.flex.r
if (!transaction) {
return;
}
ResponseInfo responseInfo = {
.identifier = self.identifierDict[requestID].longLongValue,
.timestamp = [NSDate timestamp],
.response = transaction.response,
.body = nil,
};
SKResponseInfo *responseInfo = [[SKResponseInfo alloc] initWithIndentifier:self.identifierDict[requestID].longLongValue timestamp:[NSDate timestamp] response:transaction.response data: nil];
self.identifierDict[requestID] = nil; //Clear the entry
[self.delegate didObserveResponse:responseInfo];
transaction.transactionState = FLEXNetworkTransactionStateFailed;

View File

@@ -0,0 +1,29 @@
/*
* Copyright (c) 2018-present, Facebook, Inc.
*
* 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
#pragma once
#import "SKBufferingPlugin.h"
#import "SKDispatchQueue.h"
#import <iostream>
#import <memory>
struct CachedEvent {
NSString *method;
NSDictionary<NSString *, id> *sonarObject;
};
@interface SKBufferingPlugin(CPPInitialization)
- (instancetype)initWithVectorEventSize:(NSUInteger)size connectionAccessQueue:(std::shared_ptr<facebook::sonar::DispatchQueue>)connectionAccessQueue;
- (instancetype)initWithDispatchQueue:(std::shared_ptr<facebook::sonar::DispatchQueue>)queue;
@end
#endif

View File

@@ -11,13 +11,9 @@
#import <SonarKit/SonarPlugin.h>
#import <memory>
#import "SKDispatchQueue.h"
@interface SKBufferingPlugin : NSObject<SonarPlugin>
- (instancetype)initWithQueue:(const std::shared_ptr<facebook::sonar::DispatchQueue> &)queue NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithQueue:(dispatch_queue_t)queue NS_DESIGNATED_INITIALIZER;
- (void)send:(NSString *)method sonarObject:(NSDictionary<NSString *, id> *)sonarObject;

View File

@@ -11,26 +11,31 @@
#import "SKBufferingPlugin.h"
#import <SonarKit/SonarConnection.h>
struct CachedEvent {
NSString *method;
NSDictionary<NSString *, id> *sonarObject;
};
#import "SKDispatchQueue.h"
#import "SKBufferingPlugin+CPPInitialization.h"
static const NSUInteger bufferSize = 500;
@interface SKBufferingPlugin()
@property(assign, nonatomic) std::vector<CachedEvent> ringBuffer;
@property(assign, nonatomic) std::shared_ptr<facebook::sonar::DispatchQueue> connectionAccessQueue;
@property(strong, nonatomic) id<SonarConnection> connection;
@end
@implementation SKBufferingPlugin
{
std::vector<CachedEvent> _ringBuffer;
std::shared_ptr<facebook::sonar::DispatchQueue> _connectionAccessQueue;
// {
// std::vector<CachedEvent> _ringBuffer;
// std::shared_ptr<facebook::sonar::DispatchQueue> _connectionAccessQueue;
//
// id<SonarConnection> _connection;
// }
id<SonarConnection> _connection;
}
- (instancetype)initWithQueue:(const std::shared_ptr<facebook::sonar::DispatchQueue> &)queue {
- (instancetype)initWithQueue:(dispatch_queue_t)queue {
if (self = [super init]) {
_ringBuffer.reserve(bufferSize);
_connectionAccessQueue = queue;
_connectionAccessQueue = std::make_shared<facebook::sonar::GCDQueue>(queue);
}
return self;
}
@@ -80,4 +85,22 @@ static const NSUInteger bufferSize = 500;
@end
@implementation SKBufferingPlugin(CPPInitialization)
- (instancetype)initWithVectorEventSize:(NSUInteger)size connectionAccessQueue:(std::shared_ptr<facebook::sonar::DispatchQueue>)connectionAccessQueue {
if (self = [super init]) {
_ringBuffer.reserve(size);
_connectionAccessQueue = connectionAccessQueue;
}
return self;
}
- (instancetype)initWithDispatchQueue:(std::shared_ptr<facebook::sonar::DispatchQueue>)queue {
return [self initWithVectorEventSize:bufferSize
connectionAccessQueue:queue];
}
@end
#endif

View File

@@ -6,47 +6,13 @@
*
*/
#import <Foundation/Foundation.h>
struct RequestInfo {
int64_t identifier;
uint64_t timestamp;
NSURLRequest *request;
NSString *body;
void setBody(NSData *data) {
body = data ? [data base64EncodedStringWithOptions: 0]
: [request.HTTPBody base64EncodedStringWithOptions: 0];
}
};
struct ResponseInfo {
int64_t identifier;
uint64_t timestamp;
NSURLResponse *response;
NSString *body;
bool shouldStripReponseBody() {
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)response;
NSString *contentType = httpResponse.allHeaderFields[@"content-type"];
if (!contentType) {
return NO;
}
return [contentType containsString:@"image/"] ||
[contentType containsString:@"video/"] ||
[contentType containsString:@"application/zip"];
}
void setBody(NSData *data) {
body = shouldStripReponseBody() ? nil : [data base64EncodedStringWithOptions: 0];
}
};
#import "SKRequestInfo.h"
#import "SKResponseInfo.h"
@protocol SKNetworkReporterDelegate
- (void)didObserveRequest:(RequestInfo)request;
- (void)didObserveResponse:(ResponseInfo)response;
- (void)didObserveRequest:(SKRequestInfo *)request;
- (void)didObserveResponse:(SKResponseInfo *)response;
@end

View File

@@ -0,0 +1,20 @@
/*
* Copyright (c) 2018-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the LICENSE
* file in the root directory of this source tree.
*
*/
#import <Foundation/Foundation.h>
@interface SKRequestInfo: NSObject
@property(assign, readwrite) int64_t identifier;
@property(assign, readwrite) uint64_t timestamp;
@property(strong, nonatomic) NSURLRequest* request;
@property(strong, nonatomic) NSString* body;
- (instancetype)initWithIdentifier:(int64_t)identifier timestamp:(uint64_t)timestamp request:(NSURLRequest*)request data:(NSData *)data;
- (void)setBodyFromData:(NSData * _Nullable)data;
@end

View File

@@ -0,0 +1,34 @@
/*
* Copyright (c) 2018-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the LICENSE
* file in the root directory of this source tree.
*
*/
#import "SKRequestInfo.h"
@implementation SKRequestInfo
@synthesize identifier = _identifier;
@synthesize timestamp = _timestamp;
@synthesize request = _request;
@synthesize body = _body;
- (instancetype)initWithIdentifier:(int64_t)identifier timestamp:(uint64_t)timestamp request:(NSURLRequest *)request data:(NSData *)data{
if (self = [super init]){
_identifier = identifier;
_timestamp = timestamp;
_request = request;
_body = data ? [data base64EncodedStringWithOptions: 0]
: [request.HTTPBody base64EncodedStringWithOptions: 0];
}
return self;
}
- (void)setBodyFromData:(NSData * _Nullable)data {
self.body = data ? [data base64EncodedStringWithOptions: 0]
: [self.request.HTTPBody base64EncodedStringWithOptions: 0];
}
@end

View File

@@ -0,0 +1,21 @@
/*
* Copyright (c) 2018-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the LICENSE
* file in the root directory of this source tree.
*
*/
#import <Foundation/Foundation.h>
@interface SKResponseInfo : NSObject
@property(assign, readwrite) int64_t identifier;
@property(assign, readwrite) uint64_t timestamp;
@property(strong, nonatomic) NSURLResponse* response;
@property(strong, nonatomic) NSString* body;
- (instancetype)initWithIndentifier:(int64_t)identifier timestamp:(uint64_t)timestamp response:(NSURLResponse *)response data:(NSData *)data;
- (void)setBodyFromData:(NSData * _Nullable)data;
@end

View File

@@ -0,0 +1,43 @@
/*
* Copyright (c) 2018-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the LICENSE
* file in the root directory of this source tree.
*
*/
#import "SKResponseInfo.h"
@implementation SKResponseInfo
@synthesize identifier = _identifier;
@synthesize timestamp = _timestamp;
@synthesize response = _response;
@synthesize body = _body;
- (instancetype)initWithIndentifier:(int64_t)identifier timestamp:(uint64_t)timestamp response:(NSURLResponse *)response data:(NSData *)data {
if(self = [super init]) {
_identifier = identifier;
_timestamp = timestamp;
_response = response;
_body = [SKResponseInfo shouldStripReponseBodyWithResponse:response] ? nil : [data base64EncodedStringWithOptions: 0];
}
return self;
}
+ (BOOL) shouldStripReponseBodyWithResponse:(NSURLResponse *)response {
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)response;
NSString *contentType = httpResponse.allHeaderFields[@"content-type"];
if (!contentType) {
return NO;
}
return [contentType containsString:@"image/"] ||
[contentType containsString:@"video/"] ||
[contentType containsString:@"application/zip"];
}
- (void)setBodyFromData:(NSData *_Nullable)data {
self.body = [SKResponseInfo shouldStripReponseBodyWithResponse:self.response] ? nil : [data base64EncodedStringWithOptions: 0];
}
@end

View File

@@ -0,0 +1,18 @@
/*
* Copyright (c) 2018-present, Facebook, Inc.
*
* 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
#pragma once
#import "SonarKitNetworkPlugin.h"
#import "SKDispatchQueue.h"
#import <memory>
@interface SonarKitNetworkPlugin(CPPInitialization)
- (instancetype)initWithNetworkAdapter:(id<SKNetworkAdapterDelegate>)adapter dispatchQueue:(std::shared_ptr<facebook::sonar::DispatchQueue>)queue;
@end
#endif

View File

@@ -12,12 +12,11 @@
#import "SKBufferingPlugin.h"
#import "SKNetworkReporter.h"
#import "SKDispatchQueue.h"
@interface SonarKitNetworkPlugin : SKBufferingPlugin <SKNetworkReporterDelegate>
- (instancetype)initWithNetworkAdapter:(id<SKNetworkAdapterDelegate>)adapter NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithNetworkAdapter:(id<SKNetworkAdapterDelegate>)adapter queue:(const std::shared_ptr<facebook::sonar::DispatchQueue> &)queue; //For test purposes
- (instancetype)initWithNetworkAdapter:(id<SKNetworkAdapterDelegate>)adapter queue:(dispatch_queue_t)queue; //For test purposes
@property (strong, nonatomic) id<SKNetworkAdapterDelegate> adapter;

View File

@@ -6,8 +6,14 @@
*
*/
#if FB_SONARKIT_ENABLED
#import <vector>
#import <iostream>
#import <memory>
#import "SonarKitNetworkPlugin.h"
#import "SKNetworkReporter.h"
#import "SonarKitNetworkPlugin+CPPInitialization.h"
#import "SKBufferingPlugin+CPPInitialization.h"
#import "SKDispatchQueue.h"
@interface SonarKitNetworkPlugin ()
@@ -21,20 +27,20 @@
}
- (instancetype)init {
if (self = [super initWithQueue:std::make_shared<facebook::sonar::GCDQueue>(dispatch_queue_create("com.sonarkit.network.buffer", DISPATCH_QUEUE_SERIAL))]) {
if (self = [super initWithQueue:dispatch_queue_create("com.sonarkit.network.buffer", DISPATCH_QUEUE_SERIAL)]) {
}
return self;
}
- (instancetype)initWithNetworkAdapter:(id<SKNetworkAdapterDelegate>)adapter {
if (self = [super initWithQueue:std::make_shared<facebook::sonar::GCDQueue>(dispatch_queue_create("com.sonarkit.network.buffer", DISPATCH_QUEUE_SERIAL))]) {
if (self = [super initWithQueue:dispatch_queue_create("com.sonarkit.network.buffer", DISPATCH_QUEUE_SERIAL)]) {
adapter.delegate = self;
_adapter = adapter;
}
return self;
}
- (instancetype)initWithNetworkAdapter:(id<SKNetworkAdapterDelegate>)adapter queue:(const std::shared_ptr<facebook::sonar::DispatchQueue> &)queue; {
- (instancetype)initWithNetworkAdapter:(id<SKNetworkAdapterDelegate>)adapter queue:(dispatch_queue_t)queue; {
if (self = [super initWithQueue:queue]) {
adapter.delegate = self;
_adapter = adapter;
@@ -45,7 +51,7 @@
#pragma mark - SKNetworkReporterDelegate
- (void)didObserveRequest:(RequestInfo)request;
- (void)didObserveRequest:(SKRequestInfo *)request;
{
NSMutableArray<NSDictionary<NSString *, id> *> *headers = [NSMutableArray new];
for (NSString *key in [request.request.allHTTPHeaderFields allKeys]) {
@@ -69,7 +75,7 @@
}];
}
- (void)didObserveResponse:(ResponseInfo)response
- (void)didObserveResponse:(SKResponseInfo *)response
{
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)response.response;
@@ -98,4 +104,16 @@
@end
@implementation SonarKitNetworkPlugin (CPPInitialization)
- (instancetype)initWithNetworkAdapter:(id<SKNetworkAdapterDelegate>)adapter dispatchQueue:(std::shared_ptr<facebook::sonar::DispatchQueue>)queue {
if (self = [super initWithDispatchQueue:queue]) {
adapter.delegate = self;
_adapter = adapter;
}
return self;
}
@end
#endif