Add MessageTimestampGenerator
This commit is contained in:
parent
498b7ac063
commit
0ca2c7dd47
@ -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 */,
|
||||
|
||||
@ -928,7 +928,7 @@ extension CallService: GroupCallObserver {
|
||||
self.groupCallManager.updateGroupCallModelsForPeek(
|
||||
peekInfo: peekInfo,
|
||||
groupThread: groupThread,
|
||||
triggerEventTimestamp: Date.ows_millisecondTimestamp(),
|
||||
triggerEventTimestamp: MessageTimestampGenerator.sharedInstance.generateTimestamp(),
|
||||
tx: tx
|
||||
)
|
||||
}
|
||||
|
||||
@ -240,7 +240,7 @@ public class IndividualCall: CustomDebugStringConvertible {
|
||||
offerMediaType: offerMediaType,
|
||||
state: .dialing,
|
||||
thread: thread,
|
||||
sentAtTimestamp: Date.ows_millisecondTimestamp()
|
||||
sentAtTimestamp: MessageTimestampGenerator.sharedInstance.generateTimestamp()
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@ -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];
|
||||
}
|
||||
|
||||
@ -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];
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
49
SignalServiceKit/Messages/MessageTimestampGenerator.swift
Normal file
49
SignalServiceKit/Messages/MessageTimestampGenerator.swift
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
@ -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)
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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 {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user