mirror of
https://github.com/oxen-io/session-android.git
synced 2024-11-29 04:55:15 +00:00
fix: added more migration code for deleting unnecessary threads and groups, fixed a post-migration last seen issue on last item (current read is now), comment out actual network sync while testing migrations
This commit is contained in:
parent
7ed12ce87d
commit
371fb20b6e
@ -994,6 +994,10 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
|
|||||||
showOrHideScrollToBottomButton()
|
showOrHideScrollToBottomButton()
|
||||||
val firstVisiblePosition = layoutManager?.findFirstVisibleItemPosition() ?: RecyclerView.NO_POSITION
|
val firstVisiblePosition = layoutManager?.findFirstVisibleItemPosition() ?: RecyclerView.NO_POSITION
|
||||||
if (!firstLoad.get() && firstVisiblePosition != RecyclerView.NO_POSITION) {
|
if (!firstLoad.get() && firstVisiblePosition != RecyclerView.NO_POSITION) {
|
||||||
|
if (firstVisiblePosition == 0) {
|
||||||
|
// last item, set it to now?
|
||||||
|
bufferedLastSeenChannel.trySend(SnodeAPI.nowWithOffset)
|
||||||
|
}
|
||||||
val visibleItemTimestamp = adapter.getTimestampForItemAt(firstVisiblePosition)
|
val visibleItemTimestamp = adapter.getTimestampForItemAt(firstVisiblePosition)
|
||||||
if (visibleItemTimestamp != null) {
|
if (visibleItemTimestamp != null) {
|
||||||
bufferedLastSeenChannel.trySend(visibleItemTimestamp)
|
bufferedLastSeenChannel.trySend(visibleItemTimestamp)
|
||||||
|
@ -36,9 +36,9 @@ public class GroupDatabase extends Database implements LokiOpenGroupDatabaseProt
|
|||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
private static final String TAG = GroupDatabase.class.getSimpleName();
|
private static final String TAG = GroupDatabase.class.getSimpleName();
|
||||||
|
|
||||||
static final String TABLE_NAME = "groups";
|
public static final String TABLE_NAME = "groups";
|
||||||
private static final String ID = "_id";
|
private static final String ID = "_id";
|
||||||
static final String GROUP_ID = "group_id";
|
public static final String GROUP_ID = "group_id";
|
||||||
private static final String TITLE = "title";
|
private static final String TITLE = "title";
|
||||||
private static final String MEMBERS = "members";
|
private static final String MEMBERS = "members";
|
||||||
private static final String ZOMBIE_MEMBERS = "zombie_members";
|
private static final String ZOMBIE_MEMBERS = "zombie_members";
|
||||||
|
@ -99,6 +99,8 @@ open class Storage(context: Context, helper: SQLCipherOpenHelper, private val co
|
|||||||
if (!getRecipientApproved(address)) return // don't store unapproved / message requests
|
if (!getRecipientApproved(address)) return // don't store unapproved / message requests
|
||||||
if (getUserPublicKey() == address.serialize()) {
|
if (getUserPublicKey() == address.serialize()) {
|
||||||
Log.d("Loki-DBG", "NTS created, context:\n${Thread.currentThread().stackTrace.joinToString("\n")}")
|
Log.d("Loki-DBG", "NTS created, context:\n${Thread.currentThread().stackTrace.joinToString("\n")}")
|
||||||
|
} else {
|
||||||
|
Log.d("Loki-DBG", "Thread created ${address.serialize()}")
|
||||||
}
|
}
|
||||||
|
|
||||||
val volatile = configFactory.convoVolatile ?: return
|
val volatile = configFactory.convoVolatile ?: return
|
||||||
|
@ -563,6 +563,7 @@ public class ThreadDatabase extends Database {
|
|||||||
db.execSQL(reflectUpdates, new Object[]{threadId});
|
db.execSQL(reflectUpdates, new Object[]{threadId});
|
||||||
db.setTransactionSuccessful();
|
db.setTransactionSuccessful();
|
||||||
db.endTransaction();
|
db.endTransaction();
|
||||||
|
notifyConversationListeners(threadId);
|
||||||
notifyConversationListListeners();
|
notifyConversationListListeners();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -41,6 +41,7 @@ import org.thoughtcrime.securesms.database.SessionJobDatabase;
|
|||||||
import org.thoughtcrime.securesms.database.SmsDatabase;
|
import org.thoughtcrime.securesms.database.SmsDatabase;
|
||||||
import org.thoughtcrime.securesms.database.ThreadDatabase;
|
import org.thoughtcrime.securesms.database.ThreadDatabase;
|
||||||
import org.thoughtcrime.securesms.notifications.NotificationChannels;
|
import org.thoughtcrime.securesms.notifications.NotificationChannels;
|
||||||
|
import org.thoughtcrime.securesms.util.ConfigurationMessageUtilities;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|
||||||
@ -593,7 +594,8 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
|
|||||||
|
|
||||||
if (oldVersion < lokiV41) {
|
if (oldVersion < lokiV41) {
|
||||||
db.execSQL(ConfigDatabase.CREATE_CONFIG_TABLE_COMMAND);
|
db.execSQL(ConfigDatabase.CREATE_CONFIG_TABLE_COMMAND);
|
||||||
// TODO: delete threads where necessary for one to ones
|
db.execSQL(ConfigurationMessageUtilities.DELETE_INACTIVE_GROUPS);
|
||||||
|
db.execSQL(ConfigurationMessageUtilities.DELETE_INACTIVE_ONE_TO_ONES);
|
||||||
}
|
}
|
||||||
|
|
||||||
db.setTransactionSuccessful();
|
db.setTransactionSuccessful();
|
||||||
|
@ -24,6 +24,9 @@ import org.session.libsession.utilities.TextSecurePreferences
|
|||||||
import org.session.libsession.utilities.WindowDebouncer
|
import org.session.libsession.utilities.WindowDebouncer
|
||||||
import org.session.libsignal.utilities.Hex
|
import org.session.libsignal.utilities.Hex
|
||||||
import org.session.libsignal.utilities.toHexString
|
import org.session.libsignal.utilities.toHexString
|
||||||
|
import org.thoughtcrime.securesms.database.GroupDatabase
|
||||||
|
import org.thoughtcrime.securesms.database.GroupMemberDatabase
|
||||||
|
import org.thoughtcrime.securesms.database.ThreadDatabase
|
||||||
import org.thoughtcrime.securesms.dependencies.DatabaseComponent
|
import org.thoughtcrime.securesms.dependencies.DatabaseComponent
|
||||||
import java.util.Timer
|
import java.util.Timer
|
||||||
|
|
||||||
@ -261,4 +264,15 @@ object ConfigurationMessageUtilities {
|
|||||||
return dump
|
return dump
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JvmField
|
||||||
|
val DELETE_INACTIVE_GROUPS: String = """
|
||||||
|
DELETE FROM ${GroupDatabase.TABLE_NAME} WHERE ${GroupDatabase.GROUP_ID} IN (SELECT ${ThreadDatabase.ADDRESS} FROM ${ThreadDatabase.TABLE_NAME} WHERE ${ThreadDatabase.MESSAGE_COUNT} <= 0 AND ${ThreadDatabase.ADDRESS} LIKE '${GroupUtil.CLOSED_GROUP_PREFIX}%');
|
||||||
|
DELETE FROM ${ThreadDatabase.TABLE_NAME} WHERE ${ThreadDatabase.ADDRESS} IN (SELECT ${ThreadDatabase.ADDRESS} FROM ${ThreadDatabase.TABLE_NAME} WHERE ${ThreadDatabase.MESSAGE_COUNT} <= 0 AND ${ThreadDatabase.ADDRESS} LIKE '${GroupUtil.CLOSED_GROUP_PREFIX}%');
|
||||||
|
""".trimIndent()
|
||||||
|
|
||||||
|
@JvmField
|
||||||
|
val DELETE_INACTIVE_ONE_TO_ONES: String = """
|
||||||
|
DELETE FROM ${ThreadDatabase.TABLE_NAME} WHERE ${ThreadDatabase.MESSAGE_COUNT} <= 0 AND ${ThreadDatabase.ADDRESS} NOT LIKE '${GroupUtil.CLOSED_GROUP_PREFIX}%' AND ${ThreadDatabase.ADDRESS} NOT LIKE '${GroupUtil.OPEN_GROUP_PREFIX}%' AND ${ThreadDatabase.ADDRESS} NOT LIKE '${GroupUtil.OPEN_GROUP_INBOX_PREFIX}%';
|
||||||
|
""".trimIndent()
|
||||||
|
|
||||||
}
|
}
|
@ -91,60 +91,60 @@ data class ConfigurationSyncJob(val destination: Destination): Job {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: re-add all this to do actual network sync job
|
// TODO: re-add all this to do actual network sync job
|
||||||
val batchResponse = SnodeAPI.getSingleTargetSnode(destination.destinationPublicKey()).bind { snode ->
|
// val batchResponse = SnodeAPI.getSingleTargetSnode(destination.destinationPublicKey()).bind { snode ->
|
||||||
SnodeAPI.getRawBatchResponse(
|
// SnodeAPI.getRawBatchResponse(
|
||||||
snode,
|
// snode,
|
||||||
destination.destinationPublicKey(),
|
// destination.destinationPublicKey(),
|
||||||
allRequests,
|
// allRequests,
|
||||||
sequence = true
|
// sequence = true
|
||||||
)
|
// )
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
try {
|
// try {
|
||||||
val rawResponses = batchResponse.get()
|
// val rawResponses = batchResponse.get()
|
||||||
@Suppress("UNCHECKED_CAST")
|
// @Suppress("UNCHECKED_CAST")
|
||||||
val responseList = (rawResponses["results"] as List<RawResponse>)
|
// val responseList = (rawResponses["results"] as List<RawResponse>)
|
||||||
// we are always adding in deletions at the end
|
// // we are always adding in deletions at the end
|
||||||
val deletionResponse = if (toDeleteRequest != null) responseList.last() else null
|
// val deletionResponse = if (toDeleteRequest != null) responseList.last() else null
|
||||||
val deletedHashes = deletionResponse?.let {
|
// val deletedHashes = deletionResponse?.let {
|
||||||
@Suppress("UNCHECKED_CAST")
|
// @Suppress("UNCHECKED_CAST")
|
||||||
// get the sub-request body
|
// // get the sub-request body
|
||||||
(deletionResponse["body"] as? RawResponse)?.let { body ->
|
// (deletionResponse["body"] as? RawResponse)?.let { body ->
|
||||||
// get the swarm dict
|
// // get the swarm dict
|
||||||
body["swarm"] as? RawResponse
|
// body["swarm"] as? RawResponse
|
||||||
}?.mapValues { (_, swarmDict) ->
|
// }?.mapValues { (_, swarmDict) ->
|
||||||
// get the deleted values from dict
|
// // get the deleted values from dict
|
||||||
((swarmDict as? RawResponse)?.get("deleted") as? List<String>)?.toSet() ?: emptySet()
|
// ((swarmDict as? RawResponse)?.get("deleted") as? List<String>)?.toSet() ?: emptySet()
|
||||||
}?.values?.reduce { acc, strings ->
|
// }?.values?.reduce { acc, strings ->
|
||||||
// create an intersection of all deleted hashes (common between all swarm nodes)
|
// // create an intersection of all deleted hashes (common between all swarm nodes)
|
||||||
acc intersect strings
|
// acc intersect strings
|
||||||
}
|
// }
|
||||||
} ?: emptySet()
|
// } ?: emptySet()
|
||||||
|
//
|
||||||
// at this point responseList index should line up with configsRequiringPush index
|
// // at this point responseList index should line up with configsRequiringPush index
|
||||||
configsRequiringPush.forEachIndexed { index, config ->
|
// configsRequiringPush.forEachIndexed { index, config ->
|
||||||
val (toPushMessage, _) = batchObjects[index]!!
|
// val (toPushMessage, _) = batchObjects[index]!!
|
||||||
val response = responseList[index]
|
// val response = responseList[index]
|
||||||
val responseBody = response["body"] as? RawResponse
|
// val responseBody = response["body"] as? RawResponse
|
||||||
val insertHash = responseBody?.get("hash") as? String ?: run {
|
// val insertHash = responseBody?.get("hash") as? String ?: run {
|
||||||
Log.w(TAG, "No hash returned for the configuration in namespace ${config.configNamespace()}")
|
// Log.w(TAG, "No hash returned for the configuration in namespace ${config.configNamespace()}")
|
||||||
return@forEachIndexed
|
// return@forEachIndexed
|
||||||
}
|
// }
|
||||||
Log.d(TAG, "Hash $insertHash returned from store request for new config")
|
// Log.d(TAG, "Hash $insertHash returned from store request for new config")
|
||||||
|
//
|
||||||
// confirm pushed seqno
|
// // confirm pushed seqno
|
||||||
val thisSeqNo = toPushMessage.seqNo
|
// val thisSeqNo = toPushMessage.seqNo
|
||||||
config.confirmPushed(thisSeqNo, insertHash)
|
// config.confirmPushed(thisSeqNo, insertHash)
|
||||||
Log.d(TAG, "Successfully removed the deleted hashes from ${config.javaClass.simpleName}")
|
// Log.d(TAG, "Successfully removed the deleted hashes from ${config.javaClass.simpleName}")
|
||||||
// dump and write config after successful
|
// // dump and write config after successful
|
||||||
if (config.needsDump()) { // usually this will be true?
|
// if (config.needsDump()) { // usually this will be true?
|
||||||
configFactory.persist(config)
|
// configFactory.persist(config)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
} catch (e: Exception) {
|
// } catch (e: Exception) {
|
||||||
Log.e(TAG, "Error performing batch request", e)
|
// Log.e(TAG, "Error performing batch request", e)
|
||||||
return delegate.handleJobFailed(this, dispatcherName, e)
|
// return delegate.handleJobFailed(this, dispatcherName, e)
|
||||||
}
|
// }
|
||||||
delegate.handleJobSucceeded(this, dispatcherName)
|
delegate.handleJobSucceeded(this, dispatcherName)
|
||||||
if (shouldRunAgain.get() && storage.getConfigSyncJob(destination) == null) {
|
if (shouldRunAgain.get() && storage.getConfigSyncJob(destination) == null) {
|
||||||
// reschedule if something has updated since we started this job
|
// reschedule if something has updated since we started this job
|
||||||
|
@ -124,7 +124,7 @@ class ConfigurationMessage(var closedGroups: List<ClosedGroup>, var openGroups:
|
|||||||
val profileKey = ProfileKeyUtil.getProfileKey(context)
|
val profileKey = ProfileKeyUtil.getProfileKey(context)
|
||||||
val groups = storage.getAllGroups(includeInactive = false)
|
val groups = storage.getAllGroups(includeInactive = false)
|
||||||
for (group in groups) {
|
for (group in groups) {
|
||||||
if (group.isClosedGroup) {
|
if (group.isClosedGroup && group.isActive) {
|
||||||
if (!group.members.contains(Address.fromSerialized(storage.getUserPublicKey()!!))) continue
|
if (!group.members.contains(Address.fromSerialized(storage.getUserPublicKey()!!))) continue
|
||||||
val groupPublicKey = GroupUtil.doubleDecodeGroupID(group.encodedId).toHexString()
|
val groupPublicKey = GroupUtil.doubleDecodeGroupID(group.encodedId).toHexString()
|
||||||
val encryptionKeyPair = storage.getLatestClosedGroupEncryptionKeyPair(groupPublicKey) ?: continue
|
val encryptionKeyPair = storage.getLatestClosedGroupEncryptionKeyPair(groupPublicKey) ?: continue
|
||||||
|
Loading…
Reference in New Issue
Block a user