check caps hash after retrieving them
This commit is contained in:
parent
1a09b3ed05
commit
1e6aed759b
|
@ -1884,7 +1884,8 @@ public class XmppConnection implements Runnable {
|
||||||
final var nodeHash = this.streamFeatures.getCapabilities();
|
final var nodeHash = this.streamFeatures.getCapabilities();
|
||||||
final var domainDiscoItem = Entity.discoItem(account.address.getDomain());
|
final var domainDiscoItem = Entity.discoItem(account.address.getDomain());
|
||||||
if (nodeHash != null) {
|
if (nodeHash != null) {
|
||||||
discoFutures.add(discoManager.info(domainDiscoItem, nodeHash.node, nodeHash.hash));
|
discoFutures.add(
|
||||||
|
discoManager.infoOrCache(domainDiscoItem, nodeHash.node, nodeHash.hash));
|
||||||
} else {
|
} else {
|
||||||
discoFutures.add(discoManager.info(domainDiscoItem));
|
discoFutures.add(discoManager.info(domainDiscoItem));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
package im.conversations.android.xmpp.manager;
|
package im.conversations.android.xmpp.manager;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import com.google.common.collect.Collections2;
|
import com.google.common.collect.Collections2;
|
||||||
|
import com.google.common.io.BaseEncoding;
|
||||||
import com.google.common.util.concurrent.Futures;
|
import com.google.common.util.concurrent.Futures;
|
||||||
import com.google.common.util.concurrent.ListenableFuture;
|
import com.google.common.util.concurrent.ListenableFuture;
|
||||||
import com.google.common.util.concurrent.MoreExecutors;
|
import com.google.common.util.concurrent.MoreExecutors;
|
||||||
|
@ -15,6 +17,7 @@ import im.conversations.android.xmpp.XmppConnection;
|
||||||
import im.conversations.android.xmpp.model.disco.info.InfoQuery;
|
import im.conversations.android.xmpp.model.disco.info.InfoQuery;
|
||||||
import im.conversations.android.xmpp.model.disco.items.Item;
|
import im.conversations.android.xmpp.model.disco.items.Item;
|
||||||
import im.conversations.android.xmpp.model.disco.items.ItemsQuery;
|
import im.conversations.android.xmpp.model.disco.items.ItemsQuery;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
@ -29,22 +32,30 @@ public class DiscoManager extends AbstractManager {
|
||||||
return info(entity, null);
|
return info(entity, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ListenableFuture<Void> info(
|
public ListenableFuture<Void> infoOrCache(
|
||||||
final Entity entity, @Nullable final String node, final EntityCapabilities.Hash hash) {
|
final Entity entity, @Nullable final String node, final EntityCapabilities.Hash hash) {
|
||||||
final String capabilityNode = hash.capabilityNode(node);
|
if (getDatabase().discoDao().set(getAccount(), entity, node, hash)) {
|
||||||
if (getDatabase().discoDao().set(getAccount(), entity, capabilityNode, hash)) {
|
|
||||||
return Futures.immediateFuture(null);
|
return Futures.immediateFuture(null);
|
||||||
}
|
}
|
||||||
return Futures.transform(
|
return Futures.transform(
|
||||||
info(entity, capabilityNode), f -> null, MoreExecutors.directExecutor());
|
info(entity, node, hash), f -> null, MoreExecutors.directExecutor());
|
||||||
}
|
}
|
||||||
|
|
||||||
public ListenableFuture<InfoQuery> info(final Entity entity, final String node) {
|
public ListenableFuture<InfoQuery> info(
|
||||||
|
@NonNull final Entity entity, @Nullable final String node) {
|
||||||
|
return info(entity, node, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ListenableFuture<InfoQuery> info(
|
||||||
|
final Entity entity,
|
||||||
|
@Nullable final String node,
|
||||||
|
@Nullable final EntityCapabilities.Hash hash) {
|
||||||
|
final var requestNode = hash != null && node != null ? hash.capabilityNode(node) : node;
|
||||||
final var iqRequest = new IqPacket(IqPacket.TYPE.GET);
|
final var iqRequest = new IqPacket(IqPacket.TYPE.GET);
|
||||||
iqRequest.setTo(entity.address);
|
iqRequest.setTo(entity.address);
|
||||||
final var infoQueryRequest = new InfoQuery();
|
final var infoQueryRequest = new InfoQuery();
|
||||||
if (node != null) {
|
if (requestNode != null) {
|
||||||
infoQueryRequest.setNode(node);
|
infoQueryRequest.setNode(requestNode);
|
||||||
}
|
}
|
||||||
iqRequest.addChild(infoQueryRequest);
|
iqRequest.addChild(infoQueryRequest);
|
||||||
final var future = connection.sendIqPacket(iqRequest);
|
final var future = connection.sendIqPacket(iqRequest);
|
||||||
|
@ -57,20 +68,45 @@ public class DiscoManager extends AbstractManager {
|
||||||
if (infoQuery == null) {
|
if (infoQuery == null) {
|
||||||
throw new IllegalStateException("Response did not have query child");
|
throw new IllegalStateException("Response did not have query child");
|
||||||
}
|
}
|
||||||
if (!Objects.equals(node, infoQuery.getNode())) {
|
if (!Objects.equals(requestNode, infoQuery.getNode())) {
|
||||||
throw new IllegalStateException(
|
throw new IllegalStateException(
|
||||||
"Node in response did not match node in request");
|
"Node in response did not match node in request");
|
||||||
}
|
}
|
||||||
final byte[] caps = EntityCapabilities.hash(infoQuery).hash;
|
final var caps = EntityCapabilities.hash(infoQuery);
|
||||||
final byte[] caps2 = EntityCapabilities2.hash(infoQuery).hash;
|
final var caps2 = EntityCapabilities2.hash(infoQuery);
|
||||||
|
if (hash instanceof EntityCapabilities.EntityCapsHash) {
|
||||||
|
checkMatch(
|
||||||
|
(EntityCapabilities.EntityCapsHash) hash,
|
||||||
|
caps,
|
||||||
|
EntityCapabilities.EntityCapsHash.class);
|
||||||
|
}
|
||||||
|
if (hash instanceof EntityCapabilities2.EntityCaps2Hash) {
|
||||||
|
checkMatch(
|
||||||
|
(EntityCapabilities2.EntityCaps2Hash) hash,
|
||||||
|
caps2,
|
||||||
|
EntityCapabilities2.EntityCaps2Hash.class);
|
||||||
|
}
|
||||||
getDatabase()
|
getDatabase()
|
||||||
.discoDao()
|
.discoDao()
|
||||||
.set(getAccount(), entity, node, caps, caps2, infoQuery);
|
.set(getAccount(), entity, node, caps.hash, caps2.hash, infoQuery);
|
||||||
return infoQuery;
|
return infoQuery;
|
||||||
},
|
},
|
||||||
MoreExecutors.directExecutor());
|
MoreExecutors.directExecutor());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private <H extends EntityCapabilities.Hash> void checkMatch(
|
||||||
|
final H expected, final H was, final Class<H> clazz) {
|
||||||
|
if (Arrays.equals(expected.hash, was.hash)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
throw new IllegalStateException(
|
||||||
|
String.format(
|
||||||
|
"%s mismatch. Expected %s was %s",
|
||||||
|
clazz.getSimpleName(),
|
||||||
|
BaseEncoding.base64().encode(expected.hash),
|
||||||
|
BaseEncoding.base64().encode(was.hash)));
|
||||||
|
}
|
||||||
|
|
||||||
public ListenableFuture<Collection<Item>> items(final Entity.DiscoItem entity) {
|
public ListenableFuture<Collection<Item>> items(final Entity.DiscoItem entity) {
|
||||||
final var iqPacket = new IqPacket(IqPacket.TYPE.GET);
|
final var iqPacket = new IqPacket(IqPacket.TYPE.GET);
|
||||||
iqPacket.setTo(entity.address);
|
iqPacket.setTo(entity.address);
|
||||||
|
@ -97,11 +133,9 @@ public class DiscoManager extends AbstractManager {
|
||||||
return Futures.transformAsync(
|
return Futures.transformAsync(
|
||||||
itemsFutures,
|
itemsFutures,
|
||||||
items -> {
|
items -> {
|
||||||
final var filtered =
|
|
||||||
Collections2.filter(items, i -> Objects.nonNull(i.getJid()));
|
|
||||||
Collection<ListenableFuture<InfoQuery>> infoFutures =
|
Collection<ListenableFuture<InfoQuery>> infoFutures =
|
||||||
Collections2.transform(
|
Collections2.transform(
|
||||||
filtered, i -> info(Entity.discoItem(i.getJid()), i.getNode()));
|
items, i -> info(Entity.discoItem(i.getJid()), i.getNode()));
|
||||||
return Futures.allAsList(infoFutures);
|
return Futures.allAsList(infoFutures);
|
||||||
},
|
},
|
||||||
MoreExecutors.directExecutor());
|
MoreExecutors.directExecutor());
|
||||||
|
|
|
@ -43,7 +43,7 @@ public class PresenceProcessor extends XmppConnection.Delegate implements Consum
|
||||||
final var nodeHash = presencePacket.getCapabilities();
|
final var nodeHash = presencePacket.getCapabilities();
|
||||||
if (nodeHash != null) {
|
if (nodeHash != null) {
|
||||||
getManager(DiscoManager.class)
|
getManager(DiscoManager.class)
|
||||||
.info(Entity.presence(entity), nodeHash.node, nodeHash.hash);
|
.infoOrCache(Entity.presence(entity), nodeHash.node, nodeHash.hash);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue