aboutsummaryrefslogtreecommitdiffhomepage
path: root/Firebase/Messaging/FIRMessagingSyncMessageManager.m
blob: 1257b02faee677596cf3d975eea23416eaf1bdd0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
/*
 * 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 "FIRMessagingSyncMessageManager.h"

#import "FIRMessagingConstants.h"
#import "FIRMessagingDefines.h"
#import "FIRMessagingLogger.h"
#import "FIRMessagingPersistentSyncMessage.h"
#import "FIRMessagingRmqManager.h"
#import "FIRMessagingUtilities.h"

static const int64_t kDefaultSyncMessageTTL = 4 * 7 * 24 * 60 * 60;  // 4 weeks
// 4 MB of free space is required to persist Sync messages
static const uint64_t kMinFreeDiskSpaceInMB = 1;

@interface FIRMessagingSyncMessageManager()

@property(nonatomic, readwrite, strong) FIRMessagingRmqManager *rmqManager;

@end

@implementation FIRMessagingSyncMessageManager

- (instancetype)init {
  FIRMessagingInvalidateInitializer();
}

- (instancetype)initWithRmqManager:(FIRMessagingRmqManager *)rmqManager {
  _FIRMessagingDevAssert(rmqManager, @"Invalid nil rmq manager while initalizing sync message manager");
  self = [super init];
  if (self) {
    _rmqManager = rmqManager;
  }
  return self;
}

- (void)removeExpiredSyncMessages {
  NSError *error;
  int deleteCount = [self.rmqManager deleteExpiredOrFinishedSyncMessages:&error];
  if (error) {
    FIRMessagingLoggerError(kFIRMessagingMessageCodeSyncMessageManager000,
                            @"Error while deleting expired sync messages %@", error);
  } else if (deleteCount > 0) {
    FIRMessagingLoggerDebug(kFIRMessagingMessageCodeSyncMessageManager001,
                            @"Successfully deleted %d sync messages from store", deleteCount);
  }
}

- (BOOL)didReceiveAPNSSyncMessage:(NSDictionary *)message {
  return [self didReceiveSyncMessage:message viaAPNS:YES viaMCS:NO];
}

- (BOOL)didReceiveMCSSyncMessage:(NSDictionary *)message {
  return [self didReceiveSyncMessage:message viaAPNS:NO viaMCS:YES];
}

- (BOOL)didReceiveSyncMessage:(NSDictionary *)message
                      viaAPNS:(BOOL)viaAPNS
                       viaMCS:(BOOL)viaMCS {
  NSString *rmqID = message[kFIRMessagingMessageIDKey];
  _FIRMessagingDevAssert([rmqID length], @"Invalid nil rmqID for message");
  if (![rmqID length]) {
    FIRMessagingLoggerError(kFIRMessagingMessageCodeSyncMessageManager002,
                            @"Invalid nil rmqID for sync message.");
    return NO;
  }

  FIRMessagingPersistentSyncMessage *persistentMessage =
      [self.rmqManager querySyncMessageWithRmqID:rmqID];

  NSError *error;
  if (!persistentMessage) {

    // Do not persist the new message if we don't have enough disk space
    uint64_t freeDiskSpace = FIRMessagingGetFreeDiskSpaceInMB();
    if (freeDiskSpace < kMinFreeDiskSpaceInMB) {
      return NO;
    }

    int64_t expirationTime = [[self class] expirationTimeForSyncMessage:message];
    if (![self.rmqManager saveSyncMessageWithRmqID:rmqID
                                    expirationTime:expirationTime
                                      apnsReceived:viaAPNS
                                       mcsReceived:viaMCS
                                             error:&error]) {
      FIRMessagingLoggerError(kFIRMessagingMessageCodeSyncMessageManager003,
                              @"Failed to save sync message with rmqID %@", rmqID);
    } else {
      FIRMessagingLoggerInfo(kFIRMessagingMessageCodeSyncMessageManager004,
                             @"Added sync message to cache: %@", rmqID);
    }
    return NO;
  }

  if (viaAPNS && !persistentMessage.apnsReceived) {
    persistentMessage.apnsReceived = YES;
    if (![self.rmqManager updateSyncMessageViaAPNSWithRmqID:rmqID error:&error]) {
      FIRMessagingLoggerError(kFIRMessagingMessageCodeSyncMessageManager005,
                              @"Failed to update APNS state for sync message %@", rmqID);
    }
  } else if (viaMCS && !persistentMessage.mcsReceived) {
    persistentMessage.mcsReceived = YES;
    if (![self.rmqManager updateSyncMessageViaMCSWithRmqID:rmqID error:&error]) {
      FIRMessagingLoggerError(kFIRMessagingMessageCodeSyncMessageManager006,
                              @"Failed to update MCS state for sync message %@", rmqID);
    }
  }

  // Received message via both ways we can safely delete it.
  if (persistentMessage.apnsReceived && persistentMessage.mcsReceived) {
    if (![self.rmqManager deleteSyncMessageWithRmqID:rmqID]) {
      FIRMessagingLoggerError(kFIRMessagingMessageCodeSyncMessageManager007,
                              @"Failed to delete sync message %@", rmqID);
    } else {
      FIRMessagingLoggerInfo(kFIRMessagingMessageCodeSyncMessageManager008,
                             @"Successfully deleted sync message from cache %@", rmqID);
    }
  }

  // Already received this message either via MCS or APNS.
  return YES;
}

+ (int64_t)expirationTimeForSyncMessage:(NSDictionary *)message {
  int64_t ttl = kDefaultSyncMessageTTL;
  if (message[kFIRMessagingMessageSyncMessageTTLKey]) {
    ttl = [message[kFIRMessagingMessageSyncMessageTTLKey] longLongValue];
  }
  int64_t currentTime = FIRMessagingCurrentTimestampInSeconds();
  return currentTime + ttl;
}

@end