summaryrefslogtreecommitdiffhomepage
path: root/ios/MullvadVPN/View controllers/Account/AccountInteractor.swift
blob: 055a65862179ff89aa7e9c3e6ff298e1bffd0eab (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
//
//  AccountInteractor.swift
//  MullvadVPN
//
//  Created by pronebird on 26/10/2022.
//  Copyright © 2025 Mullvad VPN AB. All rights reserved.
//

import Foundation
import MullvadREST
import MullvadSettings
import MullvadTypes
import Operations
import StoreKit

final class AccountInteractor: Sendable {
    let tunnelManager: TunnelManager
    let accountsProxy: RESTAccountHandling
    let apiProxy: APIQuerying
    let deviceProxy: DeviceHandling

    nonisolated(unsafe) var didReceiveTunnelState: (() -> Void)?
    nonisolated(unsafe) var didReceiveDeviceState: (@Sendable (DeviceState) -> Void)?

    nonisolated(unsafe) private var tunnelObserver: TunnelObserver?

    init(
        tunnelManager: TunnelManager,
        accountsProxy: RESTAccountHandling,
        apiProxy: APIQuerying,
        deviceProxy: DeviceHandling
    ) {
        self.tunnelManager = tunnelManager
        self.accountsProxy = accountsProxy
        self.apiProxy = apiProxy
        self.deviceProxy = deviceProxy

        let tunnelObserver =
            TunnelBlockObserver(
                didUpdateTunnelStatus: { [weak self] _, _ in
                    self?.didReceiveTunnelState?()
                },
                didUpdateDeviceState: { [weak self] _, deviceState, _ in
                    self?.didReceiveDeviceState?(deviceState)
                }
            )

        tunnelManager.addObserver(tunnelObserver)

        self.tunnelObserver = tunnelObserver
    }

    var tunnelState: TunnelState {
        tunnelManager.tunnelStatus.state
    }

    var deviceState: DeviceState {
        tunnelManager.deviceState
    }

    func logout() async {
        await tunnelManager.unsetAccount()
    }

    // This function is for testing only
    func getPaymentToken(for accountNumber: String) async -> Result<String, Error> {
        await withCheckedContinuation { continuation in
            _ =
                apiProxy
                .initStorekitPayment(
                    accountNumber: accountNumber,
                    retryStrategy: .noRetry,
                    completionHandler: { result in
                        continuation.resume(returning: result)
                    }
                )
        }
    }

    // This function is for testing only
    func sendStoreKitReceipt(
        _ transaction: VerificationResult<Transaction>,
        for accountNumber: String
    ) async -> Result<Void, Error> {
        await withCheckedContinuation { c in
            _ =
                apiProxy
                .checkStorekitPayment(
                    accountNumber: accountNumber,
                    transaction: StorekitTransaction(transaction: transaction.jwsRepresentation),
                    retryStrategy: .noRetry,
                    completionHandler: { result in
                        c.resume(returning: result)
                    }
                )
        }
    }
}