reconfigure node when precondition is not met
This commit is contained in:
parent
58b1e26367
commit
3be56b6775
|
@ -45,7 +45,7 @@ public abstract class AxolotlDao {
|
|||
|
||||
@Query(
|
||||
"SELECT EXISTS(SELECT deviceId FROM axolotl_device_list JOIN axolotl_device_list_item"
|
||||
+ " ON axolotl_device_list.id=axolotl_device_list_item.deviceId WHERE"
|
||||
+ " ON axolotl_device_list.id=axolotl_device_list_item.deviceListId WHERE"
|
||||
+ " accountId=:account AND address=:address AND deviceId=:deviceId)")
|
||||
public abstract boolean hasDeviceId(final long account, final Jid address, final int deviceId);
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package im.conversations.android.xmpp;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import im.conversations.android.xmpp.model.error.Condition;
|
||||
import im.conversations.android.xmpp.model.error.Error;
|
||||
import im.conversations.android.xmpp.model.stanza.Iq;
|
||||
|
||||
|
@ -19,7 +21,12 @@ public class IqErrorException extends Exception {
|
|||
private static String getErrorText(final Iq response) {
|
||||
final var error = response.getError();
|
||||
final var text = error == null ? null : error.getText();
|
||||
return text == null ? null : text.getContent();
|
||||
final var textContent = text == null ? null : text.getContent();
|
||||
if (Strings.isNullOrEmpty(textContent)) {
|
||||
final var condition = error == null ? null : error.getExtension(Condition.class);
|
||||
return condition == null ? null : condition.getName();
|
||||
}
|
||||
return textContent;
|
||||
}
|
||||
|
||||
public Iq getResponse() {
|
||||
|
|
|
@ -22,6 +22,12 @@ public class NodeConfiguration implements Map<String, Object> {
|
|||
.put(PERSIST_ITEMS, Boolean.TRUE)
|
||||
.put(ACCESS_MODEL, "open")
|
||||
.build());
|
||||
public static final NodeConfiguration PRESENCE =
|
||||
new NodeConfiguration(
|
||||
new ImmutableMap.Builder<String, Object>()
|
||||
.put(PERSIST_ITEMS, Boolean.TRUE)
|
||||
.put(ACCESS_MODEL, "presence")
|
||||
.build());
|
||||
public static final NodeConfiguration WHITELIST_MAX_ITEMS =
|
||||
new NodeConfiguration(
|
||||
new ImmutableMap.Builder<String, Object>()
|
||||
|
|
|
@ -10,6 +10,7 @@ public class PreconditionNotMetException extends PubSubErrorException {
|
|||
if (this.pubSubError instanceof PubSubError.PreconditionNotMet) {
|
||||
return;
|
||||
}
|
||||
throw new AssertionError("This exception should only be constructed for PreconditionNotMet errors");
|
||||
throw new AssertionError(
|
||||
"This exception should only be constructed for PreconditionNotMet errors");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -172,7 +172,7 @@ public class AxolotlManager extends AbstractManager {
|
|||
new FutureCallback<>() {
|
||||
@Override
|
||||
public void onSuccess(Void result) {
|
||||
LOGGER.info("Successfully publish bundle and device ID {}", myDeviceId);
|
||||
LOGGER.info("Successfully published bundle and device ID {}", myDeviceId);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -39,9 +39,6 @@ public class PresenceManager extends AbstractManager {
|
|||
final var presence = new Presence();
|
||||
presence.addExtension(capabilities);
|
||||
presence.addExtension(legacyCapabilities);
|
||||
|
||||
LOGGER.info(presence.toString());
|
||||
|
||||
connection.sendPresencePacket(presence);
|
||||
}
|
||||
|
||||
|
|
|
@ -15,12 +15,16 @@ import im.conversations.android.xmpp.PreconditionNotMetException;
|
|||
import im.conversations.android.xmpp.PubSubErrorException;
|
||||
import im.conversations.android.xmpp.XmppConnection;
|
||||
import im.conversations.android.xmpp.model.Extension;
|
||||
import im.conversations.android.xmpp.model.data.Data;
|
||||
import im.conversations.android.xmpp.model.pubsub.Items;
|
||||
import im.conversations.android.xmpp.model.pubsub.PubSub;
|
||||
import im.conversations.android.xmpp.model.pubsub.Publish;
|
||||
import im.conversations.android.xmpp.model.pubsub.PublishOptions;
|
||||
import im.conversations.android.xmpp.model.pubsub.error.PubSubError;
|
||||
import im.conversations.android.xmpp.model.pubsub.event.Event;
|
||||
import im.conversations.android.xmpp.model.pubsub.event.Purge;
|
||||
import im.conversations.android.xmpp.model.pubsub.owner.Configure;
|
||||
import im.conversations.android.xmpp.model.pubsub.owner.PubSubOwner;
|
||||
import im.conversations.android.xmpp.model.stanza.Iq;
|
||||
import im.conversations.android.xmpp.model.stanza.Message;
|
||||
import java.util.Map;
|
||||
|
@ -229,9 +233,9 @@ public class PubSubManager extends AbstractManager {
|
|||
iq.setTo(address);
|
||||
final var pubSub = iq.addExtension(new PubSub());
|
||||
pubSub.addExtension(PublishOptions.of(nodeConfiguration));
|
||||
final var pubSubItemsWrapper = pubSub.addExtension(new PubSub.ItemsWrapper());
|
||||
pubSubItemsWrapper.setNode(node);
|
||||
final var item = pubSubItemsWrapper.addExtension(new PubSub.Item());
|
||||
final var publish = pubSub.addExtension(new Publish());
|
||||
publish.setNode(node);
|
||||
final var item = publish.addExtension(new PubSub.Item());
|
||||
item.setId(itemId);
|
||||
item.addExtension(itemPayload);
|
||||
final ListenableFuture<Void> iqFuture =
|
||||
|
@ -248,8 +252,45 @@ public class PubSubManager extends AbstractManager {
|
|||
|
||||
private ListenableFuture<Void> reconfigureNode(
|
||||
final Jid address, final String node, final NodeConfiguration nodeConfiguration) {
|
||||
|
||||
return Futures.immediateVoidFuture();
|
||||
final Iq iq = new Iq(Iq.Type.GET);
|
||||
iq.setTo(address);
|
||||
final var pubSub = iq.addExtension(new PubSubOwner());
|
||||
final var configure = pubSub.addExtension(new Configure());
|
||||
configure.setNode(node);
|
||||
return Futures.transformAsync(
|
||||
connection.sendIqPacket(iq),
|
||||
result -> {
|
||||
final var pubSubOwnerResult = result.getExtension(PubSubOwner.class);
|
||||
final Configure configureResult =
|
||||
pubSubOwnerResult == null
|
||||
? null
|
||||
: pubSubOwnerResult.getExtension(Configure.class);
|
||||
if (configureResult == null) {
|
||||
throw new IllegalStateException(
|
||||
"No configuration found in configuration request result");
|
||||
}
|
||||
final var data = configureResult.getData();
|
||||
return setNodeConfiguration(address, node, data.submit(nodeConfiguration));
|
||||
},
|
||||
MoreExecutors.directExecutor());
|
||||
}
|
||||
|
||||
private ListenableFuture<Void> setNodeConfiguration(
|
||||
final Jid address, final String node, final Data data) {
|
||||
LOGGER.info("Trying to set node configuration to {}", data.toString());
|
||||
final Iq iq = new Iq(Iq.Type.SET);
|
||||
iq.setTo(address);
|
||||
final var pubSub = iq.addExtension(new PubSubOwner());
|
||||
final var configure = pubSub.addExtension(new Configure());
|
||||
configure.setNode(node);
|
||||
configure.addExtension(data);
|
||||
return Futures.transform(
|
||||
connection.sendIqPacket(iq),
|
||||
result -> {
|
||||
LOGGER.info("Modified node configuration {} on {}", node, address);
|
||||
return null;
|
||||
},
|
||||
MoreExecutors.directExecutor());
|
||||
}
|
||||
|
||||
private static class PubSubExceptionTransformer<V>
|
||||
|
|
|
@ -11,6 +11,8 @@ import java.util.Map;
|
|||
public class Data extends Extension {
|
||||
|
||||
private static final String FORM_TYPE = "FORM_TYPE";
|
||||
private static final String FIELD_TYPE_HIDDEN = "hidden";
|
||||
private static final String FORM_TYPE_SUBMIT = "submit";
|
||||
|
||||
public Data() {
|
||||
super(Data.class);
|
||||
|
@ -28,35 +30,81 @@ public class Data extends Extension {
|
|||
}
|
||||
|
||||
private void addField(final String name, final Object value) {
|
||||
addField(name, value, null);
|
||||
}
|
||||
|
||||
private void addField(final String name, final Object value, final String type) {
|
||||
if (value == null) {
|
||||
throw new IllegalArgumentException("Null values are not supported on data fields");
|
||||
}
|
||||
final var field = this.addExtension(new Field());
|
||||
field.setFieldName(name);
|
||||
final var valueExtension = field.addExtension(new Value());
|
||||
if (value instanceof String) {
|
||||
valueExtension.setContent((String) value);
|
||||
} else if (value instanceof Integer) {
|
||||
valueExtension.setContent(String.valueOf(value));
|
||||
} else if (value instanceof Boolean) {
|
||||
valueExtension.setContent(Boolean.TRUE.equals(value) ? "true" : "false");
|
||||
if (type != null) {
|
||||
field.setType(type);
|
||||
}
|
||||
if (value instanceof Collection) {
|
||||
for (final Object subValue : (Collection<?>) value) {
|
||||
if (subValue instanceof String) {
|
||||
final var valueExtension = field.addExtension(new Value());
|
||||
valueExtension.setContent((String) subValue);
|
||||
} else {
|
||||
throw new IllegalArgumentException(
|
||||
String.format(
|
||||
"%s is not a supported field value",
|
||||
subValue.getClass().getSimpleName()));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw new IllegalArgumentException(
|
||||
String.format(
|
||||
"%s is not a supported field value", value.getClass().getSimpleName()));
|
||||
final var valueExtension = field.addExtension(new Value());
|
||||
if (value instanceof String) {
|
||||
valueExtension.setContent((String) value);
|
||||
} else if (value instanceof Integer) {
|
||||
valueExtension.setContent(String.valueOf(value));
|
||||
} else if (value instanceof Boolean) {
|
||||
valueExtension.setContent(Boolean.TRUE.equals(value) ? "true" : "false");
|
||||
} else {
|
||||
throw new IllegalArgumentException(
|
||||
String.format(
|
||||
"%s is not a supported field value",
|
||||
value.getClass().getSimpleName()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setFormType(final String formType) {
|
||||
this.addField(FORM_TYPE, formType);
|
||||
this.addField(FORM_TYPE, formType, FIELD_TYPE_HIDDEN);
|
||||
}
|
||||
|
||||
public static Data of(final String formType, final Map<String, Object> values) {
|
||||
final var data = new Data();
|
||||
data.setType(FORM_TYPE_SUBMIT);
|
||||
data.setFormType(formType);
|
||||
for (final Map.Entry<String, Object> entry : values.entrySet()) {
|
||||
data.addField(entry.getKey(), entry.getValue());
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
public Data submit(final Map<String, Object> values) {
|
||||
final String formType = this.getFormType();
|
||||
final var submit = new Data();
|
||||
submit.setType(FORM_TYPE_SUBMIT);
|
||||
if (formType != null) {
|
||||
submit.setFormType(formType);
|
||||
}
|
||||
for (final Field existingField : this.getFields()) {
|
||||
final var fieldName = existingField.getFieldName();
|
||||
final Object submittedValue = values.get(fieldName);
|
||||
if (submittedValue != null) {
|
||||
submit.addField(fieldName, submittedValue);
|
||||
} else {
|
||||
submit.addField(fieldName, existingField.getValues());
|
||||
}
|
||||
}
|
||||
return submit;
|
||||
}
|
||||
|
||||
private void setType(final String type) {
|
||||
this.setAttribute("type", type);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,4 +23,8 @@ public class Field extends Extension {
|
|||
public void setFieldName(String name) {
|
||||
this.setAttribute("var", name);
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.setAttribute("type", type);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
package im.conversations.android.xmpp.model.pubsub;
|
||||
|
||||
import im.conversations.android.annotation.XmlElement;
|
||||
import im.conversations.android.xmpp.model.Extension;
|
||||
|
||||
@XmlElement
|
||||
public class Publish extends Extension {
|
||||
|
||||
public Publish() {
|
||||
super(Publish.class);
|
||||
}
|
||||
|
||||
public void setNode(String node) {
|
||||
this.setAttribute("node", node);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package im.conversations.android.xmpp.model.pubsub.owner;
|
||||
|
||||
import im.conversations.android.annotation.XmlElement;
|
||||
import im.conversations.android.xmpp.model.Extension;
|
||||
import im.conversations.android.xmpp.model.data.Data;
|
||||
|
||||
@XmlElement
|
||||
public class Configure extends Extension {
|
||||
|
||||
public Configure() {
|
||||
super(Configure.class);
|
||||
}
|
||||
|
||||
public void setNode(final String node) {
|
||||
this.setAttribute("node", node);
|
||||
}
|
||||
|
||||
public Data getData() {
|
||||
return this.getExtension(Data.class);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package im.conversations.android.xmpp.model.pubsub.owner;
|
||||
|
||||
import im.conversations.android.annotation.XmlElement;
|
||||
import im.conversations.android.xmpp.model.Extension;
|
||||
|
||||
@XmlElement(name = "pubsub")
|
||||
public class PubSubOwner extends Extension {
|
||||
|
||||
public PubSubOwner() {
|
||||
super(PubSubOwner.class);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
@XmlPackage(namespace = Namespace.PUB_SUB_OWNER)
|
||||
package im.conversations.android.xmpp.model.pubsub.owner;
|
||||
|
||||
import eu.siacs.conversations.xml.Namespace;
|
||||
import im.conversations.android.annotation.XmlPackage;
|
Loading…
Reference in a new issue