463 lines
21 KiB
Java
463 lines
21 KiB
Java
package com.google.firebase.firestore.remote;
|
|
|
|
import com.google.firebase.database.collection.ImmutableSortedSet;
|
|
import com.google.firebase.firestore.core.OnlineState;
|
|
import com.google.firebase.firestore.local.LocalStore;
|
|
import com.google.firebase.firestore.local.QueryPurpose;
|
|
import com.google.firebase.firestore.local.TargetData;
|
|
import com.google.firebase.firestore.model.DocumentKey;
|
|
import com.google.firebase.firestore.model.SnapshotVersion;
|
|
import com.google.firebase.firestore.model.mutation.MutationBatch;
|
|
import com.google.firebase.firestore.model.mutation.MutationBatchResult;
|
|
import com.google.firebase.firestore.model.mutation.MutationResult;
|
|
import com.google.firebase.firestore.remote.ConnectivityMonitor;
|
|
import com.google.firebase.firestore.remote.OnlineStateTracker;
|
|
import com.google.firebase.firestore.remote.RemoteStore;
|
|
import com.google.firebase.firestore.remote.WatchChange;
|
|
import com.google.firebase.firestore.remote.WatchChangeAggregator;
|
|
import com.google.firebase.firestore.remote.WatchStream;
|
|
import com.google.firebase.firestore.remote.WriteStream;
|
|
import com.google.firebase.firestore.util.Assert;
|
|
import com.google.firebase.firestore.util.AsyncQueue;
|
|
import com.google.firebase.firestore.util.Consumer;
|
|
import com.google.firebase.firestore.util.Logger;
|
|
import com.google.firebase.firestore.util.Util;
|
|
import io.grpc.Status;
|
|
import java.util.ArrayDeque;
|
|
import java.util.Deque;
|
|
import java.util.HashMap;
|
|
import java.util.Iterator;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.Objects;
|
|
import o.QwV;
|
|
|
|
/* loaded from: classes2.dex */
|
|
public final class RemoteStore implements WatchChangeAggregator.TargetMetadataProvider {
|
|
private final ConnectivityMonitor connectivityMonitor;
|
|
private final Datastore datastore;
|
|
private final LocalStore localStore;
|
|
private final OnlineStateTracker onlineStateTracker;
|
|
private final RemoteStoreCallback remoteStoreCallback;
|
|
private WatchChangeAggregator watchChangeAggregator;
|
|
private final WatchStream watchStream;
|
|
private final WriteStream writeStream;
|
|
private boolean networkEnabled = false;
|
|
private final Map<Integer, TargetData> listenTargets = new HashMap();
|
|
private final Deque<MutationBatch> writePipeline = new ArrayDeque();
|
|
|
|
/* loaded from: classes2.dex */
|
|
public interface RemoteStoreCallback {
|
|
ImmutableSortedSet<DocumentKey> getRemoteKeysForTarget(int i);
|
|
|
|
void handleOnlineStateChange(OnlineState onlineState);
|
|
|
|
void handleRejectedListen(int i, Status status);
|
|
|
|
void handleRejectedWrite(int i, Status status);
|
|
|
|
void handleRemoteEvent(RemoteEvent remoteEvent);
|
|
|
|
void handleSuccessfulWrite(MutationBatchResult mutationBatchResult);
|
|
}
|
|
|
|
public RemoteStore(final RemoteStoreCallback remoteStoreCallback, LocalStore localStore, Datastore datastore, final AsyncQueue asyncQueue, ConnectivityMonitor connectivityMonitor) {
|
|
this.remoteStoreCallback = remoteStoreCallback;
|
|
this.localStore = localStore;
|
|
this.datastore = datastore;
|
|
this.connectivityMonitor = connectivityMonitor;
|
|
Objects.requireNonNull(remoteStoreCallback);
|
|
this.onlineStateTracker = new OnlineStateTracker(asyncQueue, new OnlineStateTracker.OnlineStateCallback(remoteStoreCallback) { // from class: com.google.firebase.firestore.remote.RemoteStore$$ExternalSyntheticLambda1
|
|
public final RemoteStore.RemoteStoreCallback f$0;
|
|
|
|
@Override // com.google.firebase.firestore.remote.OnlineStateTracker.OnlineStateCallback
|
|
public final void handleOnlineStateChange(OnlineState onlineState) {
|
|
this.f$0.handleOnlineStateChange(onlineState);
|
|
}
|
|
|
|
{
|
|
this.f$0 = remoteStoreCallback;
|
|
}
|
|
});
|
|
this.watchStream = datastore.createWatchStream(new WatchStream.Callback(this) { // from class: com.google.firebase.firestore.remote.RemoteStore.1
|
|
final RemoteStore this$0;
|
|
|
|
{
|
|
this.this$0 = this;
|
|
}
|
|
|
|
@Override // com.google.firebase.firestore.remote.Stream.StreamCallback
|
|
public void onOpen() {
|
|
this.this$0.handleWatchStreamOpen();
|
|
}
|
|
|
|
@Override // com.google.firebase.firestore.remote.WatchStream.Callback
|
|
public void onWatchChange(SnapshotVersion snapshotVersion, WatchChange watchChange) {
|
|
this.this$0.handleWatchChange(snapshotVersion, watchChange);
|
|
}
|
|
|
|
@Override // com.google.firebase.firestore.remote.Stream.StreamCallback
|
|
public void onClose(Status status) {
|
|
this.this$0.handleWatchStreamClose(status);
|
|
}
|
|
});
|
|
this.writeStream = datastore.createWriteStream(new WriteStream.Callback(this) { // from class: com.google.firebase.firestore.remote.RemoteStore.2
|
|
final RemoteStore this$0;
|
|
|
|
{
|
|
this.this$0 = this;
|
|
}
|
|
|
|
@Override // com.google.firebase.firestore.remote.Stream.StreamCallback
|
|
public void onOpen() {
|
|
this.this$0.writeStream.writeHandshake();
|
|
}
|
|
|
|
@Override // com.google.firebase.firestore.remote.WriteStream.Callback
|
|
public void onHandshakeComplete() {
|
|
this.this$0.handleWriteStreamHandshakeComplete();
|
|
}
|
|
|
|
@Override // com.google.firebase.firestore.remote.WriteStream.Callback
|
|
public void onWriteResponse(SnapshotVersion snapshotVersion, List<MutationResult> list) {
|
|
this.this$0.handleWriteStreamMutationResults(snapshotVersion, list);
|
|
}
|
|
|
|
@Override // com.google.firebase.firestore.remote.Stream.StreamCallback
|
|
public void onClose(Status status) {
|
|
this.this$0.handleWriteStreamClose(status);
|
|
}
|
|
});
|
|
connectivityMonitor.addCallback(new Consumer(this, asyncQueue) { // from class: com.google.firebase.firestore.remote.RemoteStore$$ExternalSyntheticLambda2
|
|
public final RemoteStore f$0;
|
|
public final AsyncQueue f$1;
|
|
|
|
@Override // com.google.firebase.firestore.util.Consumer
|
|
public final void accept(Object obj) {
|
|
this.f$0.m254lambda$new$1$comgooglefirebasefirestoreremoteRemoteStore(this.f$1, (ConnectivityMonitor.NetworkStatus) obj);
|
|
}
|
|
|
|
{
|
|
this.f$0 = this;
|
|
this.f$1 = asyncQueue;
|
|
}
|
|
});
|
|
}
|
|
|
|
/* JADX INFO: Access modifiers changed from: package-private */
|
|
/* renamed from: lambda$new$1$com-google-firebase-firestore-remote-RemoteStore, reason: not valid java name */
|
|
public final /* synthetic */ void m254lambda$new$1$comgooglefirebasefirestoreremoteRemoteStore(AsyncQueue asyncQueue, final ConnectivityMonitor.NetworkStatus networkStatus) {
|
|
asyncQueue.enqueueAndForget(new Runnable(this, networkStatus) { // from class: com.google.firebase.firestore.remote.RemoteStore$$ExternalSyntheticLambda0
|
|
public final RemoteStore f$0;
|
|
public final ConnectivityMonitor.NetworkStatus f$1;
|
|
|
|
@Override // java.lang.Runnable
|
|
public final void run() {
|
|
this.f$0.m253lambda$new$0$comgooglefirebasefirestoreremoteRemoteStore(this.f$1);
|
|
}
|
|
|
|
{
|
|
this.f$0 = this;
|
|
this.f$1 = networkStatus;
|
|
}
|
|
});
|
|
}
|
|
|
|
/* JADX INFO: Access modifiers changed from: package-private */
|
|
/* renamed from: lambda$new$0$com-google-firebase-firestore-remote-RemoteStore, reason: not valid java name */
|
|
public final /* synthetic */ void m253lambda$new$0$comgooglefirebasefirestoreremoteRemoteStore(ConnectivityMonitor.NetworkStatus networkStatus) {
|
|
if (networkStatus.equals(ConnectivityMonitor.NetworkStatus.REACHABLE) && this.onlineStateTracker.getState().equals(OnlineState.ONLINE)) {
|
|
return;
|
|
}
|
|
if (!(networkStatus.equals(ConnectivityMonitor.NetworkStatus.UNREACHABLE) && this.onlineStateTracker.getState().equals(OnlineState.OFFLINE)) && canUseNetwork()) {
|
|
Logger.debug("RemoteStore", "Restarting streams for network reachability change.", new Object[0]);
|
|
restartNetwork();
|
|
}
|
|
}
|
|
|
|
public final void enableNetwork() {
|
|
this.networkEnabled = true;
|
|
if (canUseNetwork()) {
|
|
this.writeStream.setLastStreamToken(this.localStore.getLastStreamToken());
|
|
if (shouldStartWatchStream()) {
|
|
startWatchStream();
|
|
} else {
|
|
this.onlineStateTracker.updateState(OnlineState.UNKNOWN);
|
|
}
|
|
fillWritePipeline();
|
|
}
|
|
}
|
|
|
|
private void disableNetworkInternal() {
|
|
this.watchStream.stop();
|
|
this.writeStream.stop();
|
|
if (!this.writePipeline.isEmpty()) {
|
|
Logger.debug("RemoteStore", "Stopping write stream with %d pending writes", Integer.valueOf(this.writePipeline.size()));
|
|
this.writePipeline.clear();
|
|
}
|
|
cleanUpWatchStreamState();
|
|
}
|
|
|
|
private void restartNetwork() {
|
|
this.networkEnabled = false;
|
|
disableNetworkInternal();
|
|
this.onlineStateTracker.updateState(OnlineState.UNKNOWN);
|
|
this.writeStream.inhibitBackoff();
|
|
this.watchStream.inhibitBackoff();
|
|
enableNetwork();
|
|
}
|
|
|
|
public final void start() {
|
|
enableNetwork();
|
|
}
|
|
|
|
public final void handleCredentialChange() {
|
|
if (canUseNetwork()) {
|
|
Logger.debug("RemoteStore", "Restarting streams for new credential.", new Object[0]);
|
|
restartNetwork();
|
|
}
|
|
}
|
|
|
|
public final void listen(TargetData targetData) {
|
|
Integer valueOf = Integer.valueOf(targetData.getTargetId());
|
|
if (this.listenTargets.containsKey(valueOf)) {
|
|
return;
|
|
}
|
|
this.listenTargets.put(valueOf, targetData);
|
|
if (shouldStartWatchStream()) {
|
|
startWatchStream();
|
|
} else if (this.watchStream.isOpen()) {
|
|
sendWatchRequest(targetData);
|
|
}
|
|
}
|
|
|
|
private void sendWatchRequest(TargetData targetData) {
|
|
this.watchChangeAggregator.recordPendingTargetRequest(targetData.getTargetId());
|
|
this.watchStream.watchQuery(targetData);
|
|
}
|
|
|
|
public final void stopListening(int i) {
|
|
Assert.hardAssert(this.listenTargets.remove(Integer.valueOf(i)) != null, "stopListening called on target no currently watched: %d", Integer.valueOf(i));
|
|
if (this.watchStream.isOpen()) {
|
|
sendUnwatchRequest(i);
|
|
}
|
|
if (this.listenTargets.isEmpty()) {
|
|
if (this.watchStream.isOpen()) {
|
|
this.watchStream.markIdle();
|
|
} else if (canUseNetwork()) {
|
|
this.onlineStateTracker.updateState(OnlineState.UNKNOWN);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void sendUnwatchRequest(int i) {
|
|
this.watchChangeAggregator.recordPendingTargetRequest(i);
|
|
this.watchStream.unwatchTarget(i);
|
|
}
|
|
|
|
private boolean shouldStartWriteStream() {
|
|
return (!canUseNetwork() || this.writeStream.isStarted() || this.writePipeline.isEmpty()) ? false : true;
|
|
}
|
|
|
|
private boolean shouldStartWatchStream() {
|
|
return (!canUseNetwork() || this.watchStream.isStarted() || this.listenTargets.isEmpty()) ? false : true;
|
|
}
|
|
|
|
private void startWatchStream() {
|
|
Assert.hardAssert(shouldStartWatchStream(), "startWatchStream() called when shouldStartWatchStream() is false.", new Object[0]);
|
|
this.watchChangeAggregator = new WatchChangeAggregator(this);
|
|
this.watchStream.start();
|
|
this.onlineStateTracker.handleWatchStreamStart();
|
|
}
|
|
|
|
/* JADX INFO: Access modifiers changed from: private */
|
|
public void handleWatchStreamOpen() {
|
|
Iterator<TargetData> it = this.listenTargets.values().iterator();
|
|
while (it.hasNext()) {
|
|
sendWatchRequest(it.next());
|
|
}
|
|
}
|
|
|
|
/* JADX INFO: Access modifiers changed from: private */
|
|
public void handleWatchChange(SnapshotVersion snapshotVersion, WatchChange watchChange) {
|
|
this.onlineStateTracker.updateState(OnlineState.ONLINE);
|
|
Assert.hardAssert((this.watchStream == null || this.watchChangeAggregator == null) ? false : true, "WatchStream and WatchStreamAggregator should both be non-null", new Object[0]);
|
|
boolean z = watchChange instanceof WatchChange.WatchTargetChange;
|
|
WatchChange.WatchTargetChange watchTargetChange = z ? (WatchChange.WatchTargetChange) watchChange : null;
|
|
if (watchTargetChange != null && watchTargetChange.getChangeType().equals(WatchChange.WatchTargetChangeType.Removed) && watchTargetChange.getCause() != null) {
|
|
processTargetError(watchTargetChange);
|
|
return;
|
|
}
|
|
if (watchChange instanceof WatchChange.DocumentChange) {
|
|
this.watchChangeAggregator.handleDocumentChange((WatchChange.DocumentChange) watchChange);
|
|
} else if (watchChange instanceof WatchChange.ExistenceFilterWatchChange) {
|
|
this.watchChangeAggregator.handleExistenceFilter((WatchChange.ExistenceFilterWatchChange) watchChange);
|
|
} else {
|
|
Assert.hardAssert(z, "Expected watchChange to be an instance of WatchTargetChange", new Object[0]);
|
|
this.watchChangeAggregator.handleTargetChange((WatchChange.WatchTargetChange) watchChange);
|
|
}
|
|
if (snapshotVersion.equals(SnapshotVersion.NONE) || snapshotVersion.compareTo(this.localStore.getLastRemoteSnapshotVersion()) < 0) {
|
|
return;
|
|
}
|
|
raiseWatchSnapshot(snapshotVersion);
|
|
}
|
|
|
|
/* JADX INFO: Access modifiers changed from: private */
|
|
public void handleWatchStreamClose(Status status) {
|
|
if (status.isOk()) {
|
|
Assert.hardAssert(!shouldStartWatchStream(), "Watch stream was stopped gracefully while still needed.", new Object[0]);
|
|
}
|
|
cleanUpWatchStreamState();
|
|
if (shouldStartWatchStream()) {
|
|
this.onlineStateTracker.handleWatchStreamFailure(status);
|
|
startWatchStream();
|
|
} else {
|
|
this.onlineStateTracker.updateState(OnlineState.UNKNOWN);
|
|
}
|
|
}
|
|
|
|
private void raiseWatchSnapshot(SnapshotVersion snapshotVersion) {
|
|
Assert.hardAssert(!snapshotVersion.equals(SnapshotVersion.NONE), "Can't raise event for unknown SnapshotVersion", new Object[0]);
|
|
RemoteEvent createRemoteEvent = this.watchChangeAggregator.createRemoteEvent(snapshotVersion);
|
|
for (Map.Entry<Integer, TargetChange> entry : createRemoteEvent.getTargetChanges().entrySet()) {
|
|
TargetChange value = entry.getValue();
|
|
if (value.getResumeToken().g() != 0) {
|
|
int intValue = entry.getKey().intValue();
|
|
TargetData targetData = this.listenTargets.get(Integer.valueOf(intValue));
|
|
if (targetData != null) {
|
|
this.listenTargets.put(Integer.valueOf(intValue), targetData.withResumeToken(value.getResumeToken(), snapshotVersion));
|
|
}
|
|
}
|
|
}
|
|
Iterator<Integer> it = createRemoteEvent.getTargetMismatches().iterator();
|
|
while (it.hasNext()) {
|
|
int intValue2 = it.next().intValue();
|
|
TargetData targetData2 = this.listenTargets.get(Integer.valueOf(intValue2));
|
|
if (targetData2 != null) {
|
|
this.listenTargets.put(Integer.valueOf(intValue2), targetData2.withResumeToken(QwV.a, targetData2.getSnapshotVersion()));
|
|
sendUnwatchRequest(intValue2);
|
|
sendWatchRequest(new TargetData(targetData2.getTarget(), intValue2, targetData2.getSequenceNumber(), QueryPurpose.EXISTENCE_FILTER_MISMATCH));
|
|
}
|
|
}
|
|
this.remoteStoreCallback.handleRemoteEvent(createRemoteEvent);
|
|
}
|
|
|
|
private void processTargetError(WatchChange.WatchTargetChange watchTargetChange) {
|
|
Assert.hardAssert(watchTargetChange.getCause() != null, "Processing target error without a cause", new Object[0]);
|
|
for (Integer num : watchTargetChange.getTargetIds()) {
|
|
if (this.listenTargets.containsKey(num)) {
|
|
this.listenTargets.remove(num);
|
|
this.watchChangeAggregator.removeTarget(num.intValue());
|
|
this.remoteStoreCallback.handleRejectedListen(num.intValue(), watchTargetChange.getCause());
|
|
}
|
|
}
|
|
}
|
|
|
|
public final void fillWritePipeline() {
|
|
int batchId = this.writePipeline.isEmpty() ? -1 : this.writePipeline.getLast().getBatchId();
|
|
while (true) {
|
|
if (!canAddToWritePipeline()) {
|
|
break;
|
|
}
|
|
MutationBatch nextMutationBatch = this.localStore.getNextMutationBatch(batchId);
|
|
if (nextMutationBatch == null) {
|
|
if (this.writePipeline.size() == 0) {
|
|
this.writeStream.markIdle();
|
|
}
|
|
} else {
|
|
addToWritePipeline(nextMutationBatch);
|
|
batchId = nextMutationBatch.getBatchId();
|
|
}
|
|
}
|
|
if (shouldStartWriteStream()) {
|
|
startWriteStream();
|
|
}
|
|
}
|
|
|
|
private boolean canAddToWritePipeline() {
|
|
return canUseNetwork() && this.writePipeline.size() < 10;
|
|
}
|
|
|
|
private void addToWritePipeline(MutationBatch mutationBatch) {
|
|
Assert.hardAssert(canAddToWritePipeline(), "addToWritePipeline called when pipeline is full", new Object[0]);
|
|
this.writePipeline.add(mutationBatch);
|
|
if (this.writeStream.isOpen() && this.writeStream.isHandshakeComplete()) {
|
|
this.writeStream.writeMutations(mutationBatch.getMutations());
|
|
}
|
|
}
|
|
|
|
private void startWriteStream() {
|
|
Assert.hardAssert(shouldStartWriteStream(), "startWriteStream() called when shouldStartWriteStream() is false.", new Object[0]);
|
|
this.writeStream.start();
|
|
}
|
|
|
|
/* JADX INFO: Access modifiers changed from: private */
|
|
public void handleWriteStreamHandshakeComplete() {
|
|
this.localStore.setLastStreamToken(this.writeStream.getLastStreamToken());
|
|
Iterator<MutationBatch> it = this.writePipeline.iterator();
|
|
while (it.hasNext()) {
|
|
this.writeStream.writeMutations(it.next().getMutations());
|
|
}
|
|
}
|
|
|
|
/* JADX INFO: Access modifiers changed from: private */
|
|
public void handleWriteStreamMutationResults(SnapshotVersion snapshotVersion, List<MutationResult> list) {
|
|
this.remoteStoreCallback.handleSuccessfulWrite(MutationBatchResult.create(this.writePipeline.poll(), snapshotVersion, list, this.writeStream.getLastStreamToken()));
|
|
fillWritePipeline();
|
|
}
|
|
|
|
/* JADX INFO: Access modifiers changed from: private */
|
|
public void handleWriteStreamClose(Status status) {
|
|
if (status.isOk()) {
|
|
Assert.hardAssert(!shouldStartWriteStream(), "Write stream was stopped gracefully while still needed.", new Object[0]);
|
|
}
|
|
if (!status.isOk() && !this.writePipeline.isEmpty()) {
|
|
if (this.writeStream.isHandshakeComplete()) {
|
|
handleWriteError(status);
|
|
} else {
|
|
handleWriteHandshakeError(status);
|
|
}
|
|
}
|
|
if (shouldStartWriteStream()) {
|
|
startWriteStream();
|
|
}
|
|
}
|
|
|
|
private void handleWriteHandshakeError(Status status) {
|
|
Assert.hardAssert(!status.isOk(), "Handling write error with status OK.", new Object[0]);
|
|
if (Datastore.isPermanentError(status)) {
|
|
Logger.debug("RemoteStore", "RemoteStore error before completed handshake; resetting stream token %s: %s", Util.toDebugString(this.writeStream.getLastStreamToken()), status);
|
|
this.writeStream.setLastStreamToken(WriteStream.EMPTY_STREAM_TOKEN);
|
|
this.localStore.setLastStreamToken(WriteStream.EMPTY_STREAM_TOKEN);
|
|
}
|
|
}
|
|
|
|
private void handleWriteError(Status status) {
|
|
Assert.hardAssert(!status.isOk(), "Handling write error with status OK.", new Object[0]);
|
|
if (Datastore.isPermanentWriteError(status)) {
|
|
MutationBatch poll = this.writePipeline.poll();
|
|
this.writeStream.inhibitBackoff();
|
|
this.remoteStoreCallback.handleRejectedWrite(poll.getBatchId(), status);
|
|
fillWritePipeline();
|
|
}
|
|
}
|
|
|
|
@Override // com.google.firebase.firestore.remote.WatchChangeAggregator.TargetMetadataProvider
|
|
public final ImmutableSortedSet<DocumentKey> getRemoteKeysForTarget(int i) {
|
|
return this.remoteStoreCallback.getRemoteKeysForTarget(i);
|
|
}
|
|
|
|
@Override // com.google.firebase.firestore.remote.WatchChangeAggregator.TargetMetadataProvider
|
|
public final TargetData getTargetDataForTarget(int i) {
|
|
return this.listenTargets.get(Integer.valueOf(i));
|
|
}
|
|
|
|
public final boolean canUseNetwork() {
|
|
return this.networkEnabled;
|
|
}
|
|
|
|
private void cleanUpWatchStreamState() {
|
|
this.watchChangeAggregator = null;
|
|
}
|
|
}
|