@ -639,10 +639,8 @@ public final class SnodeAPI {
}
return getSwarm ( for : publicKey )
. tryFlatMap { swarm -> AnyPublisher < ( ResponseInfoType , SendMessagesResponse ) , Error > in
guard let snode : Snode = swarm . randomElement ( ) else { throw SnodeAPIError . generic }
return try sendMessage ( to : snode )
. tryFlatMapWithRandomSnode ( retry : maxRetryCount ) { snode -> AnyPublisher < ( ResponseInfoType , SendMessagesResponse ) , Error > in
try sendMessage ( to : snode )
. tryMap { info , response -> ( ResponseInfoType , SendMessagesResponse ) in
try response . validateResultMap (
sodium : sodium . wrappedValue ,
@ -651,11 +649,8 @@ public final class SnodeAPI {
return ( info , response )
}
. retry ( maxRetryCount )
. eraseToAnyPublisher ( )
}
. retry ( maxRetryCount )
. eraseToAnyPublisher ( )
}
public static func sendConfigMessages (
@ -732,10 +727,8 @@ public final class SnodeAPI {
let responseTypes = requests . map { $0 . responseType }
return getSwarm ( for : publicKey )
. tryFlatMap { swarm -> AnyPublisher < HTTP . BatchResponse , Error > in
guard let snode : Snode = swarm . randomElement ( ) else { throw SnodeAPIError . generic }
return SnodeAPI
. tryFlatMapWithRandomSnode ( retry : maxRetryCount ) { snode -> AnyPublisher < HTTP . BatchResponse , Error > in
SnodeAPI
. send (
request : SnodeRequest (
endpoint : . sequence ,
@ -749,8 +742,6 @@ public final class SnodeAPI {
. decoded ( as : responseTypes , requireAllResults : false , using : dependencies )
. eraseToAnyPublisher ( )
}
. retry ( maxRetryCount )
. eraseToAnyPublisher ( )
}
// MARK: - E d i t
@ -768,10 +759,8 @@ public final class SnodeAPI {
return getSwarm ( for : publicKey )
. subscribe ( on : Threading . workQueue )
. tryFlatMap { swarm -> AnyPublisher < [ String : [ ( hash : String , expiry : UInt64 ) ] ] , Error > in
guard let snode : Snode = swarm . randomElement ( ) else { throw SnodeAPIError . generic }
return SnodeAPI
. tryFlatMapWithRandomSnode ( retry : maxRetryCount ) { snode -> AnyPublisher < [ String : [ ( hash : String , expiry : UInt64 ) ] ] , Error > in
SnodeAPI
. send (
request : SnodeRequest (
endpoint : . expire ,
@ -796,11 +785,8 @@ public final class SnodeAPI {
validationData : serverHashes
)
}
. retry ( maxRetryCount )
. eraseToAnyPublisher ( )
}
. retry ( maxRetryCount )
. eraseToAnyPublisher ( )
}
public static func revokeSubkey (
@ -815,10 +801,8 @@ public final class SnodeAPI {
return getSwarm ( for : publicKey )
. subscribe ( on : Threading . workQueue )
. tryFlatMap { swarm -> AnyPublisher < Void , Error > in
guard let snode : Snode = swarm . randomElement ( ) else { throw SnodeAPIError . generic }
return SnodeAPI
. tryFlatMapWithRandomSnode ( retry : maxRetryCount ) { snode -> AnyPublisher < Void , Error > in
SnodeAPI
. send (
request : SnodeRequest (
endpoint : . revokeSubkey ,
@ -843,11 +827,8 @@ public final class SnodeAPI {
return ( )
}
. retry ( maxRetryCount )
. eraseToAnyPublisher ( )
}
. retry ( maxRetryCount )
. eraseToAnyPublisher ( )
}
// MARK: D e l e t e
@ -866,61 +847,46 @@ public final class SnodeAPI {
return getSwarm ( for : publicKey )
. subscribe ( on : Threading . workQueue )
. flatMap { swarm -> AnyPublisher < [ String : Bool ] , Error > in
Just ( ( ) )
. setFailureType ( to : Error . self )
. tryMap { _ -> Snode in
guard let snode : Snode = swarm . randomElement ( ) else { throw SnodeAPIError . generic }
. tryFlatMapWithRandomSnode ( retry : maxRetryCount ) { snode -> AnyPublisher < [ String : Bool ] , Error > in
SnodeAPI
. send (
request : SnodeRequest (
endpoint : . deleteMessages ,
body : DeleteMessagesRequest (
messageHashes : serverHashes ,
requireSuccessfulDeletion : false ,
pubkey : userX25519PublicKey ,
ed25519PublicKey : userED25519KeyPair . publicKey ,
ed25519SecretKey : userED25519KeyPair . secretKey
)
) ,
to : snode ,
associatedWith : publicKey ,
using : dependencies
)
. decoded ( as : DeleteMessagesResponse . self , using : dependencies )
. tryMap { _ , response -> [ String : Bool ] in
let validResultMap : [ String : Bool ] = try response . validResultMap (
sodium : sodium . wrappedValue ,
userX25519PublicKey : userX25519PublicKey ,
validationData : serverHashes
)
return snode
}
. flatMap { snode -> AnyPublisher < [ String : Bool ] , Error > in
SnodeAPI
. send (
request : SnodeRequest (
endpoint : . deleteMessages ,
body : DeleteMessagesRequest (
messageHashes : serverHashes ,
requireSuccessfulDeletion : false ,
pubkey : userX25519PublicKey ,
ed25519PublicKey : userED25519KeyPair . publicKey ,
ed25519SecretKey : userED25519KeyPair . secretKey
)
) ,
to : snode ,
associatedWith : publicKey ,
using : dependencies
// I f ` v a l i d R e s u l t M a p ` d i d n ' t t h r o w t h e n a t l e a s t o n e s e r v i c e n o d e
// d e l e t e d s u c c e s s f u l l y s o w e s h o u l d m a r k t h e h a s h a s i n v a l i d s o w e
// d o n ' t t r y t o f e t c h u p d a t e s u s i n g t h a t h a s h g o i n g f o r w a r d ( i f w e
// d o w e w o u l d e n d u p r e - f e t c h i n g a l l o l d m e s s a g e s )
Storage . shared . writeAsync { db in
try ? SnodeReceivedMessageInfo . handlePotentialDeletedOrInvalidHash (
db ,
potentiallyInvalidHashes : serverHashes
)
. subscribe ( on : Threading . workQueue )
. eraseToAnyPublisher ( )
. decoded ( as : DeleteMessagesResponse . self , using : dependencies )
. tryMap { _ , response -> [ String : Bool ] in
let validResultMap : [ String : Bool ] = try response . validResultMap (
sodium : sodium . wrappedValue ,
userX25519PublicKey : userX25519PublicKey ,
validationData : serverHashes
)
// I f ` v a l i d R e s u l t M a p ` d i d n ' t t h r o w t h e n a t l e a s t o n e s e r v i c e n o d e
// d e l e t e d s u c c e s s f u l l y s o w e s h o u l d m a r k t h e h a s h a s i n v a l i d s o w e
// d o n ' t t r y t o f e t c h u p d a t e s u s i n g t h a t h a s h g o i n g f o r w a r d ( i f w e
// d o w e w o u l d e n d u p r e - f e t c h i n g a l l o l d m e s s a g e s )
Storage . shared . writeAsync { db in
try ? SnodeReceivedMessageInfo . handlePotentialDeletedOrInvalidHash (
db ,
potentiallyInvalidHashes : serverHashes
)
}
return validResultMap
}
. retry ( maxRetryCount )
. eraseToAnyPublisher ( )
}
return validResultMap
}
. eraseToAnyPublisher ( )
}
. retry ( maxRetryCount )
. eraseToAnyPublisher ( )
}
// / C l e a r s a l l t h e u s e r ' s d a t a f r o m t h e i r s w a r m . R e t u r n s a d i c t i o n a r y o f s n o d e p u b l i c k e y t o d e l e t i o n c o n f i r m a t i o n .
@ -937,10 +903,8 @@ public final class SnodeAPI {
return getSwarm ( for : userX25519PublicKey )
. subscribe ( on : Threading . workQueue )
. tryFlatMap { swarm -> AnyPublisher < [ String : Bool ] , Error > in
guard let snode : Snode = swarm . randomElement ( ) else { throw SnodeAPIError . generic }
return getNetworkTime ( from : snode )
. tryFlatMapWithRandomSnode ( retry : maxRetryCount ) { snode -> AnyPublisher < [ String : Bool ] , Error > in
getNetworkTime ( from : snode )
. flatMap { timestampMs -> AnyPublisher < [ String : Bool ] , Error > in
SnodeAPI
. send (
@ -968,11 +932,8 @@ public final class SnodeAPI {
}
. eraseToAnyPublisher ( )
}
. retry ( maxRetryCount )
. eraseToAnyPublisher ( )
}
. retry ( maxRetryCount )
. eraseToAnyPublisher ( )
}
// / C l e a r s a l l t h e u s e r ' s d a t a f r o m t h e i r s w a r m . R e t u r n s a d i c t i o n a r y o f s n o d e p u b l i c k e y t o d e l e t i o n c o n f i r m a t i o n .
@ -990,10 +951,8 @@ public final class SnodeAPI {
return getSwarm ( for : userX25519PublicKey )
. subscribe ( on : Threading . workQueue )
. tryFlatMap { swarm -> AnyPublisher < [ String : Bool ] , Error > in
guard let snode : Snode = swarm . randomElement ( ) else { throw SnodeAPIError . generic }
return getNetworkTime ( from : snode )
. tryFlatMapWithRandomSnode ( retry : maxRetryCount ) { snode -> AnyPublisher < [ String : Bool ] , Error > in
getNetworkTime ( from : snode )
. flatMap { timestampMs -> AnyPublisher < [ String : Bool ] , Error > in
SnodeAPI
. send (
@ -1022,11 +981,8 @@ public final class SnodeAPI {
}
. eraseToAnyPublisher ( )
}
. retry ( maxRetryCount )
. eraseToAnyPublisher ( )
}
. retry ( maxRetryCount )
. eraseToAnyPublisher ( )
}
// MARK: - I n t e r n a l A P I
@ -1377,3 +1333,31 @@ public final class SNSnodeAPI: NSObject {
return UInt64 ( SnodeAPI . currentOffsetTimestampMs ( ) )
}
}
// MARK: - C o n v e n i e n c e
public extension Publisher where Output = = Set < Snode > {
func tryFlatMapWithRandomSnode < T , P > (
maxPublishers : Subscribers . Demand = . unlimited ,
retry retries : Int = 0 ,
_ transform : @ escaping ( Snode ) throws -> P
) -> AnyPublisher < T , Error > where T = = P . Output , P : Publisher , P . Failure = = Error {
return self
. mapError { $0 }
. flatMap ( maxPublishers : maxPublishers ) { swarm -> AnyPublisher < T , Error > in
var remainingSnodes : Set < Snode > = swarm
return Just ( ( ) )
. setFailureType ( to : Error . self )
. tryFlatMap ( maxPublishers : maxPublishers ) { _ -> AnyPublisher < T , Error > in
let snode : Snode = try remainingSnodes . popRandomElement ( ) ? ? { throw SnodeAPIError . generic } ( )
return try transform ( snode )
. eraseToAnyPublisher ( )
}
. retry ( retries )
. eraseToAnyPublisher ( )
}
. eraseToAnyPublisher ( )
}
}