]> nmode's Git Repositories - signal-cli/blob - lib/src/main/java/org/asamk/signal/manager/syncStorage/GroupV1RecordProcessor.java
14d3c882e9fd4316c303c18bdf146000ba709279
[signal-cli] / lib / src / main / java / org / asamk / signal / manager / syncStorage / GroupV1RecordProcessor.java
1 package org.asamk.signal.manager.syncStorage;
2
3 import org.asamk.signal.manager.api.GroupId;
4 import org.asamk.signal.manager.api.GroupIdV1;
5 import org.asamk.signal.manager.storage.SignalAccount;
6 import org.asamk.signal.manager.storage.groups.GroupInfoV2;
7 import org.asamk.signal.manager.util.KeyUtils;
8 import org.slf4j.Logger;
9 import org.slf4j.LoggerFactory;
10 import org.whispersystems.signalservice.api.storage.SignalGroupV1Record;
11
12 import java.sql.Connection;
13 import java.sql.SQLException;
14 import java.util.Arrays;
15 import java.util.Optional;
16
17 /**
18 * Handles merging remote storage updates into local group v1 state.
19 */
20 public final class GroupV1RecordProcessor extends DefaultStorageRecordProcessor<SignalGroupV1Record> {
21
22 private static final Logger logger = LoggerFactory.getLogger(GroupV1RecordProcessor.class);
23 private final SignalAccount account;
24 private final Connection connection;
25
26 public GroupV1RecordProcessor(SignalAccount account, Connection connection) {
27 this.account = account;
28 this.connection = connection;
29 }
30
31 /**
32 * We want to catch:
33 * - Invalid group IDs
34 * - GV1 IDs that map to GV2 IDs, meaning we've already migrated them.
35 */
36 @Override
37 protected boolean isInvalid(SignalGroupV1Record remote) throws SQLException {
38 try {
39 final var id = GroupId.unknownVersion(remote.getGroupId());
40 if (!(id instanceof GroupIdV1)) {
41 return true;
42 }
43 final var group = account.getGroupStore().getGroup(connection, id);
44
45 if (group instanceof GroupInfoV2) {
46 logger.debug("We already have an upgraded V2 group for this V1 group -- marking as invalid.");
47 return true;
48 } else {
49 return false;
50 }
51 } catch (AssertionError e) {
52 logger.debug("Bad Group ID -- marking as invalid.");
53 return true;
54 }
55 }
56
57 @Override
58 protected Optional<SignalGroupV1Record> getMatching(SignalGroupV1Record remote) throws SQLException {
59 final var id = GroupId.v1(remote.getGroupId());
60 final var group = account.getGroupStore().getGroup(connection, id);
61
62 if (group == null) {
63 return Optional.empty();
64 }
65
66 final var storageId = account.getGroupStore().getGroupStorageId(connection, id);
67 return Optional.of(StorageSyncModels.localToRemoteRecord(group, storageId.getRaw()).getGroupV1().get());
68 }
69
70 @Override
71 protected SignalGroupV1Record merge(SignalGroupV1Record remote, SignalGroupV1Record local) {
72 final var unknownFields = remote.serializeUnknownFields();
73 final var blocked = remote.isBlocked();
74 final var profileSharing = remote.isProfileSharingEnabled();
75 final var archived = remote.isArchived();
76 final var forcedUnread = remote.isForcedUnread();
77 final var muteUntil = remote.getMuteUntil();
78
79 final var mergedBuilder = new SignalGroupV1Record.Builder(remote.getId().getRaw(),
80 remote.getGroupId(),
81 unknownFields).setBlocked(blocked)
82 .setProfileSharingEnabled(profileSharing)
83 .setForcedUnread(forcedUnread)
84 .setMuteUntil(muteUntil)
85 .setArchived(archived);
86
87 final var merged = mergedBuilder.build();
88
89 final var matchesRemote = doProtosMatch(merged, remote);
90 if (matchesRemote) {
91 return remote;
92 }
93
94 final var matchesLocal = doProtosMatch(merged, local);
95 if (matchesLocal) {
96 return local;
97 }
98
99 return mergedBuilder.setId(KeyUtils.createRawStorageId()).build();
100 }
101
102 @Override
103 protected void insertLocal(SignalGroupV1Record record) throws SQLException {
104 // TODO send group info request (after server message queue is empty)
105 // context.getGroupHelper().sendGroupInfoRequest(groupIdV1, account.getSelfRecipientId());
106 StorageRecordUpdate<SignalGroupV1Record> update = new StorageRecordUpdate<>(null, record);
107 updateLocal(update);
108 }
109
110 @Override
111 protected void updateLocal(StorageRecordUpdate<SignalGroupV1Record> update) throws SQLException {
112 final var groupV1Record = update.newRecord();
113 final var groupIdV1 = GroupId.v1(groupV1Record.getGroupId());
114
115 final var group = account.getGroupStore().getOrCreateGroupV1(connection, groupIdV1);
116 if (group != null) {
117 group.setBlocked(groupV1Record.isBlocked());
118 account.getGroupStore().updateGroup(connection, group);
119 account.getGroupStore()
120 .storeStorageRecord(connection,
121 group.getGroupId(),
122 groupV1Record.getId(),
123 groupV1Record.toProto().encode());
124 }
125 }
126
127 @Override
128 public int compare(SignalGroupV1Record lhs, SignalGroupV1Record rhs) {
129 if (Arrays.equals(lhs.getGroupId(), rhs.getGroupId())) {
130 return 0;
131 } else {
132 return 1;
133 }
134 }
135
136 private static boolean doProtosMatch(SignalGroupV1Record merged, SignalGroupV1Record other) {
137 return Arrays.equals(merged.toProto().encode(), other.toProto().encode());
138 }
139 }