@ -45,33 +45,76 @@ public final class BackgroundPoller : NSObject {
private static func getMessages ( for publicKey : String ) -> Promise < Void > {
return SnodeAPI . getSwarm ( for : publicKey ) . then ( on : DispatchQueue . main ) { swarm -> Promise < Void > in
guard let snode = swarm . randomElement ( ) else { throw SnodeAPI . Error . generic }
return attempt ( maxRetryCount : 4 , recoveringOn : DispatchQueue . main ) {
return SnodeAPI . getRawMessages ( from : snode , associatedWith : publicKey ) . then ( on : DispatchQueue . main ) { rawResponse -> Promise < Void > in
let messages : [ SnodeReceivedMessage ] = SnodeAPI . parseRawMessagesResponse ( rawResponse , from : snode , associatedWith : publicKey )
let promises = messages . compactMap { message -> Promise < Void > ? in
// U s e a b e s t a t t e m p t a p p r o a c h h e r e ; w e d o n ' t w a n t t o f a i l t h e e n t i r e p r o c e s s
// i f o n e o f t h e m e s s a g e s f a i l e d t o p a r s e
guard
let envelope = SNProtoEnvelope . from ( message ) ,
let data = try ? envelope . serializedData ( )
else { return nil }
let job = MessageReceiveJob (
data : data ,
serverHash : message . info . hash ,
isBackgroundPoll : true
)
return job . execute ( )
}
// N o w t h a t t h e M e s s a g e R e c e i v e J o b ' s h a v e b e e n c r e a t e d w e c a n p e r s i s t t h e r e c e i v e d m e s s a g e s
if ! messages . isEmpty {
GRDBStorage . shared . write { db in
messages . forEach { try ? $0 . info . save ( db ) }
guard ! messages . isEmpty else { return Promise . value ( ( ) ) }
var jobsToRun : [ Job ] = [ ]
GRDBStorage . shared . write { db in
var threadMessages : [ String : [ MessageReceiveJob . Details . MessageInfo ] ] = [ : ]
// TODO: T e s t t h i s u p d a t e d l o g i c
messages . forEach { message in
guard let envelope = SNProtoEnvelope . from ( message ) else { return }
// E x t r a c t t h e t h r e a d I d a n d a d d t h a t t o t h e m e s s a g e R e c e i v e j o b f o r
// m u l t i - t h r e a d i n g a n d g a r b a g e c o l l e c t i o n p u r p o s e s
let threadId : String ? = MessageReceiver . extractSenderPublicKey ( db , from : envelope )
do {
threadMessages [ threadId ? ? " " ] = ( threadMessages [ threadId ? ? " " ] ? ? [ ] )
. appending (
MessageReceiveJob . Details . MessageInfo (
data : try envelope . serializedData ( ) ,
serverHash : message . info . hash
)
)
// P e r s i s t t h e r e c e i v e d m e s s a g e a f t e r t h e M e s s a g e R e c e i v e J o b i s c r e a t e d
_ = try message . info . saved ( db )
}
catch {
SNLog ( " Failed to deserialize envelope due to error: \( error ) . " )
}
}
threadMessages
. forEach { threadId , threadMessages in
let maybeJob : Job ? = Job (
variant : . messageReceive ,
behaviour : . runOnce ,
threadId : threadId ,
details : MessageReceiveJob . Details (
messages : threadMessages ,
isBackgroundPoll : false
)
)
guard let job : Job = maybeJob else { return }
JobRunner . add ( db , job : job )
jobsToRun . append ( job )
}
}
let promises = jobsToRun . compactMap { job -> Promise < Void > ? in
let ( promise , seal ) = Promise < Void > . pending ( )
// N o t e : I n t h e b a c k g r o u n d w e j u s t w a n t j o b s t o f a i l s i l e n t l y
MessageReceiveJob . run (
job ,
success : { _ , _ in seal . fulfill ( ( ) ) } ,
failure : { _ , _ , _ in seal . fulfill ( ( ) ) } ,
deferred : { _ in seal . fulfill ( ( ) ) }
)
return promise
}
return when ( fulfilled : promises ) // T h e p r o m i s e r e t u r n e d b y M e s s a g e R e c e i v e J o b n e v e r r e j e c t s
return when ( fulfilled : promises )
}
}
}