mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-09-14 16:08:51 +00:00
195 lines
5.3 KiB
Objective-C
195 lines
5.3 KiB
Objective-C
#import "BITChannel.h"
|
|
|
|
#if HOCKEYSDK_FEATURE_TELEMETRY
|
|
|
|
#import "BITHockeyHelper.h"
|
|
#import "HockeySDK.h"
|
|
#import "BITTelemetryContext.h"
|
|
#import "BITTelemetryData.h"
|
|
#import "HockeySDKPrivate.h"
|
|
#import "BITOrderedDictionary.h"
|
|
#import "BITEnvelope.h"
|
|
#import "BITData.h"
|
|
#import "BITDevice.h"
|
|
#import "BITPersistencePrivate.h"
|
|
|
|
static char *const BITDataItemsOperationsQueue = "net.hockeyapp.senderQueue";
|
|
char *BITSafeJsonEventsString;
|
|
|
|
NSInteger const defaultMaxBatchCount = 1;
|
|
static NSInteger const schemaVersion = 2;
|
|
|
|
@implementation BITChannel
|
|
|
|
@synthesize persistence = _persistence;
|
|
|
|
#pragma mark - Initialisation
|
|
|
|
- (instancetype)init {
|
|
if(self = [super init]) {
|
|
bit_resetSafeJsonStream(&BITSafeJsonEventsString);
|
|
_dataItemCount = 0;
|
|
dispatch_queue_t serialQueue = dispatch_queue_create(BITDataItemsOperationsQueue, DISPATCH_QUEUE_SERIAL);
|
|
_dataItemsOperations = serialQueue;
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (instancetype)initWithTelemetryContext:(BITTelemetryContext *)telemetryContext persistence:(BITPersistence *) persistence {
|
|
if(self = [self init]) {
|
|
_telemetryContext = telemetryContext;
|
|
_persistence = persistence;
|
|
}
|
|
return self;
|
|
}
|
|
|
|
#pragma mark - Queue management
|
|
|
|
- (BOOL)isQueueBusy{
|
|
|
|
[self.persistence isFreeSpaceAvailable];
|
|
return true;
|
|
}
|
|
|
|
- (void)persistDataItemQueue {
|
|
if(!BITSafeJsonEventsString || strlen(BITSafeJsonEventsString) == 0) {
|
|
return;
|
|
}
|
|
|
|
NSData *bundle = [NSData dataWithBytes:BITSafeJsonEventsString length:strlen(BITSafeJsonEventsString)];
|
|
[self.persistence persistBundle:bundle];
|
|
|
|
// Reset both, the async-signal-safe and item counter.
|
|
[self resetQueue];
|
|
}
|
|
|
|
- (void)resetQueue {
|
|
bit_resetSafeJsonStream(&BITSafeJsonEventsString);
|
|
_dataItemCount = 0;
|
|
}
|
|
|
|
#pragma mark - Adding to queue
|
|
|
|
- (void)enqueueTelemetryItem:(BITTelemetryData *)item {
|
|
if(item) {
|
|
BITOrderedDictionary *dict = [self dictionaryForTelemetryData:item];
|
|
__weak typeof(self) weakSelf = self;
|
|
|
|
dispatch_async(self.dataItemsOperations, ^{
|
|
typeof(self) strongSelf = weakSelf;
|
|
|
|
// Enqueue item
|
|
[strongSelf appendDictionaryToJsonStream:dict];
|
|
|
|
if(strongSelf->_dataItemCount >= self.maxBatchCount) {
|
|
// Max batch count has been reached, so write queue to disk and delete all items.
|
|
[strongSelf persistDataItemQueue];
|
|
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
#pragma mark - Envelope telemerty items
|
|
|
|
- (BITOrderedDictionary *)dictionaryForTelemetryData:(BITTelemetryData *) telemetryData {
|
|
|
|
BITEnvelope *envelope = [self envelopeForTelemetryData:telemetryData];
|
|
BITOrderedDictionary *dict = [envelope serializeToDictionary];
|
|
return dict;
|
|
}
|
|
|
|
- (BITEnvelope *)envelopeForTelemetryData:(BITTelemetryData *)telemetryData {
|
|
telemetryData.version = @(schemaVersion);
|
|
|
|
BITData *data = [BITData new];
|
|
data.baseData = telemetryData;
|
|
data.baseType = telemetryData.dataTypeName;
|
|
|
|
BITEnvelope *envelope = [BITEnvelope new];
|
|
envelope.appId = bit_mainBundleIdentifier();
|
|
envelope.appVer = _telemetryContext.application.version;
|
|
envelope.time = bit_utcDateString([NSDate date]);
|
|
envelope.iKey = _telemetryContext.appIdentifier;
|
|
|
|
BITDevice *deviceContext = _telemetryContext.device;
|
|
if (deviceContext.deviceId) {
|
|
envelope.deviceId = deviceContext.deviceId;
|
|
}
|
|
if (deviceContext.os) {
|
|
envelope.os = deviceContext.os;
|
|
}
|
|
if (deviceContext.osVersion) {
|
|
envelope.osVer = deviceContext.osVersion;
|
|
}
|
|
|
|
envelope.tags = _telemetryContext.contextDictionary;
|
|
envelope.data = data;
|
|
envelope.name = telemetryData.envelopeTypeName;
|
|
|
|
return envelope;
|
|
}
|
|
|
|
#pragma mark - Serialization Helper
|
|
|
|
- (NSString *)serializeDictionaryToJSONString:(BITOrderedDictionary *)dictionary {
|
|
NSError *error;
|
|
NSData *data = [NSJSONSerialization dataWithJSONObject:dictionary options:(NSJSONWritingOptions)0 error:&error];
|
|
if (!data) {
|
|
BITHockeyLog(@"ERROR: JSONSerialization error: %@", error.localizedDescription);
|
|
return @"{}";
|
|
} else {
|
|
return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
|
|
}
|
|
}
|
|
|
|
#pragma mark JSON Stream
|
|
|
|
- (void)appendDictionaryToJsonStream:(BITOrderedDictionary *)dictionary {
|
|
if(dictionary) {
|
|
NSString *string = [self serializeDictionaryToJSONString:dictionary];
|
|
|
|
// Since we can't persist every event right away, we write it to a simple C string.
|
|
// This can then be written to disk by a signal handler in case of a crash.
|
|
bit_appendStringToSafeJsonStream(string, &(BITSafeJsonEventsString));
|
|
_dataItemCount += 1;
|
|
}
|
|
}
|
|
|
|
void bit_appendStringToSafeJsonStream(NSString *string, char **jsonString) {
|
|
if (jsonString == NULL) { return; }
|
|
|
|
if (!string) { return; }
|
|
|
|
if (*jsonString == NULL || strlen(*jsonString) == 0) {
|
|
bit_resetSafeJsonStream(jsonString);
|
|
}
|
|
|
|
if (string.length == 0) { return; }
|
|
|
|
char *new_string = NULL;
|
|
// Concatenate old string with new JSON string and add a comma.
|
|
asprintf(&new_string, "%s%.*s\n", *jsonString, (int)MIN(string.length, (NSUInteger)INT_MAX), string.UTF8String);
|
|
free(*jsonString);
|
|
*jsonString = new_string;
|
|
}
|
|
|
|
void bit_resetSafeJsonStream(char **string) {
|
|
if (!string) { return; }
|
|
free(*string);
|
|
*string = strdup("");
|
|
}
|
|
|
|
#pragma mark - Batching
|
|
|
|
- (NSInteger)maxBatchCount {
|
|
if(_maxBatchCount <= 0){
|
|
return defaultMaxBatchCount;
|
|
}
|
|
return _maxBatchCount;
|
|
}
|
|
|
|
@end
|
|
|
|
#endif /* HOCKEYSDK_FEATURE_TELEMETRY */
|