include parentNode in disco items table

This commit is contained in:
Daniel Gultsch 2023-01-21 11:11:52 +01:00
parent d25cc059c5
commit c31fa7ed2b
No known key found for this signature in database
GPG key ID: F43D18AD2A0982C2
6 changed files with 73 additions and 27 deletions

View file

@ -2,7 +2,7 @@
"formatVersion": 1,
"database": {
"version": 1,
"identityHash": "8f1d4d8d2bdb8b2358132202037aba7a",
"identityHash": "e2dbbac3327bc8ef188286642b379e7d",
"entities": [
{
"tableName": "account",
@ -601,7 +601,7 @@
},
{
"tableName": "disco_item",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `accountId` INTEGER NOT NULL, `address` TEXT NOT NULL, `node` TEXT NOT NULL, `parent` TEXT NOT NULL, `discoId` INTEGER, FOREIGN KEY(`accountId`) REFERENCES `account`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`discoId`) REFERENCES `disco`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `accountId` INTEGER NOT NULL, `address` TEXT NOT NULL, `node` TEXT NOT NULL, `parentAddress` TEXT NOT NULL, `parentNode` TEXT NOT NULL, `discoId` INTEGER, FOREIGN KEY(`accountId`) REFERENCES `account`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`discoId`) REFERENCES `disco`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "id",
@ -628,8 +628,14 @@
"notNull": true
},
{
"fieldPath": "parent",
"columnName": "parent",
"fieldPath": "parentAddress",
"columnName": "parentAddress",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "parentNode",
"columnName": "parentNode",
"affinity": "TEXT",
"notNull": true
},
@ -648,26 +654,27 @@
},
"indices": [
{
"name": "index_disco_item_accountId_address_node_parent",
"name": "index_disco_item_accountId_address_node_parentAddress_parentNode",
"unique": true,
"columnNames": [
"accountId",
"address",
"node",
"parent"
"parentAddress",
"parentNode"
],
"orders": [],
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_disco_item_accountId_address_node_parent` ON `${TABLE_NAME}` (`accountId`, `address`, `node`, `parent`)"
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_disco_item_accountId_address_node_parentAddress_parentNode` ON `${TABLE_NAME}` (`accountId`, `address`, `node`, `parentAddress`, `parentNode`)"
},
{
"name": "index_disco_item_accountId_parent",
"name": "index_disco_item_accountId_parentAddress",
"unique": false,
"columnNames": [
"accountId",
"parent"
"parentAddress"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_disco_item_accountId_parent` ON `${TABLE_NAME}` (`accountId`, `parent`)"
"createSql": "CREATE INDEX IF NOT EXISTS `index_disco_item_accountId_parentAddress` ON `${TABLE_NAME}` (`accountId`, `parentAddress`)"
},
{
"name": "index_disco_item_discoId",
@ -1337,7 +1344,7 @@
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '8f1d4d8d2bdb8b2358132202037aba7a')"
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'e2dbbac3327bc8ef188286642b379e7d')"
]
}
}

View file

@ -37,6 +37,11 @@ public class Element {
return child;
}
public <T extends Extension> T addChild(T child) {
this.addChild(child);
return child;
}
public Element addChild(String name) {
this.content = null;
Element child = new Element(name);

View file

@ -44,10 +44,13 @@ public abstract class DiscoDao {
protected abstract void insertDiscoFeatures(Collection<DiscoFeatureEntity> features);
@Query(
"DELETE FROM disco_item WHERE accountId=:account AND parent=:parent AND address NOT"
+ " IN(:existent)")
"DELETE FROM disco_item WHERE accountId=:account AND parentAddress=:parent AND"
+ " parentNode=:parentNode AND address NOT IN(:existent)")
protected abstract void deleteNonExistentDiscoItems(
final long account, final Jid parent, final Collection<Jid> existent);
final long account,
final Jid parent,
final String parentNode,
final Collection<Jid> existent);
@Query(
"UPDATE presence SET discoId=:discoId WHERE accountId=:account AND address=:address"
@ -76,13 +79,19 @@ public abstract class DiscoDao {
@Transaction
public void set(
final Account account, final Entity.DiscoItem parent, final Collection<Item> items) {
final Account account,
final Entity.DiscoItem parent,
final String parentNode,
final Collection<Item> items) {
final var entities =
Collections2.transform(
items, i -> DiscoItemEntity.of(account.id, parent.address, i));
items, i -> DiscoItemEntity.of(account.id, parent.address, parentNode, i));
insertDiscoItems(entities);
deleteNonExistentDiscoItems(
account.id, parent.address, Collections2.transform(items, Item::getJid));
account.id,
parent.address,
Strings.nullToEmpty(parentNode),
Collections2.transform(items, Item::getJid));
}
@Transaction

View file

@ -25,10 +25,10 @@ import im.conversations.android.xmpp.model.disco.items.Item;
},
indices = {
@Index(
value = {"accountId", "address", "node", "parent"},
value = {"accountId", "address", "node", "parentAddress", "parentNode"},
unique = true),
@Index(
value = {"accountId", "parent"},
value = {"accountId", "parentAddress"},
unique = false),
@Index(value = {"discoId"})
})
@ -43,16 +43,20 @@ public class DiscoItemEntity {
@NonNull public String node;
@NonNull public String parent;
@NonNull public String parentAddress;
@NonNull public String parentNode;
public Long discoId;
public static DiscoItemEntity of(long accountId, final Jid parent, Item item) {
public static DiscoItemEntity of(
long accountId, final Jid parent, final String parentNode, final Item item) {
final var entity = new DiscoItemEntity();
entity.accountId = accountId;
entity.address = item.getJid();
entity.node = Strings.nullToEmpty(item.getNode());
entity.parent = parent.toEscapedString();
entity.parentAddress = parent.toEscapedString();
entity.parentNode = Strings.nullToEmpty(parentNode);
return entity;
}
@ -62,7 +66,7 @@ public class DiscoItemEntity {
entity.accountId = accountId;
entity.address = address;
entity.node = Strings.nullToEmpty(node);
entity.parent = "";
entity.parentAddress = "";
entity.discoId = discoId;
return entity;
}

View file

@ -3,6 +3,7 @@ package im.conversations.android.xmpp.manager;
import android.content.Context;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.google.common.base.Strings;
import com.google.common.collect.Collections2;
import com.google.common.io.BaseEncoding;
import com.google.common.util.concurrent.Futures;
@ -53,11 +54,10 @@ public class DiscoManager extends AbstractManager {
final var requestNode = hash != null && node != null ? hash.capabilityNode(node) : node;
final var iqRequest = new IqPacket(IqPacket.TYPE.GET);
iqRequest.setTo(entity.address);
final var infoQueryRequest = new InfoQuery();
final var infoQueryRequest = iqRequest.addChild(new InfoQuery());
if (requestNode != null) {
infoQueryRequest.setNode(requestNode);
}
iqRequest.addChild(infoQueryRequest);
final var future = connection.sendIqPacket(iqRequest);
// TODO we need to remove the disco info associated with $entity in case of failure
// this might happen in (rather unlikely) scenarios where an item no longer speaks disco
@ -108,9 +108,18 @@ public class DiscoManager extends AbstractManager {
}
public ListenableFuture<Collection<Item>> items(final Entity.DiscoItem entity) {
return items(entity, null);
}
public ListenableFuture<Collection<Item>> items(
@NonNull final Entity.DiscoItem entity, @Nullable final String node) {
final var requestNode = Strings.emptyToNull(node);
final var iqPacket = new IqPacket(IqPacket.TYPE.GET);
iqPacket.setTo(entity.address);
iqPacket.addChild(new ItemsQuery());
final var itemsQueryRequest = iqPacket.addChild(new ItemsQuery());
if (requestNode != null) {
itemsQueryRequest.setNode(requestNode);
}
final var future = connection.sendIqPacket(iqPacket);
return Futures.transform(
future,
@ -119,10 +128,14 @@ public class DiscoManager extends AbstractManager {
if (itemsQuery == null) {
throw new IllegalStateException();
}
if (!Objects.equals(requestNode, itemsQuery.getNode())) {
throw new IllegalStateException(
"Node in response did not match node in request");
}
final var items = itemsQuery.getExtensions(Item.class);
final var validItems =
Collections2.filter(items, i -> Objects.nonNull(i.getJid()));
getDatabase().discoDao().set(getAccount(), entity, validItems);
getDatabase().discoDao().set(getAccount(), entity, requestNode, validItems);
return validItems;
},
MoreExecutors.directExecutor());

View file

@ -8,4 +8,12 @@ public class ItemsQuery extends Extension {
public ItemsQuery() {
super(ItemsQuery.class);
}
public void setNode(final String node) {
this.setAttribute("node", node);
}
public String getNode() {
return this.getAttribute("node");
}
}