mirror of
https://github.com/oxen-io/session-android.git
synced 2025-12-30 22:17:00 +00:00
feat: introduce the handling of poll messages for closed group poller
This commit is contained in:
@@ -4,9 +4,15 @@ import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import network.loki.messenger.libsession_util.GroupInfoConfig
|
||||
import network.loki.messenger.libsession_util.GroupKeysConfig
|
||||
import network.loki.messenger.libsession_util.GroupMembersConfig
|
||||
import network.loki.messenger.libsession_util.util.GroupInfo
|
||||
import org.session.libsession.snode.RawResponse
|
||||
import org.session.libsession.snode.SnodeAPI
|
||||
import org.session.libsession.utilities.ConfigFactoryProtocol
|
||||
import org.session.libsignal.utilities.Log
|
||||
import org.session.libsignal.utilities.Namespace
|
||||
import org.session.libsignal.utilities.SessionId
|
||||
|
||||
class ClosedGroupPoller(private val executor: CoroutineScope,
|
||||
@@ -23,8 +29,18 @@ class ClosedGroupPoller(private val executor: CoroutineScope,
|
||||
fun start() {
|
||||
job?.cancel()
|
||||
job = executor.launch {
|
||||
val nextPoll = poll()
|
||||
delay(nextPoll)
|
||||
val closedGroups = configFactoryProtocol.userGroups?: return@launch
|
||||
while (true) {
|
||||
val group = closedGroups.getClosedGroup(closedGroupSessionId.hexString()) ?: break
|
||||
val nextPoll = poll(group)
|
||||
if (nextPoll != null) {
|
||||
delay(nextPoll)
|
||||
} else {
|
||||
Log.d("ClosedGroupPoller", "Stopping the closed group poller")
|
||||
return@launch
|
||||
}
|
||||
}
|
||||
// assume null poll time means don't continue polling, either the group has been deleted or something else
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,17 +48,92 @@ class ClosedGroupPoller(private val executor: CoroutineScope,
|
||||
job?.cancel()
|
||||
}
|
||||
|
||||
fun poll(): Long {
|
||||
fun poll(group: GroupInfo.ClosedGroupInfo): Long? {
|
||||
try {
|
||||
val snode = SnodeAPI.getSingleTargetSnode(closedGroupSessionId.hexString()).get()
|
||||
val info = configFactoryProtocol.getOrConstructGroupInfoConfig(closedGroupSessionId)
|
||||
val members = configFactoryProtocol.getOrConstructGroupMemberConfig(closedGroupSessionId)
|
||||
val keys = configFactoryProtocol.getGroupKeysConfig(closedGroupSessionId)
|
||||
val info = configFactoryProtocol.getGroupInfoConfig(closedGroupSessionId) ?: return null
|
||||
val members = configFactoryProtocol.getGroupMemberConfig(closedGroupSessionId) ?: return null
|
||||
val keys = configFactoryProtocol.getGroupKeysConfig(closedGroupSessionId) ?: return null
|
||||
|
||||
val keysIndex = 0
|
||||
val infoIndex = 1
|
||||
val membersIndex = 2
|
||||
val messageIndex = 3
|
||||
|
||||
val messagePoll = SnodeAPI.buildAuthenticatedRetrieveBatchRequest(
|
||||
snode,
|
||||
closedGroupSessionId.hexString(),
|
||||
Namespace.DEFAULT,
|
||||
maxSize = null,
|
||||
group.signingKey()
|
||||
) ?: return null
|
||||
val infoPoll = SnodeAPI.buildAuthenticatedRetrieveBatchRequest(
|
||||
snode,
|
||||
closedGroupSessionId.hexString(),
|
||||
info.configNamespace(),
|
||||
maxSize = null,
|
||||
group.signingKey()
|
||||
) ?: return null
|
||||
val membersPoll = SnodeAPI.buildAuthenticatedRetrieveBatchRequest(
|
||||
snode,
|
||||
closedGroupSessionId.hexString(),
|
||||
members.configNamespace(),
|
||||
maxSize = null,
|
||||
group.signingKey()
|
||||
) ?: return null
|
||||
val keysPoll = SnodeAPI.buildAuthenticatedRetrieveBatchRequest(
|
||||
snode,
|
||||
closedGroupSessionId.hexString(),
|
||||
GroupKeysConfig.storageNamespace(),
|
||||
maxSize = null,
|
||||
group.signingKey()
|
||||
) ?: return null
|
||||
|
||||
val pollResult = SnodeAPI.getRawBatchResponse(
|
||||
snode,
|
||||
closedGroupSessionId.hexString(),
|
||||
listOf(keysPoll, infoPoll, membersPoll, messagePoll)
|
||||
).get()
|
||||
|
||||
// TODO: add the extend duration TTLs for known hashes here
|
||||
|
||||
(pollResult["body"] as List<RawResponse>).forEachIndexed { index, response ->
|
||||
when (index) {
|
||||
keysIndex -> handleKeyPoll(response, keys, info, members)
|
||||
infoIndex -> handleInfo(response, info)
|
||||
membersIndex -> handleMembers(response, members)
|
||||
messageIndex -> handleMessages(response)
|
||||
}
|
||||
}
|
||||
|
||||
} catch (e: Exception) {
|
||||
Log.e("GroupPoller", "Polling failed for group", e)
|
||||
return POLL_INTERVAL
|
||||
}
|
||||
return POLL_INTERVAL // this might change in future
|
||||
}
|
||||
|
||||
private fun handleKeyPoll(response: RawResponse,
|
||||
keysConfig: GroupKeysConfig,
|
||||
infoConfig: GroupInfoConfig,
|
||||
membersConfig: GroupMembersConfig) {
|
||||
|
||||
}
|
||||
|
||||
private fun handleInfo(response: RawResponse,
|
||||
infoConfig: GroupInfoConfig) {
|
||||
|
||||
}
|
||||
|
||||
private fun handleMembers(response: RawResponse,
|
||||
membersConfig: GroupMembersConfig) {
|
||||
|
||||
}
|
||||
|
||||
private fun handleMessages(response: RawResponse) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -460,19 +460,21 @@ object SnodeAPI {
|
||||
)
|
||||
}
|
||||
|
||||
fun buildAuthenticatedRetrieveBatchRequest(snode: Snode, publicKey: String, namespace: Int = 0, maxSize: Int? = null): SnodeBatchRequestInfo? {
|
||||
fun buildAuthenticatedRetrieveBatchRequest(snode: Snode,
|
||||
publicKey: String,
|
||||
namespace: Int,
|
||||
maxSize: Int? = null,
|
||||
signingKey: ByteArray,
|
||||
ed25519PublicKey: Key? = null): SnodeBatchRequestInfo? {
|
||||
val lastHashValue = database.getLastMessageHashValue(snode, publicKey, namespace) ?: ""
|
||||
val params = mutableMapOf<String, Any>(
|
||||
"pubkey" to publicKey,
|
||||
"last_hash" to lastHashValue,
|
||||
"last_hash" to lastHashValue
|
||||
)
|
||||
val userEd25519KeyPair = try {
|
||||
MessagingModuleConfiguration.shared.getUserED25519KeyPair() ?: return null
|
||||
} catch (e: Exception) {
|
||||
return null
|
||||
if (ed25519PublicKey != null) {
|
||||
params["pubkey_ed25519"] = ed25519PublicKey.asHexString
|
||||
}
|
||||
val ed25519PublicKey = userEd25519KeyPair.publicKey.asHexString
|
||||
val timestamp = System.currentTimeMillis() + clockOffset
|
||||
val timestamp = nowWithOffset
|
||||
val signature = ByteArray(Sign.BYTES)
|
||||
val verificationData = if (namespace == 0) "retrieve$timestamp".toByteArray()
|
||||
else "retrieve$namespace$timestamp".toByteArray()
|
||||
@@ -481,14 +483,13 @@ object SnodeAPI {
|
||||
signature,
|
||||
verificationData,
|
||||
verificationData.size.toLong(),
|
||||
userEd25519KeyPair.secretKey.asBytes
|
||||
signingKey
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
Log.e("Loki", "Signing data failed with user secret key", e)
|
||||
Log.e("BatchRetrieve", "Signing data failed with provided signing key", e)
|
||||
return null
|
||||
}
|
||||
params["timestamp"] = timestamp
|
||||
params["pubkey_ed25519"] = ed25519PublicKey
|
||||
params["signature"] = Base64.encodeBytes(signature)
|
||||
if (namespace != 0) {
|
||||
params["namespace"] = namespace
|
||||
@@ -503,6 +504,24 @@ object SnodeAPI {
|
||||
)
|
||||
}
|
||||
|
||||
fun buildAuthenticatedRetrieveBatchRequest(snode: Snode, publicKey: String, namespace: Int = 0, maxSize: Int? = null): SnodeBatchRequestInfo? {
|
||||
val userEd25519KeyPair = try {
|
||||
MessagingModuleConfiguration.shared.getUserED25519KeyPair() ?: return null
|
||||
} catch (e: Exception) {
|
||||
return null
|
||||
}
|
||||
val secretKey = userEd25519KeyPair.secretKey.asBytes
|
||||
val ed25519PublicKey = userEd25519KeyPair.publicKey
|
||||
return buildAuthenticatedRetrieveBatchRequest(
|
||||
snode,
|
||||
publicKey,
|
||||
namespace,
|
||||
maxSize,
|
||||
secretKey,
|
||||
ed25519PublicKey
|
||||
)
|
||||
}
|
||||
|
||||
fun buildAuthenticatedAlterTtlBatchRequest(
|
||||
messageHashes: List<String>,
|
||||
newExpiry: Long,
|
||||
|
||||
@@ -16,8 +16,8 @@ interface ConfigFactoryProtocol {
|
||||
val convoVolatile: ConversationVolatileConfig?
|
||||
val userGroups: UserGroupsConfig?
|
||||
|
||||
fun getOrConstructGroupInfoConfig(groupSessionId: SessionId): GroupInfoConfig?
|
||||
fun getOrConstructGroupMemberConfig(groupSessionId: SessionId): GroupMembersConfig?
|
||||
fun getGroupInfoConfig(groupSessionId: SessionId): GroupInfoConfig?
|
||||
fun getGroupMemberConfig(groupSessionId: SessionId): GroupMembersConfig?
|
||||
fun getGroupKeysConfig(groupSessionId: SessionId): GroupKeysConfig?
|
||||
|
||||
fun getUserConfigs(): List<ConfigBase>
|
||||
|
||||
Reference in New Issue
Block a user