feat: start on closed group polling for new signatures

pull/1403/head
0x330a 2 years ago
parent 6067916da9
commit df29ed8f16

@ -34,10 +34,9 @@ import androidx.lifecycle.ProcessLifecycleOwner;
import org.conscrypt.Conscrypt;
import org.session.libsession.avatars.AvatarHelper;
import org.session.libsession.database.MessageDataProvider;
import org.session.libsession.database.StorageProtocol;
import org.session.libsession.messaging.MessagingModuleConfiguration;
import org.session.libsession.messaging.sending_receiving.notifications.MessageNotifier;
import org.session.libsession.messaging.sending_receiving.pollers.ClosedGroupPollerV2;
import org.session.libsession.messaging.sending_receiving.pollers.LegacyClosedGroupPollerV2;
import org.session.libsession.messaging.sending_receiving.pollers.Poller;
import org.session.libsession.snode.SnodeModule;
import org.session.libsession.utilities.Address;
@ -283,7 +282,7 @@ public class ApplicationContext extends Application implements DefaultLifecycleO
if (poller != null) {
poller.stopIfNeeded();
}
ClosedGroupPollerV2.getShared().stopAll();
LegacyClosedGroupPollerV2.getShared().stopAll();
}
@Override
@ -446,7 +445,7 @@ public class ApplicationContext extends Application implements DefaultLifecycleO
if (poller != null) {
poller.startIfNeeded();
}
ClosedGroupPollerV2.getShared().start();
LegacyClosedGroupPollerV2.getShared().start();
}
private void resubmitProfilePictureIfNeeded() {

@ -56,7 +56,7 @@ import org.session.libsession.messaging.sending_receiving.attachments.DatabaseAt
import org.session.libsession.messaging.sending_receiving.data_extraction.DataExtractionNotificationInfoMessage
import org.session.libsession.messaging.sending_receiving.link_preview.LinkPreview
import org.session.libsession.messaging.sending_receiving.notifications.PushRegistryV1
import org.session.libsession.messaging.sending_receiving.pollers.ClosedGroupPollerV2
import org.session.libsession.messaging.sending_receiving.pollers.LegacyClosedGroupPollerV2
import org.session.libsession.messaging.sending_receiving.quotes.QuoteModel
import org.session.libsession.messaging.utilities.SodiumUtilities
import org.session.libsession.messaging.utilities.UpdateMessageData
@ -124,8 +124,11 @@ open class Storage(context: Context, helper: SQLCipherOpenHelper, private val co
}
address.isClosedGroup -> {
val sessionId = address.serialize()
val closedGroup = groups.getClosedGroup(sessionId)
TODO("Set the closed group's convo volatile info")
groups.getClosedGroup(sessionId) ?: return Log.d("Closed group doesn't exist locally", NullPointerException())
val conversation = Conversation.ClosedGroup(
sessionId, 0, false
)
volatile.set(conversation)
}
address.isOpenGroup -> {
// these should be added on the group join / group info fetch
@ -465,7 +468,7 @@ open class Storage(context: Context, helper: SQLCipherOpenHelper, private val co
is ConversationVolatileConfig -> updateConvoVolatile(forConfigObject)
is UserGroupsConfig -> updateUserGroups(forConfigObject)
is GroupInfoConfig -> updateGroupInfo(forConfigObject)
is GroupKeysConfig -> updateGroupKeys(forConfigObject)
// is GroupKeysConfig -> updateGroupKeys(forConfigObject)
is GroupMembersConfig -> updateGroupMembers(forConfigObject)
}
}
@ -545,7 +548,7 @@ open class Storage(context: Context, helper: SQLCipherOpenHelper, private val co
is Conversation.OneToOne -> getThreadIdFor(conversation.sessionId, null, null, createThread = false)
is Conversation.LegacyGroup -> getThreadIdFor("", conversation.groupId,null, createThread = false)
is Conversation.Community -> getThreadIdFor("",null, "${conversation.baseCommunityInfo.baseUrl.removeSuffix("/")}.${conversation.baseCommunityInfo.room}", createThread = false)
is Conversation.ClosedGroup -> getThreadIdFor(conversation.sessionId, null, null, createThread = false)
is Conversation.ClosedGroup -> getThreadIdFor(conversation.sessionId, null, null, createThread = false) // New groups will be managed bia libsession
}
if (threadId != null) {
if (conversation.lastRead > getLastSeen(threadId)) {
@ -607,6 +610,15 @@ open class Storage(context: Context, helper: SQLCipherOpenHelper, private val co
}
}
val newClosedGroups = userGroups.allClosedGroupInfo()
for (closedGroup in newClosedGroups) {
val recipient = Recipient.from(context, Address.fromSerialized(closedGroup.groupSessionId.hexString()), false)
setRecipientApprovedMe(recipient, true)
setRecipientApproved(recipient, true)
val threadId = getOrCreateThreadIdFor(recipient.address)
setPinned(threadId, closedGroup.priority == PRIORITY_PINNED)
}
for (group in lgc) {
val existingGroup = existingClosedGroups.firstOrNull { GroupUtil.doubleDecodeGroupId(it.encodedId) == group.sessionId.hexString() }
val existingThread = existingGroup?.let { getThreadId(existingGroup.encodedId) }
@ -643,7 +655,7 @@ open class Storage(context: Context, helper: SQLCipherOpenHelper, private val co
insertOutgoingInfoMessage(context, groupId, SignalServiceGroup.Type.CREATION, title, members.map { it.serialize() }, admins.map { it.serialize() }, threadID, formationTimestamp)
// Don't create config group here, it's from a config update
// Start polling
ClosedGroupPollerV2.shared.startPolling(group.sessionId.hexString())
LegacyClosedGroupPollerV2.shared.startPolling(group.sessionId.hexString())
}
}
}
@ -883,8 +895,9 @@ open class Storage(context: Context, helper: SQLCipherOpenHelper, private val co
DatabaseComponent.get(context).groupDatabase().create(groupId, title, members, avatar, relay, admins, formationTimestamp)
}
override fun createNewGroup(groupName: String, groupDescription: String, members: Set<SessionId>): Optional<Boolean> {
override fun createNewGroup(groupName: String, groupDescription: String, members: Set<SessionId>): Optional<Recipient> {
val userGroups = configFactory.userGroups ?: return Optional.absent()
val convoVolatile = configFactory.convoVolatile ?: return Optional.absent()
val ourSessionId = getUserPublicKey() ?: return Optional.absent()
val userKp = MessagingModuleConfiguration.shared.getUserED25519KeyPair() ?: return Optional.absent()
@ -916,7 +929,9 @@ open class Storage(context: Context, helper: SQLCipherOpenHelper, private val co
val newGroupRecipient = group.groupSessionId.hexString()
val configTtl = 1 * 24 * 60 * 60 * 1000L // TODO: just testing here, 1 day so we don't fill large space on network
// Test the sending
val keyPush = groupKeys.pendingPush() ?: return Optional.absent()
val keyPush = groupKeys.pendingConfig() ?: return Optional.absent()
val pendingKey = groupKeys.pendingKey() ?: return Optional.absent()
val keysSnodeMessage = SnodeMessage(
newGroupRecipient,
Base64.encodeBytes(keyPush),
@ -932,7 +947,7 @@ open class Storage(context: Context, helper: SQLCipherOpenHelper, private val co
val (infoPush, infoSeqNo) = groupInfo.push()
val infoSnodeMessage = SnodeMessage(
newGroupRecipient,
Base64.encodeBytes(keyPush),
Base64.encodeBytes(infoPush),
configTtl,
groupCreationTimestamp
)
@ -968,13 +983,28 @@ open class Storage(context: Context, helper: SQLCipherOpenHelper, private val co
val responseList = (response["results"] as List<RawResponse>)
val keyResponse = responseList[0]
val keyHash = (keyResponse["body"] as Map<String,Any>)["hash"] as String
val keyTimestamp = (keyResponse["body"] as Map<String,Any>)["t"] as Long
val infoResponse = responseList[1]
val infoHash = (infoResponse["body"] as Map<String,Any>)["hash"] as String
val memberResponse = responseList[2]
val memberHash = (memberResponse["body"] as Map<String,Any>)["hash"] as String
// TODO: check response success
groupKeys.loadKey(keyPush, keyHash, keyTimestamp, groupInfo, groupMembers)
groupInfo.confirmPushed(infoSeqNo, infoHash)
groupMembers.confirmPushed(memberSeqNo, memberHash)
configFactory.saveGroupConfigs(groupKeys, groupInfo, groupMembers) // now check poller to be all
convoVolatile.set(Conversation.ClosedGroup(newGroupRecipient, groupCreationTimestamp, false))
ConfigurationMessageUtilities.forceSyncConfigurationNowIfNeeded(context)
Log.d("Group Config", "Saved group config for $newGroupRecipient")
return Optional.of(true)
groupKeys.free()
groupInfo.free()
groupMembers.free()
val groupRecipient = Recipient.from(context, Address.fromSerialized(newGroupRecipient), false)
setRecipientApprovedMe(groupRecipient, true)
setRecipientApproved(groupRecipient, true)
return Optional.of(groupRecipient)
} catch (e: Exception) {
Log.e("Group Config", e)
Log.e("Group Config", "Deleting group from our group")
@ -1648,7 +1678,7 @@ open class Storage(context: Context, helper: SQLCipherOpenHelper, private val co
}
override fun getRecipientApproved(address: Address): Boolean {
return DatabaseComponent.get(context).recipientDatabase().getApproved(address)
return address.isClosedGroup || DatabaseComponent.get(context).recipientDatabase().getApproved(address)
}
override fun setRecipientApproved(recipient: Recipient, approved: Boolean) {

@ -503,7 +503,8 @@ public class ThreadDatabase extends Database {
}
public Cursor getApprovedConversationList() {
String where = "((" + HAS_SENT + " = 1 OR " + RecipientDatabase.APPROVED + " = 1 OR "+ GroupDatabase.TABLE_NAME +"."+GROUP_ID+" LIKE '"+ LEGACY_CLOSED_GROUP_PREFIX +"%') OR " + GroupDatabase.TABLE_NAME + "." + GROUP_ID + " LIKE '" + OPEN_GROUP_PREFIX + "%') " +
String where = "((" + HAS_SENT + " = 1 OR " + RecipientDatabase.APPROVED + " = 1 OR "+ GroupDatabase.TABLE_NAME +"."+GROUP_ID+" LIKE '"+ LEGACY_CLOSED_GROUP_PREFIX +"%' OR "+RecipientDatabase.TABLE_NAME+"."+RecipientDatabase.ADDRESS+" LIKE '"+ IdPrefix.GROUP.getValue() +"%') " +
"OR " + GroupDatabase.TABLE_NAME + "." + GROUP_ID + " LIKE '" + OPEN_GROUP_PREFIX + "%') " +
"AND " + ARCHIVED + " = 0 ";
return getConversationList(where);
}
@ -830,9 +831,7 @@ public class ThreadDatabase extends Database {
}
private boolean deleteThreadOnEmpty(long threadId) {
return false; // TODO: test the deletion / clearing logic here to make sure this is the desired functionality
// Recipient threadRecipient = getRecipientForThreadId(threadId);
// return threadRecipient != null && !threadRecipient.isOpenGroupRecipient();
return false;
}
private @NonNull String getFormattedBodyFor(@NonNull MessageRecord messageRecord) {

@ -350,6 +350,6 @@ class ConfigFactory(
) {
val pubKey = groupInfo.id().hexString()
val timestamp = SnodeAPI.nowWithOffset
configDatabase.storeGroupConfigs(pubKey, groupKeys.dump(), groupInfo.dump(), groupMembers.dump(), timestamp)
configDatabase.storeGroupConfigs(pubKey, groupKeys.keyDump(), groupInfo.dump(), groupMembers.dump(), timestamp)
}
}

@ -4,7 +4,7 @@ import android.content.Context
import network.loki.messenger.libsession_util.ConfigBase
import org.session.libsession.messaging.MessagingModuleConfiguration
import org.session.libsession.messaging.sending_receiving.notifications.PushRegistryV1
import org.session.libsession.messaging.sending_receiving.pollers.ClosedGroupPollerV2
import org.session.libsession.messaging.sending_receiving.pollers.LegacyClosedGroupPollerV2
import org.session.libsession.utilities.Address
import org.session.libsession.utilities.GroupRecord
import org.session.libsession.utilities.GroupUtil
@ -26,7 +26,7 @@ object ClosedGroupManager {
// Notify the PN server
PushRegistryV1.unsubscribeGroup(closedGroupPublicKey = groupPublicKey, publicKey = userPublicKey)
// Stop polling
ClosedGroupPollerV2.shared.stopPolling(groupPublicKey)
LegacyClosedGroupPollerV2.shared.stopPolling(groupPublicKey)
storage.cancelPendingMessageSendJobs(threadId)
ApplicationContext.getInstance(context).messageNotifier.updateNotification(context)
if (delete) {

@ -77,9 +77,8 @@ class CreateGroupFragment : Fragment() {
}
}
private fun openConversationActivity(context: Context, threadId: Long, recipient: Recipient) {
private fun openConversationActivity(context: Context, recipient: Recipient) {
val intent = Intent(context, ConversationActivityV2::class.java)
intent.putExtra(ConversationActivityV2.THREAD_ID, threadId)
intent.putExtra(ConversationActivityV2.ADDRESS, recipient.address)
context.startActivity(intent)
}
@ -94,7 +93,10 @@ class CreateGroupFragment : Fragment() {
createGroupState,
onCreate = { newGroup ->
// launch something to create here
viewModel.tryCreateGroup(newGroup)
val groupRecipient = viewModel.tryCreateGroup(newGroup)
groupRecipient?.let { recipient ->
openConversationActivity(requireContext(), recipient)
}
},
onClose = {
delegate.onDialogClosePressed()

@ -40,7 +40,7 @@ class CreateGroupViewModel @Inject constructor(
}
}
fun tryCreateGroup(createGroupState: CreateGroupState) {
fun tryCreateGroup(createGroupState: CreateGroupState): Recipient? {
_viewState.postValue(CreateGroupFragment.ViewState(true, null, null))
val name = createGroupState.groupName
@ -49,14 +49,16 @@ class CreateGroupViewModel @Inject constructor(
// do some validations
if (name.isEmpty()) {
return _viewState.postValue(
_viewState.postValue(
CreateGroupFragment.ViewState(false, R.string.error, null)
)
return null
}
// TODO: add future validation for empty group ? we'll add ourselves anyway ig
// make a group
storage.createNewGroup(name, description, members)
val newGroup = storage.createNewGroup(name, description, members) // TODO: handle optional
return newGroup.orNull()
}
fun filter(query: String): List<Recipient> {

@ -7,8 +7,8 @@ import androidx.work.Constraints
import androidx.work.Data
import androidx.work.ExistingPeriodicWorkPolicy
import androidx.work.NetworkType
import androidx.work.PeriodicWorkRequestBuilder
import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.PeriodicWorkRequestBuilder
import androidx.work.WorkManager
import androidx.work.Worker
import androidx.work.WorkerParameters
@ -18,7 +18,7 @@ import nl.komponents.kovenant.functional.bind
import org.session.libsession.messaging.MessagingModuleConfiguration
import org.session.libsession.messaging.jobs.BatchMessageReceiveJob
import org.session.libsession.messaging.jobs.MessageReceiveParameters
import org.session.libsession.messaging.sending_receiving.pollers.ClosedGroupPollerV2
import org.session.libsession.messaging.sending_receiving.pollers.LegacyClosedGroupPollerV2
import org.session.libsession.messaging.sending_receiving.pollers.OpenGroupPoller
import org.session.libsession.snode.SnodeAPI
import org.session.libsession.utilities.TextSecurePreferences
@ -121,7 +121,7 @@ class BackgroundPollWorker(val context: Context, params: WorkerParameters) : Wor
// Closed groups
if (requestTargets.contains(Targets.CLOSED_GROUPS)) {
val closedGroupPoller = ClosedGroupPollerV2() // Intentionally don't use shared
val closedGroupPoller = LegacyClosedGroupPollerV2() // Intentionally don't use shared
val storage = MessagingModuleConfiguration.shared.storage
val allGroupPublicKeys = storage.getAllClosedGroupPublicKeys()
allGroupPublicKeys.iterator().forEach { closedGroupPoller.poll(it) }

@ -13,7 +13,7 @@ inline session::config::Contacts *ptrToContacts(JNIEnv *env, jobject obj) {
inline jobject serialize_contact(JNIEnv *env, session::config::contact_info info) {
jclass contactClass = env->FindClass("network/loki/messenger/libsession_util/util/Contact");
jmethodID constructor = env->GetMethodID(contactClass, "<init>", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZZZLnetwork/loki/messenger/libsession_util/util/UserPic;ILnetwork/loki/messenger/libsession_util/util/ExpiryMode;)V");
jmethodID constructor = env->GetMethodID(contactClass, "<init>", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZZZLnetwork/loki/messenger/libsession_util/util/UserPic;JLnetwork/loki/messenger/libsession_util/util/ExpiryMode;)V");
jstring id = env->NewStringUTF(info.session_id.data());
jstring name = env->NewStringUTF(info.name.data());
jstring nickname = env->NewStringUTF(info.nickname.data());
@ -24,7 +24,7 @@ inline jobject serialize_contact(JNIEnv *env, session::config::contact_info info
auto created = info.created;
jobject profilePic = util::serialize_user_pic(env, info.profile_picture);
jobject returnObj = env->NewObject(contactClass, constructor, id, name, nickname, approved,
approvedMe, blocked, profilePic, info.priority,
approvedMe, blocked, profilePic, (jlong)info.priority,
util::serialize_expiry(env, info.exp_mode, info.exp_timer));
return returnObj;
}
@ -42,14 +42,14 @@ deserialize_contact(JNIEnv *env, jobject info, session::config::Contacts *conf)
getBlocked = env->GetFieldID(contactClass, "blocked", "Z");
getUserPic = env->GetFieldID(contactClass, "profilePicture",
"Lnetwork/loki/messenger/libsession_util/util/UserPic;");
getPriority = env->GetFieldID(contactClass, "priority", "I");
getPriority = env->GetFieldID(contactClass, "priority", "J");
getExpiry = env->GetFieldID(contactClass, "expiryMode", "Lnetwork/loki/messenger/libsession_util/util/ExpiryMode;");
jstring name, nickname, session_id;
session_id = static_cast<jstring>(env->GetObjectField(info, getId));
name = static_cast<jstring>(env->GetObjectField(info, getName));
nickname = static_cast<jstring>(env->GetObjectField(info, getNick));
bool approved, approvedMe, blocked, hidden;
int priority = env->GetIntField(info, getPriority);
int priority = env->GetLongField(info, getPriority);
approved = env->GetBooleanField(info, getApproved);
approvedMe = env->GetBooleanField(info, getApprovedMe);
blocked = env->GetBooleanField(info, getBlocked);

@ -72,20 +72,19 @@ Java_network_loki_messenger_libsession_1util_GroupKeysConfig_groupKeys(JNIEnv *e
extern "C"
JNIEXPORT void JNICALL
Java_network_loki_messenger_libsession_1util_GroupKeysConfig_loadKey(JNIEnv *env, jobject thiz,
jbyteArray message,
jstring hash,
jbyteArray data,
jbyteArray msg_id,
jlong timestamp_ms,
jobject info_jobject,
jobject members_jobject) {
std::lock_guard lock{util::util_mutex_};
auto keys = ptrToKeys(env, thiz);
auto message_bytes = util::ustring_from_bytes(env, message);
auto hash_bytes = env->GetStringUTFChars(hash, nullptr);
auto data_bytes = util::ustring_from_bytes(env, data);
auto msg_bytes = util::ustring_from_bytes(env, msg_id);
auto info = ptrToInfo(env, info_jobject);
auto members = ptrToMembers(env, members_jobject);
keys->load_key_message(hash_bytes, data_bytes, timestamp_ms, *info, *members);
keys->load_key_message(hash_bytes, message_bytes, timestamp_ms, *info, *members);
env->ReleaseStringUTFChars(hash, hash_bytes);
}
@ -112,7 +111,7 @@ Java_network_loki_messenger_libsession_1util_GroupKeysConfig_pendingKey(JNIEnv *
extern "C"
JNIEXPORT jbyteArray JNICALL
Java_network_loki_messenger_libsession_1util_GroupKeysConfig_pendingPush(JNIEnv *env,
Java_network_loki_messenger_libsession_1util_GroupKeysConfig_pendingConfig(JNIEnv *env,
jobject thiz) {
std::lock_guard lock{util::util_mutex_};
auto keys = ptrToKeys(env, thiz);
@ -136,3 +135,19 @@ Java_network_loki_messenger_libsession_1util_GroupKeysConfig_rekey(JNIEnv *env,
auto rekey_bytes = util::bytes_from_ustring(env, rekey.data());
return rekey_bytes;
}
extern "C"
JNIEXPORT jbyteArray JNICALL
Java_network_loki_messenger_libsession_1util_GroupKeysConfig_keyDump(JNIEnv *env, jobject thiz) {
auto keys = ptrToKeys(env, thiz);
auto dump = keys->dump();
auto byte_array = util::bytes_from_ustring(env, dump);
return byte_array;
}
extern "C"
JNIEXPORT void JNICALL
Java_network_loki_messenger_libsession_1util_GroupKeysConfig_free(JNIEnv *env, jobject thiz) {
auto ptr = ptrToKeys(env, thiz);
delete ptr;
}

@ -28,7 +28,6 @@ sealed class ConfigBase(protected val /* yucky */ pointer: Long) {
is ConversationVolatileConfig -> Kind.CONVO_INFO_VOLATILE
is UserGroupsConfig -> Kind.GROUPS
is GroupInfoConfig -> Kind.CLOSED_GROUP_INFO
is GroupKeysConfig -> Kind.ENCRYPTION_KEYS
is GroupMembersConfig -> Kind.CLOSED_GROUP_MEMBERS
}
@ -275,7 +274,7 @@ class GroupMembersConfig(pointer: Long): ConfigBase(pointer), Closeable {
}
}
class GroupKeysConfig(pointer: Long): ConfigBase(pointer), Closeable {
class GroupKeysConfig(private val pointer: Long): Closeable {
companion object {
init {
System.loadLibrary("session_util")
@ -292,16 +291,16 @@ class GroupKeysConfig(pointer: Long): ConfigBase(pointer), Closeable {
}
external fun groupKeys(): Stack<ByteArray>
external fun keyDump(): ByteArray
external fun loadKey(hash: String,
data: ByteArray,
msgId: ByteArray,
external fun loadKey(message: ByteArray,
hash: String,
timestampMs: Long,
info: GroupInfoConfig,
members: GroupMembersConfig)
external fun needsRekey(): Boolean
external fun pendingKey(): ByteArray?
external fun pendingPush(): ByteArray?
external fun pendingConfig(): ByteArray?
external fun rekey(info: GroupInfoConfig, members: GroupMembersConfig): ByteArray
external fun free()
override fun close() {
free()
}

@ -156,7 +156,7 @@ interface StorageProtocol {
fun setExpirationTimer(address: String, duration: Int)
// Closed Groups
fun createNewGroup(groupName: String, groupDescription: String, members: Set<SessionId>): Optional<Boolean>
fun createNewGroup(groupName: String, groupDescription: String, members: Set<SessionId>): Optional<Recipient>
fun getMembers(groupPublicKey: String): List<network.loki.messenger.libsession_util.util.GroupMember>
// Groups

@ -9,7 +9,7 @@ import org.session.libsession.messaging.MessagingModuleConfiguration
import org.session.libsession.messaging.messages.control.ClosedGroupControlMessage
import org.session.libsession.messaging.sending_receiving.MessageSender.Error
import org.session.libsession.messaging.sending_receiving.notifications.PushRegistryV1
import org.session.libsession.messaging.sending_receiving.pollers.ClosedGroupPollerV2
import org.session.libsession.messaging.sending_receiving.pollers.LegacyClosedGroupPollerV2
import org.session.libsession.snode.SnodeAPI
import org.session.libsession.utilities.Address
import org.session.libsession.utilities.Address.Companion.fromSerialized
@ -96,7 +96,7 @@ fun MessageSender.create(
// Notify the PN server
PushRegistryV1.register(device = device, publicKey = userPublicKey)
// Start polling
ClosedGroupPollerV2.shared.startPolling(groupPublicKey)
LegacyClosedGroupPollerV2.shared.startPolling(groupPublicKey)
// Fulfill the promise
deferred.resolve(groupID)
}

@ -25,7 +25,7 @@ import org.session.libsession.messaging.sending_receiving.attachments.PointerAtt
import org.session.libsession.messaging.sending_receiving.data_extraction.DataExtractionNotificationInfoMessage
import org.session.libsession.messaging.sending_receiving.link_preview.LinkPreview
import org.session.libsession.messaging.sending_receiving.notifications.PushRegistryV1
import org.session.libsession.messaging.sending_receiving.pollers.ClosedGroupPollerV2
import org.session.libsession.messaging.sending_receiving.pollers.LegacyClosedGroupPollerV2
import org.session.libsession.messaging.sending_receiving.quotes.QuoteModel
import org.session.libsession.messaging.utilities.SodiumUtilities
import org.session.libsession.messaging.utilities.WebRtcUtils
@ -580,7 +580,7 @@ private fun handleNewClosedGroup(sender: String, sentTimestamp: Long, groupPubli
storage.insertIncomingInfoMessage(context, sender, groupID, SignalServiceGroup.Type.CREATION, name, members, admins, sentTimestamp)
}
// Start polling
ClosedGroupPollerV2.shared.startPolling(groupPublicKey)
LegacyClosedGroupPollerV2.shared.startPolling(groupPublicKey)
}
private fun MessageReceiver.handleClosedGroupEncryptionKeyPair(message: ClosedGroupControlMessage) {
@ -886,7 +886,7 @@ fun MessageReceiver.disableLocalGroupAndUnsubscribe(groupPublicKey: String, grou
// Notify the PN server
PushRegistryV1.unsubscribeGroup(groupPublicKey, publicKey = userPublicKey)
// Stop polling
ClosedGroupPollerV2.shared.stopPolling(groupPublicKey)
LegacyClosedGroupPollerV2.shared.stopPolling(groupPublicKey)
if (delete) {
val threadId = storage.getOrCreateThreadIdFor(Address.fromSerialized(groupID))

@ -0,0 +1,48 @@
package org.session.libsession.messaging.sending_receiving.pollers
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import org.session.libsession.snode.SnodeAPI
import org.session.libsession.utilities.ConfigFactoryProtocol
import org.session.libsignal.utilities.Log
import org.session.libsignal.utilities.SessionId
class ClosedGroupPoller(private val executor: CoroutineScope,
private val closedGroupSessionId: SessionId,
private val configFactoryProtocol: ConfigFactoryProtocol) {
companion object {
const val POLL_INTERVAL = 3_000L
}
private var isRunning: Boolean = false
private var job: Job? = null
fun start() {
job?.cancel()
job = executor.launch {
val nextPoll = poll()
delay(nextPoll)
}
}
fun stop() {
job?.cancel()
}
fun poll(): Long {
try {
val snode = SnodeAPI.getSingleTargetSnode(closedGroupSessionId.hexString()).get()
val info = configFactoryProtocol.getOrConstructGroupInfoConfig(closedGroupSessionId)
val members = configFactoryProtocol.getOrConstructGroupMemberConfig(closedGroupSessionId)
val keys = configFactoryProtocol.getGroupKeysConfig(closedGroupSessionId)
} catch (e: Exception) {
Log.e("GroupPoller", "Polling failed for group", e)
}
return POLL_INTERVAL // this might change in future
}
}

@ -22,7 +22,7 @@ import java.util.concurrent.ScheduledFuture
import java.util.concurrent.TimeUnit
import kotlin.math.min
class ClosedGroupPollerV2 {
class LegacyClosedGroupPollerV2 {
private val executorService = Executors.newScheduledThreadPool(1)
private var isPolling = mutableMapOf<String, Boolean>()
private var futures = mutableMapOf<String, ScheduledFuture<*>>()
@ -36,7 +36,7 @@ class ClosedGroupPollerV2 {
private val maxPollInterval = 4 * 60 * 1000
@JvmStatic
val shared = ClosedGroupPollerV2()
val shared = LegacyClosedGroupPollerV2()
}
class InsufficientSnodesException() : Exception("No snodes left to poll.")

@ -210,7 +210,6 @@ class Poller(private val configFactory: ConfigFactoryProtocol, debounceTimer: Ti
val responseList = (rawResponses["results"] as List<RawResponse>)
// in case we had null configs, the array won't be fully populated
// index of the sparse array key iterator should be the request index, with the key being the namespace
// TODO: add in specific ordering of config namespaces for processing
listOfNotNull(
configFactory.user?.configNamespace(),
configFactory.contacts?.configNamespace(),

Loading…
Cancel
Save