Merge pull request #5340 from k9mail/imap_folder_pusher

Add ImapFolderPusher to listen for changes to an IMAP folder
This commit is contained in:
cketti 2021-06-13 00:13:30 +02:00 committed by GitHub
commit 154dbe1229
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 119 additions and 0 deletions

View file

@ -0,0 +1,85 @@
package com.fsck.k9.backend.imap
import com.fsck.k9.mail.power.PowerManager
import com.fsck.k9.mail.store.imap.IdleRefreshManager
import com.fsck.k9.mail.store.imap.IdleResult
import com.fsck.k9.mail.store.imap.ImapFolderIdler
import com.fsck.k9.mail.store.imap.ImapStore
import kotlin.concurrent.thread
import timber.log.Timber
/**
* Listens for changes to an IMAP folder in a dedicated thread.
*/
class ImapFolderPusher(
private val imapStore: ImapStore,
private val powerManager: PowerManager,
private val idleRefreshManager: IdleRefreshManager,
private val callback: ImapPusherCallback,
private val accountName: String,
private val folderServerId: String,
private val idleRefreshTimeoutMs: Long
) {
@Volatile
private var folderIdler: ImapFolderIdler? = null
@Volatile
private var stopPushing = false
fun start() {
Timber.v("Starting ImapFolderPusher for %s / %s", accountName, folderServerId)
thread(name = "ImapFolderPusher-$accountName-$folderServerId") {
Timber.v("Starting ImapFolderPusher thread for %s / %s", accountName, folderServerId)
runPushLoop()
Timber.v("Exiting ImapFolderPusher thread for %s / %s", accountName, folderServerId)
}
}
fun stop() {
Timber.v("Stopping ImapFolderPusher for %s / %s", accountName, folderServerId)
stopPushing = true
folderIdler?.stop()
}
private fun runPushLoop() {
val wakeLock = powerManager.newWakeLock("ImapFolderPusher-$accountName-$folderServerId")
wakeLock.acquire()
performInitialSync()
val folderIdler = ImapFolderIdler.create(
idleRefreshManager,
wakeLock,
imapStore,
folderServerId,
idleRefreshTimeoutMs
).also {
folderIdler = it
}
try {
while (!stopPushing) {
val idleResult = folderIdler.idle()
if (idleResult == IdleResult.SYNC) {
callback.onPushEvent(folderServerId)
}
}
} catch (e: Exception) {
Timber.v(e, "Exception in ImapFolderPusher")
this.folderIdler = null
callback.onPushError(folderServerId, e)
}
wakeLock.release()
}
private fun performInitialSync() {
callback.onPushEvent(folderServerId)
}
}

View file

@ -0,0 +1,6 @@
package com.fsck.k9.backend.imap
interface ImapPusherCallback {
fun onPushEvent(folderServerId: String)
fun onPushError(folderServerId: String, exception: Exception)
}

View file

@ -1,9 +1,37 @@
package com.fsck.k9.mail.store.imap package com.fsck.k9.mail.store.imap
import com.fsck.k9.mail.power.WakeLock
interface ImapFolderIdler { interface ImapFolderIdler {
fun idle(): IdleResult fun idle(): IdleResult
fun stop() fun stop()
companion object {
private val connectionProvider = object : ImapConnectionProvider {
override fun getConnection(folder: ImapFolder): ImapConnection? {
require(folder is RealImapFolder)
return folder.connection
}
}
fun create(
idleRefreshManager: IdleRefreshManager,
wakeLock: WakeLock,
imapStore: ImapStore,
folderServerId: String,
idleRefreshTimeoutMs: Long
): ImapFolderIdler {
return RealImapFolderIdler(
idleRefreshManager,
wakeLock,
imapStore,
connectionProvider,
folderServerId,
idleRefreshTimeoutMs
)
}
}
} }
enum class IdleResult { enum class IdleResult {