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, "formatVersion": 1,
"database": { "database": {
"version": 1, "version": 1,
"identityHash": "8f1d4d8d2bdb8b2358132202037aba7a", "identityHash": "e2dbbac3327bc8ef188286642b379e7d",
"entities": [ "entities": [
{ {
"tableName": "account", "tableName": "account",
@ -601,7 +601,7 @@
}, },
{ {
"tableName": "disco_item", "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": [ "fields": [
{ {
"fieldPath": "id", "fieldPath": "id",
@ -628,8 +628,14 @@
"notNull": true "notNull": true
}, },
{ {
"fieldPath": "parent", "fieldPath": "parentAddress",
"columnName": "parent", "columnName": "parentAddress",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "parentNode",
"columnName": "parentNode",
"affinity": "TEXT", "affinity": "TEXT",
"notNull": true "notNull": true
}, },
@ -648,26 +654,27 @@
}, },
"indices": [ "indices": [
{ {
"name": "index_disco_item_accountId_address_node_parent", "name": "index_disco_item_accountId_address_node_parentAddress_parentNode",
"unique": true, "unique": true,
"columnNames": [ "columnNames": [
"accountId", "accountId",
"address", "address",
"node", "node",
"parent" "parentAddress",
"parentNode"
], ],
"orders": [], "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, "unique": false,
"columnNames": [ "columnNames": [
"accountId", "accountId",
"parent" "parentAddress"
], ],
"orders": [], "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", "name": "index_disco_item_discoId",
@ -1337,7 +1344,7 @@
"views": [], "views": [],
"setupQueries": [ "setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", "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; return child;
} }
public <T extends Extension> T addChild(T child) {
this.addChild(child);
return child;
}
public Element addChild(String name) { public Element addChild(String name) {
this.content = null; this.content = null;
Element child = new Element(name); Element child = new Element(name);

View file

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

View file

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

View file

@ -3,6 +3,7 @@ package im.conversations.android.xmpp.manager;
import android.content.Context; import android.content.Context;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import com.google.common.base.Strings;
import com.google.common.collect.Collections2; import com.google.common.collect.Collections2;
import com.google.common.io.BaseEncoding; import com.google.common.io.BaseEncoding;
import com.google.common.util.concurrent.Futures; 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 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 = iqRequest.addChild(new InfoQuery());
if (requestNode != null) { if (requestNode != null) {
infoQueryRequest.setNode(requestNode); infoQueryRequest.setNode(requestNode);
} }
iqRequest.addChild(infoQueryRequest);
final var future = connection.sendIqPacket(iqRequest); final var future = connection.sendIqPacket(iqRequest);
// TODO we need to remove the disco info associated with $entity in case of failure // 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 // 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) { 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); final var iqPacket = new IqPacket(IqPacket.TYPE.GET);
iqPacket.setTo(entity.address); 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); final var future = connection.sendIqPacket(iqPacket);
return Futures.transform( return Futures.transform(
future, future,
@ -119,10 +128,14 @@ public class DiscoManager extends AbstractManager {
if (itemsQuery == null) { if (itemsQuery == null) {
throw new IllegalStateException(); 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 items = itemsQuery.getExtensions(Item.class);
final var validItems = final var validItems =
Collections2.filter(items, i -> Objects.nonNull(i.getJid())); Collections2.filter(items, i -> Objects.nonNull(i.getJid()));
getDatabase().discoDao().set(getAccount(), entity, validItems); getDatabase().discoDao().set(getAccount(), entity, requestNode, validItems);
return validItems; return validItems;
}, },
MoreExecutors.directExecutor()); MoreExecutors.directExecutor());

View file

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