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 "FirebaseRemoteConfig/Sources/RCNConfigExperiment.h"
18
 
19
#import "FirebaseABTesting/Sources/Private/FirebaseABTestingInternal.h"
20
#import "FirebaseCore/Sources/Private/FirebaseCoreInternal.h"
21
#import "FirebaseRemoteConfig/Sources/RCNConfigDBManager.h"
22
#import "FirebaseRemoteConfig/Sources/RCNConfigDefines.h"
23
 
24
static NSString *const kExperimentMetadataKeyLastStartTime = @"last_experiment_start_time";
25
 
26
static NSString *const kServiceOrigin = @"frc";
27
static NSString *const kMethodNameLatestStartTime =
28
    @"latestExperimentStartTimestampBetweenTimestamp:andPayloads:";
29
 
30
@interface RCNConfigExperiment ()
31
@property(nonatomic, strong)
32
    NSMutableArray<NSData *> *experimentPayloads;  ///< Experiment payloads.
33
@property(nonatomic, strong)
34
    NSMutableDictionary<NSString *, id> *experimentMetadata;  ///< Experiment metadata
35
@property(nonatomic, strong) RCNConfigDBManager *DBManager;   ///< Database Manager.
36
@property(nonatomic, strong) FIRExperimentController *experimentController;
37
@property(nonatomic, strong) NSDateFormatter *experimentStartTimeDateFormatter;
38
@end
39
 
40
@implementation RCNConfigExperiment
41
/// Designated initializer
42
- (instancetype)initWithDBManager:(RCNConfigDBManager *)DBManager
43
             experimentController:(FIRExperimentController *)controller {
44
  self = [super init];
45
  if (self) {
46
    _experimentPayloads = [[NSMutableArray alloc] init];
47
    _experimentMetadata = [[NSMutableDictionary alloc] init];
48
    _experimentStartTimeDateFormatter = [[NSDateFormatter alloc] init];
49
    [_experimentStartTimeDateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"];
50
    [_experimentStartTimeDateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];
51
    // Locale needs to be hardcoded. See
52
    // https://developer.apple.com/library/ios/#qa/qa1480/_index.html for more details.
53
    [_experimentStartTimeDateFormatter
54
        setLocale:[[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"]];
55
    [_experimentStartTimeDateFormatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"UTC"]];
56
 
57
    _DBManager = DBManager;
58
    _experimentController = controller;
59
    [self loadExperimentFromTable];
60
  }
61
  return self;
62
}
63
 
64
- (void)loadExperimentFromTable {
65
  if (!_DBManager) {
66
    return;
67
  }
68
  __weak RCNConfigExperiment *weakSelf = self;
69
  RCNDBCompletion completionHandler = ^(BOOL success, NSDictionary<NSString *, id> *result) {
70
    RCNConfigExperiment *strongSelf = weakSelf;
71
    if (strongSelf == nil) {
72
      return;
73
    }
74
    if (result[@RCNExperimentTableKeyPayload]) {
75
      [strongSelf->_experimentPayloads removeAllObjects];
76
      for (NSData *experiment in result[@RCNExperimentTableKeyPayload]) {
77
        NSError *error;
78
        id experimentPayloadJSON = [NSJSONSerialization JSONObjectWithData:experiment
79
                                                                   options:kNilOptions
80
                                                                     error:&error];
81
        if (!experimentPayloadJSON || error) {
82
          FIRLogWarning(kFIRLoggerRemoteConfig, @"I-RCN000031",
83
                        @"Experiment payload could not be parsed as JSON.");
84
        } else {
85
          [strongSelf->_experimentPayloads addObject:experiment];
86
        }
87
      }
88
    }
89
    if (result[@RCNExperimentTableKeyMetadata]) {
90
      strongSelf->_experimentMetadata = [result[@RCNExperimentTableKeyMetadata] mutableCopy];
91
    }
92
  };
93
  [_DBManager loadExperimentWithCompletionHandler:completionHandler];
94
}
95
 
96
- (void)updateExperimentsWithResponse:(NSArray<NSDictionary<NSString *, id> *> *)response {
97
  // cache fetched experiment payloads.
98
  [_experimentPayloads removeAllObjects];
99
  [_DBManager deleteExperimentTableForKey:@RCNExperimentTableKeyPayload];
100
 
101
  for (NSDictionary<NSString *, id> *experiment in response) {
102
    NSError *error;
103
    NSData *JSONPayload = [NSJSONSerialization dataWithJSONObject:experiment
104
                                                          options:kNilOptions
105
                                                            error:&error];
106
    if (!JSONPayload || error) {
107
      FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000030",
108
                  @"Invalid experiment payload to be serialized.");
109
    } else {
110
      [_experimentPayloads addObject:JSONPayload];
111
      [_DBManager insertExperimentTableWithKey:@RCNExperimentTableKeyPayload
112
                                         value:JSONPayload
113
                             completionHandler:nil];
114
    }
115
  }
116
}
117
 
118
- (void)updateExperimentsWithHandler:(void (^)(NSError *_Nullable))handler {
119
  FIRLifecycleEvents *lifecycleEvent = [[FIRLifecycleEvents alloc] init];
120
 
121
  // Get the last experiment start time prior to the latest payload.
122
  NSTimeInterval lastStartTime =
123
      [_experimentMetadata[kExperimentMetadataKeyLastStartTime] doubleValue];
124
 
125
  // Update the last experiment start time with the latest payload.
126
  [self updateExperimentStartTime];
127
  [self.experimentController
128
      updateExperimentsWithServiceOrigin:kServiceOrigin
129
                                  events:lifecycleEvent
130
                                  policy:ABTExperimentPayloadExperimentOverflowPolicyDiscardOldest
131
                           lastStartTime:lastStartTime
132
                                payloads:_experimentPayloads
133
                       completionHandler:handler];
134
}
135
 
136
- (void)updateExperimentStartTime {
137
  NSTimeInterval existingLastStartTime =
138
      [_experimentMetadata[kExperimentMetadataKeyLastStartTime] doubleValue];
139
 
140
  NSTimeInterval latestStartTime =
141
      [self latestStartTimeWithExistingLastStartTime:existingLastStartTime];
142
 
143
  _experimentMetadata[kExperimentMetadataKeyLastStartTime] = @(latestStartTime);
144
 
145
  if (![NSJSONSerialization isValidJSONObject:_experimentMetadata]) {
146
    FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000028",
147
                @"Invalid fetched experiment metadata to be serialized.");
148
    return;
149
  }
150
  NSError *error;
151
  NSData *serializedExperimentMetadata =
152
      [NSJSONSerialization dataWithJSONObject:_experimentMetadata
153
                                      options:NSJSONWritingPrettyPrinted
154
                                        error:&error];
155
  [_DBManager insertExperimentTableWithKey:@RCNExperimentTableKeyMetadata
156
                                     value:serializedExperimentMetadata
157
                         completionHandler:nil];
158
}
159
 
160
- (NSTimeInterval)latestStartTimeWithExistingLastStartTime:(NSTimeInterval)existingLastStartTime {
161
  return [self.experimentController
162
      latestExperimentStartTimestampBetweenTimestamp:existingLastStartTime
163
                                         andPayloads:_experimentPayloads];
164
}
165
@end