package com.discord.stores; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import c.a.v.a; import c.a.v.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 Object $lock = new Object[0]; private final Set activeChannels = new HashSet(); private final Persister>> cache = new Persister<>("STORE_MESSAGES_CACHE_V36", new HashMap()); private boolean cacheEnabled; private Subscription cachePersistSubscription; private long cachePersistedAt = ClockFactory.get().currentTimeMillis(); private Map> cacheSnapshot = Collections.emptyMap(); private final Set detachedChannels; private Subject, Set> detachedChannelsSubject; private final Map messageNonceIds = new HashMap(); private final LinkedHashMap> messages = new LinkedHashMap<>(); private final Subject>, Map>> messagesPublisher = new SerializedSubject(BehaviorSubject.k0()); private Map> messagesSnapshot = Collections.emptyMap(); private long myUserId; private long selectedChannelId; private final Set staleMessages = new HashSet(); private final Set 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 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> 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 map = (Map) entry.getValue(); if (map.size() > 0) { hashMap.put(Long.valueOf(longValue), computeMessagesCacheSubList(longValue, map)); i--; } } return hashMap; } private List computeMessagesCacheSubList(long j, @NonNull Map 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 void messageCacheTryPersist() { synchronized (this.$lock) { if (this.cacheEnabled) { long currentTimeMillis = ClockFactory.get().currentTimeMillis(); long j = this.cachePersistedAt + 60000; if (j < currentTimeMillis) { this.cachePersistedAt = currentTimeMillis; Map> 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).q(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> 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 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 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> 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 void addMessages(@NonNull List list) { boolean z2; synchronized (this.$lock) { for (Message message : list) { long channelId = message.getChannelId(); TreeMap 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 void deleteMessages(long j, @Nullable List list) { synchronized (this.$lock) { TreeMap 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> getDetachedChannelSubject() { return this.detachedChannelsSubject; } @Nullable public TreeMap getMessagesForChannel(Long l) { TreeMap treeMap; synchronized (this.$lock) { treeMap = this.messages.get(l); } return treeMap; } public Observable>> getMessagesPublisher() { return this.messagesPublisher; } public void init(boolean z2) { synchronized (this.$lock) { if (z2) { for (Map.Entry> 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 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 void invalidate() { synchronized (this.$lock) { for (Map.Entry> entry : this.messages.entrySet()) { for (Map.Entry entry2 : entry.getValue().entrySet()) { this.staleMessages.add(Long.valueOf(entry2.getValue().getId())); } } this.activeChannels.clear(); this.activeChannels.add(Long.valueOf(this.selectedChannelId)); } } public void loadMessageChunks(@NonNull List list) { synchronized (this.$lock) { for (StoreMessagesLoader.ChannelChunk channelChunk : list) { List messages = channelChunk.getMessages(); long channelId = channelChunk.getChannelId(); if (this.activeChannels.contains(Long.valueOf(channelId))) { TreeMap 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> 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 void removeAllReactions(@NonNull MessageReactionUpdate messageReactionUpdate) { synchronized (this.$lock) { long a = messageReactionUpdate.a(); if (isChannelActive(a)) { long c2 = messageReactionUpdate.c(); TreeMap 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 void removeEmojiReactions(@NonNull MessageReactionUpdate messageReactionUpdate) { synchronized (this.$lock) { long a = messageReactionUpdate.a(); if (isChannelActive(a)) { long c2 = messageReactionUpdate.c(); TreeMap treeMap = this.messages.get(Long.valueOf(a)); Message message = treeMap.get(Long.valueOf(c2)); if (message != null) { String c3 = messageReactionUpdate.b().c(); Map reactionsMap = message.getReactionsMap(); if (reactionsMap.containsKey(c3)) { LinkedHashMap linkedHashMap = new LinkedHashMap(); for (Map.Entry 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 void setSelectedChannelId(long j) { synchronized (this.$lock) { this.selectedChannelId = j; TreeMap 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 void updateMessages(@NonNull com.discord.api.message.Message message) { synchronized (this.$lock) { long g = message.g(); TreeMap 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 void updateReactions(@NonNull List list, boolean z2) { synchronized (this.$lock) { 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 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(); } } }