-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy pathProfileStore.swift
106 lines (93 loc) · 3.34 KB
/
ProfileStore.swift
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
99
100
101
102
103
104
105
106
import Sargon
// MARK: - ProfileStore
// Until we fully migrate to have everything Profile in SargonOS, this will be kept in place.
// The next steps for migration are outlined in https://radixdlt.atlassian.net/browse/ABW-3590.
final actor ProfileStore {
static let shared = ProfileStore()
private let profileSubject: AsyncCurrentValueSubject<Profile?> = .init(nil)
private let profileStateSubject: AsyncReplaySubject<ProfileState> = .init(bufferSize: 1)
private init() {
Task {
for try await state in await ProfileStateChangeEventPublisher.shared.eventStream() {
if case let .loaded(profile) = state {
self.profileSubject.send(profile)
}
self.profileStateSubject.send(state)
}
}
}
}
extension ProfileStore {
func profile() -> Profile {
guard let profile = profileSubject.value else {
fatalError("Programmer error - tried to access profile when it was not loaded yet.")
}
return profile
}
func profileStateSequence() async -> AnyAsyncSequence<ProfileState> {
profileStateSubject.share().eraseToAnyAsyncSequence()
}
}
extension ProfileStore {
func createNewProfile() async throws {
let shouldPreDeriveInstances: Bool
#if DEBUG
shouldPreDeriveInstances = true
#else
shouldPreDeriveInstances = false
#endif
return try await SargonOS.shared.newWallet(shouldPreDeriveInstances: shouldPreDeriveInstances)
}
func finishOnboarding(
with accountsRecoveredFromScanningUsingMnemonic: AccountsRecoveredFromScanningUsingMnemonic
) async throws {
try await SargonOS.shared.newWalletWithDerivedBdfs(
hdFactorSource: accountsRecoveredFromScanningUsingMnemonic.factorSource,
accounts: accountsRecoveredFromScanningUsingMnemonic.accounts.elements
)
}
func importProfile(_ profileToImport: Profile, skippedMainBdfs: Bool) async throws {
var profileToImport = profileToImport
profileToImport.changeCurrentToMainnetIfNeeded()
try await SargonOS.shared.importWallet(profile: profileToImport, bdfsSkipped: skippedMainBdfs)
}
func deleteProfile() async throws {
try await SargonOS.shared.deleteWallet()
}
}
// MARK: Public
extension ProfileStore {
/// Mutates the in-memory copy of the Profile usung `transform`, and saves a
/// snapshot of it profile into Keychain (after having updated its header)
/// - Parameter transform: A mutating transform updating the profile.
/// - Returns: The result of the transform, often this might be `Void`.
func updating<T: Sendable>(
_ transform: @Sendable (inout Profile) async throws -> T
) async throws -> T {
var updated = profile()
let result = try await transform(&updated)
try await SargonOS.shared.setProfile(profile: updated)
return result
}
/// Update Profile, by updating the current network
/// - Parameter update: A mutating update to perform on the profiles's active network
func updatingOnCurrentNetwork(_ update: @Sendable (inout ProfileNetwork) async throws -> Void) async throws {
try await updating { profile in
var network = try await network()
try await update(&network)
try profile.updateOnNetwork(network)
}
}
}
// MARK: "Private"
extension ProfileStore {
func _lens<Property>(
_ transform: @escaping @Sendable (Profile) -> Property?
) -> AnyAsyncSequence<Property> where Property: Sendable & Equatable {
profileSubject
.compactMap { $0.flatMap(transform) }
.share() // Multicast
.removeDuplicates()
.eraseToAnyAsyncSequence()
}
}