From bf7dd703277fbc6e459bcae5bb47598de87f67b2 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Wed, 4 Sep 2019 15:55:17 +1000 Subject: [PATCH] Add basic events --- Signal.xcodeproj/project.pbxproj | 4 ---- Signal/src/AppDelegate.m | 4 ++++ Signal/src/Loki/Analytics.swift | 9 --------- Signal/src/Loki/NewConversationViewController.swift | 2 ++ Signal/src/Loki/SeedViewController.swift | 5 +++++ .../ConversationView/ConversationViewController.m | 10 ++++++++++ SignalServiceKit/src/Loki/API/LokiAPI+SwarmAPI.swift | 5 +++++ SignalServiceKit/src/Loki/API/LokiAPI.swift | 4 ++-- SignalServiceKit/src/Loki/API/LokiGroupChatAPI.swift | 8 +++++++- SignalServiceKit/src/Loki/Utilities/Analytics.swift | 11 +++++++++++ .../src/Loki/Utilities/BuildConfiguration.swift | 7 +++++++ SignalServiceKit/src/Messages/OWSMessageSender.m | 2 ++ 12 files changed, 55 insertions(+), 16 deletions(-) delete mode 100644 Signal/src/Loki/Analytics.swift create mode 100644 SignalServiceKit/src/Loki/Utilities/Analytics.swift diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 9a9b0316a..082b40de1 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -565,7 +565,6 @@ B82584A02315024B001B41CB /* LokiRSSFeedPoller.swift in Sources */ = {isa = PBXBuildFile; fileRef = B825849F2315024B001B41CB /* LokiRSSFeedPoller.swift */; }; B845B4D4230CD09100D759F0 /* LokiGroupChatPoller.swift in Sources */ = {isa = PBXBuildFile; fileRef = B845B4D3230CD09000D759F0 /* LokiGroupChatPoller.swift */; }; B846365B22B7418B00AF1514 /* Identicon+ObjC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B846365A22B7418B00AF1514 /* Identicon+ObjC.swift */; }; - B8911057231F774C00F15FCC /* Analytics.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8911056231F774C00F15FCC /* Analytics.swift */; }; B89841E322B7579F00B1BDC6 /* NewConversationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B89841E222B7579F00B1BDC6 /* NewConversationViewController.swift */; }; B90418E6183E9DD40038554A /* DateUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = B90418E5183E9DD40038554A /* DateUtil.m */; }; B9EB5ABD1884C002007CBB57 /* MessageUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B9EB5ABC1884C002007CBB57 /* MessageUI.framework */; }; @@ -1360,7 +1359,6 @@ B825849F2315024B001B41CB /* LokiRSSFeedPoller.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LokiRSSFeedPoller.swift; sourceTree = ""; }; B845B4D3230CD09000D759F0 /* LokiGroupChatPoller.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LokiGroupChatPoller.swift; sourceTree = ""; }; B846365A22B7418B00AF1514 /* Identicon+ObjC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Identicon+ObjC.swift"; sourceTree = ""; }; - B8911056231F774C00F15FCC /* Analytics.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Analytics.swift; sourceTree = ""; }; B89841E222B7579F00B1BDC6 /* NewConversationViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewConversationViewController.swift; sourceTree = ""; }; B90418E4183E9DD40038554A /* DateUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DateUtil.h; sourceTree = ""; }; B90418E5183E9DD40038554A /* DateUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DateUtil.m; sourceTree = ""; }; @@ -2618,7 +2616,6 @@ isa = PBXGroup; children = ( B821F2F72272CED3002C88C0 /* AccountDetailsViewController.swift */, - B8911056231F774C00F15FCC /* Analytics.swift */, B8162F0222891AD600D46544 /* FriendRequestView.swift */, B8162F0422892C5F00D46544 /* FriendRequestViewDelegate.swift */, B845B4D3230CD09000D759F0 /* LokiGroupChatPoller.swift */, @@ -3679,7 +3676,6 @@ 34E3EF101EFC2684007F6822 /* DebugUIPage.m in Sources */, 34A8B3512190A40E00218A25 /* MediaAlbumCellView.swift in Sources */, 34D1F0AE1F867BFC0066283D /* OWSMessageCell.m in Sources */, - B8911057231F774C00F15FCC /* Analytics.swift in Sources */, 4C4AEC4520EC343B0020E72B /* DismissableTextField.swift in Sources */, 4CB5F26720F6E1E2004D1B42 /* MenuActionsViewController.swift in Sources */, 3496955E219B605E00DCFE74 /* PhotoLibrary.swift in Sources */, diff --git a/Signal/src/AppDelegate.m b/Signal/src/AppDelegate.m index 3eadb2f82..a9a57e969 100644 --- a/Signal/src/AppDelegate.m +++ b/Signal/src/AppDelegate.m @@ -351,6 +351,10 @@ static NSTimeInterval launchStartedAt; // Loki - Set up beta analytics [Mixpanel sharedInstanceWithToken:@"0410357303b7b6b45b740e6f0e6d34be"]; + LKAnalytics.shared.trackImplementation = ^(NSString *event) { + NSDictionary *properties = @{ @"configuration" : LKBuildConfiguration.current }; + [Mixpanel.sharedInstance track:event properties:properties]; + }; return YES; } diff --git a/Signal/src/Loki/Analytics.swift b/Signal/src/Loki/Analytics.swift deleted file mode 100644 index faeecc6c0..000000000 --- a/Signal/src/Loki/Analytics.swift +++ /dev/null @@ -1,9 +0,0 @@ -import Mixpanel - -@objc(LKAnalytics) -final class Analytics : NSObject { - - @objc static func track(_ event: String) { - Mixpanel.sharedInstance()?.track(event, properties: [ "configuration" : BuildConfiguration.current.description ]) - } -} diff --git a/Signal/src/Loki/NewConversationViewController.swift b/Signal/src/Loki/NewConversationViewController.swift index f47c05e5c..be5a0dd32 100644 --- a/Signal/src/Loki/NewConversationViewController.swift +++ b/Signal/src/Loki/NewConversationViewController.swift @@ -91,6 +91,7 @@ final class NewConversationViewController : OWSViewController, OWSQRScannerDeleg } func controller(_ controller: OWSQRCodeScanningViewController, didDetectQRCodeWith string: String) { + Analytics.shared.track("QR Code Scanned") let hexEncodedPublicKey = string startNewConversationIfPossible(with: hexEncodedPublicKey) } @@ -111,6 +112,7 @@ final class NewConversationViewController : OWSViewController, OWSQRScannerDeleg presentAlert(alert) } else { let thread = TSContactThread.getOrCreateThread(contactId: hexEncodedPublicKey) + Analytics.shared.track("New Conversation Started") SignalApp.shared().presentConversation(for: thread, action: .compose, animated: false) presentingViewController!.dismiss(animated: true, completion: nil) } diff --git a/Signal/src/Loki/SeedViewController.swift b/Signal/src/Loki/SeedViewController.swift index 87e1f2143..f03b9ddca 100644 --- a/Signal/src/Loki/SeedViewController.swift +++ b/Signal/src/Loki/SeedViewController.swift @@ -207,6 +207,7 @@ final class SeedViewController : OnboardingBaseViewController { @objc private func registerOrRestore() { var seed: Data + let mode = self.mode switch mode { case .register: seed = self.seed case .restore: @@ -232,6 +233,10 @@ final class SeedViewController : OnboardingBaseViewController { accountManager.phoneNumberAwaitingVerification = hexEncodedPublicKey accountManager.didRegister() let onSuccess = { [weak self] in + switch mode { + case .register: Analytics.shared.track("Seed Created") + case .restore: Analytics.shared.track("Seed Restored") + } guard let strongSelf = self else { return } strongSelf.onboardingController.verificationDidComplete(fromView: strongSelf) UserDefaults.standard.set(true, forKey: "didUpdateForMainnet") diff --git a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m index 622fa3195..cc35a97c1 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m +++ b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m @@ -611,6 +611,16 @@ typedef enum : NSUInteger { [self loadDraftInCompose]; [self applyTheme]; [self.conversationViewModel viewDidLoad]; + + if (self.thread.isGroupThread) { + if (self.isRSSFeed) { + [LKAnalytics.shared track:@"RSS Feed Opened"]; + } else { + [LKAnalytics.shared track:@"Loki Public Chat Opened"]; + } + } else { + [LKAnalytics.shared track:@"Conversation Opened"]; + } } - (void)createContents diff --git a/SignalServiceKit/src/Loki/API/LokiAPI+SwarmAPI.swift b/SignalServiceKit/src/Loki/API/LokiAPI+SwarmAPI.swift index 6e0e99ef8..458c70d92 100644 --- a/SignalServiceKit/src/Loki/API/LokiAPI+SwarmAPI.swift +++ b/SignalServiceKit/src/Loki/API/LokiAPI+SwarmAPI.swift @@ -74,6 +74,9 @@ public extension LokiAPI { return LokiAPITarget(address: "https://\(address)", port: UInt16(port)) }) return randomSnodePool.randomElement()! + }.recover { error -> Promise in + Analytics.shared.track("Seed Node Failed") + throw error } } else { return Promise { seal in @@ -126,6 +129,7 @@ internal extension Promise { let newFailureCount = oldFailureCount + 1 LokiAPI.failureCount[target] = newFailureCount print("[Loki] Couldn't reach snode at: \(target); setting failure count to \(newFailureCount).") + Analytics.shared.track("Unreachable Snode") if newFailureCount >= LokiAPI.failureThreshold { print("[Loki] Failure threshold reached for: \(target); dropping it.") LokiAPI.dropIfNeeded(target, hexEncodedPublicKey: hexEncodedPublicKey) // Remove it from the swarm cache associated with the given public key @@ -135,6 +139,7 @@ internal extension Promise { case 421: // The snode isn't associated with the given public key anymore print("[Loki] Invalidating swarm for: \(hexEncodedPublicKey).") + Analytics.shared.track("Migrated Snode") LokiAPI.dropIfNeeded(target, hexEncodedPublicKey: hexEncodedPublicKey) case 432: // The PoW difficulty is too low diff --git a/SignalServiceKit/src/Loki/API/LokiAPI.swift b/SignalServiceKit/src/Loki/API/LokiAPI.swift index c81a39589..f9cc88fa4 100644 --- a/SignalServiceKit/src/Loki/API/LokiAPI.swift +++ b/SignalServiceKit/src/Loki/API/LokiAPI.swift @@ -76,7 +76,7 @@ public final class LokiAPI : NSObject { return lokiMessage.calculatePoW().then { lokiMessageWithPoW in return getTargetSnodes(for: destination).map { swarm in return Set(swarm.map { target in - sendLokiMessage(lokiMessageWithPoW, to: target).map { rawResponse in + sendLokiMessage(lokiMessageWithPoW, to: target).map { rawResponse -> Any in if let json = rawResponse as? JSON, let powDifficulty = json["difficulty"] as? Int { guard powDifficulty != LokiAPI.powDifficulty else { return rawResponse } print("[Loki] Setting proof of work difficulty to \(powDifficulty).") @@ -87,7 +87,7 @@ public final class LokiAPI : NSObject { return rawResponse } }) - }.retryingIfNeeded(maxRetryCount: maxRetryCount) + } } } if let peer = LokiP2PAPI.getInfo(for: destination), (lokiMessage.isPing || peer.isOnline) { diff --git a/SignalServiceKit/src/Loki/API/LokiGroupChatAPI.swift b/SignalServiceKit/src/Loki/API/LokiGroupChatAPI.swift index b1ff3f76a..e272aa506 100644 --- a/SignalServiceKit/src/Loki/API/LokiGroupChatAPI.swift +++ b/SignalServiceKit/src/Loki/API/LokiGroupChatAPI.swift @@ -178,7 +178,13 @@ public final class LokiGroupChatAPI : NSObject { storage.dbReadWriteConnection.removeObject(forKey: server, inCollection: authTokenCollection) } throw error - }.retryingIfNeeded(maxRetryCount: maxRetryCount) + }.retryingIfNeeded(maxRetryCount: maxRetryCount).map { message in + Analytics.shared.track("Group Message Sent") + return message + }.recover { error -> Promise in + Analytics.shared.track("Failed to Send Group Message") + throw error + } } public static func getDeletedMessageServerIDs(for group: UInt64, on server: String) -> Promise<[UInt64]> { diff --git a/SignalServiceKit/src/Loki/Utilities/Analytics.swift b/SignalServiceKit/src/Loki/Utilities/Analytics.swift new file mode 100644 index 000000000..49ddaee8b --- /dev/null +++ b/SignalServiceKit/src/Loki/Utilities/Analytics.swift @@ -0,0 +1,11 @@ + +@objc(LKAnalytics) +public final class Analytics : NSObject { + @objc public var trackImplementation: ((String) -> Void)! // Set in AppDelegate.m + + @objc public static let shared = Analytics() + + @objc public func track(_ event: String) { + trackImplementation(event) + } +} diff --git a/SignalServiceKit/src/Loki/Utilities/BuildConfiguration.swift b/SignalServiceKit/src/Loki/Utilities/BuildConfiguration.swift index eb5c4aaf8..00e55b775 100644 --- a/SignalServiceKit/src/Loki/Utilities/BuildConfiguration.swift +++ b/SignalServiceKit/src/Loki/Utilities/BuildConfiguration.swift @@ -17,3 +17,10 @@ public enum BuildConfiguration : CustomStringConvertible { } } } + +@objc public final class LKBuildConfiguration : NSObject { + + override private init() { } + + @objc public static var current: String { return BuildConfiguration.current.description } +} diff --git a/SignalServiceKit/src/Messages/OWSMessageSender.m b/SignalServiceKit/src/Messages/OWSMessageSender.m index 875e0b743..1adf7b43d 100644 --- a/SignalServiceKit/src/Messages/OWSMessageSender.m +++ b/SignalServiceKit/src/Messages/OWSMessageSender.m @@ -1171,6 +1171,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; [promise .thenOn(OWSDispatch.sendingQueue, ^(id result) { if (isSuccess) { return; } // Succeed as soon as the first promise succeeds + [LKAnalytics.shared track:@"Sent Message Using Swarm API"]; isSuccess = YES; if (signalMessage.type == TSFriendRequestMessageType) { [self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { @@ -1190,6 +1191,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; .catchOn(OWSDispatch.sendingQueue, ^(NSError *error) { errorCount += 1; if (errorCount != promiseCount) { return; } // Only error out if all promises failed + [LKAnalytics.shared track:@"Failed to Send Message Using Swarm API"]; handleError(error); }) retainUntilComplete]; }