Tweaked some open group handling and a couple of onboarding issues

Updated the OpenGroup adding and polling logic to reduce duplicate API calls
Updated the BackgroundGroupAddJob to start a GroupAvatarDownloadJob instead of running the download itself (to appear to run faster)
Defaulted OpenGroups to use blinded auth when no server capabilities are present
Fixed an issue where the background poller could be started even though the onboarding hadn't been completed
Fixed an issue where the database could get into an invalid state if the app was restarted during onboarding
This commit is contained in:
Morgan Pretty
2023-01-09 15:22:29 +11:00
parent d0a4bac83e
commit 5afd647686
13 changed files with 89 additions and 55 deletions

View File

@@ -41,15 +41,10 @@ class BackgroundGroupAddJob(val joinUrl: String): Job {
}
// get image
storage.setOpenGroupPublicKey(openGroup.server, openGroup.serverPublicKey)
val (capabilities, info) = OpenGroupApi.getCapabilitiesAndRoomInfo(openGroup.room, openGroup.server, false).get()
storage.setServerCapabilities(openGroup.server, capabilities.capabilities)
val imageId = info.imageId
storage.addOpenGroup(openGroup.joinUrl())
val info = storage.addOpenGroup(openGroup.joinUrl())
val imageId = info?.imageId
if (imageId != null) {
val bytes = OpenGroupApi.downloadOpenGroupProfilePicture(openGroup.server, openGroup.room, imageId).get()
val groupId = GroupUtil.getEncodedOpenGroupID("${openGroup.server}.${openGroup.room}".toByteArray())
storage.updateProfilePicture(groupId, bytes)
storage.updateTimestampUpdated(groupId, System.currentTimeMillis())
JobQueue.shared.add(GroupAvatarDownloadJob(openGroup.room, openGroup.server))
}
Log.d(KEY, "onOpenGroupAdded(${openGroup.server})")
storage.onOpenGroupAdded(openGroup.server)

View File

@@ -14,10 +14,9 @@ class GroupAvatarDownloadJob(val room: String, val server: String) : Job {
override fun execute() {
val storage = MessagingModuleConfiguration.shared.storage
val imageId = storage.getOpenGroup(room, server)?.imageId ?: return
try {
val info = OpenGroupApi.getRoomInfo(room, server).get()
val imageId = info.imageId ?: return
val bytes = OpenGroupApi.downloadOpenGroupProfilePicture(server, info.token, imageId).get()
val bytes = OpenGroupApi.downloadOpenGroupProfilePicture(server, room, imageId).get()
val groupId = GroupUtil.getEncodedOpenGroupID("$server.$room".toByteArray())
storage.updateProfilePicture(groupId, bytes)
storage.updateTimestampUpdated(groupId, System.currentTimeMillis())

View File

@@ -11,15 +11,17 @@ data class OpenGroup(
val id: String,
val name: String,
val publicKey: String,
val imageId: String?,
val infoUpdates: Int,
) {
constructor(server: String, room: String, name: String, infoUpdates: Int, publicKey: String) : this(
constructor(server: String, room: String, publicKey: String, name: String, imageId: String?, infoUpdates: Int) : this(
server = server,
room = room,
id = "$server.$room",
name = name,
publicKey = publicKey,
imageId = imageId,
infoUpdates = infoUpdates,
)
@@ -31,11 +33,12 @@ data class OpenGroup(
if (!json.has("room")) return null
val room = json.get("room").asText().toLowerCase(Locale.US)
val server = json.get("server").asText().toLowerCase(Locale.US)
val displayName = json.get("displayName").asText()
val publicKey = json.get("publicKey").asText()
val displayName = json.get("displayName").asText()
val imageId = json.get("imageId")?.asText()
val infoUpdates = json.get("infoUpdates")?.asText()?.toIntOrNull() ?: 0
val capabilities = json.get("capabilities")?.asText()?.split(",") ?: emptyList()
OpenGroup(server, room, displayName, infoUpdates, publicKey)
OpenGroup(server, room, displayName, publicKey, imageId, infoUpdates)
} catch (e: Exception) {
Log.w("Loki", "Couldn't parse open group from JSON: $jsonAsString.", e);
null
@@ -53,11 +56,12 @@ data class OpenGroup(
}
}
fun toJson(): Map<String,String> = mapOf(
fun toJson(): Map<String,String?> = mapOf(
"room" to room,
"server" to server,
"displayName" to name,
"publicKey" to publicKey,
"displayName" to name,
"imageId" to imageId,
"infoUpdates" to infoUpdates.toString(),
)

View File

@@ -91,7 +91,7 @@ object OpenGroupApi {
val created: Long = 0,
val activeUsers: Int = 0,
val activeUsersCutoff: Int = 0,
val imageId: Long? = null,
val imageId: String? = null,
val pinnedMessages: List<PinnedMessage> = emptyList(),
val admin: Boolean = false,
val globalAdmin: Boolean = false,
@@ -337,7 +337,7 @@ object OpenGroupApi {
.plus(request.verb.rawValue.toByteArray())
.plus("/${request.endpoint.value}".toByteArray())
.plus(bodyHash)
if (serverCapabilities.contains(Capability.BLIND.name.lowercase())) {
if (serverCapabilities.isEmpty() || serverCapabilities.contains(Capability.BLIND.name.lowercase())) {
SodiumUtilities.blindedKeyPair(publicKey, ed25519KeyPair)?.let { keyPair ->
pubKey = SessionId(
IdPrefix.BLINDED,
@@ -395,13 +395,13 @@ object OpenGroupApi {
fun downloadOpenGroupProfilePicture(
server: String,
roomID: String,
imageId: Long
imageId: String
): Promise<ByteArray, Exception> {
val request = Request(
verb = GET,
room = roomID,
server = server,
endpoint = Endpoint.RoomFileIndividual(roomID, imageId.toString())
endpoint = Endpoint.RoomFileIndividual(roomID, imageId)
)
return getResponseBody(request)
}
@@ -794,16 +794,14 @@ object OpenGroupApi {
private fun sequentialBatch(
server: String,
requests: MutableList<BatchRequestInfo<*>>,
authRequired: Boolean = true
requests: MutableList<BatchRequestInfo<*>>
): Promise<List<BatchResponse<*>>, Exception> {
val request = Request(
verb = POST,
room = null,
server = server,
endpoint = Endpoint.Sequence,
parameters = requests.map { it.request },
isAuthRequired = authRequired
parameters = requests.map { it.request }
)
return getBatchResponseJson(request, requests)
}
@@ -912,8 +910,7 @@ object OpenGroupApi {
fun getCapabilitiesAndRoomInfo(
room: String,
server: String,
authRequired: Boolean = true
server: String
): Promise<Pair<Capabilities, RoomInfo>, Exception> {
val requests = mutableListOf<BatchRequestInfo<*>>(
BatchRequestInfo(
@@ -933,7 +930,7 @@ object OpenGroupApi {
responseType = object : TypeReference<RoomInfo>(){}
)
)
return sequentialBatch(server, requests, authRequired).map {
return sequentialBatch(server, requests).map {
val capabilities = it.firstOrNull()?.body as? Capabilities ?: throw Error.ParsingFailed
val roomInfo = it.lastOrNull()?.body as? RoomInfo ?: throw Error.ParsingFailed
capabilities to roomInfo

View File

@@ -59,7 +59,7 @@ class OpenGroupPoller(private val server: String, private val executorService: S
fun poll(isPostCapabilitiesRetry: Boolean = false): Promise<Unit, Exception> {
val storage = MessagingModuleConfiguration.shared.storage
val rooms = storage.getAllOpenGroups().values.filter { it.server == server }.map { it.room }
rooms.forEach { downloadGroupAvatarIfNeeded(it) }
return OpenGroupApi.poll(rooms, server).successBackground { responses ->
responses.filterNot { it.body == null }.forEach { response ->
when (response.endpoint) {
@@ -123,9 +123,10 @@ class OpenGroupPoller(private val server: String, private val executorService: S
val openGroup = OpenGroup(
server = server,
room = pollInfo.token,
name = pollInfo.details?.name ?: "",
infoUpdates = pollInfo.details?.infoUpdates ?: 0,
name = if (pollInfo.details != null) { pollInfo.details.name } else { existingOpenGroup.name },
infoUpdates = if (pollInfo.details != null) { pollInfo.details.infoUpdates } else { existingOpenGroup.infoUpdates },
publicKey = publicKey,
imageId = if (pollInfo.details != null) { pollInfo.details.imageId } else { existingOpenGroup.imageId }
)
// - Open Group changes
storage.updateOpenGroup(openGroup)
@@ -155,6 +156,11 @@ class OpenGroupPoller(private val server: String, private val executorService: S
GroupMember(groupId, it, GroupMemberRole.HIDDEN_ADMIN)
})
}
// Start downloading the room image (if we don't have one or it's been updated)
if (pollInfo.details?.imageId != null && pollInfo.details.imageId != existingOpenGroup.imageId) {
JobQueue.shared.add(GroupAvatarDownloadJob(roomToken, server))
}
}
private fun handleMessages(
@@ -284,16 +290,4 @@ class OpenGroupPoller(private val server: String, private val executorService: S
JobQueue.shared.add(deleteJob)
}
}
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))
}
}
}
}