mirror of
https://github.com/RevenueCat/purchases-ios
synced 2026-11-11 22:55:55 +05:45
Co-authored-by: RevenueCat Git Bot <72824662+RCGitBot@users.noreply.github.com> Co-authored-by: andy boedo <andresboedo@gmail.com> Co-authored-by: Cesar de la Vega <cesarvegaro@gmail.com>
217 lines
8.0 KiB
Swift
217 lines
8.0 KiB
Swift
//
|
|
// Copyright RevenueCat Inc. All Rights Reserved.
|
|
//
|
|
// Licensed under the MIT License (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// https://opensource.org/licenses/MIT
|
|
//
|
|
// Backend.swift
|
|
//
|
|
// Created by Joshua Liebowitz on 8/2/21.
|
|
|
|
import Foundation
|
|
|
|
class Backend {
|
|
|
|
let identity: IdentityAPI
|
|
let offerings: OfferingsAPI
|
|
let offlineEntitlements: OfflineEntitlementsAPI
|
|
let customer: CustomerAPI
|
|
let internalAPI: InternalAPI
|
|
let customerCenterConfig: CustomerCenterConfigAPI
|
|
let redeemWebPurchaseAPI: RedeemWebPurchaseAPI
|
|
|
|
private let config: BackendConfiguration
|
|
|
|
convenience init(
|
|
apiKey: String,
|
|
systemInfo: SystemInfo,
|
|
httpClientTimeout: TimeInterval = Configuration.networkTimeoutDefault,
|
|
eTagManager: ETagManager,
|
|
operationDispatcher: OperationDispatcher,
|
|
attributionFetcher: AttributionFetcher,
|
|
offlineCustomerInfoCreator: OfflineCustomerInfoCreator?,
|
|
diagnosticsTracker: DiagnosticsTrackerType?,
|
|
dateProvider: DateProvider = DateProvider()
|
|
) {
|
|
let httpClient = HTTPClient(apiKey: apiKey,
|
|
systemInfo: systemInfo,
|
|
eTagManager: eTagManager,
|
|
signing: Signing(apiKey: apiKey, clock: systemInfo.clock),
|
|
diagnosticsTracker: diagnosticsTracker,
|
|
requestTimeout: httpClientTimeout,
|
|
operationDispatcher: OperationDispatcher.default)
|
|
let config = BackendConfiguration(httpClient: httpClient,
|
|
operationDispatcher: operationDispatcher,
|
|
operationQueue: QueueProvider.createBackendQueue(),
|
|
diagnosticsQueue: QueueProvider.createDiagnosticsQueue(),
|
|
systemInfo: systemInfo,
|
|
offlineCustomerInfoCreator: offlineCustomerInfoCreator,
|
|
dateProvider: dateProvider)
|
|
self.init(backendConfig: config, attributionFetcher: attributionFetcher)
|
|
}
|
|
|
|
convenience init(backendConfig: BackendConfiguration, attributionFetcher: AttributionFetcher) {
|
|
let customer = CustomerAPI(backendConfig: backendConfig, attributionFetcher: attributionFetcher)
|
|
let identity = IdentityAPI(backendConfig: backendConfig)
|
|
let offerings = OfferingsAPI(backendConfig: backendConfig)
|
|
let offlineEntitlements = OfflineEntitlementsAPI(backendConfig: backendConfig)
|
|
let internalAPI = InternalAPI(backendConfig: backendConfig)
|
|
let customerCenterConfig = CustomerCenterConfigAPI(backendConfig: backendConfig)
|
|
let redeemWebPurchaseAPI = RedeemWebPurchaseAPI(backendConfig: backendConfig)
|
|
|
|
self.init(backendConfig: backendConfig,
|
|
customerAPI: customer,
|
|
identityAPI: identity,
|
|
offeringsAPI: offerings,
|
|
offlineEntitlements: offlineEntitlements,
|
|
internalAPI: internalAPI,
|
|
customerCenterConfig: customerCenterConfig,
|
|
redeemWebPurchaseAPI: redeemWebPurchaseAPI)
|
|
}
|
|
|
|
required init(backendConfig: BackendConfiguration,
|
|
customerAPI: CustomerAPI,
|
|
identityAPI: IdentityAPI,
|
|
offeringsAPI: OfferingsAPI,
|
|
offlineEntitlements: OfflineEntitlementsAPI,
|
|
internalAPI: InternalAPI,
|
|
customerCenterConfig: CustomerCenterConfigAPI,
|
|
redeemWebPurchaseAPI: RedeemWebPurchaseAPI) {
|
|
self.config = backendConfig
|
|
|
|
self.customer = customerAPI
|
|
self.identity = identityAPI
|
|
self.offerings = offeringsAPI
|
|
self.offlineEntitlements = offlineEntitlements
|
|
self.internalAPI = internalAPI
|
|
self.customerCenterConfig = customerCenterConfig
|
|
self.redeemWebPurchaseAPI = redeemWebPurchaseAPI
|
|
}
|
|
|
|
func clearHTTPClientCaches() {
|
|
self.config.clearCache()
|
|
}
|
|
|
|
func post(attributionData: [String: Any],
|
|
network: AttributionNetwork,
|
|
appUserID: String,
|
|
completion: CustomerAPI.SimpleResponseHandler?) {
|
|
self.customer.post(attributionData: attributionData,
|
|
network: network,
|
|
appUserID: appUserID,
|
|
completion: completion)
|
|
}
|
|
|
|
func post(adServicesToken: String,
|
|
appUserID: String,
|
|
completion: CustomerAPI.SimpleResponseHandler?) {
|
|
self.customer.post(adServicesToken: adServicesToken,
|
|
appUserID: appUserID,
|
|
completion: completion)
|
|
}
|
|
|
|
func getCustomerInfo(appUserID: String,
|
|
isAppBackgrounded: Bool,
|
|
allowComputingOffline: Bool = true,
|
|
completion: @escaping CustomerAPI.CustomerInfoResponseHandler) {
|
|
self.customer.getCustomerInfo(appUserID: appUserID,
|
|
isAppBackgrounded: isAppBackgrounded,
|
|
allowComputingOffline: allowComputingOffline,
|
|
completion: completion)
|
|
}
|
|
|
|
func post(receipt: EncodedAppleReceipt,
|
|
productData: ProductRequestData?,
|
|
transactionData: PurchasedTransactionData,
|
|
observerMode: Bool,
|
|
appTransaction: String? = nil,
|
|
completion: @escaping CustomerAPI.CustomerInfoResponseHandler) {
|
|
self.customer.post(receipt: receipt,
|
|
productData: productData,
|
|
transactionData: transactionData,
|
|
observerMode: observerMode,
|
|
appTransaction: appTransaction,
|
|
completion: completion)
|
|
}
|
|
|
|
func post(subscriberAttributes: SubscriberAttribute.Dictionary,
|
|
appUserID: String,
|
|
completion: CustomerAPI.SimpleResponseHandler?) {
|
|
self.customer.post(subscriberAttributes: subscriberAttributes, appUserID: appUserID, completion: completion)
|
|
}
|
|
|
|
}
|
|
|
|
extension Backend {
|
|
|
|
/// - Throws: `NetworkError`
|
|
func healthRequest(signatureVerification: Bool) async throws {
|
|
try await Async.call { completion in
|
|
self.internalAPI.healthRequest(signatureVerification: signatureVerification) { error in
|
|
completion(.init(error))
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
// @unchecked because:
|
|
// - Class is not `final` (it's mocked). This implicitly makes subclasses `Sendable` even if they're not thread-safe.
|
|
extension Backend: @unchecked Sendable {}
|
|
|
|
// MARK: - Internal
|
|
|
|
extension Backend {
|
|
|
|
typealias ResponseHandler<Response> = @Sendable (Swift.Result<Response, BackendError>) -> Void
|
|
|
|
}
|
|
|
|
extension Backend {
|
|
|
|
@objc var signatureVerificationEnabled: Bool {
|
|
return self.config.httpClient.signatureVerificationEnabled
|
|
}
|
|
|
|
}
|
|
|
|
extension Backend {
|
|
|
|
enum QueueProvider {
|
|
|
|
static func createBackendQueue() -> OperationQueue {
|
|
let operationQueue = OperationQueue()
|
|
operationQueue.name = "RC Backend Queue"
|
|
operationQueue.maxConcurrentOperationCount = 1
|
|
return operationQueue
|
|
}
|
|
|
|
static func createDiagnosticsQueue() -> OperationQueue {
|
|
let operationQueue = OperationQueue()
|
|
operationQueue.name = "RC Diagnostics Queue"
|
|
operationQueue.maxConcurrentOperationCount = 1
|
|
operationQueue.qualityOfService = .background
|
|
return operationQueue
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// MARK: - Testing extensions
|
|
|
|
extension Backend {
|
|
|
|
var networkTimeout: TimeInterval {
|
|
return self.config.httpClient.timeout
|
|
}
|
|
|
|
var offlineCustomerInfoEnabled: Bool {
|
|
return self.config.offlineCustomerInfoCreator != nil
|
|
}
|
|
|
|
}
|