1616
1717#import " FirebaseMessaging/Sources/FIRMessagingPubSub.h"
1818
19+ #import < FirebaseInstanceID/FIRInstanceID_Private.h>
1920#import < FirebaseMessaging/FIRMessaging.h>
2021#import " GoogleUtilities/Environment/Private/GULSecureCoding.h"
2122#import " GoogleUtilities/UserDefaults/Private/GULUserDefaults.h"
2425#import " FirebaseMessaging/Sources/FIRMessagingDefines.h"
2526#import " FirebaseMessaging/Sources/FIRMessagingLogger.h"
2627#import " FirebaseMessaging/Sources/FIRMessagingPendingTopicsList.h"
28+ #import " FirebaseMessaging/Sources/FIRMessagingTopicOperation.h"
29+ #import " FirebaseMessaging/Sources/FIRMessagingTopicsCommon.h"
2730#import " FirebaseMessaging/Sources/FIRMessagingUtilities.h"
2831#import " FirebaseMessaging/Sources/FIRMessaging_Private.h"
2932#import " FirebaseMessaging/Sources/NSDictionary+FIRMessaging.h"
3538@interface FIRMessagingPubSub () <FIRMessagingPendingTopicsListDelegate>
3639
3740@property (nonatomic , readwrite , strong ) FIRMessagingPendingTopicsList *pendingTopicUpdates;
38- @property (nonatomic , readwrite , strong ) FIRMessagingClient *client;
41+ @property (nonatomic , readonly , strong ) NSOperationQueue *topicOperations;
42+ // Common errors, instantiated, to avoid generating multiple copies
43+ @property (nonatomic , readwrite , strong ) NSError *operationInProgressError;
3944
4045@end
4146
4247@implementation FIRMessagingPubSub
4348
4449- (instancetype )init {
45- FIRMessagingInvalidateInitializer ();
46- // Need this to disable an Xcode warning.
47- return [self initWithClient: nil ];
48- }
49-
50- - (instancetype )initWithClient : (FIRMessagingClient *)client {
5150 self = [super init ];
5251 if (self) {
53- _client = client;
52+ _topicOperations = [[NSOperationQueue alloc ] init ];
53+ // Do 10 topic operations at a time; it's enough to keep the TCP connection to the host alive,
54+ // saving hundreds of milliseconds on each request (compared to a serial queue).
55+ _topicOperations.maxConcurrentOperationCount = 10 ;
5456 [self restorePendingTopicsList ];
5557 }
5658 return self;
@@ -60,14 +62,6 @@ - (void)subscribeWithToken:(NSString *)token
6062 topic : (NSString *)topic
6163 options : (NSDictionary *)options
6264 handler : (FIRMessagingTopicOperationCompletion)handler {
63- if (!self.client ) {
64- handler ([NSError
65- messagingErrorWithCode: kFIRMessagingErrorCodePubSubClientNotSetup
66- failureReason: @" Firebase Messaging Client does not exist. Firebase Messaging was "
67- @" not setup property and subscription failed." ]);
68- return ;
69- }
70-
7165 token = [token copy ];
7266 topic = [topic copy ];
7367
@@ -93,26 +87,64 @@ - (void)subscribeWithToken:(NSString *)token
9387 // copy the dictionary would trim non-string keys or values if any.
9488 options = [options fcm_trimNonStringValues ];
9589
96- [self .client updateSubscriptionWithToken: token
97- topic: topic
98- options: options
99- shouldDelete: NO
100- handler: ^void (NSError *error) {
101- handler (error);
102- }];
90+ [self updateSubscriptionWithToken: token
91+ topic: topic
92+ options: options
93+ shouldDelete: NO
94+ handler: handler];
95+ }
96+
97+ - (void )dealloc {
98+ [self .topicOperations cancelAllOperations ];
99+ }
100+
101+ #pragma mark - FIRMessaging subscribe
102+
103+ - (void )updateSubscriptionWithToken : (NSString *)token
104+ topic : (NSString *)topic
105+ options : (NSDictionary *)options
106+ shouldDelete : (BOOL )shouldDelete
107+ handler : (FIRMessagingTopicOperationCompletion)handler {
108+ if ([[FIRInstanceID instanceID ] tryToLoadValidCheckinInfo ]) {
109+ FIRMessagingTopicAction action =
110+ shouldDelete ? FIRMessagingTopicActionUnsubscribe : FIRMessagingTopicActionSubscribe;
111+ FIRMessagingTopicOperation *operation = [[FIRMessagingTopicOperation alloc ]
112+ initWithTopic: topic
113+ action: action
114+ token: token
115+ options: options
116+ completion: ^(NSError *_Nullable error) {
117+ if (error) {
118+ FIRMessagingLoggerError (kFIRMessagingMessageCodeClient001 ,
119+ @" Failed to subscribe to topic %@ " , error);
120+ } else {
121+ if (shouldDelete) {
122+ FIRMessagingLoggerInfo (kFIRMessagingMessageCodeClient002 ,
123+ @" Successfully unsubscribed from topic %@ " , topic);
124+ } else {
125+ FIRMessagingLoggerInfo (kFIRMessagingMessageCodeClient003 ,
126+ @" Successfully subscribed to topic %@ " , topic);
127+ }
128+ }
129+ if (handler) {
130+ handler (error);
131+ }
132+ }];
133+ [self .topicOperations addOperation: operation];
134+ } else {
135+ NSString *failureReason = @" Device ID and checkin info is not found. Will not proceed with "
136+ @" subscription/unsubscription." ;
137+ FIRMessagingLoggerDebug (kFIRMessagingMessageCodeRegistrar000 , @" %@ " , failureReason);
138+ NSError *error = [NSError messagingErrorWithCode: kFIRMessagingErrorCodeMissingDeviceID
139+ failureReason: failureReason];
140+ handler (error);
141+ }
103142}
104143
105144- (void )unsubscribeWithToken : (NSString *)token
106145 topic : (NSString *)topic
107146 options : (NSDictionary *)options
108147 handler : (FIRMessagingTopicOperationCompletion)handler {
109- if (!self.client ) {
110- handler ([NSError
111- messagingErrorWithCode: kFIRMessagingErrorCodePubSubClientNotSetup
112- failureReason: @" Firebase Messaging Client does not exist. Firebase Messaging was "
113- @" not setup property and subscription failed." ]);
114- return ;
115- }
116148 token = [token copy ];
117149 topic = [topic copy ];
118150 if (![options count ]) {
@@ -136,13 +168,13 @@ - (void)unsubscribeWithToken:(NSString *)token
136168 // copy the dictionary would trim non-string keys or values if any.
137169 options = [options fcm_trimNonStringValues ];
138170
139- [self .client updateSubscriptionWithToken: token
140- topic: topic
141- options: options
142- shouldDelete: YES
143- handler: ^void (NSError *error) {
144- handler (error);
145- }];
171+ [self updateSubscriptionWithToken: token
172+ topic: topic
173+ options: options
174+ shouldDelete: YES
175+ handler: ^void (NSError *error) {
176+ handler (error);
177+ }];
146178}
147179
148180- (void )subscribeToTopic : (NSString *)topic
0 commit comments