This included: - Removing unavailable inits wholesale if no longer `required` - Marking a few classes `final` so they could continue using `Self(...)` rather than `OWSWhatever(...)`
105 lines
3.0 KiB
Swift
105 lines
3.0 KiB
Swift
//
|
|
// Copyright 2019 Signal Messenger, LLC
|
|
// SPDX-License-Identifier: AGPL-3.0-only
|
|
//
|
|
|
|
import Foundation
|
|
|
|
class DownloadStickerOperation: CDNDownloadOperation {
|
|
|
|
// MARK: - Cache
|
|
|
|
private static let cache = LRUCache<String, URL>(maxSize: 256)
|
|
|
|
public class func cachedUrl(for stickerInfo: StickerInfo) -> URL? {
|
|
guard let stickerUrl = cache.object(forKey: stickerInfo.asKey()) else {
|
|
return nil
|
|
}
|
|
guard OWSFileSystem.fileOrFolderExists(url: stickerUrl) else { return nil }
|
|
return stickerUrl
|
|
}
|
|
|
|
private class func setCachedUrl(_ url: URL, for stickerInfo: StickerInfo) {
|
|
cache.setObject(url, forKey: stickerInfo.asKey())
|
|
}
|
|
|
|
// MARK: -
|
|
|
|
private let stickerInfo: StickerInfo
|
|
private let success: (URL) -> Void
|
|
private let failure: (Error) -> Void
|
|
|
|
@objc
|
|
public init(
|
|
stickerInfo: StickerInfo,
|
|
success: @escaping (URL) -> Void,
|
|
failure: @escaping (Error) -> Void
|
|
) {
|
|
assert(stickerInfo.packId.count > 0)
|
|
assert(stickerInfo.packKey.count > 0)
|
|
|
|
self.stickerInfo = stickerInfo
|
|
self.success = success
|
|
self.failure = failure
|
|
|
|
super.init()
|
|
}
|
|
|
|
override public func run() {
|
|
if let stickerUrl = DownloadStickerOperation.cachedUrl(for: stickerInfo) {
|
|
success(stickerUrl)
|
|
self.reportSuccess()
|
|
return
|
|
}
|
|
|
|
if let stickerUrl = loadInstalledStickerUrl() {
|
|
success(stickerUrl)
|
|
self.reportSuccess()
|
|
return
|
|
}
|
|
|
|
// https://cdn.signal.org/stickers/<pack_id>/full/<sticker_id>
|
|
let urlPath = "stickers/\(stickerInfo.packId.hexadecimalString)/full/\(stickerInfo.stickerId)"
|
|
|
|
firstly {
|
|
return try tryToDownload(urlPath: urlPath, maxDownloadSize: kMaxStickerDataDownloadSize)
|
|
}.done(on: DispatchQueue.global()) { [weak self] (url: URL) in
|
|
guard let self = self else {
|
|
return
|
|
}
|
|
|
|
do {
|
|
let url = try StickerManager.decrypt(at: url, packKey: self.stickerInfo.packKey)
|
|
|
|
DownloadStickerOperation.setCachedUrl(url, for: self.stickerInfo)
|
|
|
|
self.success(url)
|
|
|
|
self.reportSuccess()
|
|
} catch {
|
|
owsFailDebug("Decryption failed: \(error)")
|
|
|
|
self.markUrlPathAsCorrupt(urlPath)
|
|
|
|
// Fail immediately; do not retry.
|
|
return self.reportError(SSKUnretryableError.stickerDecryptionFailure)
|
|
}
|
|
}.catch(on: DispatchQueue.global()) { [weak self] error in
|
|
guard let self = self else {
|
|
return
|
|
}
|
|
return self.reportError(withUndefinedRetry: error)
|
|
}
|
|
}
|
|
|
|
private func loadInstalledStickerUrl() -> URL? {
|
|
return StickerManager.stickerDataUrlWithSneakyTransaction(stickerInfo: stickerInfo, verifyExists: true)
|
|
}
|
|
|
|
override public func didFail(error: Error) {
|
|
Logger.error("Download exhausted retries: \(error)")
|
|
|
|
failure(error)
|
|
}
|
|
}
|