mirror of
https://github.com/oxen-io/session-ios.git
synced 2023-12-13 21:30:14 +01:00
Merge pull request #16 from loki-project/message-expiration
Added friend request message expiration.
This commit is contained in:
commit
8a815e1496
2
Pods
2
Pods
|
@ -1 +1 @@
|
|||
Subproject commit 76e8209c9ef47b3d1e4e9a5d2039b883e4cd4640
|
||||
Subproject commit 7fc33eedb29c3e93aacbc5c04b2a26571771c39b
|
|
@ -158,6 +158,11 @@ static NSTimeInterval launchStartedAt;
|
|||
return AppEnvironment.shared.legacyNotificationActionHandler;
|
||||
}
|
||||
|
||||
- (OWSLokiFriendRequestExpireJob *)lokiFriendRequestExpireJob
|
||||
{
|
||||
return SSKEnvironment.shared.lokiFriendRequestExpireJob;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
- (void)applicationDidEnterBackground:(UIApplication *)application
|
||||
|
@ -682,6 +687,9 @@ static NSTimeInterval launchStartedAt;
|
|||
// Clean up any messages that expired since last launch immediately
|
||||
// and continue cleaning in the background.
|
||||
[self.disappearingMessagesJob startIfNecessary];
|
||||
|
||||
// Start loki friend request expire job
|
||||
[self.lokiFriendRequestExpireJob startIfNecessary];
|
||||
|
||||
[self enableBackgroundRefreshIfNecessary];
|
||||
|
||||
|
@ -1317,6 +1325,9 @@ static NSTimeInterval launchStartedAt;
|
|||
// enables this feature
|
||||
[self.disappearingMessagesJob startIfNecessary];
|
||||
[self.profileManager ensureLocalProfileCached];
|
||||
|
||||
// Start loki friend request expire job
|
||||
[self.lokiFriendRequestExpireJob startIfNecessary];
|
||||
|
||||
// For non-legacy users, read receipts are on by default.
|
||||
[self.readReceiptManager setAreReadReceiptsEnabled:YES];
|
||||
|
|
|
@ -143,7 +143,7 @@ public class SessionResetOperation: OWSOperation, DurableOperation {
|
|||
*/
|
||||
|
||||
if (self.contactThread.sessionResetState != .requestReceived) {
|
||||
let message = TSInfoMessage(timestamp: NSDate.ows_millisecondTimeStamp(), in: self.contactThread, messageType: .typeLokiSessionResetProgress)
|
||||
let message = TSInfoMessage(timestamp: NSDate.ows_millisecondTimeStamp(), in: self.contactThread, messageType: .typeLokiSessionResetInProgress)
|
||||
message.save(with: transaction)
|
||||
|
||||
// Loki: We have initiated a session reset
|
||||
|
|
|
@ -83,27 +83,22 @@
|
|||
switch kind {
|
||||
case .incoming:
|
||||
guard let message = message as? TSIncomingMessage else { preconditionFailure() }
|
||||
buttonStackView.isHidden = didAcceptRequest || didDeclineRequest
|
||||
let text: String = {
|
||||
if didAcceptRequest {
|
||||
return String(format: NSLocalizedString("You've accepted %@'s friend request", comment: ""), message.authorId)
|
||||
} else if didDeclineRequest {
|
||||
return String(format: NSLocalizedString("You've declined %@'s friend request", comment: ""), message.authorId)
|
||||
} else {
|
||||
return String(format: NSLocalizedString("%@ sent you a friend request", comment: ""), message.authorId)
|
||||
}
|
||||
buttonStackView.isHidden = didAcceptRequest || didDeclineRequest || message.isFriendRequestExpired
|
||||
let format: String = {
|
||||
if didAcceptRequest { return NSLocalizedString("You've accepted %@'s friend request", comment: "") }
|
||||
else if didDeclineRequest { return NSLocalizedString("You've declined %@'s friend request", comment: "") }
|
||||
else if message.isFriendRequestExpired { return NSLocalizedString("%@'s friend request has expired", comment: "") }
|
||||
else { return NSLocalizedString("%@ sent you a friend request", comment: "") }
|
||||
}()
|
||||
label.text = text
|
||||
label.text = String(format: format, message.authorId)
|
||||
case .outgoing:
|
||||
guard let message = message as? TSOutgoingMessage else { preconditionFailure() }
|
||||
let text: String = {
|
||||
if didAcceptRequest {
|
||||
return String(format: NSLocalizedString("%@ accepted your friend request", comment: ""), message.thread.contactIdentifier()!)
|
||||
} else {
|
||||
return String(format: NSLocalizedString("You've sent %@ a friend request", comment: ""), message.thread.contactIdentifier()!)
|
||||
}
|
||||
let format: String = {
|
||||
if didAcceptRequest { return NSLocalizedString("%@ accepted your friend request", comment: "") }
|
||||
else if message.isFriendRequestExpired { return NSLocalizedString("Your friend request to %@ has expired", comment: "") }
|
||||
else { return NSLocalizedString("You've sent %@ a friend request", comment: "") }
|
||||
}()
|
||||
label.text = text
|
||||
label.text = String(format: format, message.thread.contactIdentifier()!)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4315,7 +4315,7 @@ typedef enum : NSUInteger {
|
|||
- (void)acceptFriendRequest:(TSIncomingMessage *)friendRequest
|
||||
{
|
||||
// Update the thread's friend request state
|
||||
[self.thread setFriendRequestStatus:TSThreadFriendRequestStatusFriends withTransaction:nil];
|
||||
[self.thread saveFriendRequestStatus:TSThreadFriendRequestStatusFriends withTransaction:nil];
|
||||
// Send friend request accepted message
|
||||
[ThreadUtil enqueueAcceptFriendRequestMessageInThread:self.thread];
|
||||
}
|
||||
|
@ -4323,7 +4323,7 @@ typedef enum : NSUInteger {
|
|||
- (void)declineFriendRequest:(TSIncomingMessage *)friendRequest
|
||||
{
|
||||
// Reset friend request status
|
||||
[self.thread setFriendRequestStatus:TSThreadFriendRequestStatusNone withTransaction:nil];
|
||||
[self.thread saveFriendRequestStatus:TSThreadFriendRequestStatusNone withTransaction:nil];
|
||||
// Delete prekeys
|
||||
NSString *contactID = self.thread.recipientIdentifiers.firstObject;
|
||||
OWSPrimaryStorage *primaryStorage = SSKEnvironment.shared.primaryStorage;
|
||||
|
|
|
@ -2582,3 +2582,5 @@
|
|||
"You've declined %@'s friend request" = "You've declined %@'s friend request";
|
||||
"You've accepted %@'s friend request" = "You've accepted %@'s friend request";
|
||||
"%@ accepted your friend request" = "%@ accepted your friend request";
|
||||
"%@'s friend request has expired" = "%@'s friend request has expired";
|
||||
"Your friend request to %@ has expired" = "Your friend request to %@ has expired";
|
||||
|
|
|
@ -125,6 +125,10 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
syncManager:syncManager
|
||||
typingIndicators:typingIndicators
|
||||
attachmentDownloads:attachmentDownloads]];
|
||||
|
||||
// Loki
|
||||
OWSLokiFriendRequestExpireJob *lokiFriendRequestExpireJob = [[OWSLokiFriendRequestExpireJob alloc] initWithPrimaryStorage:primaryStorage];
|
||||
[SSKEnvironment.shared setLokiFriendRequestExpireJob:lokiFriendRequestExpireJob];
|
||||
|
||||
appSpecificSingletonBlock();
|
||||
|
||||
|
|
|
@ -198,7 +198,7 @@ typedef NS_ENUM(NSInteger, TSThreadFriendRequestStatus) {
|
|||
|
||||
#pragma mark - Loki Friend Request Handling
|
||||
|
||||
- (void)setFriendRequestStatus:(TSThreadFriendRequestStatus)friendRequestStatus withTransaction:(YapDatabaseReadWriteTransaction *_Nullable)transaction;
|
||||
- (void)saveFriendRequestStatus:(TSThreadFriendRequestStatus)friendRequestStatus withTransaction:(YapDatabaseReadWriteTransaction *_Nullable)transaction;
|
||||
|
||||
@end
|
||||
|
||||
|
|
|
@ -698,19 +698,18 @@ ConversationColorName const kConversationColorName_Default = ConversationColorNa
|
|||
|
||||
#pragma mark - Loki Friend Request Handling
|
||||
|
||||
- (void)setFriendRequestStatus:(TSThreadFriendRequestStatus)friendRequestStatus withTransaction:(YapDatabaseReadWriteTransaction *_Nullable)transaction
|
||||
- (void)saveFriendRequestStatus:(TSThreadFriendRequestStatus)friendRequestStatus withTransaction:(YapDatabaseReadWriteTransaction *_Nullable)transaction
|
||||
{
|
||||
self.friendRequestStatus = friendRequestStatus;
|
||||
void (^postNotification)() = ^() {
|
||||
[NSNotificationCenter.defaultCenter postNotificationName:NSNotification.threadFriendRequestStatusChanged object:self.uniqueId];
|
||||
};
|
||||
if (transaction == nil) {
|
||||
[self save];
|
||||
[self.dbReadWriteConnection flushTransactionsWithCompletionQueue:dispatch_get_main_queue() completionBlock:^{
|
||||
[NSNotificationCenter.defaultCenter postNotificationName:NSNotification.threadFriendRequestStatusChanged object:self.uniqueId];
|
||||
}];
|
||||
[self.dbReadWriteConnection flushTransactionsWithCompletionQueue:dispatch_get_main_queue() completionBlock:^{ postNotification(); }];
|
||||
} else {
|
||||
[self saveWithTransaction:transaction];
|
||||
[transaction.connection flushTransactionsWithCompletionQueue:dispatch_get_main_queue() completionBlock:^{
|
||||
[NSNotificationCenter.defaultCenter postNotificationName:NSNotification.threadFriendRequestStatusChanged object:self.uniqueId];
|
||||
}];
|
||||
[transaction.connection flushTransactionsWithCompletionQueue:dispatch_get_main_queue() completionBlock:^{ postNotification(); }];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,13 +16,7 @@
|
|||
|
||||
@objc public func createPreKeyBundle(withTransaction transaction: YapDatabaseReadWriteTransaction) -> PreKeyBundle? {
|
||||
let registrationId = TSAccountManager.sharedInstance().getOrGenerateRegistrationId(transaction)
|
||||
return PreKeyBundle(registrationId: Int32(registrationId),
|
||||
deviceId: Int32(deviceID),
|
||||
preKeyId: Int32(prekeyID),
|
||||
preKeyPublic: prekey,
|
||||
signedPreKeyPublic: signedKey,
|
||||
signedPreKeyId: Int32(signedKeyID),
|
||||
signedPreKeySignature: signature,
|
||||
identityKey: identityKey)
|
||||
return PreKeyBundle(registrationId: Int32(registrationId), deviceId: Int32(deviceID), preKeyId: Int32(prekeyID), preKeyPublic: prekey,
|
||||
signedPreKeyPublic: signedKey, signedPreKeyId: Int32(signedKeyID), signedPreKeySignature: signature, identityKey: identityKey)
|
||||
}
|
||||
}
|
||||
|
|
214
SignalServiceKit/src/Loki/Utilities/FriendRequestExpireJob.swift
Normal file
214
SignalServiceKit/src/Loki/Utilities/FriendRequestExpireJob.swift
Normal file
|
@ -0,0 +1,214 @@
|
|||
/*
|
||||
This class is used for settings friend requests to expired
|
||||
This is modelled after `OWSDisappearingMessagesJob`.
|
||||
*/
|
||||
|
||||
@objc(OWSLokiFriendRequestExpireJob)
|
||||
public class FriendRequestExpireJob: NSObject {
|
||||
|
||||
private let databaseConnection: YapDatabaseConnection
|
||||
private let messageFinder: FriendRequestExpireMessageFinder
|
||||
|
||||
// These three properties should only be accessed on the main thread.
|
||||
private var hasStarted = false
|
||||
private var fallbackTimer: Timer?
|
||||
private var nextExpireTimer: Timer?
|
||||
private var nextExpireDate: Date?
|
||||
|
||||
// Our queue
|
||||
public static var serialQueue: DispatchQueue = {
|
||||
return DispatchQueue(label: "network.loki.friendrequest.expire")
|
||||
}()
|
||||
|
||||
/// Create a `FriendRequestExpireJob`.
|
||||
/// This will create a auto-running job which will set friend requests to expired.
|
||||
///
|
||||
/// - Parameter primaryStorage: The primary storage.
|
||||
@objc public init(withPrimaryStorage primaryStorage: OWSPrimaryStorage) {
|
||||
databaseConnection = primaryStorage.newDatabaseConnection()
|
||||
messageFinder = FriendRequestExpireMessageFinder()
|
||||
super.init()
|
||||
|
||||
// This makes sure we only ever have one instance of this class
|
||||
SwiftSingletons.register(self)
|
||||
|
||||
// Setup a timer that runs periodically to check for new friend request messages that will soon expire
|
||||
AppReadiness.runNowOrWhenAppDidBecomeReady {
|
||||
if (CurrentAppContext().isMainApp) {
|
||||
let fallbackInterval = 5 * kMinuteInterval
|
||||
self.fallbackTimer = WeakTimer.scheduledTimer(timeInterval: fallbackInterval, target: self, userInfo: nil, repeats: true) { [weak self] _ in
|
||||
AssertIsOnMainThread()
|
||||
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
||||
strongSelf.timerDidFire(mainTimer: false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(didBecomeActive), name: .OWSApplicationDidBecomeActive, object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(willResignActive), name: .OWSApplicationWillResignActive, object: nil)
|
||||
}
|
||||
|
||||
deinit {
|
||||
NotificationCenter.default.removeObserver(self)
|
||||
}
|
||||
|
||||
/// Start the job if we haven't done it yet
|
||||
@objc public func startIfNecessary() {
|
||||
DispatchQueue.main.async {
|
||||
guard !self.hasStarted else {
|
||||
return
|
||||
}
|
||||
|
||||
self.hasStarted = true;
|
||||
FriendRequestExpireJob.serialQueue.async {
|
||||
self.runLoop()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The main loop
|
||||
private func runLoop() {
|
||||
AssertIsOnFriendRequestExpireQueue();
|
||||
|
||||
// Expire any messages
|
||||
self.expireMessages()
|
||||
|
||||
var nextExpirationTimestamp: UInt64? = nil
|
||||
self.databaseConnection.readWrite { transaction in
|
||||
nextExpirationTimestamp = self.messageFinder.nextExpirationTimestamp(with: transaction)
|
||||
}
|
||||
|
||||
guard let timestamp = nextExpirationTimestamp,
|
||||
let nextExpireDate = NSDate.ows_date(withMillisecondsSince1970: timestamp) as? Date else {
|
||||
return
|
||||
}
|
||||
|
||||
// Schedule the next timer
|
||||
self.scheduleRun(by: nextExpireDate)
|
||||
}
|
||||
|
||||
// Schedule the next timer to run
|
||||
private func scheduleRun(by date: Date) {
|
||||
DispatchQueue.main.async {
|
||||
guard CurrentAppContext().isMainAppAndActive else {
|
||||
// Don't schedule run when inactive or not in main app.
|
||||
return
|
||||
}
|
||||
|
||||
let minDelaySeconds: TimeInterval = 1.0
|
||||
let delaySeconds = max(minDelaySeconds, date.timeIntervalSinceNow)
|
||||
let newTimerScheduleDate = Date(timeIntervalSinceNow: delaySeconds)
|
||||
|
||||
// check that we only set the date if needed
|
||||
if let previousDate = self.nextExpireDate, previousDate < date {
|
||||
// If the date is later than the one we have stored then just ignore
|
||||
return
|
||||
}
|
||||
|
||||
self.resetNextExpireTimer()
|
||||
self.nextExpireDate = newTimerScheduleDate
|
||||
self.nextExpireTimer = WeakTimer.scheduledTimer(timeInterval: delaySeconds, target: self, userInfo: nil, repeats: false) { [weak self] _ in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
||||
strongSelf.timerDidFire(mainTimer: true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Expire any friend request messages
|
||||
private func expireMessages() {
|
||||
AssertIsOnFriendRequestExpireQueue()
|
||||
let now = NSDate.ows_millisecondTimeStamp()
|
||||
|
||||
var backgroundTask: OWSBackgroundTask? = OWSBackgroundTask(label: "\(#function)", completionBlock: { [weak self] status in
|
||||
AssertIsOnMainThread()
|
||||
|
||||
guard status == .expired else {
|
||||
return
|
||||
}
|
||||
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
||||
strongSelf.databaseConnection.readWrite { transaction in
|
||||
strongSelf.messageFinder.enumurateExpiredMessages(with: { message in
|
||||
|
||||
// Sanity check
|
||||
guard message.friendRequestExpiresAt <= now else {
|
||||
owsFailDebug("Refusing to expire friend request which doesn't expire until: \(message.friendRequestExpiresAt)")
|
||||
return;
|
||||
}
|
||||
|
||||
// Check that we only expire sent messages
|
||||
guard message.thread.friendRequestStatus == .requestSent else {
|
||||
// Set message to not expire, so our other logic works correctly
|
||||
message.saveFriendRequestExpires(at: 0, with: transaction)
|
||||
return;
|
||||
}
|
||||
|
||||
// Loki: Expire the friend request message
|
||||
message.thread.saveFriendRequestStatus(.requestExpired, with: transaction)
|
||||
message.saveFriendRequestExpires(at: 0, with: transaction)
|
||||
message.saveIsFriendRequestExpired(true, with: transaction)
|
||||
}, transaction: transaction)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private func resetNextExpireTimer() {
|
||||
nextExpireTimer?.invalidate()
|
||||
nextExpireTimer = nil
|
||||
nextExpireDate = nil
|
||||
}
|
||||
|
||||
private func timerDidFire(mainTimer: Bool) {
|
||||
guard CurrentAppContext().isMainAppAndActive else {
|
||||
let infoString = mainTimer ? "Main timer fired while main app is inactive" : "Ignoring fallbacktimer for app which is not main and active."
|
||||
Logger.info("[Loki Friend Request Expire Job] \(infoString)")
|
||||
return
|
||||
}
|
||||
|
||||
if (mainTimer) { self.resetNextExpireTimer() }
|
||||
|
||||
FriendRequestExpireJob.serialQueue.async {
|
||||
self.runLoop()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// MARK: Events
|
||||
private extension FriendRequestExpireJob {
|
||||
|
||||
@objc func didBecomeActive() {
|
||||
AssertIsOnMainThread()
|
||||
AppReadiness.runNowOrWhenAppDidBecomeReady {
|
||||
FriendRequestExpireJob.serialQueue.async {
|
||||
self.runLoop()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@objc func willResignActive() {
|
||||
AssertIsOnMainThread()
|
||||
resetNextExpireTimer()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// MARK: Asserts
|
||||
private extension FriendRequestExpireJob {
|
||||
func AssertIsOnFriendRequestExpireQueue() {
|
||||
#if DEBUG
|
||||
guard #available(iOS 10.0, *) else { return }
|
||||
dispatchPrecondition(condition: .onQueue(FriendRequestExpireJob.serialQueue))
|
||||
#endif
|
||||
}
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
This class is used for finding friend request messages which are expired.
|
||||
This is modelled after `OWSDisappearingMessagesFinder`.
|
||||
*/
|
||||
|
||||
@objc(OWSLokiFriendRequestExpireMessageFinder)
|
||||
public class FriendRequestExpireMessageFinder: NSObject {
|
||||
|
||||
public static let friendRequestExpireColumn = "friend_request_expires_at"
|
||||
public static let friendRequestExpireIndex = "loki_index_friend_request_expires_at"
|
||||
|
||||
public func nextExpirationTimestamp(with transaction: YapDatabaseReadTransaction) -> UInt64? {
|
||||
let query = "WHERE \(FriendRequestExpireMessageFinder.friendRequestExpireColumn) > 0 ORDER BY \(FriendRequestExpireMessageFinder.friendRequestExpireColumn) ASC"
|
||||
|
||||
let dbQuery = YapDatabaseQuery(string: query, parameters: [])
|
||||
let ext = transaction.ext(FriendRequestExpireMessageFinder.friendRequestExpireIndex) as? YapDatabaseSecondaryIndexTransaction
|
||||
var firstMessage: TSMessage? = nil
|
||||
ext?.enumerateKeysAndObjects(matching: dbQuery) { (collection, key, object, stop) in
|
||||
firstMessage = object as? TSMessage
|
||||
stop.pointee = true
|
||||
}
|
||||
|
||||
guard let expireTime = firstMessage?.friendRequestExpiresAt, expireTime > 0 else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return expireTime
|
||||
}
|
||||
|
||||
public func enumurateExpiredMessages(with block: (TSMessage) -> Void, transaction: YapDatabaseReadTransaction) {
|
||||
for messageId in self.fetchExpiredMessageIds(with: transaction) {
|
||||
guard let message = TSMessage.fetch(uniqueId: messageId, transaction: transaction) else {
|
||||
continue
|
||||
}
|
||||
block(message)
|
||||
}
|
||||
}
|
||||
|
||||
private func fetchExpiredMessageIds(with transaction: YapDatabaseReadTransaction) -> [String] {
|
||||
var messageIds = [String]()
|
||||
let now = NSDate.ows_millisecondTimeStamp()
|
||||
|
||||
let query = "WHERE \(FriendRequestExpireMessageFinder.friendRequestExpireColumn) > 0 AND \(FriendRequestExpireMessageFinder.friendRequestExpireColumn) <= \(now)"
|
||||
// When (expireAt == 0) then the friend request SHOULD NOT expire
|
||||
let dbQuery = YapDatabaseQuery(string: query, parameters: [])
|
||||
let ext = transaction.ext(FriendRequestExpireMessageFinder.friendRequestExpireIndex) as? YapDatabaseSecondaryIndexTransaction
|
||||
ext?.enumerateKeys(matching: dbQuery) { (collection, key, stop) in
|
||||
messageIds.append(key)
|
||||
}
|
||||
|
||||
return Array(messageIds)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// MARK: YapDatabaseExtension
|
||||
|
||||
public extension FriendRequestExpireMessageFinder {
|
||||
@objc public static var indexDatabaseExtension: YapDatabaseSecondaryIndex {
|
||||
let setup = YapDatabaseSecondaryIndexSetup()
|
||||
setup.addColumn(friendRequestExpireColumn, with: .integer)
|
||||
|
||||
let handler = YapDatabaseSecondaryIndexHandler.withObjectBlock { (transaction, dict, collection, key, object) in
|
||||
guard let message = object as? TSMessage else {
|
||||
return
|
||||
}
|
||||
|
||||
// Only select messages whose status is sent
|
||||
guard message.thread.friendRequestStatus == .requestSent else {
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: Replace this with unlock timer
|
||||
dict[friendRequestExpireColumn] = message.expiresAt
|
||||
}
|
||||
|
||||
return YapDatabaseSecondaryIndex(setup: setup, handler: handler)
|
||||
}
|
||||
|
||||
@objc public static var databaseExtensionName: String {
|
||||
return friendRequestExpireIndex
|
||||
}
|
||||
|
||||
@objc public static func asyncRegisterDatabaseExtensions(_ storage: OWSStorage) {
|
||||
storage.register(self.indexDatabaseExtension, withName: friendRequestExpireIndex)
|
||||
}
|
||||
}
|
||||
|
|
@ -29,6 +29,8 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
@property (nonatomic, readonly, nullable) OWSContact *contactShare;
|
||||
@property (nonatomic, readonly, nullable) OWSLinkPreview *linkPreview;
|
||||
@property (nonatomic) BOOL isFriendRequest; // Loki
|
||||
@property (nonatomic) uint64_t friendRequestExpiresAt;
|
||||
@property (nonatomic) BOOL isFriendRequestExpired;
|
||||
|
||||
- (instancetype)initInteractionWithTimestamp:(uint64_t)timestamp inThread:(TSThread *)thread NS_UNAVAILABLE;
|
||||
|
||||
|
@ -71,7 +73,9 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
#pragma mark - Loki Friend Request Handling
|
||||
|
||||
- (void)setIsFriendRequest:(BOOL)isFriendRequest withTransaction:(YapDatabaseReadWriteTransaction *)transaction;
|
||||
- (void)saveIsFriendRequest:(BOOL)isFriendRequest withTransaction:(YapDatabaseReadWriteTransaction *_Nullable)transaction;
|
||||
- (void)saveFriendRequestExpiresAt:(u_int64_t)expiresAt withTransaction:(YapDatabaseReadWriteTransaction *_Nullable)transaction;
|
||||
- (void)saveIsFriendRequestExpired:(BOOL)isFriendRequestExpired withTransaction:(YapDatabaseReadWriteTransaction *_Nullable)transaction;
|
||||
|
||||
@end
|
||||
|
||||
|
|
|
@ -82,6 +82,7 @@ static const NSUInteger OWSMessageSchemaVersion = 4;
|
|||
_quotedMessage = quotedMessage;
|
||||
_contactShare = contactShare;
|
||||
_linkPreview = linkPreview;
|
||||
_friendRequestExpiresAt = 0;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
@ -440,7 +441,7 @@ static const NSUInteger OWSMessageSchemaVersion = 4;
|
|||
|
||||
#pragma mark - Loki Friend Request Handling
|
||||
|
||||
- (void)setIsFriendRequest:(BOOL)isFriendRequest withTransaction:(YapDatabaseReadWriteTransaction *)transaction
|
||||
- (void)saveIsFriendRequest:(BOOL)isFriendRequest withTransaction:(YapDatabaseReadWriteTransaction *_Nullable)transaction
|
||||
{
|
||||
self.isFriendRequest = isFriendRequest;
|
||||
if (transaction == nil) {
|
||||
|
@ -450,6 +451,26 @@ static const NSUInteger OWSMessageSchemaVersion = 4;
|
|||
}
|
||||
}
|
||||
|
||||
- (void)saveFriendRequestExpiresAt:(u_int64_t)expiresAt withTransaction:(YapDatabaseReadWriteTransaction *_Nullable)transaction
|
||||
{
|
||||
self.friendRequestExpiresAt = expiresAt;
|
||||
if (transaction == nil) {
|
||||
[self save];
|
||||
} else {
|
||||
[self saveWithTransaction:transaction];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)saveIsFriendRequestExpired:(BOOL)isFriendRequestExpired withTransaction:(YapDatabaseReadWriteTransaction *_Nullable)transaction
|
||||
{
|
||||
self.isFriendRequest = isFriendRequestExpired;
|
||||
if (transaction == nil) {
|
||||
[self save];
|
||||
} else {
|
||||
[self saveWithTransaction:transaction];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
|
|
@ -1474,7 +1474,8 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
// before updating Alice's thread's friend request status to TSThreadFriendRequestStatusFriends,
|
||||
// we can end up in a deadlock where both users' threads' friend request statuses are
|
||||
// TSThreadFriendRequestStatusRequestSent.
|
||||
[thread setFriendRequestStatus:TSThreadFriendRequestStatusFriends withTransaction:transaction];
|
||||
[thread saveFriendRequestStatus:TSThreadFriendRequestStatusFriends withTransaction:transaction];
|
||||
|
||||
// The two lines below are equivalent to calling [ThreadUtil enqueueAcceptFriendRequestMessageInThread:thread]
|
||||
OWSEphemeralMessage *emptyMessage = [OWSEphemeralMessage createEmptyOutgoingMessageInThread:thread];
|
||||
[self.messageSenderJobQueue addMessage:emptyMessage transaction:transaction];
|
||||
|
@ -1484,13 +1485,13 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
// friend request status is reset to TSThreadFriendRequestStatusNone. Bob now sends Alice a friend
|
||||
// request. Alice's thread's friend request status is reset to
|
||||
// TSThreadFriendRequestStatusRequestReceived.
|
||||
[thread setFriendRequestStatus:TSThreadFriendRequestStatusRequestReceived withTransaction:transaction];
|
||||
[thread saveFriendRequestStatus:TSThreadFriendRequestStatusRequestReceived withTransaction:transaction];
|
||||
message.isFriendRequest = YES;
|
||||
}
|
||||
} else if (!thread.isContactFriend) {
|
||||
// If the thread's friend request status is not TSThreadFriendRequestStatusFriends, but we're receiving a message,
|
||||
// it must be a friend request accepted message. Declining a friend request doesn't send a message.
|
||||
[thread setFriendRequestStatus:TSThreadFriendRequestStatusFriends withTransaction:transaction];
|
||||
[thread saveFriendRequestStatus:TSThreadFriendRequestStatusFriends withTransaction:transaction];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1110,7 +1110,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
|
|||
// Update the thread's friend request status if needed
|
||||
NSInteger *messageType = ((NSNumber *)signalMessage[@"type"]).integerValue;
|
||||
if (messageType == TSFriendRequestMessageType) {
|
||||
[message.thread setFriendRequestStatus:TSThreadFriendRequestStatusRequestSending withTransaction:nil];
|
||||
[message.thread saveFriendRequestStatus:TSThreadFriendRequestStatusRequestSending withTransaction:nil];
|
||||
}
|
||||
BOOL isPoWRequired = YES; // TODO: Base on message type
|
||||
[[LokiAPI objc_sendSignalMessage:signalMessage to:recipient.recipientId timestamp:message.timestamp requiringPoW:isPoWRequired]
|
||||
|
@ -1118,7 +1118,14 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
|
|||
// Loki
|
||||
// ========
|
||||
if (messageType == TSFriendRequestMessageType) {
|
||||
[message.thread setFriendRequestStatus:TSThreadFriendRequestStatusRequestSent withTransaction:nil];
|
||||
[message.thread saveFriendRequestStatus:TSThreadFriendRequestStatusRequestSent withTransaction:nil];
|
||||
|
||||
// We also want to expire the message after 72 hours
|
||||
NSTimeInterval expireTimeInterval = 72 * kHourInterval;
|
||||
NSDate *expireDate = [[NSDate new] dateByAddingTimeInterval:expireTimeInterval];
|
||||
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[message saveFriendRequestExpiresAt:[NSDate ows_millisecondsSince1970ForDate:expireDate] withTransaction:transaction];
|
||||
}];
|
||||
}
|
||||
// ========
|
||||
// Invoke the completion handler
|
||||
|
@ -1131,7 +1138,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
|
|||
// Loki
|
||||
// ========
|
||||
if (messageType == TSFriendRequestMessageType) {
|
||||
[message.thread setFriendRequestStatus:TSThreadFriendRequestStatusNone withTransaction:nil];
|
||||
[message.thread saveFriendRequestStatus:TSThreadFriendRequestStatusNone withTransaction:nil];
|
||||
}
|
||||
// ========
|
||||
// Handle the error
|
||||
|
|
|
@ -27,6 +27,9 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
@class TSSocketManager;
|
||||
@class YapDatabaseConnection;
|
||||
|
||||
// Loki
|
||||
@class OWSLokiFriendRequestExpireJob;
|
||||
|
||||
@protocol ContactsManagerProtocol;
|
||||
@protocol NotificationsProtocol;
|
||||
@protocol OWSCallMessageHandler;
|
||||
|
@ -111,6 +114,10 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
@property (atomic, readonly) YapDatabaseConnection *migrationDBConnection;
|
||||
@property (atomic, readonly) YapDatabaseConnection *analyticsDBConnection;
|
||||
|
||||
// Loki
|
||||
@property (nonatomic, readonly) OWSLokiFriendRequestExpireJob *lokiFriendRequestExpireJob;
|
||||
- (void)setLokiFriendRequestExpireJob:(OWSLokiFriendRequestExpireJob *)lokiFriendRequestExpireJob;
|
||||
|
||||
- (BOOL)isComplete;
|
||||
|
||||
@end
|
||||
|
|
|
@ -37,6 +37,9 @@ static SSKEnvironment *sharedSSKEnvironment;
|
|||
@property (nonatomic) id<OWSTypingIndicators> typingIndicators;
|
||||
@property (nonatomic) OWSAttachmentDownloads *attachmentDownloads;
|
||||
|
||||
// Loki
|
||||
@property (nonatomic) OWSLokiFriendRequestExpireJob *lokiFriendRequestExpireJob;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
@ -196,6 +199,15 @@ static SSKEnvironment *sharedSSKEnvironment;
|
|||
}
|
||||
}
|
||||
|
||||
- (void)setLokiFriendRequestExpireJob:(OWSLokiFriendRequestExpireJob *)lokiFriendRequestExpireJob {
|
||||
@synchronized(self) {
|
||||
OWSAssertDebug(lokiFriendRequestExpireJob);
|
||||
OWSAssertDebug(!_lokiFriendRequestExpireJob);
|
||||
|
||||
_lokiFriendRequestExpireJob = lokiFriendRequestExpireJob;
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)isComplete
|
||||
{
|
||||
return (self.callMessageHandler != nil && self.notificationsManager != nil);
|
||||
|
|
|
@ -214,6 +214,8 @@ void VerifyRegistrationsForPrimaryStorage(OWSStorage *storage)
|
|||
[OWSMediaGalleryFinder asyncRegisterDatabaseExtensionsWithPrimaryStorage:self];
|
||||
[TSDatabaseView asyncRegisterLazyRestoreAttachmentsDatabaseView:self];
|
||||
[SSKJobRecordFinder asyncRegisterDatabaseExtensionObjCWithStorage:self];
|
||||
|
||||
[OWSLokiFriendRequestExpireMessageFinder asyncRegisterDatabaseExtensions:self];
|
||||
|
||||
[self.database
|
||||
flushExtensionRequestsWithCompletionQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
|
||||
|
|
Loading…
Reference in a new issue