Initial commit 🎉

fbshipit-source-id: b6fc29740c6875d2e78953b8a7123890a67930f2
Co-authored-by: Sebastian McKenzie <sebmck@fb.com>
Co-authored-by: John Knox <jknox@fb.com>
Co-authored-by: Emil Sjölander <emilsj@fb.com>
Co-authored-by: Pritesh Nandgaonkar <prit91@fb.com>
This commit is contained in:
Daniel Büchele
2018-04-13 08:38:06 -07:00
committed by Daniel Buchele
commit fbbf8cf16b
659 changed files with 87130 additions and 0 deletions

View File

@@ -0,0 +1,26 @@
/*
* 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
#import <Foundation/Foundation.h>
#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;
- (void)send:(NSString *)method sonarObject:(NSDictionary<NSString *, id> *)sonarObject;
@end
#endif

View File

@@ -0,0 +1,83 @@
/*
* 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
#import <vector>
#import "SKBufferingPlugin.h"
#import <SonarKit/SonarConnection.h>
struct CachedEvent {
NSString *method;
NSDictionary<NSString *, id> *sonarObject;
};
static const NSUInteger bufferSize = 500;
@implementation SKBufferingPlugin
{
std::vector<CachedEvent> _ringBuffer;
std::shared_ptr<facebook::sonar::DispatchQueue> _connectionAccessQueue;
id<SonarConnection> _connection;
}
- (instancetype)initWithQueue:(const std::shared_ptr<facebook::sonar::DispatchQueue> &)queue {
if (self = [super init]) {
_ringBuffer.reserve(bufferSize);
_connectionAccessQueue = queue;
}
return self;
}
- (NSString *)identifier {
// Note: This must match with the javascript pulgin identifier!!
return @"Network";
}
- (void)didConnect:(id<SonarConnection>)connection {
_connectionAccessQueue->async(^{
self->_connection = connection;
[self sendBufferedEvents];
});
}
- (void)didDisconnect {
_connectionAccessQueue->async(^{
self->_connection = nil;
});
}
- (void)send:(NSString *)method
sonarObject:(NSDictionary<NSString *, id> *)sonarObject {
_connectionAccessQueue->async(^{
if (self->_connection) {
[self->_connection send:method withParams:sonarObject];
} else {
if (self->_ringBuffer.size() == bufferSize) {
return;
}
self->_ringBuffer.push_back({
.method = method,
.sonarObject = sonarObject
});
}
});
}
- (void)sendBufferedEvents {
NSAssert(_connection, @"connection object cannot be nil");
for (const auto &event : _ringBuffer) {
[_connection send:event.method withParams:event.sonarObject];
}
_ringBuffer.clear();
}
@end
#endif

View File

@@ -0,0 +1,39 @@
/*
* 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 <dispatch/dispatch.h>
namespace facebook {
namespace sonar {
class DispatchQueue
{
public:
virtual void async(dispatch_block_t block) = 0;
};
class GCDQueue: public DispatchQueue
{
public:
GCDQueue(dispatch_queue_t underlyingQueue)
:_underlyingQueue(underlyingQueue) { }
void async(dispatch_block_t block) override
{
dispatch_async(_underlyingQueue, block);
}
private:
dispatch_queue_t _underlyingQueue;
};
}
}
#endif

View File

@@ -0,0 +1,57 @@
/*
* 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>
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];
}
};
@protocol SKNetworkReporterDelegate
- (void)didObserveRequest:(RequestInfo)request;
- (void)didObserveResponse:(ResponseInfo)response;
@end
@protocol SKNetworkAdapterDelegate
@property (weak, nonatomic) id<SKNetworkReporterDelegate> delegate;
@end

View File

@@ -0,0 +1,26 @@
/*
* 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
#import <Foundation/Foundation.h>
#import <SonarKit/SonarPlugin.h>
#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
@property (strong, nonatomic) id<SKNetworkAdapterDelegate> adapter;
@end
#endif

View File

@@ -0,0 +1,101 @@
/*
* 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
#import "SonarKitNetworkPlugin.h"
#import "SKNetworkReporter.h"
@interface SonarKitNetworkPlugin ()
@end
@implementation SonarKitNetworkPlugin
- (void)setAdapter:(id<SKNetworkAdapterDelegate>)adapter {
_adapter = adapter;
_adapter.delegate = self;
}
- (instancetype)init {
if (self = [super initWithQueue:std::make_shared<facebook::sonar::GCDQueue>(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))]) {
adapter.delegate = self;
_adapter = adapter;
}
return self;
}
- (instancetype)initWithNetworkAdapter:(id<SKNetworkAdapterDelegate>)adapter queue:(const std::shared_ptr<facebook::sonar::DispatchQueue> &)queue; {
if (self = [super initWithQueue:queue]) {
adapter.delegate = self;
_adapter = adapter;
}
return self;
}
#pragma mark - SKNetworkReporterDelegate
- (void)didObserveRequest:(RequestInfo)request;
{
NSMutableArray<NSDictionary<NSString *, id> *> *headers = [NSMutableArray new];
for (NSString *key in [request.request.allHTTPHeaderFields allKeys]) {
NSDictionary<NSString *, id> *header = @{
@"key": key,
@"value": request.request.allHTTPHeaderFields[key]
};
[headers addObject: header];
}
NSString *body = request.body;
[self send:@"newRequest"
sonarObject:@{
@"id": @(request.identifier),
@"timestamp": @(request.timestamp),
@"method": request.request.HTTPMethod ?: [NSNull null],
@"url": [request.request.URL absoluteString] ?: [NSNull null],
@"headers": headers,
@"data": body ? body : [NSNull null]
}];
}
- (void)didObserveResponse:(ResponseInfo)response
{
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)response.response;
NSMutableArray<NSDictionary<NSString *, id> *> *headers = [NSMutableArray new];
for (NSString *key in [httpResponse.allHeaderFields allKeys]) {
NSDictionary<NSString *, id> *header = @{
@"key": key,
@"value": httpResponse.allHeaderFields[key]
};
[headers addObject: header];
}
NSString *body = response.body;
[self send:@"newResponse"
sonarObject:@{
@"id": @(response.identifier),
@"timestamp": @(response.timestamp),
@"status": @(httpResponse.statusCode),
@"reason": [NSHTTPURLResponse localizedStringForStatusCode: httpResponse.statusCode] ?: [NSNull null],
@"headers": headers,
@"data": body ? body : [NSNull null]
}];
}
@end
#endif