mastodon-ios/Mastodon/Service/InstanceService.swift

104 lines
4.0 KiB
Swift

//
// InstanceService.swift
// Mastodon
//
// Created by Cirno MainasuK on 2021-10-9.
//
import os.log
import Foundation
import Combine
import CoreData
import CoreDataStack
import MastodonSDK
final class InstanceService {
var disposeBag = Set<AnyCancellable>()
let logger = Logger(subsystem: "InstanceService", category: "Logic")
// input
let backgroundManagedObjectContext: NSManagedObjectContext
weak var apiService: APIService?
weak var authenticationService: AuthenticationService?
// output
init(
apiService: APIService,
authenticationService: AuthenticationService
) {
self.backgroundManagedObjectContext = apiService.backgroundManagedObjectContext
self.apiService = apiService
self.authenticationService = authenticationService
authenticationService.activeMastodonAuthenticationBox
.receive(on: DispatchQueue.main)
.compactMap { $0?.domain }
.removeDuplicates() // prevent infinity loop
.sink { [weak self] domain in
guard let self = self else { return }
self.updateInstance(domain: domain)
}
.store(in: &disposeBag)
}
}
extension InstanceService {
func updateInstance(domain: String) {
guard let apiService = self.apiService else { return }
apiService.instance(domain: domain)
.flatMap { response -> AnyPublisher<Mastodon.Response.Content<Mastodon.Entity.Instance>, Error> in
let managedObjectContext = self.backgroundManagedObjectContext
return managedObjectContext.performChanges {
// get instance
let (instance, _) = APIService.CoreData.createOrMergeInstance(
into: managedObjectContext,
domain: domain,
entity: response.value,
networkDate: response.networkDate,
log: OSLog.api
)
// update relationship
let request = MastodonAuthentication.sortedFetchRequest
request.predicate = MastodonAuthentication.predicate(domain: domain)
request.returnsObjectsAsFaults = false
do {
let authentications = try managedObjectContext.fetch(request)
for authentication in authentications {
authentication.update(instance: instance)
}
} catch {
assertionFailure(error.localizedDescription)
}
}
.setFailureType(to: Error.self)
.tryMap { result -> Mastodon.Response.Content<Mastodon.Entity.Instance> in
switch result {
case .success:
return response
case .failure(let error):
throw error
}
}
.eraseToAnyPublisher()
}
.sink { [weak self] completion in
guard let self = self else { return }
switch completion {
case .failure(let error):
self.logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): [Instance] update instance failure: \(error.localizedDescription)")
case .finished:
self.logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): [Instance] update instance for domain: \(domain)")
}
} receiveValue: { [weak self] response in
guard let self = self else { return }
// do nothing
}
.store(in: &disposeBag)
}
}