From d25cc059c566eb356110018cdbda818e15f17b2f Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Fri, 20 Jan 2023 18:35:13 +0100 Subject: [PATCH] add AccountRepository --- .../conversations/ui/util/PendingItem.java | 43 +++++++++++-------- .../repository/AbstractRepository.java | 15 +++++++ .../android/repository/AccountRepository.java | 36 ++++++++++++++++ .../android/xmpp/ConnectionException.java | 10 +++++ .../android/xmpp/XmppConnection.java | 21 +++++++++ 5 files changed, 108 insertions(+), 17 deletions(-) create mode 100644 src/main/java/im/conversations/android/repository/AbstractRepository.java create mode 100644 src/main/java/im/conversations/android/repository/AccountRepository.java create mode 100644 src/main/java/im/conversations/android/xmpp/ConnectionException.java diff --git a/src/main/java/eu/siacs/conversations/ui/util/PendingItem.java b/src/main/java/eu/siacs/conversations/ui/util/PendingItem.java index 66e34000f..a02281f77 100644 --- a/src/main/java/eu/siacs/conversations/ui/util/PendingItem.java +++ b/src/main/java/eu/siacs/conversations/ui/util/PendingItem.java @@ -29,27 +29,36 @@ package eu.siacs.conversations.ui.util; +import java.util.function.Supplier; + public class PendingItem { - private T item = null; + private T item = null; - public synchronized void push(T item) { - this.item = item; - } + public synchronized void push(T item) { + this.item = item; + } - public synchronized T pop() { - final T item = this.item; - this.item = null; - return item; - } + public synchronized T pop() { + final T item = this.item; + this.item = null; + return item; + } - public synchronized T peek() { - return item; - } + public synchronized T peek() { + return item; + } - public synchronized boolean clear() { - boolean notNull = this.item != null; - this.item = null; - return notNull; - } + public synchronized T peekOrCreate(final Supplier supplier) { + if (this.item == null) { + this.item = supplier.get(); + } + return this.item; + } + + public synchronized boolean clear() { + boolean notNull = this.item != null; + this.item = null; + return notNull; + } } diff --git a/src/main/java/im/conversations/android/repository/AbstractRepository.java b/src/main/java/im/conversations/android/repository/AbstractRepository.java new file mode 100644 index 000000000..bee959b2b --- /dev/null +++ b/src/main/java/im/conversations/android/repository/AbstractRepository.java @@ -0,0 +1,15 @@ +package im.conversations.android.repository; + +import android.content.Context; +import im.conversations.android.database.ConversationsDatabase; + +public abstract class AbstractRepository { + + protected final Context context; + protected final ConversationsDatabase database; + + protected AbstractRepository(final Context context) { + this.context = context; + this.database = ConversationsDatabase.getInstance(context); + } +} diff --git a/src/main/java/im/conversations/android/repository/AccountRepository.java b/src/main/java/im/conversations/android/repository/AccountRepository.java new file mode 100644 index 000000000..aebbcf551 --- /dev/null +++ b/src/main/java/im/conversations/android/repository/AccountRepository.java @@ -0,0 +1,36 @@ +package im.conversations.android.repository; + +import android.content.Context; +import androidx.annotation.NonNull; +import com.google.common.base.Preconditions; +import eu.siacs.conversations.xmpp.Jid; +import im.conversations.android.IDs; +import im.conversations.android.database.CredentialStore; +import im.conversations.android.database.entity.AccountEntity; +import im.conversations.android.database.model.Account; + +public class AccountRepository extends AbstractRepository { + + public AccountRepository(final Context context) { + super(context); + } + + public Account createAccount(@NonNull final Jid address, final String password) { + Preconditions.checkArgument( + address.isBareJid(), "Account should be specified without resource"); + Preconditions.checkArgument(password != null, "Missing password"); + final byte[] randomSeed = IDs.seed(); + final var entity = new AccountEntity(); + entity.address = address; + entity.enabled = true; + entity.randomSeed = randomSeed; + final long id = database.accountDao().insert(entity); + final var account = new Account(id, address, entity.randomSeed); + try { + CredentialStore.getInstance(context).setPassword(account, password); + } catch (final Exception e) { + throw new IllegalStateException("Could not store password", e); + } + return account; + } +} diff --git a/src/main/java/im/conversations/android/xmpp/ConnectionException.java b/src/main/java/im/conversations/android/xmpp/ConnectionException.java new file mode 100644 index 000000000..608463c7a --- /dev/null +++ b/src/main/java/im/conversations/android/xmpp/ConnectionException.java @@ -0,0 +1,10 @@ +package im.conversations.android.xmpp; + +public class ConnectionException extends Exception { + + private final ConnectionState connectionState; + + public ConnectionException(ConnectionState state) { + this.connectionState = state; + } +} diff --git a/src/main/java/im/conversations/android/xmpp/XmppConnection.java b/src/main/java/im/conversations/android/xmpp/XmppConnection.java index 19fb9a4c5..b5d323179 100644 --- a/src/main/java/im/conversations/android/xmpp/XmppConnection.java +++ b/src/main/java/im/conversations/android/xmpp/XmppConnection.java @@ -30,6 +30,7 @@ import eu.siacs.conversations.persistance.FileBackend; import eu.siacs.conversations.services.MemorizingTrustManager; import eu.siacs.conversations.services.MessageArchiveService; import eu.siacs.conversations.services.NotificationService; +import eu.siacs.conversations.ui.util.PendingItem; import eu.siacs.conversations.utils.Patterns; import eu.siacs.conversations.utils.PhoneHelper; import eu.siacs.conversations.utils.Resolver; @@ -160,6 +161,7 @@ public class XmppConnection implements Runnable { private final Consumer bindConsumer; private final ClassToInstanceMap managers; private Consumer statusListener = null; + private PendingItem> connectedFuture = new PendingItem<>(); private SaslMechanism saslMechanism; private HashedToken.Mechanism hashTokenRequest; private HttpUrl redirectionUrl = null; @@ -244,6 +246,16 @@ public class XmppConnection implements Runnable { if (nextStatus.isError() || nextStatus == ConnectionState.ONLINE) { this.recentErrorConnectionState = nextStatus; } + if (nextStatus != ConnectionState.CONNECTING && nextStatus != ConnectionState.OFFLINE) { + final var future = this.connectedFuture.pop(); + if (future != null) { + if (nextStatus == ConnectionState.ONLINE) { + future.set(this); + } else { + future.setException(new ConnectionException(nextStatus)); + } + } + } } if (statusListener != null) { statusListener.accept(this); @@ -2225,6 +2237,15 @@ public class XmppConnection implements Runnable { this.statusListener = listener; } + public ListenableFuture asConnectedFuture() { + synchronized (this) { + if (this.connectionState == ConnectionState.ONLINE) { + return Futures.immediateFuture(this); + } + return this.connectedFuture.peekOrCreate(SettableFuture::create); + } + } + private void forceCloseSocket() { FileBackend.close(this.socket); FileBackend.close(this.tagReader);