Add MessageTimestampGenerator

This commit is contained in:
Max Radermacher 2024-07-25 01:45:20 -05:00 committed by GitHub
parent 498b7ac063
commit 0ca2c7dd47
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 97 additions and 10 deletions

View File

@ -544,6 +544,8 @@
500AEE052A4B68E200371F05 /* WallpaperStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 500AEE042A4B68E200371F05 /* WallpaperStore.swift */; };
500AEE072A4DF48700371F05 /* ChatColorSettingStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 500AEE062A4DF48700371F05 /* ChatColorSettingStore.swift */; };
500AEE092A4E09AD00371F05 /* AuthorMergeObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 500AEE082A4E09AD00371F05 /* AuthorMergeObserver.swift */; };
500BAD802C519F2D00B4CD7F /* MessageTimestampGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 500BAD7E2C519F2D00B4CD7F /* MessageTimestampGenerator.swift */; };
500BAD822C519F3600B4CD7F /* MessageTimestampGeneratorTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 500BAD7F2C519F2D00B4CD7F /* MessageTimestampGeneratorTest.swift */; };
500FB6182915B86D00257951 /* UITableView+ReusableCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 500FB6172915B86D00257951 /* UITableView+ReusableCell.swift */; };
500FE4E0288A11B000FA090C /* ConversationViewController+GiftBadges.swift in Sources */ = {isa = PBXBuildFile; fileRef = 500FE4DF288A11AF00FA090C /* ConversationViewController+GiftBadges.swift */; };
500FE4E2288A373100FA090C /* BadgeGiftingAlreadyRedeemedSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 500FE4E1288A373100FA090C /* BadgeGiftingAlreadyRedeemedSheet.swift */; };
@ -3579,6 +3581,8 @@
500AEE042A4B68E200371F05 /* WallpaperStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WallpaperStore.swift; sourceTree = "<group>"; };
500AEE062A4DF48700371F05 /* ChatColorSettingStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatColorSettingStore.swift; sourceTree = "<group>"; };
500AEE082A4E09AD00371F05 /* AuthorMergeObserver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthorMergeObserver.swift; sourceTree = "<group>"; };
500BAD7E2C519F2D00B4CD7F /* MessageTimestampGenerator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageTimestampGenerator.swift; sourceTree = "<group>"; };
500BAD7F2C519F2D00B4CD7F /* MessageTimestampGeneratorTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageTimestampGeneratorTest.swift; sourceTree = "<group>"; };
500FB6172915B86D00257951 /* UITableView+ReusableCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UITableView+ReusableCell.swift"; sourceTree = "<group>"; };
500FE48E2886148800FA090C /* CachedBadge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CachedBadge.swift; sourceTree = "<group>"; };
500FE4DF288A11AF00FA090C /* ConversationViewController+GiftBadges.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ConversationViewController+GiftBadges.swift"; sourceTree = "<group>"; };
@ -10940,6 +10944,8 @@
F9C5C954289453B100548EEE /* MessageSender+SenderKey.swift */,
F9C5C8D5289453B100548EEE /* MessageSender.swift */,
F9C5C976289453B100548EEE /* MessageSendLog.swift */,
500BAD7E2C519F2D00B4CD7F /* MessageTimestampGenerator.swift */,
500BAD7F2C519F2D00B4CD7F /* MessageTimestampGeneratorTest.swift */,
50F9460F2AD768AF002EF293 /* MockIdentityManager.swift */,
502C696F2B06CE9C00012867 /* OutgoingAttachmentInfo.swift */,
F96A534228A1AE7B003262D4 /* OutgoingGroupUpdateMessage.swift */,
@ -14520,6 +14526,7 @@
F9C5CC64289453B300548EEE /* MessageSendLog.swift in Sources */,
F9C5CC19289453B300548EEE /* MessageSticker.swift in Sources */,
66E793E52BC0D8A600929E5E /* MessageStickerManager.swift in Sources */,
500BAD802C519F2D00B4CD7F /* MessageTimestampGenerator.swift in Sources */,
C16AFAC92BE9CA2700838FFB /* MetadataStreamTransform.swift in Sources */,
721BC7EC2BC8253600648981 /* MimeTypeUtil.swift in Sources */,
501052642BDAEEDC0097DDC5 /* MobileCoinExternal.pb.swift in Sources */,
@ -15357,6 +15364,7 @@
F9426246289B1B5500460798 /* MessageSendJobQueueTest.swift in Sources */,
F9426293289B1B5600460798 /* MessageSendLogTests.swift in Sources */,
6633B3932BACF3EB003AFF60 /* MessageStickerSerializationTest.swift in Sources */,
500BAD822C519F3600B4CD7F /* MessageTimestampGeneratorTest.swift in Sources */,
D9F399B92A9EA1FA001599EC /* MockDBV2Test.swift in Sources */,
F942624C289B1B5500460798 /* ModelReadCacheTest.swift in Sources */,
F9426256289B1B5500460798 /* NSData+ImageTest.swift in Sources */,

View File

@ -928,7 +928,7 @@ extension CallService: GroupCallObserver {
self.groupCallManager.updateGroupCallModelsForPeek(
peekInfo: peekInfo,
groupThread: groupThread,
triggerEventTimestamp: Date.ows_millisecondTimestamp(),
triggerEventTimestamp: MessageTimestampGenerator.sharedInstance.generateTimestamp(),
tx: tx
)
}

View File

@ -240,7 +240,7 @@ public class IndividualCall: CustomDebugStringConvertible {
offerMediaType: offerMediaType,
state: .dialing,
thread: thread,
sentAtTimestamp: Date.ows_millisecondTimestamp()
sentAtTimestamp: MessageTimestampGenerator.sharedInstance.generateTimestamp()
)
}

View File

@ -24,7 +24,7 @@ NS_ASSUME_NONNULL_BEGIN
plainTextDataBlock:(DynamicOutgoingMessageBlock)block
{
return [self initWithThread:thread
timestamp:[NSDate ows_millisecondTimeStamp]
timestamp:[MessageTimestampGenerator.sharedInstance generateTimestamp]
transaction:transaction
plainTextDataBlock:block];
}

View File

@ -24,7 +24,7 @@ NS_ASSUME_NONNULL_BEGIN
transaction:(SDSAnyReadTransaction *)transaction
{
return [self initWithThread:thread
timestamp:[NSDate ows_millisecondTimeStamp]
timestamp:[MessageTimestampGenerator.sharedInstance generateTimestamp]
plaintextData:plaintextData
transaction:transaction];
}

View File

@ -61,7 +61,9 @@ NSString *NSStringFromOWSInteractionType(OWSInteractionType value)
- (instancetype)initWithUniqueId:(NSString *)uniqueId thread:(TSThread *)thread
{
return [self initWithUniqueId:uniqueId timestamp:NSDate.ows_millisecondTimeStamp thread:thread];
return [self initWithUniqueId:uniqueId
timestamp:[MessageTimestampGenerator.sharedInstance generateTimestamp]
thread:thread];
}
- (instancetype)initWithUniqueId:(NSString *)uniqueId timestamp:(uint64_t)timestamp thread:(TSThread *)thread

View File

@ -0,0 +1,49 @@
//
// Copyright 2023 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
//
import Foundation
/// Generates timestamps for messages/envelopes.
@objc
public class MessageTimestampGenerator: NSObject {
private let rangeToAvoid = AtomicValue<ClosedRange<UInt64>?>(nil, lock: .init())
private let nowMs: () -> UInt64
@objc
public static let sharedInstance = MessageTimestampGenerator()
public init(nowMs: @escaping () -> UInt64 = NSDate.ows_millisecondTimeStamp) {
self.nowMs = nowMs
}
/// Generates a new timestamp from the device's local clock.
///
/// Performs a few heuristics to try and avoid generating the same timestamp
/// repeatedly when called in a tight loop.
@objc
public func generateTimestamp() -> UInt64 {
let generatedTimestamp = max(nowMs(), 1)
return rangeToAvoid.update { rangeToAvoid in
let newRangeToAvoid = Self.avoidAndExtendRange(rangeToAvoid, proposedValue: generatedTimestamp)
rangeToAvoid = newRangeToAvoid
return newRangeToAvoid.upperBound
}
}
private static func avoidAndExtendRange(
_ oldRange: ClosedRange<UInt64>?,
proposedValue: UInt64
) -> ClosedRange<UInt64> {
if let oldRange, oldRange.contains(proposedValue) {
// If we have a range from the last value, ensure that the new one is
// higher. We track the range to handle cases where `generateTimestamp()`
// is called twice for `t1` and then once for `t1 + 1`.
return oldRange.lowerBound...(oldRange.upperBound + 1)
} else {
// Otherwise, we assume there's no conflict and return `proposedValue`.
return proposedValue...proposedValue
}
}
}

View File

@ -0,0 +1,28 @@
//
// Copyright 2023 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
//
import XCTest
@testable import SignalServiceKit
class MessageTimestampGeneratorTest: XCTestCase {
func testGenerateTimestamp() {
var nowMs: UInt64 = 0
let generator = MessageTimestampGenerator(nowMs: { return nowMs })
nowMs = 1
let ts1 = generator.generateTimestamp()
let ts2 = generator.generateTimestamp()
nowMs = 2
let ts3 = generator.generateTimestamp()
nowMs = 4
let ts4 = generator.generateTimestamp()
XCTAssertEqual(ts1, 1)
XCTAssertEqual(ts2, 2)
XCTAssertEqual(ts3, 3)
XCTAssertEqual(ts4, 4)
}
}

View File

@ -756,7 +756,7 @@ public class OWSMessageDecrypter: OWSMessageHandler {
let errorMessage = TSErrorMessage.failedDecryption(
forSender: placeholder.sender,
thread: thread,
timestamp: NSDate.ows_millisecondTimeStamp()
timestamp: MessageTimestampGenerator.sharedInstance.generateTimestamp()
)
errorMessage.anyInsert(transaction: tx)
self.notificationPresenter.notifyUser(forErrorMessage: errorMessage, thread: thread, transaction: tx)

View File

@ -635,7 +635,7 @@ public class AttachmentMultisend {
}
let storyMessage = try StoryMessage.createAndInsert(
timestamp: Date.ows_millisecondTimestamp(),
timestamp: MessageTimestampGenerator.sharedInstance.generateTimestamp(),
authorAci: self.localAci,
groupId: groupId,
manifest: manifest,

View File

@ -130,7 +130,7 @@ extension OutgoingStoryMessage {
)
let storyMessage = try StoryMessage.createAndInsert(
timestamp: Date.ows_millisecondTimestamp(),
timestamp: MessageTimestampGenerator.sharedInstance.generateTimestamp(),
authorAci: DependenciesBridge.shared.tsAccountManager.localIdentifiers(tx: transaction.asV2Read)!.aci,
groupId: (thread as? TSGroupThread)?.groupId,
manifest: storyManifest,

View File

@ -19,7 +19,7 @@ extension ThreadUtil {
) {
AssertIsOnMainThread()
let messageTimestamp = Date.ows_millisecondTimestamp()
let messageTimestamp = MessageTimestampGenerator.sharedInstance.generateTimestamp()
let benchEventId = sendMessageBenchEventStart(messageTimestamp: messageTimestamp)
self.enqueueSendQueue.async {
@ -74,7 +74,7 @@ extension ThreadUtil {
) {
AssertIsOnMainThread()
let messageTimestamp = Date.ows_millisecondTimestamp()
let messageTimestamp = MessageTimestampGenerator.sharedInstance.generateTimestamp()
let benchEventId = sendMessageBenchEventStart(messageTimestamp: messageTimestamp)
self.enqueueSendQueue.async {