added iOS source code
[wl-app.git] / iOS / Pods / FirebaseMessaging / Firebase / Messaging / FIRMessagingTopicOperation.m
diff --git a/iOS/Pods/FirebaseMessaging/Firebase/Messaging/FIRMessagingTopicOperation.m b/iOS/Pods/FirebaseMessaging/Firebase/Messaging/FIRMessagingTopicOperation.m
new file mode 100644 (file)
index 0000000..6703178
--- /dev/null
@@ -0,0 +1,263 @@
+/*
+ * Copyright 2017 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 "FIRMessagingTopicOperation.h"
+
+#import "FIRMessagingCheckinService.h"
+#import "FIRMessagingDefines.h"
+#import "FIRMessagingLogger.h"
+#import "FIRMessagingUtilities.h"
+#import "NSError+FIRMessaging.h"
+
+#define DEBUG_LOG_SUBSCRIPTION_OPERATION_DURATIONS 0
+
+static NSString *const kFIRMessagingSubscribeServerHost =
+    @"https://iid.googleapis.com/iid/register";
+
+NSString *FIRMessagingSubscriptionsServer() {
+  static NSString *serverHost = nil;
+  static dispatch_once_t onceToken;
+  dispatch_once(&onceToken, ^{
+    NSDictionary *environment = [[NSProcessInfo processInfo] environment];
+    NSString *customServerHost = environment[@"FCM_SERVER_ENDPOINT"];
+    if (customServerHost.length) {
+      serverHost = customServerHost;
+    } else {
+      serverHost = kFIRMessagingSubscribeServerHost;
+    }
+  });
+  return serverHost;
+}
+
+@interface FIRMessagingTopicOperation () {
+  BOOL _isFinished;
+  BOOL _isExecuting;
+}
+
+@property(nonatomic, readwrite, copy) NSString *topic;
+@property(nonatomic, readwrite, assign) FIRMessagingTopicAction action;
+@property(nonatomic, readwrite, copy) NSString *token;
+@property(nonatomic, readwrite, copy) NSDictionary *options;
+@property(nonatomic, readwrite, strong) FIRMessagingCheckinService *checkinService;
+@property(nonatomic, readwrite, copy) FIRMessagingTopicOperationCompletion completion;
+
+@property(atomic, strong) NSURLSessionDataTask *dataTask;
+
+@end
+
+@implementation FIRMessagingTopicOperation
+
++ (NSURLSession *)sharedSession {
+  static NSURLSession *subscriptionOperationSharedSession;
+  static dispatch_once_t onceToken;
+  dispatch_once(&onceToken, ^{
+    NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
+    config.timeoutIntervalForResource = 60.0f;  // 1 minute
+    subscriptionOperationSharedSession = [NSURLSession sessionWithConfiguration:config];
+    subscriptionOperationSharedSession.sessionDescription = @"com.google.fcm.topics.session";
+  });
+  return subscriptionOperationSharedSession;
+}
+
+- (instancetype)initWithTopic:(NSString *)topic
+                       action:(FIRMessagingTopicAction)action
+                        token:(NSString *)token
+                      options:(NSDictionary *)options
+               checkinService:(FIRMessagingCheckinService *)checkinService
+                   completion:(FIRMessagingTopicOperationCompletion)completion {
+  if (self = [super init]) {
+    _topic = topic;
+    _action = action;
+    _token = token;
+    _options = options;
+    _checkinService = checkinService;
+    _completion = completion;
+
+    _isExecuting = NO;
+    _isFinished = NO;
+  }
+  return self;
+}
+
+- (void)dealloc {
+  _topic = nil;
+  _token = nil;
+  _checkinService = nil;
+  _completion = nil;
+}
+
+- (BOOL)isAsynchronous {
+  return YES;
+}
+
+- (BOOL)isExecuting {
+  return _isExecuting;
+}
+
+- (void)setExecuting:(BOOL)executing {
+  [self willChangeValueForKey:@"isExecuting"];
+  _isExecuting = executing;
+  [self didChangeValueForKey:@"isExecuting"];
+}
+
+- (BOOL)isFinished {
+  return _isFinished;
+}
+
+- (void)setFinished:(BOOL)finished {
+  [self willChangeValueForKey:@"isFinished"];
+  _isFinished = finished;
+  [self didChangeValueForKey:@"isFinished"];
+}
+
+- (void)start {
+  if (self.isCancelled) {
+    NSError *error =
+        [NSError errorWithFCMErrorCode:kFIRMessagingErrorCodePubSubOperationIsCancelled];
+    [self finishWithError:error];
+    return;
+  }
+
+  [self setExecuting:YES];
+
+  [self performSubscriptionChange];
+}
+
+- (void)finishWithError:(NSError *)error {
+  // Add a check to prevent this finish from being called more than once.
+  if (self.isFinished) {
+    return;
+  }
+  self.dataTask = nil;
+  if (self.completion) {
+    self.completion(error);
+  }
+
+  [self setExecuting:NO];
+  [self setFinished:YES];
+}
+
+- (void)cancel {
+  [super cancel];
+  [self.dataTask cancel];
+  NSError *error = [NSError errorWithFCMErrorCode:kFIRMessagingErrorCodePubSubOperationIsCancelled];
+  [self finishWithError:error];
+}
+
+- (void)performSubscriptionChange {
+
+  NSURL *url = [NSURL URLWithString:FIRMessagingSubscriptionsServer()];
+  NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
+  NSString *appIdentifier = FIRMessagingAppIdentifier();
+  NSString *deviceAuthID = self.checkinService.deviceAuthID;
+  NSString *secretToken = self.checkinService.secretToken;
+  NSString *authString = [NSString stringWithFormat:@"AidLogin %@:%@", deviceAuthID, secretToken];
+  [request setValue:authString forHTTPHeaderField:@"Authorization"];
+  [request setValue:appIdentifier forHTTPHeaderField:@"app"];
+  [request setValue:self.checkinService.versionInfo forHTTPHeaderField:@"info"];
+
+  // Topic can contain special characters (like `%`) so encode the value.
+  NSCharacterSet *characterSet = [NSCharacterSet URLQueryAllowedCharacterSet];
+  NSString *encodedTopic =
+      [self.topic stringByAddingPercentEncodingWithAllowedCharacters:characterSet];
+  if (encodedTopic == nil) {
+    // The transformation was somehow not possible, so use the original topic.
+    FIRMessagingLoggerWarn(kFIRMessagingMessageCodeTopicOptionTopicEncodingFailed,
+                           @"Unable to encode the topic '%@' during topic subscription change. "
+                           @"Please ensure that the topic name contains only valid characters.",
+                           self.topic);
+    encodedTopic = self.topic;
+  }
+
+  NSMutableString *content = [NSMutableString stringWithFormat:
+                              @"sender=%@&app=%@&device=%@&"
+                              @"app_ver=%@&X-gcm.topic=%@&X-scope=%@",
+                              self.token,
+                              appIdentifier,
+                              deviceAuthID,
+                              FIRMessagingCurrentAppVersion(),
+                              encodedTopic,
+                              encodedTopic];
+
+  if (self.action == FIRMessagingTopicActionUnsubscribe) {
+    [content appendString:@"&delete=true"];
+  }
+
+  FIRMessagingLoggerInfo(kFIRMessagingMessageCodeTopicOption000, @"Topic subscription request: %@",
+                         content);
+
+  request.HTTPBody = [content dataUsingEncoding:NSUTF8StringEncoding];
+  [request setHTTPMethod:@"POST"];
+
+#if DEBUG_LOG_SUBSCRIPTION_OPERATION_DURATIONS
+  NSDate *start = [NSDate date];
+#endif
+
+  FIRMessaging_WEAKIFY(self)
+  void(^requestHandler)(NSData *, NSURLResponse *, NSError *) =
+      ^(NSData *data, NSURLResponse *URLResponse, NSError *error) {
+        FIRMessaging_STRONGIFY(self)
+    if (error) {
+      // Our operation could have been cancelled, which would result in our data task's error being
+      // NSURLErrorCancelled
+      if (error.code == NSURLErrorCancelled) {
+        // We would only have been cancelled in the -cancel method, which will call finish for us
+        // so just return and do nothing.
+        return;
+      }
+      FIRMessagingLoggerDebug(kFIRMessagingMessageCodeTopicOption001,
+                              @"Device registration HTTP fetch error. Error Code: %ld",
+                              _FIRMessaging_L(error.code));
+      [self finishWithError:error];
+      return;
+    }
+    NSString *response = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
+    if (response.length == 0) {
+      FIRMessagingLoggerDebug(kFIRMessagingMessageCodeTopicOperationEmptyResponse,
+                              @"Invalid registration response - zero length.");
+      [self finishWithError:[NSError errorWithFCMErrorCode:kFIRMessagingErrorCodeUnknown]];
+      return;
+    }
+    NSArray *parts = [response componentsSeparatedByString:@"="];
+    _FIRMessagingDevAssert(parts.count, @"Invalid registration response");
+    if (![parts[0] isEqualToString:@"token"] || parts.count <= 1) {
+      FIRMessagingLoggerDebug(kFIRMessagingMessageCodeTopicOption002,
+                              @"Invalid registration response %@", response);
+      [self finishWithError:[NSError errorWithFCMErrorCode:kFIRMessagingErrorCodeUnknown]];
+      return;
+    }
+#if DEBUG_LOG_SUBSCRIPTION_OPERATION_DURATIONS
+    NSTimeInterval duration = -[start timeIntervalSinceNow];
+    FIRMessagingLoggerDebug(@"%@ change took %.2fs", self.topic, duration);
+#endif
+    [self finishWithError:nil];
+
+  };
+
+  NSURLSession *urlSession = [FIRMessagingTopicOperation sharedSession];
+
+  self.dataTask = [urlSession dataTaskWithRequest:request completionHandler:requestHandler];
+  NSString *description;
+  if (_action == FIRMessagingTopicActionSubscribe) {
+    description = [NSString stringWithFormat:@"com.google.fcm.topics.subscribe: %@", _topic];
+  } else {
+    description = [NSString stringWithFormat:@"com.google.fcm.topics.unsubscribe: %@", _topic];
+  }
+  self.dataTask.taskDescription = description;
+  [self.dataTask resume];
+}
+
+@end