feat: Update open group avatars periodically (#807)

* feat: Update open group avatars periodically

* Updated timestamp

* Existing job check

* Refresh avatar on the conversation

* Remove println statement

* Update profile picture on recipient modified event
This commit is contained in:
ceokot
2021-12-15 08:11:55 +02:00
committed by GitHub
parent 5601da0e22
commit 44f5684b21
12 changed files with 135 additions and 27 deletions

View File

@@ -4,6 +4,7 @@ import android.content.Context
import android.net.Uri
import org.session.libsession.messaging.contacts.Contact
import org.session.libsession.messaging.jobs.AttachmentUploadJob
import org.session.libsession.messaging.jobs.GroupAvatarDownloadJob
import org.session.libsession.messaging.jobs.Job
import org.session.libsession.messaging.jobs.MessageSendJob
import org.session.libsession.messaging.messages.control.ConfigurationMessage
@@ -43,6 +44,7 @@ interface StorageProtocol {
fun getAttachmentUploadJob(attachmentID: Long): AttachmentUploadJob?
fun getMessageSendJob(messageSendJobID: String): MessageSendJob?
fun getMessageReceiveJob(messageReceiveJobID: String): Job?
fun getGroupAvatarDownloadJob(server: String, room: String): Job?
fun resumeMessageSendJobIfNeeded(messageSendJobID: String)
fun isJobCanceled(job: Job): Boolean
@@ -117,6 +119,7 @@ interface StorageProtocol {
fun getClosedGroupEncryptionKeyPairs(groupPublicKey: String): MutableList<ECKeyPair>
fun getLatestClosedGroupEncryptionKeyPair(groupPublicKey: String): ECKeyPair?
fun updateFormationTimestamp(groupID: String, formationTimestamp: Long)
fun updateTimestampUpdated(groupID: String, updatedTimestamp: Long)
fun setExpirationTimer(groupID: String, duration: Int)
// Groups

View File

@@ -0,0 +1,54 @@
package org.session.libsession.messaging.jobs
import org.session.libsession.messaging.MessagingModuleConfiguration
import org.session.libsession.messaging.open_groups.OpenGroupAPIV2
import org.session.libsession.messaging.utilities.Data
import org.session.libsession.utilities.GroupUtil
class GroupAvatarDownloadJob(val room: String, val server: String) : Job {
override var delegate: JobDelegate? = null
override var id: String? = null
override var failureCount: Int = 0
override val maxFailureCount: Int = 10
override fun execute() {
val storage = MessagingModuleConfiguration.shared.storage
try {
val info = OpenGroupAPIV2.getInfo(room, server).get()
val bytes = OpenGroupAPIV2.downloadOpenGroupProfilePicture(info.id, server).get()
val groupId = GroupUtil.getEncodedOpenGroupID("$server.$room".toByteArray())
storage.updateProfilePicture(groupId, bytes)
storage.updateTimestampUpdated(groupId, System.currentTimeMillis())
delegate?.handleJobSucceeded(this)
} catch (e: Exception) {
delegate?.handleJobFailed(this, e)
}
}
override fun serialize(): Data {
return Data.Builder()
.putString(ROOM, room)
.putString(SERVER, server)
.build()
}
override fun getFactoryKey(): String = KEY
companion object {
const val KEY = "GroupAvatarDownloadJob"
private const val ROOM = "room"
private const val SERVER = "server"
}
class Factory : Job.Factory<GroupAvatarDownloadJob> {
override fun create(data: Data): GroupAvatarDownloadJob {
return GroupAvatarDownloadJob(
data.getString(ROOM),
data.getString(SERVER)
)
}
}
}

View File

@@ -45,9 +45,16 @@ class JobQueue : JobDelegate {
while (isActive) {
for (job in queue) {
when (job) {
is NotifyPNServerJob, is AttachmentUploadJob, is MessageSendJob -> txQueue.send(job)
is MessageReceiveJob, is TrimThreadJob, is BatchMessageReceiveJob, is AttachmentDownloadJob-> rxQueue.send(job)
else -> throw IllegalStateException("Unexpected job type.")
is NotifyPNServerJob, is AttachmentUploadJob, is MessageSendJob -> {
txQueue.send(job)
}
is MessageReceiveJob, is TrimThreadJob, is BatchMessageReceiveJob,
is AttachmentDownloadJob, is GroupAvatarDownloadJob -> {
rxQueue.send(job)
}
else -> {
throw IllegalStateException("Unexpected job type.")
}
}
}
}
@@ -123,7 +130,8 @@ class JobQueue : JobDelegate {
MessageReceiveJob.KEY,
MessageSendJob.KEY,
NotifyPNServerJob.KEY,
BatchMessageReceiveJob.KEY
BatchMessageReceiveJob.KEY,
GroupAvatarDownloadJob.KEY
)
allJobTypes.forEach { type ->
resumePendingJobs(type)

View File

@@ -12,7 +12,8 @@ class SessionJobManagerFactories {
MessageSendJob.KEY to MessageSendJob.Factory(),
NotifyPNServerJob.KEY to NotifyPNServerJob.Factory(),
TrimThreadJob.KEY to TrimThreadJob.Factory(),
BatchMessageReceiveJob.KEY to BatchMessageReceiveJob.Factory()
BatchMessageReceiveJob.KEY to BatchMessageReceiveJob.Factory(),
GroupAvatarDownloadJob.KEY to GroupAvatarDownloadJob.Factory()
)
}
}

View File

@@ -40,6 +40,7 @@ class OpenGroupPollerV2(private val server: String, private val executorService:
fun poll(isBackgroundPoll: Boolean = false): Promise<Unit, Exception> {
val storage = MessagingModuleConfiguration.shared.storage
val rooms = storage.getAllV2OpenGroups().values.filter { it.server == server }.map { it.room }
rooms.forEach { downloadGroupAvatarIfNeeded(it) }
return OpenGroupAPIV2.compactPoll(rooms, server).successBackground { responses ->
responses.forEach { (room, response) ->
val openGroupID = "$server.$room"
@@ -50,7 +51,7 @@ class OpenGroupPollerV2(private val server: String, private val executorService:
}
}
}.always {
executorService?.schedule(this@OpenGroupPollerV2::poll, OpenGroupPollerV2.pollInterval, TimeUnit.MILLISECONDS)
executorService?.schedule(this@OpenGroupPollerV2::poll, pollInterval, TimeUnit.MILLISECONDS)
}.map { }
}
@@ -103,4 +104,15 @@ class OpenGroupPollerV2(private val server: String, private val executorService:
storage.setLastDeletionServerID(room, server, latestMax)
}
}
private fun downloadGroupAvatarIfNeeded(room: String) {
val storage = MessagingModuleConfiguration.shared.storage
if (storage.getGroupAvatarDownloadJob(server, room) != null) return
val groupId = GroupUtil.getEncodedOpenGroupID("$server.$room".toByteArray())
storage.getGroup(groupId)?.let {
if (System.currentTimeMillis() > it.updatedTimestamp + TimeUnit.DAYS.toMillis(7)) {
JobQueue.shared.add(GroupAvatarDownloadJob(room, server))
}
}
}
}

View File

@@ -1,15 +1,14 @@
package org.session.libsession.utilities
import android.text.TextUtils
import org.session.libsession.utilities.Address
import java.io.IOException
import java.util.*
import java.util.LinkedList
class GroupRecord(
val encodedId: String, val title: String, members: String?, val avatar: ByteArray?,
val avatarId: Long?, val avatarKey: ByteArray?, val avatarContentType: String?,
val relay: String?, val isActive: Boolean, val avatarDigest: ByteArray?, val isMms: Boolean,
val url: String?, admins: String?, val formationTimestamp: Long
val url: String?, admins: String?, val formationTimestamp: Long, val updatedTimestamp: Long
) {
var members: List<Address> = LinkedList<Address>()
var admins: List<Address> = LinkedList<Address>()