// // Copyright 2017 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only // #import "TSInteraction.h" #import "TSThread.h" #import #import NS_ASSUME_NONNULL_BEGIN NSString *NSStringFromOWSInteractionType(OWSInteractionType value) { switch (value) { case OWSInteractionType_Unknown: return @"OWSInteractionType_Unknown"; case OWSInteractionType_IncomingMessage: return @"OWSInteractionType_IncomingMessage"; case OWSInteractionType_OutgoingMessage: return @"OWSInteractionType_OutgoingMessage"; case OWSInteractionType_Error: return @"OWSInteractionType_Error"; case OWSInteractionType_Call: return @"OWSInteractionType_Call"; case OWSInteractionType_Info: return @"OWSInteractionType_Info"; case OWSInteractionType_ThreadDetails: return @"OWSInteractionType_ThreadDetails"; case OWSInteractionType_TypingIndicator: return @"OWSInteractionType_TypingIndicator"; case OWSInteractionType_UnreadIndicator: return @"OWSInteractionType_UnreadIndicator"; case OWSInteractionType_DateHeader: return @"OWSInteractionType_DateHeader"; case OWSInteractionType_UnknownThreadWarning: return @"OWSInteractionType_UnknownThreadWarning"; case OWSInteractionType_DefaultDisappearingMessageTimer: return @"OWSInteractionType_DefaultDisappearingMessageTimer"; } } // MARK: - @interface TSInteraction () @property (nonatomic) uint64_t sortId; @property (nonatomic) uint64_t receivedAtTimestamp; @property (nonatomic) uint64_t timestamp; @end // MARK: - @implementation TSInteraction + (NSString *)collection { return @"TSInteraction"; } - (instancetype)initWithUniqueId:(NSString *)uniqueId thread:(TSThread *)thread { return [self initWithUniqueId:uniqueId timestamp:NSDate.ows_millisecondTimeStamp thread:thread]; } - (instancetype)initWithUniqueId:(NSString *)uniqueId timestamp:(uint64_t)timestamp thread:(TSThread *)thread { OWSAssertDebug(timestamp > 0); OWSAssertDebug(thread); self = [super initWithUniqueId:uniqueId]; if (!self) { return self; } _timestamp = timestamp; _uniqueThreadId = thread.uniqueId; return self; } - (instancetype)initWithUniqueId:(NSString *)uniqueId timestamp:(uint64_t)timestamp receivedAtTimestamp:(uint64_t)receivedAtTimestamp thread:(TSThread *)thread { OWSAssertDebug(timestamp > 0); OWSAssertDebug(thread); self = [super initWithUniqueId:uniqueId]; if (!self) { return self; } _timestamp = timestamp; _receivedAtTimestamp = receivedAtTimestamp; _uniqueThreadId = thread.uniqueId; return self; } - (instancetype)initInteractionWithTimestamp:(uint64_t)timestamp thread:(TSThread *)thread { OWSAssertDebug(timestamp > 0); NSString *uniqueId = [[self class] generateUniqueId]; self = [super initWithUniqueId:uniqueId]; if (!self) { return self; } _timestamp = timestamp; _uniqueThreadId = thread.uniqueId; _receivedAtTimestamp = [NSDate ows_millisecondTimeStamp]; return self; } // --- CODE GENERATION MARKER // This snippet is generated by /Scripts/sds_codegen/sds_generate.py. Do not manually edit it, instead run // `sds_codegen.sh`. // clang-format off - (instancetype)initWithGrdbId:(int64_t)grdbId uniqueId:(NSString *)uniqueId receivedAtTimestamp:(uint64_t)receivedAtTimestamp sortId:(uint64_t)sortId timestamp:(uint64_t)timestamp uniqueThreadId:(NSString *)uniqueThreadId { self = [super initWithGrdbId:grdbId uniqueId:uniqueId]; if (!self) { return self; } _receivedAtTimestamp = receivedAtTimestamp; _sortId = sortId; _timestamp = timestamp; _uniqueThreadId = uniqueThreadId; return self; } // clang-format on // --- CODE GENERATION MARKER - (nullable instancetype)initWithCoder:(NSCoder *)coder { self = [super initWithCoder:coder]; if (!self) { return nil; } // Previously the receivedAtTimestamp field lived on TSMessage, but we've moved it up // to the TSInteraction superclass. if (_receivedAtTimestamp == 0) { // Upgrade from the older "TSMessage.receivedAtDate" and "TSMessage.receivedAt" properties if // necessary. NSDate *receivedAtDate = [coder decodeObjectForKey:@"receivedAtDate"]; if (!receivedAtDate) { receivedAtDate = [coder decodeObjectForKey:@"receivedAt"]; } if (receivedAtDate) { _receivedAtTimestamp = [NSDate ows_millisecondsSince1970ForDate:receivedAtDate]; } // For TSInteractions which are not TSMessage's, the timestamp *is* the receivedAtTimestamp if (_receivedAtTimestamp == 0) { _receivedAtTimestamp = _timestamp; } } return self; } #pragma mark Thread - (nullable TSThread *)threadWithTx:(SDSAnyReadTransaction *)tx { if (self.uniqueThreadId == nil) { // This might be true for a few legacy interactions enqueued in the message // sender. The message sender will handle this case. return nil; } // However, it's also possible that the thread doesn't exist. return [TSThread anyFetchWithUniqueId:self.uniqueThreadId transaction:tx]; } #pragma mark Date operations - (NSDate *)receivedAtDate { return [NSDate ows_dateWithMillisecondsSince1970:self.receivedAtTimestamp]; } - (NSDate *)timestampDate { return [NSDate ows_dateWithMillisecondsSince1970:self.timestamp]; } - (OWSInteractionType)interactionType { OWSFailDebug(@"unknown interaction type."); return OWSInteractionType_Unknown; } - (NSString *)description { return [NSString stringWithFormat:@"%@ in thread: %@ timestamp: %llu", [super description], self.uniqueThreadId, self.timestamp]; } #pragma mark - Any Transaction Hooks - (void)anyDidInsertWithTransaction:(SDSAnyWriteTransaction *)transaction { [super anyDidInsertWithTransaction:transaction]; TSThread *fetchedThread = [self threadWithTx:transaction]; [fetchedThread updateWithInsertedMessage:self transaction:transaction]; // Don't update interactionReadCache; this instance's sortId isn't // populated yet. } - (void)anyDidUpdateWithTransaction:(SDSAnyWriteTransaction *)transaction { [super anyDidUpdateWithTransaction:transaction]; TSThread *fetchedThread = [self threadWithTx:transaction]; [fetchedThread updateWithUpdatedMessage:self transaction:transaction]; [self.modelReadCaches.interactionReadCache didUpdateInteraction:self transaction:transaction]; } #pragma mark - - (BOOL)isDynamicInteraction { return NO; } #pragma mark - sorting migration - (void)replaceSortId:(uint64_t)sortId { _sortId = sortId; } #if TESTABLE_BUILD - (void)replaceTimestamp:(uint64_t)timestamp transaction:(SDSAnyWriteTransaction *)transaction { [self anyUpdateWithTransaction:transaction block:^(TSInteraction *interaction) { interaction.timestamp = timestamp; }]; } - (void)replaceReceivedAtTimestamp:(uint64_t)receivedAtTimestamp { self.receivedAtTimestamp = receivedAtTimestamp; } - (void)replaceReceivedAtTimestamp:(uint64_t)receivedAtTimestamp transaction:(SDSAnyWriteTransaction *)transaction { [self anyUpdateWithTransaction:transaction block:^(TSInteraction *interaction) { interaction.receivedAtTimestamp = receivedAtTimestamp; }]; } #endif @end NS_ASSUME_NONNULL_END