// Copyright © 2020 Metabolist. All rights reserved. import Foundation import Combine class IdentityService { @Published var identity: Identity let observationErrors: AnyPublisher private let networkClient: MastodonClient private let appEnvironment: AppEnvironment private let observationErrorsInput = PassthroughSubject() private var cancellables = Set() init(identityID: UUID, appEnvironment: AppEnvironment) throws { self.appEnvironment = appEnvironment observationErrors = observationErrorsInput.eraseToAnyPublisher() networkClient = MastodonClient(configuration: appEnvironment.URLSessionConfiguration) networkClient.accessToken = try SecretsService( identityID: identityID, keychainService: appEnvironment.keychainService) .item(.accessToken) let observation = appEnvironment.identityDatabase.identityObservation(id: identityID).share() var initialIdentity: Identity? observation.first().sink( receiveCompletion: { _ in }, receiveValue: { initialIdentity = $0 }) .store(in: &cancellables) guard let identity = initialIdentity else { throw IdentityDatabaseError.identityNotFound } self.identity = identity networkClient.instanceURL = identity.url observation.catch { [weak self] error -> Empty in self?.observationErrorsInput.send(error) return Empty() } .assign(to: &$identity) } } extension IdentityService { var isAuthorized: Bool { networkClient.accessToken != nil } func verifyCredentials() -> AnyPublisher { networkClient.request(AccountEndpoint.verifyCredentials) .continuingIfWeakReferenceIsStillAlive(to: self) .map { ($0, $1.identity.id) } .flatMap(appEnvironment.identityDatabase.updateAccount) .eraseToAnyPublisher() } func refreshServerPreferences() -> AnyPublisher { networkClient.request(PreferencesEndpoint.preferences) .continuingIfWeakReferenceIsStillAlive(to: self) .map { ($1.identity.preferences.updated(from: $0), $1.identity.id) } .flatMap(appEnvironment.identityDatabase.updatePreferences) .eraseToAnyPublisher() } func refreshInstance() -> AnyPublisher { networkClient.request(InstanceEndpoint.instance) .continuingIfWeakReferenceIsStillAlive(to: self) .map { ($0, $1.identity.id) } .flatMap(appEnvironment.identityDatabase.updateInstance) .eraseToAnyPublisher() } func identitiesObservation() -> AnyPublisher<[Identity], Error> { appEnvironment.identityDatabase.identitiesObservation() } func recentIdentitiesObservation() -> AnyPublisher<[Identity], Error> { appEnvironment.identityDatabase.recentIdentitiesObservation(excluding: identity.id) } func updatePreferences(_ preferences: Identity.Preferences) -> AnyPublisher { appEnvironment.identityDatabase.updatePreferences(preferences, forIdentityID: identity.id) } }