256 lines
7.1 KiB
Objective-C
256 lines
7.1 KiB
Objective-C
//
|
|
// Copyright 2017 Signal Messenger, LLC
|
|
// SPDX-License-Identifier: AGPL-3.0-only
|
|
//
|
|
|
|
#import "TSInteraction.h"
|
|
#import "TSThread.h"
|
|
#import <SignalServiceKit/NSDate+OWS.h>
|
|
#import <SignalServiceKit/SignalServiceKit-Swift.h>
|
|
|
|
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
|
|
|
|
- (instancetype)initWithCustomUniqueId:(NSString *)uniqueId
|
|
timestamp:(uint64_t)timestamp
|
|
receivedAtTimestamp:(uint64_t)receivedAtTimestamp
|
|
thread:(TSThread *)thread
|
|
{
|
|
self = [super initWithUniqueId:uniqueId];
|
|
|
|
if (!self) {
|
|
return self;
|
|
}
|
|
|
|
_timestamp = timestamp;
|
|
_receivedAtTimestamp = receivedAtTimestamp;
|
|
_uniqueThreadId = thread.uniqueId;
|
|
|
|
return self;
|
|
}
|
|
|
|
- (instancetype)initWithTimestamp:(uint64_t)timestamp
|
|
receivedAtTimestamp:(uint64_t)receivedAtTimestamp
|
|
thread:(TSThread *)thread
|
|
{
|
|
NSString *uniqueId = [[self class] generateUniqueId];
|
|
self = [super initWithUniqueId:uniqueId];
|
|
|
|
if (!self) {
|
|
return self;
|
|
}
|
|
|
|
_timestamp = timestamp;
|
|
_receivedAtTimestamp = receivedAtTimestamp;
|
|
_uniqueThreadId = thread.uniqueId;
|
|
|
|
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];
|
|
|
|
[SSKEnvironment.shared.modelReadCachesRef.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
|