Proyectos de Subversion Iphone Microlearning

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
/*
2
 * Copyright 2019 Google
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *      http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
 
17
#import "GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTNanopbHelpers.h"
18
 
19
#if TARGET_OS_IOS || TARGET_OS_TV
20
#import <UIKit/UIKit.h>
21
#elif TARGET_OS_OSX
22
#import <AppKit/AppKit.h>
23
#endif  // TARGET_OS_IOS || TARGET_OS_TV
24
 
25
#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORPlatform.h"
26
#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORClock.h"
27
#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORConsoleLogger.h"
28
#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREvent.h"
29
 
30
#import <nanopb/pb.h>
31
#import <nanopb/pb_decode.h>
32
#import <nanopb/pb_encode.h>
33
 
34
#import "GoogleDataTransport/GDTCCTLibrary/Public/GDTCOREvent+GDTCCTSupport.h"
35
 
36
#pragma mark - General purpose encoders
37
 
38
pb_bytes_array_t *GDTCCTEncodeString(NSString *string) {
39
  NSData *stringBytes = [string dataUsingEncoding:NSUTF8StringEncoding];
40
  return GDTCCTEncodeData(stringBytes);
41
}
42
 
43
pb_bytes_array_t *GDTCCTEncodeData(NSData *data) {
44
  pb_bytes_array_t *pbBytesArray = calloc(1, PB_BYTES_ARRAY_T_ALLOCSIZE(data.length));
45
  if (pbBytesArray != NULL) {
46
    [data getBytes:pbBytesArray->bytes length:data.length];
47
    pbBytesArray->size = (pb_size_t)data.length;
48
  }
49
  return pbBytesArray;
50
}
51
 
52
#pragma mark - CCT object constructors
53
 
54
NSData *_Nullable GDTCCTEncodeBatchedLogRequest(gdt_cct_BatchedLogRequest *batchedLogRequest) {
55
  pb_ostream_t sizestream = PB_OSTREAM_SIZING;
56
  // Encode 1 time to determine the size.
57
  if (!pb_encode(&sizestream, gdt_cct_BatchedLogRequest_fields, batchedLogRequest)) {
58
    GDTCORLogError(GDTCORMCEGeneralError, @"Error in nanopb encoding for size: %s",
59
                   PB_GET_ERROR(&sizestream));
60
  }
61
 
62
  // Encode a 2nd time to actually get the bytes from it.
63
  size_t bufferSize = sizestream.bytes_written;
64
  CFMutableDataRef dataRef = CFDataCreateMutable(CFAllocatorGetDefault(), bufferSize);
65
  CFDataSetLength(dataRef, bufferSize);
66
  pb_ostream_t ostream = pb_ostream_from_buffer((void *)CFDataGetBytePtr(dataRef), bufferSize);
67
  if (!pb_encode(&ostream, gdt_cct_BatchedLogRequest_fields, batchedLogRequest)) {
68
    GDTCORLogError(GDTCORMCEGeneralError, @"Error in nanopb encoding for bytes: %s",
69
                   PB_GET_ERROR(&ostream));
70
  }
71
 
72
  return CFBridgingRelease(dataRef);
73
}
74
 
75
gdt_cct_BatchedLogRequest GDTCCTConstructBatchedLogRequest(
76
    NSDictionary<NSString *, NSSet<GDTCOREvent *> *> *logMappingIDToLogSet) {
77
  gdt_cct_BatchedLogRequest batchedLogRequest = gdt_cct_BatchedLogRequest_init_default;
78
  NSUInteger numberOfLogRequests = logMappingIDToLogSet.count;
79
  gdt_cct_LogRequest *logRequests = calloc(numberOfLogRequests, sizeof(gdt_cct_LogRequest));
80
  if (logRequests == NULL) {
81
    return batchedLogRequest;
82
  }
83
 
84
  __block int i = 0;
85
  [logMappingIDToLogSet enumerateKeysAndObjectsUsingBlock:^(NSString *_Nonnull logMappingID,
86
                                                            NSSet<GDTCOREvent *> *_Nonnull logSet,
87
                                                            BOOL *_Nonnull stop) {
88
    int32_t logSource = [logMappingID intValue];
89
    gdt_cct_LogRequest logRequest = GDTCCTConstructLogRequest(logSource, logSet);
90
    logRequests[i] = logRequest;
91
    i++;
92
  }];
93
 
94
  batchedLogRequest.log_request = logRequests;
95
  batchedLogRequest.log_request_count = (pb_size_t)numberOfLogRequests;
96
  return batchedLogRequest;
97
}
98
 
99
gdt_cct_LogRequest GDTCCTConstructLogRequest(int32_t logSource,
100
                                             NSSet<GDTCOREvent *> *_Nonnull logSet) {
101
  if (logSet.count == 0) {
102
    GDTCORLogError(GDTCORMCEGeneralError, @"%@",
103
                   @"An empty event set can't be serialized to proto.");
104
    gdt_cct_LogRequest logRequest = gdt_cct_LogRequest_init_default;
105
    return logRequest;
106
  }
107
  gdt_cct_LogRequest logRequest = gdt_cct_LogRequest_init_default;
108
  logRequest.log_source = logSource;
109
  logRequest.has_log_source = 1;
110
  logRequest.client_info = GDTCCTConstructClientInfo();
111
  logRequest.has_client_info = 1;
112
  logRequest.log_event = calloc(logSet.count, sizeof(gdt_cct_LogEvent));
113
  if (logRequest.log_event == NULL) {
114
    return logRequest;
115
  }
116
  int i = 0;
117
  for (GDTCOREvent *log in logSet) {
118
    gdt_cct_LogEvent logEvent = GDTCCTConstructLogEvent(log);
119
    logRequest.log_event[i] = logEvent;
120
    i++;
121
  }
122
  logRequest.log_event_count = (pb_size_t)logSet.count;
123
 
124
  GDTCORClock *currentTime = [GDTCORClock snapshot];
125
  logRequest.request_time_ms = currentTime.timeMillis;
126
  logRequest.has_request_time_ms = 1;
127
  logRequest.request_uptime_ms = [currentTime uptimeMilliseconds];
128
  logRequest.has_request_uptime_ms = 1;
129
 
130
  return logRequest;
131
}
132
 
133
gdt_cct_LogEvent GDTCCTConstructLogEvent(GDTCOREvent *event) {
134
  gdt_cct_LogEvent logEvent = gdt_cct_LogEvent_init_default;
135
  logEvent.event_time_ms = event.clockSnapshot.timeMillis;
136
  logEvent.has_event_time_ms = 1;
137
  logEvent.event_uptime_ms = [event.clockSnapshot uptimeMilliseconds];
138
  logEvent.has_event_uptime_ms = 1;
139
  logEvent.timezone_offset_seconds = event.clockSnapshot.timezoneOffsetSeconds;
140
  logEvent.has_timezone_offset_seconds = 1;
141
  if (event.customBytes) {
142
    NSData *networkConnectionInfoData = event.networkConnectionInfoData;
143
    if (networkConnectionInfoData) {
144
      [networkConnectionInfoData getBytes:&logEvent.network_connection_info
145
                                   length:networkConnectionInfoData.length];
146
      logEvent.has_network_connection_info = 1;
147
    }
148
    NSNumber *eventCode = event.eventCode;
149
    if (eventCode != nil) {
150
      logEvent.has_event_code = 1;
151
      logEvent.event_code = [eventCode intValue];
152
    }
153
  }
154
  NSError *error;
155
  NSData *extensionBytes;
156
  extensionBytes = event.serializedDataObjectBytes;
157
  if (error) {
158
    GDTCORLogWarning(GDTCORMCWFileReadError,
159
                     @"There was an error reading extension bytes from disk: %@", error);
160
    return logEvent;
161
  }
162
  logEvent.source_extension = GDTCCTEncodeData(extensionBytes);  // read bytes from the file.
163
  return logEvent;
164
}
165
 
166
gdt_cct_ClientInfo GDTCCTConstructClientInfo() {
167
  gdt_cct_ClientInfo clientInfo = gdt_cct_ClientInfo_init_default;
168
  clientInfo.client_type = gdt_cct_ClientInfo_ClientType_IOS_FIREBASE;
169
  clientInfo.has_client_type = 1;
170
#if TARGET_OS_IOS || TARGET_OS_TV
171
  clientInfo.ios_client_info = GDTCCTConstructiOSClientInfo();
172
  clientInfo.has_ios_client_info = 1;
173
#elif TARGET_OS_OSX
174
  // TODO(mikehaney24): Expand the proto to include macOS client info.
175
#endif
176
  return clientInfo;
177
}
178
 
179
gdt_cct_IosClientInfo GDTCCTConstructiOSClientInfo() {
180
  gdt_cct_IosClientInfo iOSClientInfo = gdt_cct_IosClientInfo_init_default;
181
#if TARGET_OS_IOS || TARGET_OS_TV
182
  UIDevice *device = [UIDevice currentDevice];
183
  NSBundle *bundle = [NSBundle mainBundle];
184
  NSLocale *locale = [NSLocale currentLocale];
185
  iOSClientInfo.os_full_version = GDTCCTEncodeString(device.systemVersion);
186
  NSArray *versionComponents = [device.systemVersion componentsSeparatedByString:@"."];
187
  iOSClientInfo.os_major_version = GDTCCTEncodeString(versionComponents[0]);
188
  NSString *version = [bundle objectForInfoDictionaryKey:(NSString *)kCFBundleVersionKey];
189
  if (version) {
190
    iOSClientInfo.application_build = GDTCCTEncodeString(version);
191
  }
192
  NSString *countryCode = [locale objectForKey:NSLocaleCountryCode];
193
  if (countryCode) {
194
    iOSClientInfo.country = GDTCCTEncodeString([locale objectForKey:NSLocaleCountryCode]);
195
  }
196
  iOSClientInfo.model = GDTCCTEncodeString(GDTCORDeviceModel());
197
  NSString *languageCode = bundle.preferredLocalizations.firstObject;
198
  iOSClientInfo.language_code =
199
      languageCode ? GDTCCTEncodeString(languageCode) : GDTCCTEncodeString(@"en");
200
  iOSClientInfo.application_bundle_id = GDTCCTEncodeString(bundle.bundleIdentifier);
201
#endif
202
  return iOSClientInfo;
203
}
204
 
205
NSData *GDTCCTConstructNetworkConnectionInfoData() {
206
  gdt_cct_NetworkConnectionInfo networkConnectionInfo = gdt_cct_NetworkConnectionInfo_init_default;
207
  NSInteger currentNetworkType = GDTCORNetworkTypeMessage();
208
  if (currentNetworkType) {
209
    networkConnectionInfo.has_network_type = 1;
210
    if (currentNetworkType == GDTCORNetworkTypeMobile) {
211
      networkConnectionInfo.network_type = gdt_cct_NetworkConnectionInfo_NetworkType_MOBILE;
212
      networkConnectionInfo.mobile_subtype = GDTCCTNetworkConnectionInfoNetworkMobileSubtype();
213
      if (networkConnectionInfo.mobile_subtype !=
214
          gdt_cct_NetworkConnectionInfo_MobileSubtype_UNKNOWN_MOBILE_SUBTYPE) {
215
        networkConnectionInfo.has_mobile_subtype = 1;
216
      }
217
    } else {
218
      networkConnectionInfo.network_type = gdt_cct_NetworkConnectionInfo_NetworkType_WIFI;
219
    }
220
  }
221
  NSData *networkConnectionInfoData = [NSData dataWithBytes:&networkConnectionInfo
222
                                                     length:sizeof(networkConnectionInfo)];
223
  return networkConnectionInfoData;
224
}
225
 
226
gdt_cct_NetworkConnectionInfo_MobileSubtype GDTCCTNetworkConnectionInfoNetworkMobileSubtype() {
227
  NSNumber *networkMobileSubtypeMessage = @(GDTCORNetworkMobileSubTypeMessage());
228
  if (!networkMobileSubtypeMessage.intValue) {
229
    return gdt_cct_NetworkConnectionInfo_MobileSubtype_UNKNOWN_MOBILE_SUBTYPE;
230
  }
231
  static NSDictionary<NSNumber *, NSNumber *> *MessageToNetworkSubTypeMessage;
232
  static dispatch_once_t onceToken;
233
  dispatch_once(&onceToken, ^{
234
    MessageToNetworkSubTypeMessage = @{
235
      @(GDTCORNetworkMobileSubtypeGPRS) : @(gdt_cct_NetworkConnectionInfo_MobileSubtype_GPRS),
236
      @(GDTCORNetworkMobileSubtypeEdge) : @(gdt_cct_NetworkConnectionInfo_MobileSubtype_EDGE),
237
      @(GDTCORNetworkMobileSubtypeWCDMA) :
238
          @(gdt_cct_NetworkConnectionInfo_MobileSubtype_UNKNOWN_MOBILE_SUBTYPE),
239
      @(GDTCORNetworkMobileSubtypeHSDPA) : @(gdt_cct_NetworkConnectionInfo_MobileSubtype_HSDPA),
240
      @(GDTCORNetworkMobileSubtypeHSUPA) : @(gdt_cct_NetworkConnectionInfo_MobileSubtype_HSUPA),
241
      @(GDTCORNetworkMobileSubtypeCDMA1x) : @(gdt_cct_NetworkConnectionInfo_MobileSubtype_CDMA),
242
      @(GDTCORNetworkMobileSubtypeCDMAEVDORev0) :
243
          @(gdt_cct_NetworkConnectionInfo_MobileSubtype_EVDO_0),
244
      @(GDTCORNetworkMobileSubtypeCDMAEVDORevA) :
245
          @(gdt_cct_NetworkConnectionInfo_MobileSubtype_EVDO_A),
246
      @(GDTCORNetworkMobileSubtypeCDMAEVDORevB) :
247
          @(gdt_cct_NetworkConnectionInfo_MobileSubtype_EVDO_B),
248
      @(GDTCORNetworkMobileSubtypeHRPD) : @(gdt_cct_NetworkConnectionInfo_MobileSubtype_EHRPD),
249
      @(GDTCORNetworkMobileSubtypeLTE) : @(gdt_cct_NetworkConnectionInfo_MobileSubtype_LTE),
250
    };
251
  });
252
  NSNumber *networkMobileSubtype = MessageToNetworkSubTypeMessage[networkMobileSubtypeMessage];
253
  return networkMobileSubtype.intValue;
254
}
255
 
256
#pragma mark - CCT Object decoders
257
 
258
gdt_cct_LogResponse GDTCCTDecodeLogResponse(NSData *data, NSError **error) {
259
  gdt_cct_LogResponse response = gdt_cct_LogResponse_init_default;
260
  pb_istream_t istream = pb_istream_from_buffer([data bytes], [data length]);
261
  if (!pb_decode(&istream, gdt_cct_LogResponse_fields, &response)) {
262
    NSString *nanopb_error = [NSString stringWithFormat:@"%s", PB_GET_ERROR(&istream)];
263
    NSDictionary *userInfo = @{@"nanopb error:" : nanopb_error};
264
    if (error != NULL) {
265
      *error = [NSError errorWithDomain:NSURLErrorDomain code:-1 userInfo:userInfo];
266
    }
267
    response = (gdt_cct_LogResponse)gdt_cct_LogResponse_init_default;
268
  }
269
  return response;
270
}