2021-10-09 19:01:08 +08:00
//
// I n s t a n c e S e r v i c e . s w i f t
// M a s t o d o n
//
// C r e a t e d b y C i r n o M a i n a s u K o n 2 0 2 1 - 1 0 - 9 .
//
import os . log
import Foundation
import Combine
import CoreData
import CoreDataStack
import MastodonSDK
2022-09-30 19:28:09 +08:00
public final class InstanceService {
2021-10-09 19:01:08 +08:00
var disposeBag = Set < AnyCancellable > ( )
let logger = Logger ( subsystem : " InstanceService " , category : " Logic " )
// i n p u t
let backgroundManagedObjectContext : NSManagedObjectContext
weak var apiService : APIService ?
weak var authenticationService : AuthenticationService ?
// o u t p u t
2022-11-14 13:12:16 +01:00
2021-10-09 19:01:08 +08:00
init (
apiService : APIService ,
authenticationService : AuthenticationService
) {
self . backgroundManagedObjectContext = apiService . backgroundManagedObjectContext
self . apiService = apiService
self . authenticationService = authenticationService
2022-10-09 20:07:57 +08:00
authenticationService . $ mastodonAuthenticationBoxes
2021-10-09 19:01:08 +08:00
. receive ( on : DispatchQueue . main )
2022-10-09 20:07:57 +08:00
. compactMap { $0 . first ? . domain }
2021-10-09 19:01:08 +08:00
. removeDuplicates ( ) // p r e v e n t i n f i n i t y l o o p
. 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 )
2022-12-12 16:41:13 +01:00
. flatMap { [ unowned self ] response -> AnyPublisher < Void , Error > in
if response . value . version ? . majorServerVersion ( greaterThanOrEquals : 4 ) = = true {
return apiService . instanceV2 ( domain : domain )
. flatMap { return self . updateInstanceV2 ( domain : domain , response : $0 ) }
. eraseToAnyPublisher ( )
} else {
return self . updateInstance ( domain : domain , response : response )
2021-10-09 19:01:08 +08:00
}
}
2022-12-12 16:41:13 +01:00
// . f l a t M a p { [ u n o w n e d s e l f ] r e s p o n s e - > A n y P u b l i s h e r < V o i d , E r r o r > i n
// r e t u r n
// }
2021-10-09 19:01:08 +08:00
. 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
2022-05-07 11:42:10 +08:00
guard let _ = self else { return }
2021-10-09 19:01:08 +08:00
// d o n o t h i n g
}
. store ( in : & disposeBag )
}
2022-12-12 16:41:13 +01:00
private func updateInstance ( domain : String , response : Mastodon . Response . Content < Mastodon . Entity . Instance > ) -> AnyPublisher < Void , Error > {
let managedObjectContext = self . backgroundManagedObjectContext
return managedObjectContext . performChanges {
// g e t i n s t a n c e
let ( instance , _ ) = APIService . CoreData . createOrMergeInstance (
into : managedObjectContext ,
domain : domain ,
entity : response . value ,
networkDate : response . networkDate ,
log : Logger ( subsystem : " Update " , category : " InstanceService " )
)
// u p d a t e r e l a t i o n s h i p
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 in
switch result {
case . success :
break
case . failure ( let error ) :
throw error
}
}
. eraseToAnyPublisher ( )
}
private func updateInstanceV2 ( domain : String , response : Mastodon . Response . Content < Mastodon . Entity . V2 . Instance > ) -> AnyPublisher < Void , Error > {
let managedObjectContext = self . backgroundManagedObjectContext
return managedObjectContext . performChanges {
// g e t i n s t a n c e
2022-12-14 09:51:15 +01:00
let ( instance , _ ) = APIService . CoreData . createOrMergeInstance (
in : managedObjectContext ,
context : . init (
domain : domain ,
entity : response . value ,
networkDate : response . networkDate ,
log : Logger ( subsystem : " Update " , category : " InstanceService " )
)
2022-12-12 16:41:13 +01:00
)
// u p d a t e r e l a t i o n s h i p
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 in
switch result {
case . success :
break
case . failure ( let error ) :
throw error
}
}
. eraseToAnyPublisher ( )
}
2021-10-09 19:01:08 +08:00
}
2022-11-24 07:46:27 +01:00
public extension InstanceService {
func updateMutesAndBlocks ( ) {
Task {
for authBox in authenticationService ? . mastodonAuthenticationBoxes ? ? [ ] {
do {
try await apiService ? . getMutes (
authenticationBox : authBox
)
2022-11-24 07:53:04 +01:00
try await apiService ? . getBlocked (
authenticationBox : authBox
)
2022-11-24 07:46:27 +01:00
self . logger . log ( level : . debug , " \( ( #file as NSString ) . lastPathComponent , privacy : . public ) [ \( #line , privacy : . public ) ], \( #function , privacy : . public ) : [Instance] update mutes and blocks succeeded " )
} catch {
self . logger . log ( level : . debug , " \( ( #file as NSString ) . lastPathComponent , privacy : . public ) [ \( #line , privacy : . public ) ], \( #function , privacy : . public ) : [Instance] update mutes and blocks failure: \( error . localizedDescription ) " )
}
}
}
}
}