Add chat folder support to storage service.

This commit is contained in:
Michelle Tang
2025-04-04 11:36:17 -04:00
parent f6ecb572b1
commit eb1cf8d62f
26 changed files with 1131 additions and 84 deletions

View File

@@ -0,0 +1,27 @@
package org.whispersystems.signalservice.api.storage
import org.whispersystems.signalservice.internal.storage.protos.ChatFolderRecord
import java.io.IOException
/**
* Wrapper around a [ChatFolderRecord] to pair it with a [StorageId].
*/
data class SignalChatFolderRecord(
override val id: StorageId,
override val proto: ChatFolderRecord
) : SignalRecord<ChatFolderRecord> {
companion object {
fun newBuilder(serializedUnknowns: ByteArray?): ChatFolderRecord.Builder {
return serializedUnknowns?.let { builderFromUnknowns(it) } ?: ChatFolderRecord.Builder()
}
private fun builderFromUnknowns(serializedUnknowns: ByteArray): ChatFolderRecord.Builder {
return try {
ChatFolderRecord.ADAPTER.decode(serializedUnknowns).newBuilder()
} catch (e: IOException) {
ChatFolderRecord.Builder()
}
}
}
}

View File

@@ -10,7 +10,7 @@ data class SignalStorageRecord(
val proto: StorageRecord
) {
val isUnknown: Boolean
get() = proto.contact == null && proto.groupV1 == null && proto.groupV2 == null && proto.account == null && proto.storyDistributionList == null && proto.callLink == null
get() = proto.contact == null && proto.groupV1 == null && proto.groupV2 == null && proto.account == null && proto.storyDistributionList == null && proto.callLink == null && proto.chatFolder == null
companion object {
@JvmStatic

View File

@@ -38,6 +38,10 @@ public class StorageId {
return new StorageId(ManifestRecord.Identifier.Type.CALL_LINK.getValue(), Preconditions.checkNotNull(raw));
}
public static StorageId forChatFolder(byte[] raw) {
return new StorageId(ManifestRecord.Identifier.Type.CHAT_FOLDER.getValue(), Preconditions.checkNotNull(raw));
}
public static StorageId forType(byte[] raw, int type) {
return new StorageId(type, raw);
}

View File

@@ -7,6 +7,7 @@ package org.whispersystems.signalservice.api.storage
import org.whispersystems.signalservice.internal.storage.protos.AccountRecord
import org.whispersystems.signalservice.internal.storage.protos.CallLinkRecord
import org.whispersystems.signalservice.internal.storage.protos.ChatFolderRecord
import org.whispersystems.signalservice.internal.storage.protos.ContactRecord
import org.whispersystems.signalservice.internal.storage.protos.GroupV1Record
import org.whispersystems.signalservice.internal.storage.protos.GroupV2Record
@@ -41,6 +42,10 @@ fun CallLinkRecord.toSignalCallLinkRecord(storageId: StorageId): SignalCallLinkR
return SignalCallLinkRecord(storageId, this)
}
fun ChatFolderRecord.toSignalChatFolderRecord(storageId: StorageId): SignalChatFolderRecord {
return SignalChatFolderRecord(storageId, this)
}
fun SignalContactRecord.toSignalStorageRecord(): SignalStorageRecord {
return SignalStorageRecord(id, StorageRecord(contact = this.proto))
}
@@ -64,3 +69,7 @@ fun SignalStoryDistributionListRecord.toSignalStorageRecord(): SignalStorageReco
fun SignalCallLinkRecord.toSignalStorageRecord(): SignalStorageRecord {
return SignalStorageRecord(id, StorageRecord(callLink = this.proto))
}
fun SignalChatFolderRecord.toSignalStorageRecord(): SignalStorageRecord {
return SignalStorageRecord(id, StorageRecord(chatFolder = this.proto))
}

View File

@@ -51,6 +51,7 @@ message ManifestRecord {
ACCOUNT = 4;
STORY_DISTRIBUTION_LIST = 5;
CALL_LINK = 7;
CHAT_FOLDER = 8;
}
bytes raw = 1;
@@ -72,6 +73,7 @@ message StorageRecord {
AccountRecord account = 4;
StoryDistributionListRecord storyDistributionList = 5;
CallLinkRecord callLink = 7;
ChatFolderRecord chatFolder = 8;
}
}
@@ -280,4 +282,38 @@ message CallLinkRecord {
bytes rootKey = 1;
bytes adminPasskey = 2;
uint64 deletedAtTimestampMs = 3;
}
}
message ChatFolderRecord {
message Recipient {
message Contact {
string serviceId = 1;
string e164 = 2;
}
oneof identifier {
Contact contact = 1;
bytes legacyGroupId = 2;
bytes groupMasterKey = 3;
}
}
// Represents the default "All chats" folder record vs all other custom folders
enum FolderType {
UNKNOWN = 0;
ALL = 1;
CUSTOM = 2;
}
bytes identifier = 1;
string name = 2;
uint32 position = 3;
bool showOnlyUnread = 4;
bool showMutedChats = 5;
bool includeAllIndividualChats = 6; // Folder includes all 1:1 chats, unless excluded
bool includeAllGroupChats = 7; // Folder includes all group chats, unless excluded
FolderType folderType = 8;
repeated Recipient includedRecipients = 9;
repeated Recipient excludedRecipients = 10;
uint64 deletedAtTimestampMs = 11; // When non-zero, `position` should be set to -1 and includedRecipients should be empty
}