From 48f166b893b53b7081e5c8bcb2273559540b3e15 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Fri, 6 Nov 2020 09:49:16 +1100 Subject: [PATCH] Implement typing indicator proto conversion --- .../Control Message/TypingIndicator.swift | 56 +++++++++++++++++++ SessionMessagingKit/Messages/Message.swift | 8 +-- .../Visible Message/VisibleMessage.swift | 13 +++-- SessionSnodeKit/OnionRequestAPI.swift | 1 + SessionSnodeKit/SnodeAPI.swift | 1 + SessionUtilities/HTTP.swift | 1 + SessionUtilities/Meta/SessionUtilities.h | 2 + SessionUtilities/NSDate+Timestamp.h | 11 ++++ SessionUtilities/NSDate+Timestamp.mm | 16 ++++++ Signal.xcodeproj/project.pbxproj | 30 +++++++++- 10 files changed, 127 insertions(+), 12 deletions(-) create mode 100644 SessionUtilities/NSDate+Timestamp.h create mode 100644 SessionUtilities/NSDate+Timestamp.mm diff --git a/SessionMessagingKit/Messages/Control Message/TypingIndicator.swift b/SessionMessagingKit/Messages/Control Message/TypingIndicator.swift index 58687af55..e77a4e505 100644 --- a/SessionMessagingKit/Messages/Control Message/TypingIndicator.swift +++ b/SessionMessagingKit/Messages/Control Message/TypingIndicator.swift @@ -1,5 +1,61 @@ +import SessionUtilities @objc(SNTypingIndicator) public final class TypingIndicator : ControlMessage { + public var kind: Kind? + public enum Kind { + case started, stopped + + static func fromProto(_ proto: SNProtoTypingMessage.SNProtoTypingMessageAction) -> Kind { + switch proto { + case .started: return .started + case .stopped: return .stopped + } + } + + func toProto() -> SNProtoTypingMessage.SNProtoTypingMessageAction { + switch self { + case .started: return .started + case .stopped: return .stopped + } + } + } + + convenience init(sentTimestamp: UInt64, receivedTimestamp: UInt64, kind: Kind) { + self.init() + self.sentTimestamp = sentTimestamp + self.receivedTimestamp = receivedTimestamp + self.kind = kind + } + + public override class func fromSerializedProto(_ serializedProto: Data) -> TypingIndicator? { + do { + let contentProto = try SNProtoContent.parseData(serializedProto) + guard let typingIndicatorProto = contentProto.typingMessage else { + SNLog("Couldn't parse typing indicator from: \(contentProto).") + return nil + } + let timestamp = typingIndicatorProto.timestamp + let now = NSDate.millisecondTimestamp() + let kind = Kind.fromProto(typingIndicatorProto.action) + return TypingIndicator(sentTimestamp: timestamp, receivedTimestamp: now, kind: kind) + } catch { + SNLog("Couldn't deserialize typing indicator.") + return nil + } + } + + public override func toSerializedProto() -> Data? { + guard let timestamp = sentTimestamp, let kind = kind else { return nil } + let typingIndicatorProto = SNProtoTypingMessage.builder(timestamp: timestamp, action: kind.toProto()) + let contentProto = SNProtoContent.builder() + do { + contentProto.setTypingMessage(try typingIndicatorProto.build()) + return try contentProto.buildSerializedData() + } catch { + SNLog("Couldn't construct typing indicator proto from: \(self).") + return nil + } + } } diff --git a/SessionMessagingKit/Messages/Message.swift b/SessionMessagingKit/Messages/Message.swift index a8ce58677..1a5fb1bdd 100644 --- a/SessionMessagingKit/Messages/Message.swift +++ b/SessionMessagingKit/Messages/Message.swift @@ -17,11 +17,11 @@ public class Message : NSObject, NSCoding { // Not a protocol for YapDatabase co preconditionFailure("encode(with:) is abstract and must be overridden.") } - public class func fromProto(_ proto: SNProtoContent) -> Self? { - preconditionFailure("fromProto(_:) is abstract and must be overridden.") + public class func fromSerializedProto(_ serializedProto: Data) -> Self? { + preconditionFailure("fromSerializedProto(_:) is abstract and must be overridden.") } - public func toProto() -> Any? { - preconditionFailure("toProto() is abstract and must be overridden.") + public func toSerializedProto() -> Data? { + preconditionFailure("toSerializedProto() is abstract and must be overridden.") } } diff --git a/SessionMessagingKit/Messages/Visible Message/VisibleMessage.swift b/SessionMessagingKit/Messages/Visible Message/VisibleMessage.swift index 9181d44a2..e8b77855e 100644 --- a/SessionMessagingKit/Messages/Visible Message/VisibleMessage.swift +++ b/SessionMessagingKit/Messages/Visible Message/VisibleMessage.swift @@ -8,11 +8,12 @@ public final class VisibleMessage : Message { public var contact: Contact? public var profile: Profile? - public override class func fromProto(_ proto: SNProtoContent) -> VisibleMessage? { - guard let data = proto.dataMessage, - let text = data.body else { return nil } - let result = VisibleMessage() - result.text = text - return result + public override class func fromSerializedProto(_ serializedProto: Data) -> VisibleMessage? { + return nil +// guard let data = proto.dataMessage, +// let text = data.body else { return nil } +// let result = VisibleMessage() +// result.text = text +// return result } } diff --git a/SessionSnodeKit/OnionRequestAPI.swift b/SessionSnodeKit/OnionRequestAPI.swift index 6479972eb..18755a5e1 100644 --- a/SessionSnodeKit/OnionRequestAPI.swift +++ b/SessionSnodeKit/OnionRequestAPI.swift @@ -1,5 +1,6 @@ import CryptoSwift import PromiseKit +import SessionUtilities /// See the "Onion Requests" section of [The Session Whitepaper](https://arxiv.org/pdf/2002.04609.pdf) for more information. public enum OnionRequestAPI { diff --git a/SessionSnodeKit/SnodeAPI.swift b/SessionSnodeKit/SnodeAPI.swift index 227fabc87..edae9f476 100644 --- a/SessionSnodeKit/SnodeAPI.swift +++ b/SessionSnodeKit/SnodeAPI.swift @@ -1,4 +1,5 @@ import PromiseKit +import SessionUtilities public enum SnodeAPI { diff --git a/SessionUtilities/HTTP.swift b/SessionUtilities/HTTP.swift index cf4ab2d94..0f81181fa 100644 --- a/SessionUtilities/HTTP.swift +++ b/SessionUtilities/HTTP.swift @@ -1,5 +1,6 @@ import Foundation import PromiseKit +import SessionUtilities public enum HTTP { private static let sslURLSession = URLSession(configuration: .ephemeral) diff --git a/SessionUtilities/Meta/SessionUtilities.h b/SessionUtilities/Meta/SessionUtilities.h index 7fc2ab866..fb88bfe97 100644 --- a/SessionUtilities/Meta/SessionUtilities.h +++ b/SessionUtilities/Meta/SessionUtilities.h @@ -2,3 +2,5 @@ FOUNDATION_EXPORT double SessionUtilitiesVersionNumber; FOUNDATION_EXPORT const unsigned char SessionUtilitiesVersionString[]; + +#import diff --git a/SessionUtilities/NSDate+Timestamp.h b/SessionUtilities/NSDate+Timestamp.h new file mode 100644 index 000000000..87dc05235 --- /dev/null +++ b/SessionUtilities/NSDate+Timestamp.h @@ -0,0 +1,11 @@ +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface NSDate (Session) + ++ (uint64_t)millisecondTimestamp; + +@end + +NS_ASSUME_NONNULL_END diff --git a/SessionUtilities/NSDate+Timestamp.mm b/SessionUtilities/NSDate+Timestamp.mm new file mode 100644 index 000000000..375b62a1c --- /dev/null +++ b/SessionUtilities/NSDate+Timestamp.mm @@ -0,0 +1,16 @@ +#import "NSDate+Timestamp.h" +#import + +NS_ASSUME_NONNULL_BEGIN + +@implementation NSDate (Session) + ++ (uint64_t)millisecondTimestamp +{ + return (uint64_t)(std::chrono::system_clock::now().time_since_epoch() / std::chrono::milliseconds(1)); +} + +@end + +NS_ASSUME_NONNULL_END + diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index f057aa636..336ffd44a 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -575,6 +575,9 @@ C300A5E72554B07300555489 /* ExpirationTimerUpdate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C300A5E62554B07300555489 /* ExpirationTimerUpdate.swift */; }; C300A5F22554B09800555489 /* SendingPipeline.swift in Sources */ = {isa = PBXBuildFile; fileRef = C300A5F12554B09800555489 /* SendingPipeline.swift */; }; C300A5FC2554B0A000555489 /* ReceivingPipeline.swift in Sources */ = {isa = PBXBuildFile; fileRef = C300A5FB2554B0A000555489 /* ReceivingPipeline.swift */; }; + C300A60D2554B31900555489 /* Logging.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3C2A5CE2553860700C340D1 /* Logging.swift */; }; + C300A6322554B6D100555489 /* NSDate+Timestamp.mm in Sources */ = {isa = PBXBuildFile; fileRef = C300A6312554B6D100555489 /* NSDate+Timestamp.mm */; }; + C300A63B2554B72200555489 /* NSDate+Timestamp.h in Headers */ = {isa = PBXBuildFile; fileRef = C300A6302554B68200555489 /* NSDate+Timestamp.h */; settings = {ATTRIBUTES = (Public, ); }; }; C31A6C5A247F214E001123EF /* UIView+Glow.swift in Sources */ = {isa = PBXBuildFile; fileRef = C31A6C59247F214E001123EF /* UIView+Glow.swift */; }; C31A6C5C247F2CF3001123EF /* CGRect+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C31A6C5B247F2CF3001123EF /* CGRect+Utilities.swift */; }; C31D1DD325216101005D4DA8 /* UIView+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C31D1DD225216101005D4DA8 /* UIView+Utilities.swift */; }; @@ -621,7 +624,6 @@ C3C2A5C5255385EE00C340D1 /* HTTP.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3C2A5BC255385EE00C340D1 /* HTTP.swift */; }; C3C2A5C6255385EE00C340D1 /* Notification+OnionRequestAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3C2A5BD255385EE00C340D1 /* Notification+OnionRequestAPI.swift */; }; C3C2A5C7255385EE00C340D1 /* SnodeAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3C2A5BE255385EE00C340D1 /* SnodeAPI.swift */; }; - C3C2A5DA2553860B00C340D1 /* Logging.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3C2A5CE2553860700C340D1 /* Logging.swift */; }; C3C2A5DB2553860B00C340D1 /* Promise+Hashing.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3C2A5CF2553860700C340D1 /* Promise+Hashing.swift */; }; C3C2A5DC2553860B00C340D1 /* Promise+Threading.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3C2A5D02553860800C340D1 /* Promise+Threading.swift */; }; C3C2A5DE2553860B00C340D1 /* String+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3C2A5D22553860900C340D1 /* String+Utilities.swift */; }; @@ -1564,6 +1566,8 @@ C300A5E62554B07300555489 /* ExpirationTimerUpdate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExpirationTimerUpdate.swift; sourceTree = ""; }; C300A5F12554B09800555489 /* SendingPipeline.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SendingPipeline.swift; sourceTree = ""; }; C300A5FB2554B0A000555489 /* ReceivingPipeline.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReceivingPipeline.swift; sourceTree = ""; }; + C300A6302554B68200555489 /* NSDate+Timestamp.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSDate+Timestamp.h"; sourceTree = ""; }; + C300A6312554B6D100555489 /* NSDate+Timestamp.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = "NSDate+Timestamp.mm"; sourceTree = ""; }; C31A6C59247F214E001123EF /* UIView+Glow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+Glow.swift"; sourceTree = ""; }; C31A6C5B247F2CF3001123EF /* CGRect+Utilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CGRect+Utilities.swift"; sourceTree = ""; }; C31D1DD225216101005D4DA8 /* UIView+Utilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+Utilities.swift"; sourceTree = ""; }; @@ -3285,6 +3289,8 @@ C3C2A5BC255385EE00C340D1 /* HTTP.swift */, C3C2A5D92553860B00C340D1 /* JSON.swift */, C3C2A5CE2553860700C340D1 /* Logging.swift */, + C300A6302554B68200555489 /* NSDate+Timestamp.h */, + C300A6312554B6D100555489 /* NSDate+Timestamp.mm */, C3C2A5D62553860B00C340D1 /* Promise+Retrying.swift */, C3C2AC2D2553CBEB00C340D1 /* String+Trimming.swift */, ); @@ -3736,6 +3742,7 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( + C300A63B2554B72200555489 /* NSDate+Timestamp.h in Headers */, C3C2A67D255388CC00C340D1 /* SessionUtilities.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; @@ -4824,7 +4831,6 @@ files = ( C3C2A5E02553860B00C340D1 /* Threading.swift in Sources */, C3C2A5BF255385EE00C340D1 /* Message.swift in Sources */, - C3C2A5DA2553860B00C340D1 /* Logging.swift in Sources */, C3C2A5E22553860B00C340D1 /* Promise+Retrying.swift in Sources */, C3C2A5C0255385EE00C340D1 /* Snode.swift in Sources */, C3C2A5C7255385EE00C340D1 /* SnodeAPI.swift in Sources */, @@ -4852,6 +4858,8 @@ C3AABDDF2553ECF00042FF4C /* Array+Description.swift in Sources */, C3C2ABD22553C6C900C340D1 /* Data+SecureRandom.swift in Sources */, C3C2AC2E2553CBEB00C340D1 /* String+Trimming.swift in Sources */, + C300A60D2554B31900555489 /* Logging.swift in Sources */, + C300A6322554B6D100555489 /* NSDate+Timestamp.mm in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -5841,6 +5849,15 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; + OTHER_LDFLAGS = ( + "$(inherited)", + "-framework", + "\"Foundation\"", + "-framework", + "\"PromiseKit\"", + "-framework", + "\"UIKit\"", + ); PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.SessionUtilities"; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; @@ -5914,6 +5931,15 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; + OTHER_LDFLAGS = ( + "$(inherited)", + "-framework", + "\"Foundation\"", + "-framework", + "\"PromiseKit\"", + "-framework", + "\"UIKit\"", + ); PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.SessionUtilities"; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SDKROOT = iphoneos;