Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 31 additions & 14 deletions Modules/Sources/NetworkingCore/Network/AlamofireNetwork.swift
Original file line number Diff line number Diff line change
Expand Up @@ -57,21 +57,25 @@ public class AlamofireNetwork: Network {

public var session: URLSession { Session.default.session }

private var subscription: AnyCancellable?
private var siteSubscription: AnyCancellable?

/// Thread-safe error handler for failure tracking and retry logic
private let errorHandler: AlamofireNetworkErrorHandler

private var appPasswordSupportSubscription: AnyCancellable?

/// Public Initializer
///
/// - Parameters:
/// - credentials: Authentication credentials for requests.
/// - selectedSite: Publisher for site selection changes.
/// This is necessary if you wish to enable network switching to direct requests while authenticated with WPCOM for better performance.
/// - sessionManager: Optional pre-configured session manager.
/// - ensuresSessionManagerIsInitialized: If true, the session is always set during initialization immediately to avoid lazy initialization race conditions.
/// Defaults to false for backward compatibility. Set to true when making concurrent requests immediately after initialization.
public required init(credentials: Credentials?,
selectedSite: AnyPublisher<JetpackSite?, Never>? = nil,
selectedSite: AnyPublisher<JetpackSite?, Never>?,
appPasswordSupportState: AnyPublisher<Bool, Never>?,
userDefaults: UserDefaults = .standard,
sessionManager: Alamofire.Session? = nil,
ensuresSessionManagerIsInitialized: Bool = false) {
Expand Down Expand Up @@ -110,17 +114,8 @@ public class AlamofireNetwork: Network {
}
}()
updateAuthenticationMode(authenticationMode)
}

public func updateAppPasswordSwitching(enabled: Bool) {
guard let credentials, case .wpcom = credentials else { return }
if enabled, let selectedSite {
observeSelectedSite(selectedSite)
} else {
requestConverter = RequestConverter(siteAddress: nil)
requestAuthenticator.updateAuthenticator(DefaultRequestAuthenticator(credentials: credentials))
requestAuthenticator.delegate = nil
updateAuthenticationMode(.jetpackTunnel)
if let appPasswordSupportState {
observeAppPasswordSupportState(appPasswordSupportState)
}
}

Expand Down Expand Up @@ -277,6 +272,28 @@ public class AlamofireNetwork: Network {
}

private extension AlamofireNetwork {

func observeAppPasswordSupportState(_ appPasswordSupportState: AnyPublisher<Bool, Never>) {
appPasswordSupportSubscription = appPasswordSupportState
.removeDuplicates()
.sink { [weak self] enabled in
self?.updateAppPasswordSwitching(enabled: enabled)
}
}

func updateAppPasswordSwitching(enabled: Bool) {
guard let credentials, case .wpcom = credentials else { return }
if enabled, let selectedSite {
observeSelectedSite(selectedSite)
} else {
requestConverter = RequestConverter(siteAddress: nil)
requestAuthenticator.updateAuthenticator(DefaultRequestAuthenticator(credentials: credentials))
requestAuthenticator.delegate = nil
updateAuthenticationMode(.jetpackTunnel)
siteSubscription = nil
}
}

/// Creates a session manager with request retrier and adapter
///
func makeSession(configuration sessionConfiguration: URLSessionConfiguration) -> Alamofire.Session {
Expand All @@ -286,7 +303,7 @@ private extension AlamofireNetwork {
/// Updates `requestConverter` and `requestAuthenticator` when selected site changes
///
func observeSelectedSite(_ selectedSite: AnyPublisher<JetpackSite?, Never>) {
subscription = selectedSite
siteSubscription = selectedSite
.removeDuplicates()
.combineLatest(userDefaults.publisher(for: \.applicationPasswordUnsupportedList))
.sink { [weak self] site, unsupportedList in
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import class WooFoundation.CurrencySettings
import protocol Storage.StorageManagerType
import class Networking.CouponsRemote
import class Networking.AlamofireNetwork
import struct Combine.AnyPublisher
import struct NetworkingCore.JetpackSite

public struct PointOfSaleCouponFetchStrategyFactory {
private let siteID: Int64
Expand All @@ -13,8 +15,12 @@ public struct PointOfSaleCouponFetchStrategyFactory {
public init(siteID: Int64,
currencySettings: CurrencySettings,
credentials: Credentials?,
selectedSite: AnyPublisher<JetpackSite?, Never>,
appPasswordSupportState: AnyPublisher<Bool, Never>,
storage: StorageManagerType) {
let network = AlamofireNetwork(credentials: credentials)
let network = AlamofireNetwork(credentials: credentials,
selectedSite: selectedSite,
appPasswordSupportState: appPasswordSupportState)
let remote = CouponsRemote(network: network)
self.siteID = siteID
self.currencySettings = currencySettings
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import class WooFoundation.CurrencyFormatter
import class WooFoundation.CurrencySettings
import Storage
import enum Alamofire.AFError
import struct Combine.AnyPublisher
import struct NetworkingCore.JetpackSite

public protocol PointOfSaleCouponServiceProtocol {
func provideLocalPointOfSaleCoupons(fetchStrategy: PointOfSaleCouponFetchStrategy) async throws -> [POSItem]
Expand All @@ -30,8 +32,12 @@ public final class PointOfSaleCouponService: PointOfSaleCouponServiceProtocol {
public convenience init(siteID: Int64,
currencySettings: CurrencySettings,
credentials: Credentials?,
selectedSite: AnyPublisher<JetpackSite?, Never>,
appPasswordSupportState: AnyPublisher<Bool, Never>,
storage: StorageManagerType) {
let network = AlamofireNetwork(credentials: credentials)
let network = AlamofireNetwork(credentials: credentials,
selectedSite: selectedSite,
appPasswordSupportState: appPasswordSupportState)
self.init(siteID: siteID,
currencySettings: currencySettings,
settingStoreMethods: SettingStoreMethods(storageManager: storage, network: network),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import Foundation
import Networking
import Storage
import struct Combine.AnyPublisher

public protocol POSSystemStatusServiceProtocol {
/// Loads WooCommerce plugin and POS feature switch value remotely for eligibility checks.
Expand All @@ -27,8 +28,13 @@ public final class POSSystemStatusService: POSSystemStatusServiceProtocol {
private let storageManager: StorageManagerType
private let pluginsService: PluginsServiceProtocol

public init(credentials: Credentials?, storageManager: StorageManagerType) {
let network = AlamofireNetwork(credentials: credentials)
public init(credentials: Credentials?,
selectedSite: AnyPublisher<JetpackSite?, Never>,
appPasswordSupportState: AnyPublisher<Bool, Never>,
storageManager: StorageManagerType) {
let network = AlamofireNetwork(credentials: credentials,
selectedSite: selectedSite,
appPasswordSupportState: appPasswordSupportState)
self.remote = SystemStatusRemote(network: network)
self.storageManager = storageManager
self.pluginsService = PluginsService(storageManager: storageManager)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import class Networking.ProductsRemote
import class WooFoundation.CurrencySettings
import class Networking.AlamofireNetwork
import enum Networking.NetworkError
import struct Combine.AnyPublisher
import struct NetworkingCore.JetpackSite

public protocol PointOfSaleBarcodeScanServiceProtocol {
func getItem(barcode: String) async throws(PointOfSaleBarcodeScanError) -> POSItem
Expand Down Expand Up @@ -40,8 +42,12 @@ public final class PointOfSaleBarcodeScanService: PointOfSaleBarcodeScanServiceP

public convenience init(siteID: Int64,
credentials: Credentials?,
selectedSite: AnyPublisher<JetpackSite?, Never>,
appPasswordSupportState: AnyPublisher<Bool, Never>,
currencySettings: CurrencySettings) {
let network = AlamofireNetwork(credentials: credentials)
let network = AlamofireNetwork(credentials: credentials,
selectedSite: selectedSite,
appPasswordSupportState: appPasswordSupportState)
self.init(siteID: siteID,
productsRemote: ProductsRemote(network: network),
currencySettings: currencySettings)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import Foundation
import class Networking.ProductsRemote
import class Networking.ProductVariationsRemote
import class Networking.AlamofireNetwork
import struct Combine.AnyPublisher
import struct NetworkingCore.JetpackSite

public protocol PointOfSaleItemFetchStrategyFactoryProtocol {
func defaultStrategy(analytics: POSItemFetchAnalyticsTracking) -> PointOfSalePurchasableItemFetchStrategy
Expand All @@ -18,9 +20,13 @@ public final class PointOfSaleItemFetchStrategyFactory: PointOfSaleItemFetchStra
private let variationsRemote: ProductVariationsRemote

public init(siteID: Int64,
credentials: Credentials?) {
credentials: Credentials?,
selectedSite: AnyPublisher<JetpackSite?, Never>? = nil,
appPasswordSupportState: AnyPublisher<Bool, Never>? = nil) {
self.siteID = siteID
let network = AlamofireNetwork(credentials: credentials)
let network = AlamofireNetwork(credentials: credentials,
selectedSite: selectedSite,
appPasswordSupportState: appPasswordSupportState)
self.productsRemote = ProductsRemote(network: network)
self.variationsRemote = ProductVariationsRemote(network: network)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import Foundation
import class Networking.AlamofireNetwork
import class Networking.OrdersRemote
import class WooFoundationCore.CurrencyFormatter
import struct Combine.AnyPublisher
import struct NetworkingCore.JetpackSite

public protocol POSOrderListFetchStrategyFactoryProtocol {
func defaultStrategy() -> POSOrderListFetchStrategy
Expand All @@ -15,9 +17,13 @@ public final class POSOrderListFetchStrategyFactory: POSOrderListFetchStrategyFa

public init(siteID: Int64,
credentials: Credentials?,
selectedSite: AnyPublisher<JetpackSite?, Never>,
appPasswordSupportState: AnyPublisher<Bool, Never>,
currencyFormatter: CurrencyFormatter) {
self.siteID = siteID
let network = AlamofireNetwork(credentials: credentials)
let network = AlamofireNetwork(credentials: credentials,
selectedSite: selectedSite,
appPasswordSupportState: appPasswordSupportState)
self.ordersRemote = OrdersRemote(network: network)
self.currencyFormatter = currencyFormatter
}
Expand Down
13 changes: 11 additions & 2 deletions Modules/Sources/Yosemite/Tools/POS/POSCatalogFullSyncService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import protocol Networking.POSCatalogSyncRemoteProtocol
import class Networking.AlamofireNetwork
import class Networking.POSCatalogSyncRemote
import Storage
import struct Combine.AnyPublisher
import struct NetworkingCore.JetpackSite

// TODO - remove the periphery ignore comment when the catalog is integrated with POS.
// periphery:ignore
Expand Down Expand Up @@ -30,12 +32,19 @@ public final class POSCatalogFullSyncService: POSCatalogFullSyncServiceProtocol
private let persistenceService: POSCatalogPersistenceServiceProtocol
private let batchedLoader: BatchedRequestLoader

public convenience init?(credentials: Credentials?, batchSize: Int = 2, grdbManager: GRDBManagerProtocol) {
public convenience init?(credentials: Credentials?,
selectedSite: AnyPublisher<JetpackSite?, Never>,
appPasswordSupportState: AnyPublisher<Bool, Never>,
batchSize: Int = 2,
grdbManager: GRDBManagerProtocol) {
guard let credentials else {
DDLogError("⛔️ Could not create POSCatalogFullSyncService due missing credentials")
return nil
}
let network = AlamofireNetwork(credentials: credentials, ensuresSessionManagerIsInitialized: true)
let network = AlamofireNetwork(credentials: credentials,
selectedSite: selectedSite,
appPasswordSupportState: appPasswordSupportState,
ensuresSessionManagerIsInitialized: true)
let syncRemote = POSCatalogSyncRemote(network: network)
let persistenceService = POSCatalogPersistenceService(grdbManager: grdbManager)
self.init(syncRemote: syncRemote, batchSize: batchSize, persistenceService: persistenceService)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import protocol Networking.POSCatalogSyncRemoteProtocol
import class Networking.AlamofireNetwork
import class Networking.POSCatalogSyncRemote
import protocol Storage.GRDBManagerProtocol
import struct NetworkingCore.JetpackSite
import struct Combine.AnyPublisher

// TODO - remove the periphery ignore comment when the service is integrated with POS.
// periphery:ignore
Expand All @@ -22,12 +24,19 @@ public final class POSCatalogIncrementalSyncService: POSCatalogIncrementalSyncSe
private let persistenceService: POSCatalogPersistenceServiceProtocol
private let batchedLoader: BatchedRequestLoader

public convenience init?(credentials: Credentials?, batchSize: Int = 1, grdbManager: GRDBManagerProtocol) {
public convenience init?(credentials: Credentials?,
selectedSite: AnyPublisher<JetpackSite?, Never>,
appPasswordSupportState: AnyPublisher<Bool, Never>,
batchSize: Int = 1,
grdbManager: GRDBManagerProtocol) {
guard let credentials else {
DDLogError("⛔️ Could not create POSCatalogIncrementalSyncService due missing credentials")
return nil
}
let network = AlamofireNetwork(credentials: credentials, ensuresSessionManagerIsInitialized: true)
let network = AlamofireNetwork(credentials: credentials,
selectedSite: selectedSite,
appPasswordSupportState: appPasswordSupportState,
ensuresSessionManagerIsInitialized: true)
let syncRemote = POSCatalogSyncRemote(network: network)
let persistenceService = POSCatalogPersistenceService(grdbManager: grdbManager)
self.init(syncRemote: syncRemote, batchSize: batchSize, persistenceService: persistenceService)
Expand Down
11 changes: 9 additions & 2 deletions Modules/Sources/Yosemite/Tools/POS/POSOrderService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import Foundation
import Networking
import class WooFoundation.CurrencyFormatter
import enum WooFoundation.CurrencyCode
import struct Combine.AnyPublisher
import struct NetworkingCore.JetpackSite

public protocol POSOrderServiceProtocol {
/// Syncs order based on the cart.
Expand All @@ -17,12 +19,17 @@ public final class POSOrderService: POSOrderServiceProtocol {
private let siteID: Int64
private let ordersRemote: POSOrdersRemoteProtocol

public convenience init?(siteID: Int64, credentials: Credentials?) {
public convenience init?(siteID: Int64,
credentials: Credentials?,
selectedSite: AnyPublisher<JetpackSite?, Never>,
appPasswordSupportState: AnyPublisher<Bool, Never>) {
guard let credentials else {
DDLogError("⛔️ Could not create POSOrderService due to not finding credentials")
return nil
}
let network = AlamofireNetwork(credentials: credentials)
let network = AlamofireNetwork(credentials: credentials,
selectedSite: selectedSite,
appPasswordSupportState: appPasswordSupportState)
self.init(siteID: siteID,
ordersRemote: OrdersRemote(network: network))
}
Expand Down
10 changes: 8 additions & 2 deletions Modules/Sources/Yosemite/Tools/POS/POSReceiptService.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import SwiftUI
import Networking
import struct Combine.AnyPublisher

public protocol POSReceiptServiceProtocol {
func sendReceipt(orderID: Int64, recipientEmail: String, isEligibleForPOSReceipt: Bool) async throws
Expand All @@ -9,12 +10,17 @@ public final class POSReceiptService: POSReceiptServiceProtocol {
private let siteID: Int64
private let receiptsRemote: POSReceiptsRemoteProtocol

public convenience init?(siteID: Int64, credentials: Credentials?) {
public convenience init?(siteID: Int64,
credentials: Credentials?,
selectedSite: AnyPublisher<JetpackSite?, Never>,
appPasswordSupportState: AnyPublisher<Bool, Never>) {
guard let credentials else {
DDLogError("⛔️ Could not create POSReceiptService due to not finding credentials")
return nil
}
let network = AlamofireNetwork(credentials: credentials)
let network = AlamofireNetwork(credentials: credentials,
selectedSite: selectedSite,
appPasswordSupportState: appPasswordSupportState)
self.init(siteID: siteID,
receiptsRemote: ReceiptRemote(network: network))
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Foundation
import Networking
import struct Combine.AnyPublisher

/// Protocol for POS site setting service that manages WooCommerce feature flags.
public protocol POSSiteSettingServiceProtocol {
Expand All @@ -17,8 +18,12 @@ public protocol POSSiteSettingServiceProtocol {
public final class POSSiteSettingService: POSSiteSettingServiceProtocol {
private let remote: SiteSettingsRemoteProtocol

public init(credentials: Credentials?) {
let network = AlamofireNetwork(credentials: credentials)
public init(credentials: Credentials?,
selectedSite: AnyPublisher<JetpackSite?, Never>,
appPasswordSupportState: AnyPublisher<Bool, Never>) {
let network = AlamofireNetwork(credentials: credentials,
selectedSite: selectedSite,
appPasswordSupportState: appPasswordSupportState)
self.remote = SiteSettingsRemote(network: network)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import Foundation
import Networking
import Storage
import struct Combine.AnyPublisher
import struct NetworkingCore.JetpackSite

public protocol PointOfSaleSettingsServiceProtocol {
func retrievePointOfSaleSettings() async throws -> POSReceiptInformation
Expand All @@ -18,8 +20,12 @@ public final class PointOfSaleSettingsService: PointOfSaleSettingsServiceProtoco

public convenience init(siteID: Int64,
credentials: Credentials?,
selectedSite: AnyPublisher<JetpackSite?, Never>,
appPasswordSupportState: AnyPublisher<Bool, Never>,
storage: StorageManagerType) {
let network = AlamofireNetwork(credentials: credentials)
let network = AlamofireNetwork(credentials: credentials,
selectedSite: selectedSite,
appPasswordSupportState: appPasswordSupportState)
self.init(siteID: siteID, settingStoreMethods: SettingStoreMethods(storageManager: storage,
network: network))
}
Expand Down
Loading