You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			82 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			Kotlin
		
	
			
		
		
	
	
			82 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			Kotlin
		
	
package org.thoughtcrime.securesms.loki.api
 | 
						|
 | 
						|
import android.content.Context
 | 
						|
import android.os.Handler
 | 
						|
import nl.komponents.kovenant.functional.bind
 | 
						|
import nl.komponents.kovenant.functional.map
 | 
						|
import org.thoughtcrime.securesms.jobs.PushContentReceiveJob
 | 
						|
import org.thoughtcrime.securesms.logging.Log
 | 
						|
import org.thoughtcrime.securesms.loki.database.SharedSenderKeysDatabase
 | 
						|
import org.thoughtcrime.securesms.loki.utilities.successBackground
 | 
						|
import org.whispersystems.signalservice.api.messages.SignalServiceEnvelope
 | 
						|
import org.whispersystems.signalservice.loki.api.SnodeAPI
 | 
						|
import org.whispersystems.signalservice.loki.api.SwarmAPI
 | 
						|
import org.whispersystems.signalservice.loki.utilities.getRandomElementOrNull
 | 
						|
 | 
						|
class ClosedGroupPoller private constructor(private val context: Context, private val database: SharedSenderKeysDatabase) {
 | 
						|
    private var isPolling = false
 | 
						|
    private val handler = Handler()
 | 
						|
 | 
						|
    private val task = object : Runnable {
 | 
						|
 | 
						|
        override fun run() {
 | 
						|
            poll()
 | 
						|
            handler.postDelayed(this, ClosedGroupPoller.pollInterval)
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    // region Settings
 | 
						|
    companion object {
 | 
						|
        private val pollInterval: Long = 2 * 1000
 | 
						|
 | 
						|
        public lateinit var shared: ClosedGroupPoller
 | 
						|
 | 
						|
        public fun configureIfNeeded(context: Context, sskDatabase: SharedSenderKeysDatabase) {
 | 
						|
            if (::shared.isInitialized) { return; }
 | 
						|
            shared = ClosedGroupPoller(context, sskDatabase)
 | 
						|
        }
 | 
						|
    }
 | 
						|
    // endregion
 | 
						|
 | 
						|
    // region Error
 | 
						|
    public class InsufficientSnodesException() : Exception("No snodes left to poll.")
 | 
						|
    public class PollingCanceledException() : Exception("Polling canceled.")
 | 
						|
    // endregion
 | 
						|
 | 
						|
    // region Public API
 | 
						|
    public fun startIfNeeded() {
 | 
						|
        if (isPolling) { return }
 | 
						|
        isPolling = true
 | 
						|
        task.run()
 | 
						|
    }
 | 
						|
 | 
						|
    public fun stopIfNeeded() {
 | 
						|
        isPolling = false
 | 
						|
        handler.removeCallbacks(task)
 | 
						|
    }
 | 
						|
    // endregion
 | 
						|
 | 
						|
    // region Private API
 | 
						|
    private fun poll() {
 | 
						|
        if (!isPolling) { return }
 | 
						|
        val publicKeys = database.getAllClosedGroupPublicKeys()
 | 
						|
        publicKeys.forEach { publicKey ->
 | 
						|
            SwarmAPI.shared.getSwarm(publicKey).bind { swarm ->
 | 
						|
                val snode = swarm.getRandomElementOrNull() ?: throw InsufficientSnodesException() // Should be cryptographically secure
 | 
						|
                if (!isPolling) { throw PollingCanceledException() }
 | 
						|
                SnodeAPI.shared.getRawMessages(snode, publicKey).map {SnodeAPI.shared.parseRawMessagesResponse(it, snode, publicKey) }
 | 
						|
            }.successBackground { messages ->
 | 
						|
                if (messages.isNotEmpty()) {
 | 
						|
                    Log.d("Loki", "Received ${messages.count()} new message(s) in closed group with public key: $publicKey.")
 | 
						|
                }
 | 
						|
                messages.forEach {
 | 
						|
                    PushContentReceiveJob(context).processEnvelope(SignalServiceEnvelope(it), false)
 | 
						|
                }
 | 
						|
            }.fail {
 | 
						|
                Log.d("Loki", "Polling failed for closed group with public key: $publicKey due to error: $it.")
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
    // endregion
 | 
						|
}
 |