Archived
Push from command line
This commit is contained in:
Pods/GoogleDataTransportCCTSupport/GoogleDataTransportCCTSupport/GDTCCTLibrary/GDTCCTNanopbHelpers.m
Generated
+188
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
* Copyright 2019 Google
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import "GDTCCTLibrary/Private/GDTCCTNanopbHelpers.h"
|
||||
|
||||
#if TARGET_OS_IOS || TARGET_OS_TV
|
||||
#import <UIKit/UIKit.h>
|
||||
#elif TARGET_OS_OSX
|
||||
#import <AppKit/AppKit.h>
|
||||
#endif // TARGET_OS_IOS || TARGET_OS_TV
|
||||
|
||||
#import <GoogleDataTransport/GDTConsoleLogger.h>
|
||||
|
||||
#import <nanopb/pb.h>
|
||||
#import <nanopb/pb_decode.h>
|
||||
#import <nanopb/pb_encode.h>
|
||||
|
||||
#import "GDTCCTLibrary/Private/GDTCCTPrioritizer.h"
|
||||
|
||||
#pragma mark - General purpose encoders
|
||||
|
||||
pb_bytes_array_t *GDTCCTEncodeString(NSString *string) {
|
||||
NSData *stringBytes = [string dataUsingEncoding:NSUTF8StringEncoding];
|
||||
return GDTCCTEncodeData(stringBytes);
|
||||
}
|
||||
|
||||
pb_bytes_array_t *GDTCCTEncodeData(NSData *data) {
|
||||
pb_bytes_array_t *pbBytes = malloc(PB_BYTES_ARRAY_T_ALLOCSIZE(data.length));
|
||||
memcpy(pbBytes->bytes, [data bytes], data.length);
|
||||
pbBytes->size = (pb_size_t)data.length;
|
||||
return pbBytes;
|
||||
}
|
||||
|
||||
#pragma mark - CCT object constructors
|
||||
|
||||
NSData *_Nullable GDTCCTEncodeBatchedLogRequest(gdt_cct_BatchedLogRequest *batchedLogRequest) {
|
||||
pb_ostream_t sizestream = PB_OSTREAM_SIZING;
|
||||
// Encode 1 time to determine the size.
|
||||
if (!pb_encode(&sizestream, gdt_cct_BatchedLogRequest_fields, batchedLogRequest)) {
|
||||
GDTLogError(GDTMCEGeneralError, @"Error in nanopb encoding for size: %s",
|
||||
PB_GET_ERROR(&sizestream));
|
||||
}
|
||||
|
||||
// Encode a 2nd time to actually get the bytes from it.
|
||||
size_t bufferSize = sizestream.bytes_written;
|
||||
CFMutableDataRef dataRef = CFDataCreateMutable(CFAllocatorGetDefault(), bufferSize);
|
||||
pb_ostream_t ostream = pb_ostream_from_buffer((void *)CFDataGetBytePtr(dataRef), bufferSize);
|
||||
if (!pb_encode(&ostream, gdt_cct_BatchedLogRequest_fields, batchedLogRequest)) {
|
||||
GDTLogError(GDTMCEGeneralError, @"Error in nanopb encoding for bytes: %s",
|
||||
PB_GET_ERROR(&ostream));
|
||||
}
|
||||
CFDataSetLength(dataRef, ostream.bytes_written);
|
||||
|
||||
return CFBridgingRelease(dataRef);
|
||||
}
|
||||
|
||||
gdt_cct_BatchedLogRequest GDTCCTConstructBatchedLogRequest(
|
||||
NSDictionary<NSString *, NSSet<GDTStoredEvent *> *> *logMappingIDToLogSet) {
|
||||
gdt_cct_BatchedLogRequest batchedLogRequest = gdt_cct_BatchedLogRequest_init_default;
|
||||
NSUInteger numberOfLogRequests = logMappingIDToLogSet.count;
|
||||
gdt_cct_LogRequest *logRequests = malloc(sizeof(gdt_cct_LogRequest) * numberOfLogRequests);
|
||||
|
||||
__block int i = 0;
|
||||
[logMappingIDToLogSet enumerateKeysAndObjectsUsingBlock:^(
|
||||
NSString *_Nonnull logMappingID,
|
||||
NSSet<GDTStoredEvent *> *_Nonnull logSet, BOOL *_Nonnull stop) {
|
||||
int32_t logSource = [logMappingID intValue];
|
||||
gdt_cct_LogRequest logRequest = GDTCCTConstructLogRequest(logSource, logSet);
|
||||
logRequests[i] = logRequest;
|
||||
i++;
|
||||
}];
|
||||
|
||||
batchedLogRequest.log_request = logRequests;
|
||||
batchedLogRequest.log_request_count = (pb_size_t)numberOfLogRequests;
|
||||
return batchedLogRequest;
|
||||
}
|
||||
|
||||
gdt_cct_LogRequest GDTCCTConstructLogRequest(int32_t logSource,
|
||||
NSSet<GDTStoredEvent *> *_Nonnull logSet) {
|
||||
if (logSet.count == 0) {
|
||||
GDTLogError(GDTMCEGeneralError, @"%@", @"An empty event set can't be serialized to proto.");
|
||||
gdt_cct_LogRequest logRequest = gdt_cct_LogRequest_init_default;
|
||||
return logRequest;
|
||||
}
|
||||
gdt_cct_LogRequest logRequest = gdt_cct_LogRequest_init_default;
|
||||
logRequest.log_source = logSource;
|
||||
logRequest.has_log_source = 1;
|
||||
logRequest.client_info = GDTCCTConstructClientInfo();
|
||||
logRequest.has_client_info = 1;
|
||||
logRequest.log_event = malloc(sizeof(gdt_cct_LogEvent) * logSet.count);
|
||||
int i = 0;
|
||||
for (GDTStoredEvent *log in logSet) {
|
||||
gdt_cct_LogEvent logEvent = GDTCCTConstructLogEvent(log);
|
||||
logRequest.log_event[i] = logEvent;
|
||||
i++;
|
||||
}
|
||||
logRequest.log_event_count = (pb_size_t)logSet.count;
|
||||
|
||||
return logRequest;
|
||||
}
|
||||
|
||||
gdt_cct_LogEvent GDTCCTConstructLogEvent(GDTStoredEvent *event) {
|
||||
gdt_cct_LogEvent logEvent = gdt_cct_LogEvent_init_default;
|
||||
logEvent.event_time_ms = event.clockSnapshot.timeMillis;
|
||||
logEvent.has_event_time_ms = 1;
|
||||
logEvent.event_uptime_ms = event.clockSnapshot.uptime;
|
||||
logEvent.has_event_uptime_ms = 1;
|
||||
logEvent.timezone_offset_seconds = event.clockSnapshot.timezoneOffsetSeconds;
|
||||
logEvent.has_timezone_offset_seconds = 1;
|
||||
// TODO: Read network_connection_info from the custom params dict.
|
||||
|
||||
NSError *error;
|
||||
NSData *extensionBytes = [NSData dataWithContentsOfURL:event.dataFuture.fileURL
|
||||
options:0
|
||||
error:&error];
|
||||
if (error) {
|
||||
GDTLogError(GDTMCEGeneralError, @"There was an error reading extension bytes from disk: %@",
|
||||
error);
|
||||
return logEvent;
|
||||
}
|
||||
logEvent.source_extension = GDTCCTEncodeData(extensionBytes); // read bytes from the file.
|
||||
return logEvent;
|
||||
}
|
||||
|
||||
gdt_cct_ClientInfo GDTCCTConstructClientInfo() {
|
||||
gdt_cct_ClientInfo clientInfo = gdt_cct_ClientInfo_init_default;
|
||||
clientInfo.client_type = gdt_cct_ClientInfo_ClientType_IOS_FIREBASE;
|
||||
clientInfo.has_client_type = 1;
|
||||
#if TARGET_OS_IOS || TARGET_OS_TV
|
||||
clientInfo.ios_client_info = GDTCCTConstructiOSClientInfo();
|
||||
clientInfo.has_ios_client_info = 1;
|
||||
#elif TARGET_OS_OSX
|
||||
// TODO(mikehaney24): Expand the proto to include macOS client info.
|
||||
#endif
|
||||
return clientInfo;
|
||||
}
|
||||
|
||||
gdt_cct_IosClientInfo GDTCCTConstructiOSClientInfo() {
|
||||
gdt_cct_IosClientInfo iOSClientInfo = gdt_cct_IosClientInfo_init_default;
|
||||
#if TARGET_OS_IOS || TARGET_OS_TV
|
||||
UIDevice *device = [UIDevice currentDevice];
|
||||
NSBundle *bundle = [NSBundle mainBundle];
|
||||
NSLocale *locale = [NSLocale currentLocale];
|
||||
iOSClientInfo.os_full_version = GDTCCTEncodeString(device.systemVersion);
|
||||
NSArray *versionComponents = [device.systemVersion componentsSeparatedByString:@"."];
|
||||
iOSClientInfo.os_major_version = GDTCCTEncodeString(versionComponents[0]);
|
||||
NSString *version = [bundle objectForInfoDictionaryKey:(NSString *)kCFBundleVersionKey];
|
||||
if (version) {
|
||||
iOSClientInfo.application_build = GDTCCTEncodeString(version);
|
||||
}
|
||||
iOSClientInfo.country = GDTCCTEncodeString([locale objectForKey:NSLocaleCountryCode]);
|
||||
iOSClientInfo.model = GDTCCTEncodeString(device.model);
|
||||
NSString *languageCode = bundle.preferredLocalizations.firstObject;
|
||||
iOSClientInfo.language_code =
|
||||
languageCode ? GDTCCTEncodeString(languageCode) : GDTCCTEncodeString(@"en");
|
||||
iOSClientInfo.application_bundle_id = GDTCCTEncodeString(bundle.bundleIdentifier);
|
||||
#endif
|
||||
return iOSClientInfo;
|
||||
}
|
||||
|
||||
#pragma mark - CCT Object decoders
|
||||
|
||||
gdt_cct_LogResponse GDTCCTDecodeLogResponse(NSData *data, NSError **error) {
|
||||
gdt_cct_LogResponse response = gdt_cct_LogResponse_init_default;
|
||||
pb_istream_t istream = pb_istream_from_buffer([data bytes], [data length]);
|
||||
if (!pb_decode(&istream, gdt_cct_LogResponse_fields, &response)) {
|
||||
NSString *nanopb_error = [NSString stringWithFormat:@"%s", PB_GET_ERROR(&istream)];
|
||||
NSDictionary *userInfo = @{@"nanopb error:" : nanopb_error};
|
||||
if (error != NULL) {
|
||||
*error = [NSError errorWithDomain:NSURLErrorDomain code:-1 userInfo:userInfo];
|
||||
}
|
||||
response = (gdt_cct_LogResponse)gdt_cct_LogResponse_init_default;
|
||||
}
|
||||
return response;
|
||||
}
|
||||
Generated
+188
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
* Copyright 2019 Google
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import "GDTCCTLibrary/Private/GDTCCTPrioritizer.h"
|
||||
|
||||
#import <GoogleDataTransport/GDTEvent.h>
|
||||
#import <GoogleDataTransport/GDTRegistrar.h>
|
||||
#import <GoogleDataTransport/GDTStoredEvent.h>
|
||||
#import <GoogleDataTransport/GDTTargets.h>
|
||||
|
||||
const static int64_t kMillisPerDay = 8.64e+7;
|
||||
|
||||
@implementation GDTCCTPrioritizer
|
||||
|
||||
+ (void)load {
|
||||
GDTCCTPrioritizer *prioritizer = [GDTCCTPrioritizer sharedInstance];
|
||||
[[GDTRegistrar sharedInstance] registerPrioritizer:prioritizer target:kGDTTargetCCT];
|
||||
}
|
||||
|
||||
+ (instancetype)sharedInstance {
|
||||
static GDTCCTPrioritizer *sharedInstance;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
sharedInstance = [[GDTCCTPrioritizer alloc] init];
|
||||
});
|
||||
return sharedInstance;
|
||||
}
|
||||
|
||||
- (instancetype)init {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_queue = dispatch_queue_create("com.google.GDTCCTPrioritizer", DISPATCH_QUEUE_SERIAL);
|
||||
_events = [[NSMutableSet alloc] init];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - GDTPrioritizer Protocol
|
||||
|
||||
- (void)prioritizeEvent:(GDTStoredEvent *)event {
|
||||
dispatch_async(_queue, ^{
|
||||
[self.events addObject:event];
|
||||
});
|
||||
}
|
||||
|
||||
- (GDTUploadPackage *)uploadPackageWithConditions:(GDTUploadConditions)conditions {
|
||||
GDTUploadPackage *package = [[GDTUploadPackage alloc] initWithTarget:kGDTTargetCCT];
|
||||
dispatch_sync(_queue, ^{
|
||||
NSSet<GDTStoredEvent *> *logEventsThatWillBeSent;
|
||||
// A high priority event effectively flushes all events to be sent.
|
||||
if ((conditions & GDTUploadConditionHighPriority) == GDTUploadConditionHighPriority) {
|
||||
package.events = self.events;
|
||||
return;
|
||||
}
|
||||
|
||||
// If on wifi, upload logs that are ok to send on wifi.
|
||||
if ((conditions & GDTUploadConditionWifiData) == GDTUploadConditionWifiData) {
|
||||
logEventsThatWillBeSent = [self logEventsOkToSendOnWifi];
|
||||
} else {
|
||||
logEventsThatWillBeSent = [self logEventsOkToSendOnMobileData];
|
||||
}
|
||||
|
||||
// If it's been > 24h since the last daily upload, upload logs with the daily QoS.
|
||||
if (self.timeOfLastDailyUpload) {
|
||||
int64_t millisSinceLastUpload =
|
||||
[GDTClock snapshot].timeMillis - self.timeOfLastDailyUpload.timeMillis;
|
||||
if (millisSinceLastUpload > kMillisPerDay) {
|
||||
logEventsThatWillBeSent =
|
||||
[logEventsThatWillBeSent setByAddingObjectsFromSet:[self logEventsOkToSendDaily]];
|
||||
}
|
||||
} else {
|
||||
self.timeOfLastDailyUpload = [GDTClock snapshot];
|
||||
logEventsThatWillBeSent =
|
||||
[logEventsThatWillBeSent setByAddingObjectsFromSet:[self logEventsOkToSendDaily]];
|
||||
}
|
||||
package.events = logEventsThatWillBeSent;
|
||||
});
|
||||
return package;
|
||||
}
|
||||
|
||||
#pragma mark - Private helper methods
|
||||
|
||||
/** The different possible quality of service specifiers. High values indicate high priority. */
|
||||
typedef NS_ENUM(NSInteger, GDTCCTQoSTier) {
|
||||
/** The QoS tier wasn't set, and won't ever be sent. */
|
||||
GDTCCTQoSDefault = 0,
|
||||
|
||||
/** This event is internal telemetry data that should not be sent on its own if possible. */
|
||||
GDTCCTQoSTelemetry = 1,
|
||||
|
||||
/** This event should be sent, but in a batch only roughly once per day. */
|
||||
GDTCCTQoSDaily = 2,
|
||||
|
||||
/** This event should only be uploaded on wifi. */
|
||||
GDTCCTQoSWifiOnly = 5,
|
||||
};
|
||||
|
||||
/** Converts a GDTEventQoS to a GDTCCTQoS tier.
|
||||
*
|
||||
* @param qosTier The GDTEventQoS value.
|
||||
* @return A static NSNumber that represents the CCT QoS tier.
|
||||
*/
|
||||
FOUNDATION_STATIC_INLINE
|
||||
NSNumber *GDTCCTQosTierFromGDTEventQosTier(GDTEventQoS qosTier) {
|
||||
switch (qosTier) {
|
||||
case GDTEventQoSWifiOnly:
|
||||
return @(GDTCCTQoSWifiOnly);
|
||||
break;
|
||||
|
||||
case GDTEventQoSTelemetry:
|
||||
// falls through.
|
||||
case GDTEventQoSDaily:
|
||||
return @(GDTCCTQoSDaily);
|
||||
break;
|
||||
|
||||
default:
|
||||
return @(GDTCCTQoSDefault);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns a set of logs that are ok to upload whilst on mobile data.
|
||||
*
|
||||
* @note This should be called from a thread safe method.
|
||||
* @return A set of logs that are ok to upload whilst on mobile data.
|
||||
*/
|
||||
- (NSSet<GDTStoredEvent *> *)logEventsOkToSendOnMobileData {
|
||||
return
|
||||
[self.events objectsPassingTest:^BOOL(GDTStoredEvent *_Nonnull event, BOOL *_Nonnull stop) {
|
||||
return [GDTCCTQosTierFromGDTEventQosTier(event.qosTier) isEqual:@(GDTCCTQoSDefault)];
|
||||
}];
|
||||
}
|
||||
|
||||
/** Returns a set of logs that are ok to upload whilst on wifi.
|
||||
*
|
||||
* @note This should be called from a thread safe method.
|
||||
* @return A set of logs that are ok to upload whilst on wifi.
|
||||
*/
|
||||
- (NSSet<GDTStoredEvent *> *)logEventsOkToSendOnWifi {
|
||||
return
|
||||
[self.events objectsPassingTest:^BOOL(GDTStoredEvent *_Nonnull event, BOOL *_Nonnull stop) {
|
||||
NSNumber *qosTier = GDTCCTQosTierFromGDTEventQosTier(event.qosTier);
|
||||
return [qosTier isEqual:@(GDTCCTQoSDefault)] || [qosTier isEqual:@(GDTCCTQoSWifiOnly)] ||
|
||||
[qosTier isEqual:@(GDTCCTQoSDaily)];
|
||||
}];
|
||||
}
|
||||
|
||||
/** Returns a set of logs that only should have a single upload attempt per day.
|
||||
*
|
||||
* @note This should be called from a thread safe method.
|
||||
* @return A set of logs that are ok to upload only once per day.
|
||||
*/
|
||||
- (NSSet<GDTStoredEvent *> *)logEventsOkToSendDaily {
|
||||
return
|
||||
[self.events objectsPassingTest:^BOOL(GDTStoredEvent *_Nonnull event, BOOL *_Nonnull stop) {
|
||||
return [GDTCCTQosTierFromGDTEventQosTier(event.qosTier) isEqual:@(GDTCCTQoSDaily)];
|
||||
}];
|
||||
}
|
||||
|
||||
#pragma mark - GDTUploadPackageProtocol
|
||||
|
||||
- (void)packageDelivered:(GDTUploadPackage *)package successful:(BOOL)successful {
|
||||
dispatch_async(_queue, ^{
|
||||
NSSet<GDTStoredEvent *> *events = [package.events copy];
|
||||
for (GDTStoredEvent *event in events) {
|
||||
[self.events removeObject:event];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
- (void)packageExpired:(GDTUploadPackage *)package {
|
||||
[self packageDelivered:package successful:YES];
|
||||
}
|
||||
|
||||
@end
|
||||
Generated
+206
@@ -0,0 +1,206 @@
|
||||
/*
|
||||
* Copyright 2019 Google
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import "GDTCCTLibrary/Private/GDTCCTUploader.h"
|
||||
|
||||
#import <GoogleDataTransport/GDTConsoleLogger.h>
|
||||
#import <GoogleDataTransport/GDTPlatform.h>
|
||||
#import <GoogleDataTransport/GDTRegistrar.h>
|
||||
|
||||
#import <nanopb/pb.h>
|
||||
#import <nanopb/pb_decode.h>
|
||||
#import <nanopb/pb_encode.h>
|
||||
|
||||
#import "GDTCCTLibrary/Private/GDTCCTNanopbHelpers.h"
|
||||
#import "GDTCCTLibrary/Private/GDTCCTPrioritizer.h"
|
||||
|
||||
#import "GDTCCTLibrary/Protogen/nanopb/cct.nanopb.h"
|
||||
|
||||
@interface GDTCCTUploader ()
|
||||
|
||||
// Redeclared as readwrite.
|
||||
@property(nullable, nonatomic, readwrite) NSURLSessionUploadTask *currentTask;
|
||||
|
||||
/** If running in the background, the current background ID. */
|
||||
@property(nonatomic) GDTBackgroundIdentifier backgroundID;
|
||||
|
||||
@end
|
||||
|
||||
@implementation GDTCCTUploader
|
||||
|
||||
+ (void)load {
|
||||
GDTCCTUploader *uploader = [GDTCCTUploader sharedInstance];
|
||||
[[GDTRegistrar sharedInstance] registerUploader:uploader target:kGDTTargetCCT];
|
||||
}
|
||||
|
||||
+ (instancetype)sharedInstance {
|
||||
static GDTCCTUploader *sharedInstance;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
sharedInstance = [[GDTCCTUploader alloc] init];
|
||||
});
|
||||
return sharedInstance;
|
||||
}
|
||||
|
||||
- (instancetype)init {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_uploaderQueue = dispatch_queue_create("com.google.GDTCCTUploader", DISPATCH_QUEUE_SERIAL);
|
||||
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
|
||||
_uploaderSession = [NSURLSession sessionWithConfiguration:config];
|
||||
_backgroundID = GDTBackgroundIdentifierInvalid;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSURL *)defaultServerURL {
|
||||
static NSURL *defaultServerURL;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
// These strings should be interleaved to construct the real URL. This is just to (hopefully)
|
||||
// fool github URL scanning bots.
|
||||
const char *p1 = "hts/frbslgiggolai.o/0clgbth";
|
||||
const char *p2 = "tp:/ieaeogn.ogepscmvc/o/ac";
|
||||
const char defaultURL[54] = {
|
||||
p1[0], p2[0], p1[1], p2[1], p1[2], p2[2], p1[3], p2[3], p1[4], p2[4], p1[5],
|
||||
p2[5], p1[6], p2[6], p1[7], p2[7], p1[8], p2[8], p1[9], p2[9], p1[10], p2[10],
|
||||
p1[11], p2[11], p1[12], p2[12], p1[13], p2[13], p1[14], p2[14], p1[15], p2[15], p1[16],
|
||||
p2[16], p1[17], p2[17], p1[18], p2[18], p1[19], p2[19], p1[20], p2[20], p1[21], p2[21],
|
||||
p1[22], p2[22], p1[23], p2[23], p1[24], p2[24], p1[25], p2[25], p1[26], '\0'};
|
||||
defaultServerURL = [NSURL URLWithString:[NSString stringWithUTF8String:defaultURL]];
|
||||
});
|
||||
return defaultServerURL;
|
||||
}
|
||||
|
||||
- (void)uploadPackage:(GDTUploadPackage *)package {
|
||||
dispatch_async(_uploaderQueue, ^{
|
||||
if (self->_currentTask || self->_currentUploadPackage) {
|
||||
GDTLogWarning(GDTMCWUploadFailed, @"%@",
|
||||
@"An upload shouldn't be initiated with another in progress.");
|
||||
return;
|
||||
}
|
||||
NSURL *serverURL = self.serverURL ? self.serverURL : [self defaultServerURL];
|
||||
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:serverURL];
|
||||
request.HTTPMethod = @"POST";
|
||||
|
||||
id completionHandler =
|
||||
^(NSData *_Nullable data, NSURLResponse *_Nullable response, NSError *_Nullable error) {
|
||||
if (error) {
|
||||
GDTLogWarning(GDTMCWUploadFailed, @"There was an error uploading events: %@", error);
|
||||
}
|
||||
NSError *decodingError;
|
||||
gdt_cct_LogResponse logResponse = GDTCCTDecodeLogResponse(data, &decodingError);
|
||||
if (!decodingError && logResponse.has_next_request_wait_millis) {
|
||||
self->_nextUploadTime =
|
||||
[GDTClock clockSnapshotInTheFuture:logResponse.next_request_wait_millis];
|
||||
} else {
|
||||
// 15 minutes from now.
|
||||
self->_nextUploadTime = [GDTClock clockSnapshotInTheFuture:15 * 60 * 1000];
|
||||
}
|
||||
pb_release(gdt_cct_LogResponse_fields, &logResponse);
|
||||
[package completeDelivery];
|
||||
if (self->_backgroundID != GDTBackgroundIdentifierInvalid) {
|
||||
[[GDTApplication sharedApplication] endBackgroundTask:self->_backgroundID];
|
||||
self->_backgroundID = GDTBackgroundIdentifierInvalid;
|
||||
}
|
||||
self.currentTask = nil;
|
||||
self.currentUploadPackage = nil;
|
||||
};
|
||||
self->_currentUploadPackage = package;
|
||||
NSData *requestProtoData = [self constructRequestProtoFromPackage:(GDTUploadPackage *)package];
|
||||
self.currentTask = [self.uploaderSession uploadTaskWithRequest:request
|
||||
fromData:requestProtoData
|
||||
completionHandler:completionHandler];
|
||||
[self.currentTask resume];
|
||||
});
|
||||
}
|
||||
|
||||
- (BOOL)readyToUploadWithConditions:(GDTUploadConditions)conditions {
|
||||
__block BOOL result = NO;
|
||||
dispatch_sync(_uploaderQueue, ^{
|
||||
if (self->_currentUploadPackage) {
|
||||
result = NO;
|
||||
return;
|
||||
}
|
||||
if (self->_currentTask) {
|
||||
result = NO;
|
||||
return;
|
||||
}
|
||||
if ((conditions & GDTUploadConditionHighPriority) == GDTUploadConditionHighPriority) {
|
||||
result = YES;
|
||||
return;
|
||||
} else if (self->_nextUploadTime) {
|
||||
result = [[GDTClock snapshot] isAfter:self->_nextUploadTime];
|
||||
return;
|
||||
}
|
||||
result = YES;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
#pragma mark - Private helper methods
|
||||
|
||||
/** Constructs data given an upload package.
|
||||
*
|
||||
* @param package The upload package used to construct the request proto bytes.
|
||||
* @return Proto bytes representing a gdt_cct_LogRequest object.
|
||||
*/
|
||||
- (nonnull NSData *)constructRequestProtoFromPackage:(GDTUploadPackage *)package {
|
||||
// Segment the log events by log type.
|
||||
NSMutableDictionary<NSString *, NSMutableSet<GDTStoredEvent *> *> *logMappingIDToLogSet =
|
||||
[[NSMutableDictionary alloc] init];
|
||||
[package.events
|
||||
enumerateObjectsUsingBlock:^(GDTStoredEvent *_Nonnull event, BOOL *_Nonnull stop) {
|
||||
NSMutableSet *logSet = logMappingIDToLogSet[event.mappingID];
|
||||
logSet = logSet ? logSet : [[NSMutableSet alloc] init];
|
||||
[logSet addObject:event];
|
||||
logMappingIDToLogSet[event.mappingID] = logSet;
|
||||
}];
|
||||
|
||||
gdt_cct_BatchedLogRequest batchedLogRequest =
|
||||
GDTCCTConstructBatchedLogRequest(logMappingIDToLogSet);
|
||||
|
||||
NSData *data = GDTCCTEncodeBatchedLogRequest(&batchedLogRequest);
|
||||
pb_release(gdt_cct_BatchedLogRequest_fields, &batchedLogRequest);
|
||||
return data ? data : [[NSData alloc] init];
|
||||
}
|
||||
|
||||
#pragma mark - GDTUploadPackageProtocol
|
||||
|
||||
- (void)packageExpired:(GDTUploadPackage *)package {
|
||||
dispatch_async(_uploaderQueue, ^{
|
||||
[self.currentTask cancel];
|
||||
self.currentTask = nil;
|
||||
self.currentUploadPackage = nil;
|
||||
});
|
||||
}
|
||||
|
||||
#pragma mark - GDTLifecycleProtocol
|
||||
|
||||
- (void)appWillBackground:(GDTApplication *)app {
|
||||
_backgroundID = [app beginBackgroundTaskWithExpirationHandler:^{
|
||||
[app endBackgroundTask:self->_backgroundID];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)appWillTerminate:(GDTApplication *)application {
|
||||
dispatch_sync(_uploaderQueue, ^{
|
||||
[self.currentTask cancel];
|
||||
[self.currentUploadPackage completeDelivery];
|
||||
});
|
||||
}
|
||||
|
||||
@end
|
||||
+112
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Copyright 2019 Google
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import <GoogleDataTransport/GDTStoredEvent.h>
|
||||
|
||||
#import "GDTCCTLibrary/Protogen/nanopb/cct.nanopb.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
#pragma mark - General purpose encoders
|
||||
|
||||
/** Converts an NSString* to a pb_bytes_array_t*.
|
||||
*
|
||||
* @note malloc is called in this method. Ensure that pb_release is called on this or the parent.
|
||||
*
|
||||
* @param string The string to convert.
|
||||
* @return A newly allocated array of bytes representing the UTF8 encoding of the string.
|
||||
*/
|
||||
pb_bytes_array_t *GDTCCTEncodeString(NSString *string);
|
||||
|
||||
/** Converts an NSData to a pb_bytes_array_t*.
|
||||
*
|
||||
* @note malloc is called in this method. Ensure that pb_release is called on this or the parent.
|
||||
*
|
||||
* @param data The data to convert.
|
||||
* @return A newly allocated array of bytes with [data bytes] copied into it.
|
||||
*/
|
||||
pb_bytes_array_t *GDTCCTEncodeData(NSData *data);
|
||||
|
||||
#pragma mark - CCT object constructors
|
||||
|
||||
/** Encodes a batched log request.
|
||||
*
|
||||
* @note Ensure that pb_release is called on the batchedLogRequest param.
|
||||
*
|
||||
* @param batchedLogRequest A pointer to the log batch to encode to bytes.
|
||||
* @return An NSData object representing the bytes of the log request batch.
|
||||
*/
|
||||
FOUNDATION_EXPORT
|
||||
NSData *GDTCCTEncodeBatchedLogRequest(gdt_cct_BatchedLogRequest *batchedLogRequest);
|
||||
|
||||
/** Constructs a gdt_cct_BatchedLogRequest given sets of events segemented by mapping ID.
|
||||
*
|
||||
* @note malloc is called in this method. Ensure that pb_release is called on this or the parent.
|
||||
*
|
||||
* @param logMappingIDToLogSet A map of mapping IDs to sets of events to convert into a batch.
|
||||
* @return A newly created gdt_cct_BatchedLogRequest.
|
||||
*/
|
||||
FOUNDATION_EXPORT
|
||||
gdt_cct_BatchedLogRequest GDTCCTConstructBatchedLogRequest(
|
||||
NSDictionary<NSString *, NSSet<GDTStoredEvent *> *> *logMappingIDToLogSet);
|
||||
|
||||
/** Constructs a log request given a log source and a set of events.
|
||||
*
|
||||
* @note malloc is called in this method. Ensure that pb_release is called on this or the parent.
|
||||
* @param logSource The CCT log source to put into the log request.
|
||||
* @param logSet The set of events to send in this log request.
|
||||
*/
|
||||
FOUNDATION_EXPORT
|
||||
gdt_cct_LogRequest GDTCCTConstructLogRequest(int32_t logSource, NSSet<GDTStoredEvent *> *logSet);
|
||||
|
||||
/** Constructs a gdt_cct_LogEvent given a GDTStoredEvent*.
|
||||
*
|
||||
* @param event The GDTStoredEvent to convert.
|
||||
* @return The new gdt_cct_LogEvent object.
|
||||
*/
|
||||
FOUNDATION_EXPORT
|
||||
gdt_cct_LogEvent GDTCCTConstructLogEvent(GDTStoredEvent *event);
|
||||
|
||||
/** Constructs a gdt_cct_ClientInfo representing the client device.
|
||||
*
|
||||
* @return The new gdt_cct_ClientInfo object.
|
||||
*/
|
||||
FOUNDATION_EXPORT
|
||||
gdt_cct_ClientInfo GDTCCTConstructClientInfo(void);
|
||||
|
||||
/** Constructs a gdt_cct_IosClientInfo representing the client device.
|
||||
*
|
||||
* @return The new gdt_cct_IosClientInfo object.
|
||||
*/
|
||||
FOUNDATION_EXPORT
|
||||
gdt_cct_IosClientInfo GDTCCTConstructiOSClientInfo(void);
|
||||
|
||||
#pragma mark - CCT object decoders
|
||||
|
||||
/** Decodes a gdt_cct_LogResponse given proto bytes.
|
||||
*
|
||||
* @note malloc is called in this method. Ensure that pb_release is called on the return value.
|
||||
*
|
||||
* @param data The proto bytes of the gdt_cct_LogResponse.
|
||||
* @param error An error that will be populated if something went wrong during decoding.
|
||||
* @return A newly allocated gdt_cct_LogResponse from the data, if the bytes decoded properly.
|
||||
*/
|
||||
FOUNDATION_EXPORT
|
||||
gdt_cct_LogResponse GDTCCTDecodeLogResponse(NSData *data, NSError **error);
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2019 Google
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import <GoogleDataTransport/GDTClock.h>
|
||||
#import <GoogleDataTransport/GDTPrioritizer.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/** Manages the prioritization of events from GoogleDataTransport. */
|
||||
@interface GDTCCTPrioritizer : NSObject <GDTPrioritizer>
|
||||
|
||||
/** The queue on which this prioritizer operates. */
|
||||
@property(nonatomic) dispatch_queue_t queue;
|
||||
|
||||
/** All log events that have been processed by this prioritizer. */
|
||||
@property(nonatomic) NSMutableSet<GDTStoredEvent *> *events;
|
||||
|
||||
/** The most recent attempted upload of daily uploaded logs. */
|
||||
@property(nonatomic) GDTClock *timeOfLastDailyUpload;
|
||||
|
||||
/** Creates and/or returns the singleton instance of this class.
|
||||
*
|
||||
* @return The singleton instance of this class.
|
||||
*/
|
||||
+ (instancetype)sharedInstance;
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@end
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2019 Google
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import <GoogleDataTransport/GDTUploader.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/** Class capable of uploading events to the CCT backend. */
|
||||
@interface GDTCCTUploader : NSObject <GDTUploader>
|
||||
|
||||
/** The queue on which all CCT uploading will occur. */
|
||||
@property(nonatomic, readonly) dispatch_queue_t uploaderQueue;
|
||||
|
||||
/** The server URL to upload to. Look at .m for the default value. */
|
||||
@property(nonatomic) NSURL *serverURL;
|
||||
|
||||
/** The URL session that will attempt upload. */
|
||||
@property(nonatomic, readonly) NSURLSession *uploaderSession;
|
||||
|
||||
/** The current upload task. */
|
||||
@property(nullable, nonatomic, readonly) NSURLSessionUploadTask *currentTask;
|
||||
|
||||
/** Current upload package. */
|
||||
@property(nullable, nonatomic) GDTUploadPackage *currentUploadPackage;
|
||||
|
||||
/** The next upload time. */
|
||||
@property(nullable, nonatomic) GDTClock *nextUploadTime;
|
||||
|
||||
/** Creates and/or returns the singleton instance of this class.
|
||||
*
|
||||
* @return The singleton instance of this class.
|
||||
*/
|
||||
+ (instancetype)sharedInstance;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
+128
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright 2019 Google
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* Automatically generated nanopb constant definitions */
|
||||
/* Generated by nanopb-0.3.9.2 */
|
||||
|
||||
#include "cct.nanopb.h"
|
||||
|
||||
/* @@protoc_insertion_point(includes) */
|
||||
#if PB_PROTO_HEADER_VERSION != 30
|
||||
#error Regenerate this file with the current version of nanopb generator.
|
||||
#endif
|
||||
|
||||
const gdt_cct_NetworkConnectionInfo_NetworkType gdt_cct_NetworkConnectionInfo_network_type_default = gdt_cct_NetworkConnectionInfo_NetworkType_NONE;
|
||||
const gdt_cct_NetworkConnectionInfo_MobileSubtype gdt_cct_NetworkConnectionInfo_mobile_subtype_default = gdt_cct_NetworkConnectionInfo_MobileSubtype_UNKNOWN_MOBILE_SUBTYPE;
|
||||
const gdt_cct_QosTierConfiguration_QosTier gdt_cct_LogRequest_qos_tier_default = gdt_cct_QosTierConfiguration_QosTier_DEFAULT;
|
||||
const int32_t gdt_cct_QosTierConfiguration_log_source_default = 0;
|
||||
|
||||
|
||||
const pb_field_t gdt_cct_LogEvent_fields[7] = {
|
||||
PB_FIELD( 1, INT64 , OPTIONAL, STATIC , FIRST, gdt_cct_LogEvent, event_time_ms, event_time_ms, 0),
|
||||
PB_FIELD( 6, BYTES , OPTIONAL, POINTER , OTHER, gdt_cct_LogEvent, source_extension, event_time_ms, 0),
|
||||
PB_FIELD( 11, INT32 , OPTIONAL, STATIC , OTHER, gdt_cct_LogEvent, event_code, source_extension, 0),
|
||||
PB_FIELD( 15, SINT64 , OPTIONAL, STATIC , OTHER, gdt_cct_LogEvent, timezone_offset_seconds, event_code, 0),
|
||||
PB_FIELD( 17, INT64 , OPTIONAL, STATIC , OTHER, gdt_cct_LogEvent, event_uptime_ms, timezone_offset_seconds, 0),
|
||||
PB_FIELD( 23, MESSAGE , OPTIONAL, STATIC , OTHER, gdt_cct_LogEvent, network_connection_info, event_uptime_ms, &gdt_cct_NetworkConnectionInfo_fields),
|
||||
PB_LAST_FIELD
|
||||
};
|
||||
|
||||
const pb_field_t gdt_cct_NetworkConnectionInfo_fields[3] = {
|
||||
PB_FIELD( 1, ENUM , OPTIONAL, STATIC , FIRST, gdt_cct_NetworkConnectionInfo, network_type, network_type, &gdt_cct_NetworkConnectionInfo_network_type_default),
|
||||
PB_FIELD( 2, UENUM , OPTIONAL, STATIC , OTHER, gdt_cct_NetworkConnectionInfo, mobile_subtype, network_type, &gdt_cct_NetworkConnectionInfo_mobile_subtype_default),
|
||||
PB_LAST_FIELD
|
||||
};
|
||||
|
||||
const pb_field_t gdt_cct_IosClientInfo_fields[8] = {
|
||||
PB_FIELD( 3, BYTES , OPTIONAL, POINTER , FIRST, gdt_cct_IosClientInfo, os_major_version, os_major_version, 0),
|
||||
PB_FIELD( 4, BYTES , OPTIONAL, POINTER , OTHER, gdt_cct_IosClientInfo, os_full_version, os_major_version, 0),
|
||||
PB_FIELD( 5, BYTES , OPTIONAL, POINTER , OTHER, gdt_cct_IosClientInfo, application_build, os_full_version, 0),
|
||||
PB_FIELD( 6, BYTES , OPTIONAL, POINTER , OTHER, gdt_cct_IosClientInfo, country, application_build, 0),
|
||||
PB_FIELD( 7, BYTES , OPTIONAL, POINTER , OTHER, gdt_cct_IosClientInfo, model, country, 0),
|
||||
PB_FIELD( 8, BYTES , OPTIONAL, POINTER , OTHER, gdt_cct_IosClientInfo, language_code, model, 0),
|
||||
PB_FIELD( 11, BYTES , OPTIONAL, POINTER , OTHER, gdt_cct_IosClientInfo, application_bundle_id, language_code, 0),
|
||||
PB_LAST_FIELD
|
||||
};
|
||||
|
||||
const pb_field_t gdt_cct_ClientInfo_fields[3] = {
|
||||
PB_FIELD( 1, UENUM , OPTIONAL, STATIC , FIRST, gdt_cct_ClientInfo, client_type, client_type, 0),
|
||||
PB_FIELD( 4, MESSAGE , OPTIONAL, STATIC , OTHER, gdt_cct_ClientInfo, ios_client_info, client_type, &gdt_cct_IosClientInfo_fields),
|
||||
PB_LAST_FIELD
|
||||
};
|
||||
|
||||
const pb_field_t gdt_cct_BatchedLogRequest_fields[2] = {
|
||||
PB_FIELD( 1, MESSAGE , REPEATED, POINTER , FIRST, gdt_cct_BatchedLogRequest, log_request, log_request, &gdt_cct_LogRequest_fields),
|
||||
PB_LAST_FIELD
|
||||
};
|
||||
|
||||
const pb_field_t gdt_cct_LogRequest_fields[7] = {
|
||||
PB_FIELD( 1, MESSAGE , OPTIONAL, STATIC , FIRST, gdt_cct_LogRequest, client_info, client_info, &gdt_cct_ClientInfo_fields),
|
||||
PB_FIELD( 2, INT32 , OPTIONAL, STATIC , OTHER, gdt_cct_LogRequest, log_source, client_info, 0),
|
||||
PB_FIELD( 3, MESSAGE , REPEATED, POINTER , OTHER, gdt_cct_LogRequest, log_event, log_source, &gdt_cct_LogEvent_fields),
|
||||
PB_FIELD( 4, INT64 , OPTIONAL, STATIC , OTHER, gdt_cct_LogRequest, request_time_ms, log_event, 0),
|
||||
PB_FIELD( 8, INT64 , OPTIONAL, STATIC , OTHER, gdt_cct_LogRequest, request_uptime_ms, request_time_ms, 0),
|
||||
PB_FIELD( 9, UENUM , OPTIONAL, STATIC , OTHER, gdt_cct_LogRequest, qos_tier, request_uptime_ms, &gdt_cct_LogRequest_qos_tier_default),
|
||||
PB_LAST_FIELD
|
||||
};
|
||||
|
||||
const pb_field_t gdt_cct_QosTierConfiguration_fields[3] = {
|
||||
PB_FIELD( 2, UENUM , OPTIONAL, STATIC , FIRST, gdt_cct_QosTierConfiguration, qos_tier, qos_tier, 0),
|
||||
PB_FIELD( 3, INT32 , OPTIONAL, STATIC , OTHER, gdt_cct_QosTierConfiguration, log_source, qos_tier, &gdt_cct_QosTierConfiguration_log_source_default),
|
||||
PB_LAST_FIELD
|
||||
};
|
||||
|
||||
const pb_field_t gdt_cct_QosTiersOverride_fields[3] = {
|
||||
PB_FIELD( 1, MESSAGE , REPEATED, POINTER , FIRST, gdt_cct_QosTiersOverride, qos_tier_configuration, qos_tier_configuration, &gdt_cct_QosTierConfiguration_fields),
|
||||
PB_FIELD( 2, INT64 , OPTIONAL, STATIC , OTHER, gdt_cct_QosTiersOverride, qos_tier_fingerprint, qos_tier_configuration, 0),
|
||||
PB_LAST_FIELD
|
||||
};
|
||||
|
||||
const pb_field_t gdt_cct_LogResponse_fields[3] = {
|
||||
PB_FIELD( 1, INT64 , OPTIONAL, STATIC , FIRST, gdt_cct_LogResponse, next_request_wait_millis, next_request_wait_millis, 0),
|
||||
PB_FIELD( 3, MESSAGE , OPTIONAL, STATIC , OTHER, gdt_cct_LogResponse, qos_tier, next_request_wait_millis, &gdt_cct_QosTiersOverride_fields),
|
||||
PB_LAST_FIELD
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* Check that field information fits in pb_field_t */
|
||||
#if !defined(PB_FIELD_32BIT)
|
||||
/* If you get an error here, it means that you need to define PB_FIELD_32BIT
|
||||
* compile-time option. You can do that in pb.h or on compiler command line.
|
||||
*
|
||||
* The reason you need to do this is that some of your messages contain tag
|
||||
* numbers or field sizes that are larger than what can fit in 8 or 16 bit
|
||||
* field descriptors.
|
||||
*/
|
||||
PB_STATIC_ASSERT((pb_membersize(gdt_cct_LogEvent, network_connection_info) < 65536 && pb_membersize(gdt_cct_ClientInfo, ios_client_info) < 65536 && pb_membersize(gdt_cct_LogRequest, client_info) < 65536 && pb_membersize(gdt_cct_LogResponse, qos_tier) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_gdt_cct_LogEvent_gdt_cct_NetworkConnectionInfo_gdt_cct_IosClientInfo_gdt_cct_ClientInfo_gdt_cct_BatchedLogRequest_gdt_cct_LogRequest_gdt_cct_QosTierConfiguration_gdt_cct_QosTiersOverride_gdt_cct_LogResponse)
|
||||
#endif
|
||||
|
||||
#if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT)
|
||||
/* If you get an error here, it means that you need to define PB_FIELD_16BIT
|
||||
* compile-time option. You can do that in pb.h or on compiler command line.
|
||||
*
|
||||
* The reason you need to do this is that some of your messages contain tag
|
||||
* numbers or field sizes that are larger than what can fit in the default
|
||||
* 8 bit descriptors.
|
||||
*/
|
||||
PB_STATIC_ASSERT((pb_membersize(gdt_cct_LogEvent, network_connection_info) < 256 && pb_membersize(gdt_cct_ClientInfo, ios_client_info) < 256 && pb_membersize(gdt_cct_LogRequest, client_info) < 256 && pb_membersize(gdt_cct_LogResponse, qos_tier) < 256), YOU_MUST_DEFINE_PB_FIELD_16BIT_FOR_MESSAGES_gdt_cct_LogEvent_gdt_cct_NetworkConnectionInfo_gdt_cct_IosClientInfo_gdt_cct_ClientInfo_gdt_cct_BatchedLogRequest_gdt_cct_LogRequest_gdt_cct_QosTierConfiguration_gdt_cct_QosTiersOverride_gdt_cct_LogResponse)
|
||||
#endif
|
||||
|
||||
|
||||
/* @@protoc_insertion_point(eof) */
|
||||
+281
@@ -0,0 +1,281 @@
|
||||
/*
|
||||
* Copyright 2019 Google
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* Automatically generated nanopb header */
|
||||
/* Generated by nanopb-0.3.9.2 */
|
||||
|
||||
#ifndef PB_GDT_CCT_CCT_NANOPB_H_INCLUDED
|
||||
#define PB_GDT_CCT_CCT_NANOPB_H_INCLUDED
|
||||
#include <nanopb/pb.h>
|
||||
|
||||
/* @@protoc_insertion_point(includes) */
|
||||
#if PB_PROTO_HEADER_VERSION != 30
|
||||
#error Regenerate this file with the current version of nanopb generator.
|
||||
#endif
|
||||
|
||||
|
||||
/* Enum definitions */
|
||||
typedef enum _gdt_cct_NetworkConnectionInfo_NetworkType {
|
||||
gdt_cct_NetworkConnectionInfo_NetworkType_NONE = -1,
|
||||
gdt_cct_NetworkConnectionInfo_NetworkType_MOBILE = 0,
|
||||
gdt_cct_NetworkConnectionInfo_NetworkType_WIFI = 1,
|
||||
gdt_cct_NetworkConnectionInfo_NetworkType_MOBILE_MMS = 2,
|
||||
gdt_cct_NetworkConnectionInfo_NetworkType_MOBILE_SUPL = 3,
|
||||
gdt_cct_NetworkConnectionInfo_NetworkType_MOBILE_DUN = 4,
|
||||
gdt_cct_NetworkConnectionInfo_NetworkType_MOBILE_HIPRI = 5,
|
||||
gdt_cct_NetworkConnectionInfo_NetworkType_WIMAX = 6,
|
||||
gdt_cct_NetworkConnectionInfo_NetworkType_BLUETOOTH = 7,
|
||||
gdt_cct_NetworkConnectionInfo_NetworkType_DUMMY = 8,
|
||||
gdt_cct_NetworkConnectionInfo_NetworkType_ETHERNET = 9,
|
||||
gdt_cct_NetworkConnectionInfo_NetworkType_MOBILE_FOTA = 10,
|
||||
gdt_cct_NetworkConnectionInfo_NetworkType_MOBILE_IMS = 11,
|
||||
gdt_cct_NetworkConnectionInfo_NetworkType_MOBILE_CBS = 12,
|
||||
gdt_cct_NetworkConnectionInfo_NetworkType_WIFI_P2P = 13,
|
||||
gdt_cct_NetworkConnectionInfo_NetworkType_MOBILE_IA = 14,
|
||||
gdt_cct_NetworkConnectionInfo_NetworkType_MOBILE_EMERGENCY = 15,
|
||||
gdt_cct_NetworkConnectionInfo_NetworkType_PROXY = 16,
|
||||
gdt_cct_NetworkConnectionInfo_NetworkType_VPN = 17
|
||||
} gdt_cct_NetworkConnectionInfo_NetworkType;
|
||||
#define _gdt_cct_NetworkConnectionInfo_NetworkType_MIN gdt_cct_NetworkConnectionInfo_NetworkType_NONE
|
||||
#define _gdt_cct_NetworkConnectionInfo_NetworkType_MAX gdt_cct_NetworkConnectionInfo_NetworkType_VPN
|
||||
#define _gdt_cct_NetworkConnectionInfo_NetworkType_ARRAYSIZE ((gdt_cct_NetworkConnectionInfo_NetworkType)(gdt_cct_NetworkConnectionInfo_NetworkType_VPN+1))
|
||||
|
||||
typedef enum _gdt_cct_NetworkConnectionInfo_MobileSubtype {
|
||||
gdt_cct_NetworkConnectionInfo_MobileSubtype_UNKNOWN_MOBILE_SUBTYPE = 0,
|
||||
gdt_cct_NetworkConnectionInfo_MobileSubtype_GPRS = 1,
|
||||
gdt_cct_NetworkConnectionInfo_MobileSubtype_EDGE = 2,
|
||||
gdt_cct_NetworkConnectionInfo_MobileSubtype_UMTS = 3,
|
||||
gdt_cct_NetworkConnectionInfo_MobileSubtype_CDMA = 4,
|
||||
gdt_cct_NetworkConnectionInfo_MobileSubtype_EVDO_0 = 5,
|
||||
gdt_cct_NetworkConnectionInfo_MobileSubtype_EVDO_A = 6,
|
||||
gdt_cct_NetworkConnectionInfo_MobileSubtype_RTT = 7,
|
||||
gdt_cct_NetworkConnectionInfo_MobileSubtype_HSDPA = 8,
|
||||
gdt_cct_NetworkConnectionInfo_MobileSubtype_HSUPA = 9,
|
||||
gdt_cct_NetworkConnectionInfo_MobileSubtype_HSPA = 10,
|
||||
gdt_cct_NetworkConnectionInfo_MobileSubtype_IDEN = 11,
|
||||
gdt_cct_NetworkConnectionInfo_MobileSubtype_EVDO_B = 12,
|
||||
gdt_cct_NetworkConnectionInfo_MobileSubtype_LTE = 13,
|
||||
gdt_cct_NetworkConnectionInfo_MobileSubtype_EHRPD = 14,
|
||||
gdt_cct_NetworkConnectionInfo_MobileSubtype_HSPAP = 15,
|
||||
gdt_cct_NetworkConnectionInfo_MobileSubtype_GSM = 16,
|
||||
gdt_cct_NetworkConnectionInfo_MobileSubtype_TD_SCDMA = 17,
|
||||
gdt_cct_NetworkConnectionInfo_MobileSubtype_IWLAN = 18,
|
||||
gdt_cct_NetworkConnectionInfo_MobileSubtype_LTE_CA = 19,
|
||||
gdt_cct_NetworkConnectionInfo_MobileSubtype_COMBINED = 100
|
||||
} gdt_cct_NetworkConnectionInfo_MobileSubtype;
|
||||
#define _gdt_cct_NetworkConnectionInfo_MobileSubtype_MIN gdt_cct_NetworkConnectionInfo_MobileSubtype_UNKNOWN_MOBILE_SUBTYPE
|
||||
#define _gdt_cct_NetworkConnectionInfo_MobileSubtype_MAX gdt_cct_NetworkConnectionInfo_MobileSubtype_COMBINED
|
||||
#define _gdt_cct_NetworkConnectionInfo_MobileSubtype_ARRAYSIZE ((gdt_cct_NetworkConnectionInfo_MobileSubtype)(gdt_cct_NetworkConnectionInfo_MobileSubtype_COMBINED+1))
|
||||
|
||||
typedef enum _gdt_cct_ClientInfo_ClientType {
|
||||
gdt_cct_ClientInfo_ClientType_CLIENT_UNKNOWN = 0,
|
||||
gdt_cct_ClientInfo_ClientType_IOS_FIREBASE = 15
|
||||
} gdt_cct_ClientInfo_ClientType;
|
||||
#define _gdt_cct_ClientInfo_ClientType_MIN gdt_cct_ClientInfo_ClientType_CLIENT_UNKNOWN
|
||||
#define _gdt_cct_ClientInfo_ClientType_MAX gdt_cct_ClientInfo_ClientType_IOS_FIREBASE
|
||||
#define _gdt_cct_ClientInfo_ClientType_ARRAYSIZE ((gdt_cct_ClientInfo_ClientType)(gdt_cct_ClientInfo_ClientType_IOS_FIREBASE+1))
|
||||
|
||||
typedef enum _gdt_cct_QosTierConfiguration_QosTier {
|
||||
gdt_cct_QosTierConfiguration_QosTier_DEFAULT = 0,
|
||||
gdt_cct_QosTierConfiguration_QosTier_UNMETERED_ONLY = 1,
|
||||
gdt_cct_QosTierConfiguration_QosTier_UNMETERED_OR_DAILY = 2,
|
||||
gdt_cct_QosTierConfiguration_QosTier_FAST_IF_RADIO_AWAKE = 3,
|
||||
gdt_cct_QosTierConfiguration_QosTier_NEVER = 4
|
||||
} gdt_cct_QosTierConfiguration_QosTier;
|
||||
#define _gdt_cct_QosTierConfiguration_QosTier_MIN gdt_cct_QosTierConfiguration_QosTier_DEFAULT
|
||||
#define _gdt_cct_QosTierConfiguration_QosTier_MAX gdt_cct_QosTierConfiguration_QosTier_NEVER
|
||||
#define _gdt_cct_QosTierConfiguration_QosTier_ARRAYSIZE ((gdt_cct_QosTierConfiguration_QosTier)(gdt_cct_QosTierConfiguration_QosTier_NEVER+1))
|
||||
|
||||
/* Struct definitions */
|
||||
typedef struct _gdt_cct_BatchedLogRequest {
|
||||
pb_size_t log_request_count;
|
||||
struct _gdt_cct_LogRequest *log_request;
|
||||
/* @@protoc_insertion_point(struct:gdt_cct_BatchedLogRequest) */
|
||||
} gdt_cct_BatchedLogRequest;
|
||||
|
||||
typedef struct _gdt_cct_IosClientInfo {
|
||||
pb_bytes_array_t *os_major_version;
|
||||
pb_bytes_array_t *os_full_version;
|
||||
pb_bytes_array_t *application_build;
|
||||
pb_bytes_array_t *country;
|
||||
pb_bytes_array_t *model;
|
||||
pb_bytes_array_t *language_code;
|
||||
pb_bytes_array_t *application_bundle_id;
|
||||
/* @@protoc_insertion_point(struct:gdt_cct_IosClientInfo) */
|
||||
} gdt_cct_IosClientInfo;
|
||||
|
||||
typedef struct _gdt_cct_ClientInfo {
|
||||
bool has_client_type;
|
||||
gdt_cct_ClientInfo_ClientType client_type;
|
||||
bool has_ios_client_info;
|
||||
gdt_cct_IosClientInfo ios_client_info;
|
||||
/* @@protoc_insertion_point(struct:gdt_cct_ClientInfo) */
|
||||
} gdt_cct_ClientInfo;
|
||||
|
||||
typedef struct _gdt_cct_NetworkConnectionInfo {
|
||||
bool has_network_type;
|
||||
gdt_cct_NetworkConnectionInfo_NetworkType network_type;
|
||||
bool has_mobile_subtype;
|
||||
gdt_cct_NetworkConnectionInfo_MobileSubtype mobile_subtype;
|
||||
/* @@protoc_insertion_point(struct:gdt_cct_NetworkConnectionInfo) */
|
||||
} gdt_cct_NetworkConnectionInfo;
|
||||
|
||||
typedef struct _gdt_cct_QosTierConfiguration {
|
||||
bool has_qos_tier;
|
||||
gdt_cct_QosTierConfiguration_QosTier qos_tier;
|
||||
bool has_log_source;
|
||||
int32_t log_source;
|
||||
/* @@protoc_insertion_point(struct:gdt_cct_QosTierConfiguration) */
|
||||
} gdt_cct_QosTierConfiguration;
|
||||
|
||||
typedef struct _gdt_cct_QosTiersOverride {
|
||||
pb_size_t qos_tier_configuration_count;
|
||||
struct _gdt_cct_QosTierConfiguration *qos_tier_configuration;
|
||||
bool has_qos_tier_fingerprint;
|
||||
int64_t qos_tier_fingerprint;
|
||||
/* @@protoc_insertion_point(struct:gdt_cct_QosTiersOverride) */
|
||||
} gdt_cct_QosTiersOverride;
|
||||
|
||||
typedef struct _gdt_cct_LogEvent {
|
||||
bool has_event_time_ms;
|
||||
int64_t event_time_ms;
|
||||
pb_bytes_array_t *source_extension;
|
||||
bool has_event_code;
|
||||
int32_t event_code;
|
||||
bool has_timezone_offset_seconds;
|
||||
int64_t timezone_offset_seconds;
|
||||
bool has_event_uptime_ms;
|
||||
int64_t event_uptime_ms;
|
||||
bool has_network_connection_info;
|
||||
gdt_cct_NetworkConnectionInfo network_connection_info;
|
||||
/* @@protoc_insertion_point(struct:gdt_cct_LogEvent) */
|
||||
} gdt_cct_LogEvent;
|
||||
|
||||
typedef struct _gdt_cct_LogRequest {
|
||||
bool has_client_info;
|
||||
gdt_cct_ClientInfo client_info;
|
||||
bool has_log_source;
|
||||
int32_t log_source;
|
||||
pb_size_t log_event_count;
|
||||
struct _gdt_cct_LogEvent *log_event;
|
||||
bool has_request_time_ms;
|
||||
int64_t request_time_ms;
|
||||
bool has_request_uptime_ms;
|
||||
int64_t request_uptime_ms;
|
||||
bool has_qos_tier;
|
||||
gdt_cct_QosTierConfiguration_QosTier qos_tier;
|
||||
/* @@protoc_insertion_point(struct:gdt_cct_LogRequest) */
|
||||
} gdt_cct_LogRequest;
|
||||
|
||||
typedef struct _gdt_cct_LogResponse {
|
||||
bool has_next_request_wait_millis;
|
||||
int64_t next_request_wait_millis;
|
||||
bool has_qos_tier;
|
||||
gdt_cct_QosTiersOverride qos_tier;
|
||||
/* @@protoc_insertion_point(struct:gdt_cct_LogResponse) */
|
||||
} gdt_cct_LogResponse;
|
||||
|
||||
/* Default values for struct fields */
|
||||
extern const gdt_cct_NetworkConnectionInfo_NetworkType gdt_cct_NetworkConnectionInfo_network_type_default;
|
||||
extern const gdt_cct_NetworkConnectionInfo_MobileSubtype gdt_cct_NetworkConnectionInfo_mobile_subtype_default;
|
||||
extern const gdt_cct_QosTierConfiguration_QosTier gdt_cct_LogRequest_qos_tier_default;
|
||||
extern const int32_t gdt_cct_QosTierConfiguration_log_source_default;
|
||||
|
||||
/* Initializer values for message structs */
|
||||
#define gdt_cct_LogEvent_init_default {false, 0, NULL, false, 0, false, 0, false, 0, false, gdt_cct_NetworkConnectionInfo_init_default}
|
||||
#define gdt_cct_NetworkConnectionInfo_init_default {false, gdt_cct_NetworkConnectionInfo_NetworkType_NONE, false, gdt_cct_NetworkConnectionInfo_MobileSubtype_UNKNOWN_MOBILE_SUBTYPE}
|
||||
#define gdt_cct_IosClientInfo_init_default {NULL, NULL, NULL, NULL, NULL, NULL, NULL}
|
||||
#define gdt_cct_ClientInfo_init_default {false, _gdt_cct_ClientInfo_ClientType_MIN, false, gdt_cct_IosClientInfo_init_default}
|
||||
#define gdt_cct_BatchedLogRequest_init_default {0, NULL}
|
||||
#define gdt_cct_LogRequest_init_default {false, gdt_cct_ClientInfo_init_default, false, 0, 0, NULL, false, 0, false, 0, false, gdt_cct_QosTierConfiguration_QosTier_DEFAULT}
|
||||
#define gdt_cct_QosTierConfiguration_init_default {false, _gdt_cct_QosTierConfiguration_QosTier_MIN, false, 0}
|
||||
#define gdt_cct_QosTiersOverride_init_default {0, NULL, false, 0}
|
||||
#define gdt_cct_LogResponse_init_default {false, 0, false, gdt_cct_QosTiersOverride_init_default}
|
||||
#define gdt_cct_LogEvent_init_zero {false, 0, NULL, false, 0, false, 0, false, 0, false, gdt_cct_NetworkConnectionInfo_init_zero}
|
||||
#define gdt_cct_NetworkConnectionInfo_init_zero {false, _gdt_cct_NetworkConnectionInfo_NetworkType_MIN, false, _gdt_cct_NetworkConnectionInfo_MobileSubtype_MIN}
|
||||
#define gdt_cct_IosClientInfo_init_zero {NULL, NULL, NULL, NULL, NULL, NULL, NULL}
|
||||
#define gdt_cct_ClientInfo_init_zero {false, _gdt_cct_ClientInfo_ClientType_MIN, false, gdt_cct_IosClientInfo_init_zero}
|
||||
#define gdt_cct_BatchedLogRequest_init_zero {0, NULL}
|
||||
#define gdt_cct_LogRequest_init_zero {false, gdt_cct_ClientInfo_init_zero, false, 0, 0, NULL, false, 0, false, 0, false, _gdt_cct_QosTierConfiguration_QosTier_MIN}
|
||||
#define gdt_cct_QosTierConfiguration_init_zero {false, _gdt_cct_QosTierConfiguration_QosTier_MIN, false, 0}
|
||||
#define gdt_cct_QosTiersOverride_init_zero {0, NULL, false, 0}
|
||||
#define gdt_cct_LogResponse_init_zero {false, 0, false, gdt_cct_QosTiersOverride_init_zero}
|
||||
|
||||
/* Field tags (for use in manual encoding/decoding) */
|
||||
#define gdt_cct_BatchedLogRequest_log_request_tag 1
|
||||
#define gdt_cct_IosClientInfo_os_major_version_tag 3
|
||||
#define gdt_cct_IosClientInfo_os_full_version_tag 4
|
||||
#define gdt_cct_IosClientInfo_application_build_tag 5
|
||||
#define gdt_cct_IosClientInfo_country_tag 6
|
||||
#define gdt_cct_IosClientInfo_model_tag 7
|
||||
#define gdt_cct_IosClientInfo_language_code_tag 8
|
||||
#define gdt_cct_IosClientInfo_application_bundle_id_tag 11
|
||||
#define gdt_cct_ClientInfo_client_type_tag 1
|
||||
#define gdt_cct_ClientInfo_ios_client_info_tag 4
|
||||
#define gdt_cct_NetworkConnectionInfo_network_type_tag 1
|
||||
#define gdt_cct_NetworkConnectionInfo_mobile_subtype_tag 2
|
||||
#define gdt_cct_QosTierConfiguration_qos_tier_tag 2
|
||||
#define gdt_cct_QosTierConfiguration_log_source_tag 3
|
||||
#define gdt_cct_QosTiersOverride_qos_tier_configuration_tag 1
|
||||
#define gdt_cct_QosTiersOverride_qos_tier_fingerprint_tag 2
|
||||
#define gdt_cct_LogEvent_event_time_ms_tag 1
|
||||
#define gdt_cct_LogEvent_event_code_tag 11
|
||||
#define gdt_cct_LogEvent_event_uptime_ms_tag 17
|
||||
#define gdt_cct_LogEvent_source_extension_tag 6
|
||||
#define gdt_cct_LogEvent_timezone_offset_seconds_tag 15
|
||||
#define gdt_cct_LogEvent_network_connection_info_tag 23
|
||||
#define gdt_cct_LogRequest_request_time_ms_tag 4
|
||||
#define gdt_cct_LogRequest_request_uptime_ms_tag 8
|
||||
#define gdt_cct_LogRequest_client_info_tag 1
|
||||
#define gdt_cct_LogRequest_log_source_tag 2
|
||||
#define gdt_cct_LogRequest_log_event_tag 3
|
||||
#define gdt_cct_LogRequest_qos_tier_tag 9
|
||||
#define gdt_cct_LogResponse_next_request_wait_millis_tag 1
|
||||
#define gdt_cct_LogResponse_qos_tier_tag 3
|
||||
|
||||
/* Struct field encoding specification for nanopb */
|
||||
extern const pb_field_t gdt_cct_LogEvent_fields[7];
|
||||
extern const pb_field_t gdt_cct_NetworkConnectionInfo_fields[3];
|
||||
extern const pb_field_t gdt_cct_IosClientInfo_fields[8];
|
||||
extern const pb_field_t gdt_cct_ClientInfo_fields[3];
|
||||
extern const pb_field_t gdt_cct_BatchedLogRequest_fields[2];
|
||||
extern const pb_field_t gdt_cct_LogRequest_fields[7];
|
||||
extern const pb_field_t gdt_cct_QosTierConfiguration_fields[3];
|
||||
extern const pb_field_t gdt_cct_QosTiersOverride_fields[3];
|
||||
extern const pb_field_t gdt_cct_LogResponse_fields[3];
|
||||
|
||||
/* Maximum encoded size of messages (where known) */
|
||||
/* gdt_cct_LogEvent_size depends on runtime parameters */
|
||||
#define gdt_cct_NetworkConnectionInfo_size 13
|
||||
/* gdt_cct_IosClientInfo_size depends on runtime parameters */
|
||||
/* gdt_cct_ClientInfo_size depends on runtime parameters */
|
||||
/* gdt_cct_BatchedLogRequest_size depends on runtime parameters */
|
||||
/* gdt_cct_LogRequest_size depends on runtime parameters */
|
||||
#define gdt_cct_QosTierConfiguration_size 13
|
||||
/* gdt_cct_QosTiersOverride_size depends on runtime parameters */
|
||||
/* gdt_cct_LogResponse_size depends on runtime parameters */
|
||||
|
||||
/* Message IDs (where set with "msgid" option) */
|
||||
#ifdef PB_MSGID
|
||||
|
||||
#define CCT_MESSAGES \
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
/* @@protoc_insertion_point(eof) */
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user