From ef1f227e6598dcd1e167bedf98e862aaff204ac8 Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Thu, 18 Apr 2019 13:48:24 -0400 Subject: [PATCH] Sketch out installed sticker classes. --- Scripts/sds_codegen/sds_codegen.sh | 3 + .../Messages/Stickers/InstalledStickers.swift | 138 +++++++++++++++++- 2 files changed, 134 insertions(+), 7 deletions(-) diff --git a/Scripts/sds_codegen/sds_codegen.sh b/Scripts/sds_codegen/sds_codegen.sh index 76a77cfd51..ec060f7787 100755 --- a/Scripts/sds_codegen/sds_codegen.sh +++ b/Scripts/sds_codegen/sds_codegen.sh @@ -42,6 +42,9 @@ $REPO_ROOT/Scripts/sds_codegen/sds_parse_objc.py --src-path SignalServiceKit/src $REPO_ROOT/Scripts/sds_codegen/sds_parse_objc.py --src-path Signal/src/ViewControllers/ConversationView/TypingIndicatorInteraction.swift --swift-bridging-path $REPO_ROOT/Scripts/sds_codegen/sds-includes $REPO_ROOT/Scripts/sds_codegen/sds_parse_objc.py --src-path SignalServiceKit/src/Messages --swift-bridging-path $REPO_ROOT/Scripts/sds_codegen/sds-includes +# Other +$REPO_ROOT/Scripts/sds_codegen/sds_parse_objc.py --src-path SignalServiceKit/src/Messages/Stickers --swift-bridging-path $REPO_ROOT/Scripts/sds_codegen/sds-includes + # We parse Swift source files to extract simple class descriptions (class name, base class, property names and types, etc.) # # NOTE: This script isn't working yet. diff --git a/SignalServiceKit/src/Messages/Stickers/InstalledStickers.swift b/SignalServiceKit/src/Messages/Stickers/InstalledStickers.swift index fe917faea9..bcf988182e 100644 --- a/SignalServiceKit/src/Messages/Stickers/InstalledStickers.swift +++ b/SignalServiceKit/src/Messages/Stickers/InstalledStickers.swift @@ -12,9 +12,21 @@ public class InstalledStickers: NSObject { return SDSDatabaseStorage.shared } - public static let collection = "InstalledStickers" +// private static var cdnSessionManager: AFHTTPSessionManager { +// return OWSSignalService.sharedInstance().cdnSessionManager +// } - private let store = SDSKeyValueStore(collection: InstalledStickers.collection) +// public static let collection = "InstalledStickers" +// +// private let store = SDSKeyValueStore(collection: InstalledStickers.collection) + +// private static let serialQueue = DispatchQueue(label: "org.signal.installedStickers") + private static let operationQueue: OperationQueue = { + let operationQueue = OperationQueue() + operationQueue.name = "org.signal.installedStickers" + operationQueue.maxConcurrentOperationCount = 1 + return operationQueue + }() private override init() {} @@ -40,8 +52,6 @@ public class InstalledStickers: NSObject { return url } - // MARK: - Internal Methods - // MARK: - @objc @@ -77,9 +87,9 @@ public class InstalledStickers: NSObject { @objc public class func installSticker(packId: Data, - packKey: Data, - stickerId: UInt32, - stickerData: Data) { + packKey: Data, + stickerId: UInt32, + stickerData: Data) { assert(packId.count > 0) assert(packKey.count > 0) assert(stickerData.count > 0) @@ -110,4 +120,118 @@ public class InstalledStickers: NSObject { } } } + + @objc + public class func tryToDownloadAndInstallSticker(packId: Data, + packKey: Data, + stickerId: UInt32) { + assert(packId.count > 0) + assert(packKey.count > 0) + + let operation = DownloadStickerOperation(packId: packId, + packKey: packKey, + stickerId: stickerId, + success: { (stickerData) in + self.installSticker(packId: packId, packKey: packKey, stickerId: stickerId, stickerData: stickerData) + }, + failure: { (_) in + // Do nothing. + }) + operationQueue.addOperation(operation) + } +} + +// MARK: - + +private class DownloadStickerOperation: OWSOperation { + + private let success: (Data) -> Void + private let failure: (Error) -> Void + private let packId: Data + private let packKey: Data + private let stickerId: UInt32 + + var stickerData: Data? + + @objc public required init(packId: Data, + packKey: Data, + stickerId: UInt32, + success : @escaping (Data) -> Void, + failure : @escaping (Error) -> Void) { + assert(packId.count > 0) + assert(packKey.count > 0) + + self.success = success + self.failure = failure + self.packId = packId + self.packKey = packKey + self.stickerId = stickerId + + super.init() + + self.remainingRetries = 10 + } + + // MARK: Dependencies + + private var cdnSessionManager: AFHTTPSessionManager { + return OWSSignalService.sharedInstance().cdnSessionManager + } + + var firstAttempt = true + + override public func run() { + + // https://cdn.signal.org/stickers//full/ + let urlPath = "stickers/\(packId.hexadecimalString)/full/\(stickerId)" + cdnSessionManager.get(urlPath, + parameters: nil, + progress: { (_) in + // Do nothing. + }, + success: { [weak self] (_, response) in + guard let self = self else { + return + } + guard let data = response as? Data else { + owsFailDebug("Unexpected response: \(type(of: response))") + return + } + Logger.verbose("Download succeeded.") + self.stickerData = data + self.success(data) + self.didSucceed() + }) { [weak self] (_, error) in + guard let self = self else { + return + } + Logger.error("Download failed: \(error)") + self.failureCount += 1 + self.reportError(error) + } + } + + override public func didFail(error: Error) { + Logger.error("Download exhausted retries: \(error)") + + failure(error) + } + + private var failureCount: UInt = 0 + + override public func retryInterval() -> TimeInterval { + // Arbitrary backoff factor... + // With backOffFactor of 1.9 + // try 1 delay: 0.00s + // try 2 delay: 0.19s + // ... + // try 5 delay: 1.30s + // ... + // try 11 delay: 61.31s + let backoffFactor = 1.9 + let maxBackoff = kHourInterval + + let seconds = 0.1 * min(maxBackoff, pow(backoffFactor, Double(self.failureCount))) + return seconds + } }