discord-jadx/app/src/main/java/com/discord/stores/StoreMessagesHolder.java

435 lines
19 KiB
Java

package com.discord.stores;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import c.a.u.a;
import c.a.u.b;
import com.discord.api.message.reaction.MessageReaction;
import com.discord.api.message.reaction.MessageReactionEmoji;
import com.discord.api.message.reaction.MessageReactionUpdate;
import com.discord.models.message.Message;
import com.discord.stores.StoreMessagesLoader;
import com.discord.utilities.message.LocalMessageCreatorsKt;
import com.discord.utilities.message.MessageUtils;
import com.discord.utilities.persister.Persister;
import com.discord.utilities.time.ClockFactory;
import j0.l.e.j;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.concurrent.TimeUnit;
import rx.Observable;
import rx.Subscription;
import rx.subjects.BehaviorSubject;
import rx.subjects.SerializedSubject;
import rx.subjects.Subject;
public class StoreMessagesHolder {
private static final int CACHE_MAX_CHANNELS = 8;
private static final int CACHE_MAX_MESSAGES = 10;
private static final int CACHE_PERSIST_INTERVAL = 60000;
private static final int MAX_MESSAGES_PER_CHANNEL = 200;
private static final int MAX_MESSAGES_PER_CHANNEL_TRIM = 100;
private final Set<Long> activeChannels = new HashSet();
private final Persister<Map<Long, List<Message>>> cache = new Persister<>("STORE_MESSAGES_CACHE_V37", new HashMap());
private boolean cacheEnabled;
private Subscription cachePersistSubscription;
private long cachePersistedAt = ClockFactory.get().currentTimeMillis();
private Map<Long, List<Message>> cacheSnapshot = Collections.emptyMap();
private final Set<Long> detachedChannels;
private final Subject<Set<Long>, Set<Long>> detachedChannelsSubject;
private final Map<String, Long> messageNonceIds = new HashMap();
private final LinkedHashMap<Long, TreeMap<Long, Message>> messages = new LinkedHashMap<>();
private final Subject<Map<Long, List<Message>>, Map<Long, List<Message>>> messagesPublisher = new SerializedSubject(BehaviorSubject.k0());
private Map<Long, List<Message>> messagesSnapshot = Collections.emptyMap();
private long myUserId;
private long selectedChannelId;
private final Set<Long> staleMessages = new HashSet();
private final Set<Long> updatedChannels = new HashSet();
public StoreMessagesHolder() {
HashSet hashSet = new HashSet();
this.detachedChannels = hashSet;
this.detachedChannelsSubject = new SerializedSubject(BehaviorSubject.l0(new HashSet(hashSet)));
}
private static Message addReaction(Message message, MessageReactionEmoji messageReactionEmoji, boolean z2) {
MessageReaction messageReaction;
Map<String, MessageReaction> reactionsMap = message.getReactionsMap();
String c2 = messageReactionEmoji.c();
if (z2 && reactionsMap.containsKey(c2) && reactionsMap.get(c2).c()) {
return message;
}
LinkedHashMap linkedHashMap = new LinkedHashMap(reactionsMap);
boolean z3 = true;
if (reactionsMap.containsKey(c2)) {
MessageReaction messageReaction2 = (MessageReaction) linkedHashMap.get(messageReactionEmoji.c());
int a = messageReaction2.a() + 1;
MessageReactionEmoji b = messageReaction2.b();
if (!messageReaction2.c() && !z2) {
z3 = false;
}
messageReaction = new MessageReaction(a, b, z3);
} else {
messageReaction = new MessageReaction(1, messageReactionEmoji, z2);
}
linkedHashMap.put(c2, messageReaction);
return LocalMessageCreatorsKt.createWithReactions(message, linkedHashMap);
}
private Map<Long, List<Message>> computeMessagesCache() {
HashMap hashMap = new HashMap();
ListIterator listIterator = new ArrayList(this.messages.entrySet()).listIterator(this.messages.size());
int i = 8;
while (listIterator.hasPrevious() && i > 0) {
Map.Entry entry = (Map.Entry) listIterator.previous();
long longValue = ((Long) entry.getKey()).longValue();
Map<?, Message> map = (Map) entry.getValue();
if (map.size() > 0) {
hashMap.put(Long.valueOf(longValue), computeMessagesCacheSubList(longValue, map));
i--;
}
}
return hashMap;
}
private List<Message> computeMessagesCacheSubList(long j, @NonNull Map<?, Message> map) {
return new ArrayList(new ArrayList(map.values()).subList(Math.max(0, map.size() - (j == this.selectedChannelId ? 20 : 10)), map.size()));
}
private boolean isChannelActive(long j) {
return this.activeChannels.contains(Long.valueOf(j));
}
private boolean isChannelDetached(long j) {
return this.detachedChannels.contains(Long.valueOf(j));
}
private synchronized void messageCacheTryPersist() {
if (this.cacheEnabled) {
long currentTimeMillis = ClockFactory.get().currentTimeMillis();
long j = this.cachePersistedAt + 60000;
if (j < currentTimeMillis) {
this.cachePersistedAt = currentTimeMillis;
Map<Long, List<Message>> computeMessagesCache = computeMessagesCache();
if (!this.cacheSnapshot.equals(computeMessagesCache)) {
this.cacheSnapshot = computeMessagesCache;
this.cache.set(computeMessagesCache);
}
} else {
long j2 = (j - currentTimeMillis) + 1000;
Subscription subscription = this.cachePersistSubscription;
if (subscription != null) {
subscription.unsubscribe();
}
this.cachePersistSubscription = new j(null).p(j2, TimeUnit.MILLISECONDS).W(new b(this), a.i);
}
}
}
private void publishIfUpdated() {
publishIfUpdated(false);
}
private void publishIfUpdated(boolean z2) {
if (!this.updatedChannels.isEmpty() || z2) {
HashMap hashMap = new HashMap();
for (Long l : this.updatedChannels) {
long longValue = l.longValue();
hashMap.put(Long.valueOf(longValue), new ArrayList(this.messages.get(Long.valueOf(longValue)).values()));
}
for (Map.Entry<Long, List<Message>> entry : this.messagesSnapshot.entrySet()) {
long longValue2 = entry.getKey().longValue();
if (!this.updatedChannels.contains(Long.valueOf(longValue2))) {
hashMap.put(Long.valueOf(longValue2), entry.getValue());
}
}
this.updatedChannels.clear();
this.messagesSnapshot = hashMap;
this.messagesPublisher.onNext(hashMap);
messageCacheTryPersist();
}
}
private static Message removeReaction(Message message, MessageReactionEmoji messageReactionEmoji, boolean z2) {
Map<String, MessageReaction> reactionsMap = message.getReactionsMap();
String c2 = messageReactionEmoji.c();
if (!reactionsMap.containsKey(c2)) {
return message;
}
if (z2 && !reactionsMap.get(c2).c()) {
return message;
}
LinkedHashMap linkedHashMap = new LinkedHashMap(reactionsMap);
MessageReaction messageReaction = (MessageReaction) linkedHashMap.get(c2);
boolean z3 = true;
if (messageReaction.a() == 1) {
linkedHashMap.remove(c2);
} else {
int a = messageReaction.a() - 1;
MessageReactionEmoji b = messageReaction.b();
if (!messageReaction.c() || z2) {
z3 = false;
}
linkedHashMap.put(c2, new MessageReaction(a, b, z3));
}
if (linkedHashMap.isEmpty()) {
linkedHashMap = null;
}
return LocalMessageCreatorsKt.createWithReactions(message, linkedHashMap);
}
private boolean updateDetachedState(long j, Map<Long, Message> map, boolean z2, boolean z3, boolean z4) {
int size = map.size();
boolean z5 = true;
boolean z6 = size >= 200;
if (z6) {
int i = z2 ? 100 : size - 100;
Iterator<Map.Entry<Long, Message>> it = map.entrySet().iterator();
int i2 = 0;
while (it.hasNext()) {
it.next();
if ((z2 && i2 >= i) || (!z2 && i2 < i)) {
it.remove();
}
i2++;
}
}
boolean isChannelDetached = isChannelDetached(j);
if (!z6 || !z2 || z3) {
z5 = false;
}
if (!isChannelDetached && (z5 || z4)) {
this.detachedChannels.add(Long.valueOf(j));
this.detachedChannelsSubject.onNext(new HashSet(this.detachedChannels));
} else if (isChannelDetached && z3) {
this.detachedChannels.remove(Long.valueOf(j));
this.detachedChannelsSubject.onNext(new HashSet(this.detachedChannels));
}
return z6;
}
public /* synthetic */ void a(Object obj) {
messageCacheTryPersist();
}
public synchronized void addMessages(@NonNull List<Message> list) {
boolean z2;
for (Message message : list) {
long channelId = message.getChannelId();
TreeMap<Long, Message> treeMap = this.messages.get(Long.valueOf(channelId));
if (isChannelActive(channelId) && !isChannelDetached(channelId)) {
String nonce = message.getNonce();
if (message.isLocal()) {
this.messageNonceIds.put(nonce, Long.valueOf(message.getId()));
} else {
Long l = this.messageNonceIds.get(nonce);
if (l != null) {
this.messageNonceIds.remove(nonce);
if (treeMap.containsKey(l)) {
treeMap.remove(l);
z2 = true;
treeMap.put(Long.valueOf(message.getId()), message);
if (!updateDetachedState(channelId, treeMap, false, true, false) || !z2) {
this.updatedChannels.add(Long.valueOf(channelId));
}
}
}
}
z2 = false;
treeMap.put(Long.valueOf(message.getId()), message);
if (!updateDetachedState(channelId, treeMap, false, true, false)) {
}
this.updatedChannels.add(Long.valueOf(channelId));
}
}
publishIfUpdated();
}
public synchronized void deleteMessages(long j, @Nullable List<Long> list) {
TreeMap<Long, Message> treeMap = this.messages.get(Long.valueOf(j));
if (isChannelActive(j) && list != null) {
if (!list.isEmpty()) {
for (Long l : list) {
long longValue = l.longValue();
if (treeMap.containsKey(Long.valueOf(longValue))) {
treeMap.remove(Long.valueOf(longValue));
this.updatedChannels.add(Long.valueOf(j));
}
}
publishIfUpdated();
}
}
}
public Observable<Set<Long>> getDetachedChannelsSubject() {
return this.detachedChannelsSubject;
}
@Nullable
public synchronized TreeMap<Long, Message> getMessagesForChannel(Long l) {
return this.messages.get(l);
}
public Observable<Map<Long, List<Message>>> getMessagesPublisher() {
return this.messagesPublisher;
}
public synchronized void init(boolean z2) {
if (z2) {
for (Map.Entry<Long, List<Message>> entry : this.cache.get().entrySet()) {
if (entry != null) {
if (entry.getKey() != null) {
long longValue = entry.getKey().longValue();
this.messages.put(Long.valueOf(longValue), new TreeMap<>(MessageUtils.getSORT_BY_IDS_COMPARATOR()));
TreeMap<Long, Message> treeMap = this.messages.get(Long.valueOf(longValue));
for (Message message : entry.getValue()) {
this.staleMessages.add(Long.valueOf(message.getId()));
treeMap.put(Long.valueOf(message.getId()), message);
}
this.updatedChannels.add(Long.valueOf(longValue));
}
}
}
}
this.cacheEnabled = z2;
publishIfUpdated(true);
}
public synchronized void invalidate() {
for (Map.Entry<Long, TreeMap<Long, Message>> entry : this.messages.entrySet()) {
for (Map.Entry<Long, Message> entry2 : entry.getValue().entrySet()) {
this.staleMessages.add(Long.valueOf(entry2.getValue().getId()));
}
}
this.activeChannels.clear();
this.activeChannels.add(Long.valueOf(this.selectedChannelId));
}
public synchronized void loadMessageChunks(@NonNull List<StoreMessagesLoader.ChannelChunk> list) {
for (StoreMessagesLoader.ChannelChunk channelChunk : list) {
List<Message> messages = channelChunk.getMessages();
long channelId = channelChunk.getChannelId();
if (this.activeChannels.contains(Long.valueOf(channelId))) {
TreeMap<Long, Message> treeMap = this.messages.get(Long.valueOf(channelId));
boolean isChannelDetached = isChannelDetached(channelId);
boolean isJump = channelChunk.isJump();
boolean isInitial = channelChunk.isInitial();
boolean isPresent = channelChunk.isPresent();
if (isInitial || isJump) {
Iterator<Map.Entry<Long, Message>> it = treeMap.entrySet().iterator();
while (it.hasNext()) {
Long valueOf = Long.valueOf(it.next().getValue().getId());
if (this.staleMessages.contains(valueOf) || isChannelDetached || isJump) {
it.remove();
this.staleMessages.remove(valueOf);
}
}
}
for (Message message : messages) {
treeMap.put(Long.valueOf(message.getId()), message);
}
updateDetachedState(channelId, treeMap, channelChunk.isAppendingTop(), isPresent, isJump);
this.updatedChannels.add(Long.valueOf(channelId));
}
}
publishIfUpdated();
}
public synchronized void removeAllReactions(@NonNull MessageReactionUpdate messageReactionUpdate) {
long a = messageReactionUpdate.a();
if (isChannelActive(a)) {
long c2 = messageReactionUpdate.c();
TreeMap<Long, Message> treeMap = this.messages.get(Long.valueOf(a));
Message message = treeMap.get(Long.valueOf(c2));
if (message != null) {
treeMap.put(Long.valueOf(c2), LocalMessageCreatorsKt.createWithReactions(message, null));
this.updatedChannels.add(Long.valueOf(a));
publishIfUpdated();
}
}
}
public synchronized void removeEmojiReactions(@NonNull MessageReactionUpdate messageReactionUpdate) {
long a = messageReactionUpdate.a();
if (isChannelActive(a)) {
long c2 = messageReactionUpdate.c();
TreeMap<Long, Message> treeMap = this.messages.get(Long.valueOf(a));
Message message = treeMap.get(Long.valueOf(c2));
if (message != null) {
String c3 = messageReactionUpdate.b().c();
Map<String, MessageReaction> reactionsMap = message.getReactionsMap();
if (reactionsMap.containsKey(c3)) {
LinkedHashMap linkedHashMap = new LinkedHashMap();
for (Map.Entry<String, MessageReaction> entry : reactionsMap.entrySet()) {
String key = entry.getKey();
if (!key.equals(c3)) {
linkedHashMap.put(key, entry.getValue());
}
}
treeMap.put(Long.valueOf(c2), LocalMessageCreatorsKt.createWithReactions(message, linkedHashMap));
this.updatedChannels.add(Long.valueOf(a));
publishIfUpdated();
}
}
}
}
public void setMyUserId(long j) {
this.myUserId = j;
}
public synchronized void setSelectedChannelId(long j) {
this.selectedChannelId = j;
TreeMap<Long, Message> treeMap = this.messages.get(Long.valueOf(j));
if (treeMap != null) {
this.messages.remove(Long.valueOf(j));
this.messages.put(Long.valueOf(j), treeMap);
} else {
this.messages.put(Long.valueOf(j), new TreeMap<>(MessageUtils.getSORT_BY_IDS_COMPARATOR()));
}
this.activeChannels.add(Long.valueOf(j));
}
public synchronized void updateMessages(@NonNull com.discord.api.message.Message message) {
long g = message.g();
TreeMap<Long, Message> treeMap = this.messages.get(Long.valueOf(g));
if (isChannelActive(g)) {
Message message2 = treeMap.get(Long.valueOf(message.o()));
if (!isChannelDetached(g)) {
if (message2 != null) {
treeMap.put(Long.valueOf(message.o()), message2.merge(message));
this.updatedChannels.add(Long.valueOf(g));
}
}
return;
}
publishIfUpdated();
}
public synchronized void updateReactions(@NonNull List<MessageReactionUpdate> list, boolean z2) {
for (MessageReactionUpdate messageReactionUpdate : list) {
long a = messageReactionUpdate.a();
if (isChannelActive(a)) {
long c2 = messageReactionUpdate.c();
MessageReactionEmoji b = messageReactionUpdate.b();
boolean z3 = messageReactionUpdate.d() == this.myUserId;
TreeMap<Long, Message> treeMap = this.messages.get(Long.valueOf(a));
Message message = treeMap.get(Long.valueOf(c2));
if (message != null) {
treeMap.put(Long.valueOf(c2), z2 ? addReaction(message, b, z3) : removeReaction(message, b, z3));
this.updatedChannels.add(Long.valueOf(a));
}
}
}
publishIfUpdated();
}
}