Skip to content
Snippets Groups Projects
Verified Commit 199168cf authored by Janne Mareike Koschinski's avatar Janne Mareike Koschinski
Browse files

Implements more userfriendly error messages for connection errors

parent 588c6739
No related branches found
No related tags found
No related merge requests found
Pipeline #272 passed
Showing
with 558 additions and 3 deletions
......@@ -28,6 +28,7 @@ import android.graphics.Canvas
import android.graphics.drawable.Drawable
import android.os.Build
import android.os.Bundle
import android.system.ErrnoException
import android.text.Html
import android.view.ActionMode
import android.view.Menu
......@@ -36,6 +37,7 @@ import android.view.View
import android.widget.EditText
import android.widget.LinearLayout
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.ActionBarDrawerToggle
import androidx.appcompat.widget.AppCompatImageView
import androidx.appcompat.widget.Toolbar
......@@ -55,6 +57,7 @@ import com.bumptech.glide.request.target.SimpleTarget
import com.bumptech.glide.request.transition.Transition
import com.google.android.material.bottomsheet.BottomSheetBehavior
import de.kuschku.libquassel.connection.ConnectionState
import de.kuschku.libquassel.connection.ProtocolVersionException
import de.kuschku.libquassel.connection.QuasselSecurityException
import de.kuschku.libquassel.protocol.Buffer_Type
import de.kuschku.libquassel.protocol.Message
......@@ -85,6 +88,7 @@ import de.kuschku.quasseldroid.ui.setup.accounts.selection.AccountSelectionActiv
import de.kuschku.quasseldroid.ui.setup.user.UserSetupActivity
import de.kuschku.quasseldroid.util.ColorContext
import de.kuschku.quasseldroid.util.avatars.AvatarHelper
import de.kuschku.quasseldroid.util.backport.OsConstants
import de.kuschku.quasseldroid.util.helper.*
import de.kuschku.quasseldroid.util.irc.format.IrcFormatDeserializer
import de.kuschku.quasseldroid.util.missingfeatures.MissingFeaturesDialog
......@@ -100,6 +104,8 @@ import org.threeten.bp.Instant
import org.threeten.bp.ZoneId
import org.threeten.bp.format.DateTimeFormatter
import org.threeten.bp.format.FormatStyle
import java.net.ConnectException
import java.net.UnknownHostException
import java.security.cert.CertificateExpiredException
import java.security.cert.CertificateNotYetValidException
import javax.inject.Inject
......@@ -541,6 +547,52 @@ class ChatActivity : ServiceBoundActivity(), SharedPreferences.OnSharedPreferenc
}
})
// Connection errors that should show up as toast
viewModel.connectionErrors.toLiveData().observe(this, Observer { error ->
error?.let {
val cause = it.cause
when {
it is UnknownHostException -> {
val host = it.message?.replace("Host is unresolved: ", "")
Toast.makeText(this,
getString(R.string.label_error_unknown_host, host),
Toast.LENGTH_LONG).show()
}
it is ProtocolVersionException -> {
Toast.makeText(this,
getString(R.string.label_error_invalid_protocol_version,
it.protocol.version),
Toast.LENGTH_LONG).show()
}
it is ConnectException &&
cause is libcore.io.ErrnoException -> {
val errorCode = OsConstants.errnoName(cause.errno)
val errorName = OsConstants.strerror(cause.errno)
Toast.makeText(this,
getString(R.string.label_error_connection, errorName, errorCode),
Toast.LENGTH_LONG).show()
}
it is ConnectException &&
Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP &&
cause is ErrnoException -> {
val errorCode = OsConstants.errnoName(cause.errno)
val errorName = OsConstants.strerror(cause.errno)
Toast.makeText(this,
getString(R.string.label_error_connection, errorName, errorCode),
Toast.LENGTH_LONG).show()
}
else -> {
Toast.makeText(this,
getString(R.string.label_error_connection_closed),
Toast.LENGTH_LONG).show()
}
}
}
})
// After initial connect, open the drawer
viewModel.connectionProgress
.filter { (it, _, _) -> it == ConnectionState.CONNECTED }
......
package de.kuschku.quasseldroid.util.backport
object OsConstants {
const val EPERM = 1
const val ENOENT = 2
const val ESRCH = 3
const val EINTR = 4
const val EIO = 5
const val ENXIO = 6
const val E2BIG = 7
const val ENOEXEC = 8
const val EBADF = 9
const val ECHILD = 10
const val EAGAIN = 11
const val ENOMEM = 12
const val EACCES = 13
const val EFAULT = 14
const val ENOTBLK = 15
const val EBUSY = 16
const val EEXIST = 17
const val EXDEV = 18
const val ENODEV = 19
const val ENOTDIR = 20
const val EISDIR = 21
const val EINVAL = 22
const val ENFILE = 23
const val EMFILE = 24
const val ENOTTY = 25
const val ETXTBSY = 26
const val EFBIG = 27
const val ENOSPC = 28
const val ESPIPE = 29
const val EROFS = 30
const val EMLINK = 31
const val EPIPE = 32
const val EDOM = 33
const val ERANGE = 34
const val EDEADLK = 35
const val ENAMETOOLONG = 36
const val ENOLCK = 37
const val ENOSYS = 38
const val ENOTEMPTY = 39
const val ELOOP = 40
const val EWOULDBLOCK = 11
const val ENOMSG = 42
const val EIDRM = 43
const val ECHRNG = 44
const val EL2NSYNC = 45
const val EL3HLT = 46
const val EL3RST = 47
const val ELNRNG = 48
const val EUNATCH = 49
const val ENOCSI = 50
const val EL2HLT = 51
const val EBADE = 52
const val EBADR = 53
const val EXFULL = 54
const val ENOANO = 55
const val EBADRQC = 56
const val EBADSLT = 57
const val EDEADLOCK = 35
const val EBFONT = 59
const val ENOSTR = 60
const val ENODATA = 61
const val ETIME = 62
const val ENOSR = 63
const val ENONET = 64
const val ENOPKG = 65
const val EREMOTE = 66
const val ENOLINK = 67
const val EADV = 68
const val ESRMNT = 69
const val ECOMM = 70
const val EPROTO = 71
const val EMULTIHOP = 72
const val EDOTDOT = 73
const val EBADMSG = 74
const val EOVERFLOW = 75
const val ENOTUNIQ = 76
const val EBADFD = 77
const val EREMCHG = 78
const val ELIBACC = 79
const val ELIBBAD = 80
const val ELIBSCN = 81
const val ELIBMAX = 82
const val ELIBEXEC = 83
const val EILSEQ = 84
const val ERESTART = 85
const val ESTRPIPE = 86
const val EUSERS = 87
const val ENOTSOCK = 88
const val EDESTADDRREQ = 89
const val EMSGSIZE = 90
const val EPROTOTYPE = 91
const val ENOPROTOOPT = 92
const val EPROTONOSUPPORT = 93
const val ESOCKTNOSUPPORT = 94
const val EOPNOTSUPP = 95
const val EPFNOSUPPORT = 96
const val EAFNOSUPPORT = 97
const val EADDRINUSE = 98
const val EADDRNOTAVAIL = 99
const val ENETDOWN = 100
const val ENETUNREACH = 101
const val ENETRESET = 102
const val ECONNABORTED = 103
const val ECONNRESET = 104
const val ENOBUFS = 105
const val EISCONN = 106
const val ENOTCONN = 107
const val ESHUTDOWN = 108
const val ETOOMANYREFS = 109
const val ETIMEDOUT = 110
const val ECONNREFUSED = 111
const val EHOSTDOWN = 112
const val EHOSTUNREACH = 113
const val EALREADY = 114
const val EINPROGRESS = 115
const val ESTALE = 116
const val EUCLEAN = 117
const val ENOTNAM = 118
const val ENAVAIL = 119
const val EISNAM = 120
const val EREMOTEIO = 121
const val EDQUOT = 122
const val ENOMEDIUM = 123
const val EMEDIUMTYPE = 124
const val ECANCELED = 125
const val ENOKEY = 126
const val EKEYEXPIRED = 127
const val EKEYREVOKED = 128
const val EKEYREJECTED = 129
const val EOWNERDEAD = 130
const val ENOTRECOVERABLE = 131
const val ERFKILL = 132
const val EHWPOISON = 133
const val ENOTSUP = 95
fun errnoName(errno: Int): String? {
return when (errno) {
EPERM -> "EPERM"
ENOENT -> "ENOENT"
ESRCH -> "ESRCH"
EINTR -> "EINTR"
EIO -> "EIO"
ENXIO -> "ENXIO"
E2BIG -> "E2BIG"
ENOEXEC -> "ENOEXEC"
EBADF -> "EBADF"
ECHILD -> "ECHILD"
EAGAIN -> "EAGAIN"
ENOMEM -> "ENOMEM"
EACCES -> "EACCES"
EFAULT -> "EFAULT"
ENOTBLK -> "ENOTBLK"
EBUSY -> "EBUSY"
EEXIST -> "EEXIST"
EXDEV -> "EXDEV"
ENODEV -> "ENODEV"
ENOTDIR -> "ENOTDIR"
EISDIR -> "EISDIR"
EINVAL -> "EINVAL"
ENFILE -> "ENFILE"
EMFILE -> "EMFILE"
ENOTTY -> "ENOTTY"
ETXTBSY -> "ETXTBSY"
EFBIG -> "EFBIG"
ENOSPC -> "ENOSPC"
ESPIPE -> "ESPIPE"
EROFS -> "EROFS"
EMLINK -> "EMLINK"
EPIPE -> "EPIPE"
EDOM -> "EDOM"
ERANGE -> "ERANGE"
EDEADLK -> "EDEADLK"
ENAMETOOLONG -> "ENAMETOOLONG"
ENOLCK -> "ENOLCK"
ENOSYS -> "ENOSYS"
ENOTEMPTY -> "ENOTEMPTY"
ELOOP -> "ELOOP"
EWOULDBLOCK -> "EWOULDBLOCK"
ENOMSG -> "ENOMSG"
EIDRM -> "EIDRM"
ECHRNG -> "ECHRNG"
EL2NSYNC -> "EL2NSYNC"
EL3HLT -> "EL3HLT"
EL3RST -> "EL3RST"
ELNRNG -> "ELNRNG"
EUNATCH -> "EUNATCH"
ENOCSI -> "ENOCSI"
EL2HLT -> "EL2HLT"
EBADE -> "EBADE"
EBADR -> "EBADR"
EXFULL -> "EXFULL"
ENOANO -> "ENOANO"
EBADRQC -> "EBADRQC"
EBADSLT -> "EBADSLT"
EDEADLOCK -> "EDEADLOCK"
EBFONT -> "EBFONT"
ENOSTR -> "ENOSTR"
ENODATA -> "ENODATA"
ETIME -> "ETIME"
ENOSR -> "ENOSR"
ENONET -> "ENONET"
ENOPKG -> "ENOPKG"
EREMOTE -> "EREMOTE"
ENOLINK -> "ENOLINK"
EADV -> "EADV"
ESRMNT -> "ESRMNT"
ECOMM -> "ECOMM"
EPROTO -> "EPROTO"
EMULTIHOP -> "EMULTIHOP"
EDOTDOT -> "EDOTDOT"
EBADMSG -> "EBADMSG"
EOVERFLOW -> "EOVERFLOW"
ENOTUNIQ -> "ENOTUNIQ"
EBADFD -> "EBADFD"
EREMCHG -> "EREMCHG"
ELIBACC -> "ELIBACC"
ELIBBAD -> "ELIBBAD"
ELIBSCN -> "ELIBSCN"
ELIBMAX -> "ELIBMAX"
ELIBEXEC -> "ELIBEXEC"
EILSEQ -> "EILSEQ"
ERESTART -> "ERESTART"
ESTRPIPE -> "ESTRPIPE"
EUSERS -> "EUSERS"
ENOTSOCK -> "ENOTSOCK"
EDESTADDRREQ -> "EDESTADDRREQ"
EMSGSIZE -> "EMSGSIZE"
EPROTOTYPE -> "EPROTOTYPE"
ENOPROTOOPT -> "ENOPROTOOPT"
EPROTONOSUPPORT -> "EPROTONOSUPPORT"
ESOCKTNOSUPPORT -> "ESOCKTNOSUPPORT"
EOPNOTSUPP -> "EOPNOTSUPP"
EPFNOSUPPORT -> "EPFNOSUPPORT"
EAFNOSUPPORT -> "EAFNOSUPPORT"
EADDRINUSE -> "EADDRINUSE"
EADDRNOTAVAIL -> "EADDRNOTAVAIL"
ENETDOWN -> "ENETDOWN"
ENETUNREACH -> "ENETUNREACH"
ENETRESET -> "ENETRESET"
ECONNABORTED -> "ECONNABORTED"
ECONNRESET -> "ECONNRESET"
ENOBUFS -> "ENOBUFS"
EISCONN -> "EISCONN"
ENOTCONN -> "ENOTCONN"
ESHUTDOWN -> "ESHUTDOWN"
ETOOMANYREFS -> "ETOOMANYREFS"
ETIMEDOUT -> "ETIMEDOUT"
ECONNREFUSED -> "ECONNREFUSED"
EHOSTDOWN -> "EHOSTDOWN"
EHOSTUNREACH -> "EHOSTUNREACH"
EALREADY -> "EALREADY"
EINPROGRESS -> "EINPROGRESS"
ESTALE -> "ESTALE"
EUCLEAN -> "EUCLEAN"
ENOTNAM -> "ENOTNAM"
ENAVAIL -> "ENAVAIL"
EISNAM -> "EISNAM"
EREMOTEIO -> "EREMOTEIO"
EDQUOT -> "EDQUOT"
ENOMEDIUM -> "ENOMEDIUM"
EMEDIUMTYPE -> "EMEDIUMTYPE"
ECANCELED -> "ECANCELED"
ENOKEY -> "ENOKEY"
EKEYEXPIRED -> "EKEYEXPIRED"
EKEYREVOKED -> "EKEYREVOKED"
EKEYREJECTED -> "EKEYREJECTED"
EOWNERDEAD -> "EOWNERDEAD"
ENOTRECOVERABLE -> "ENOTRECOVERABLE"
ERFKILL -> "ERFKILL"
EHWPOISON -> "EHWPOISON"
ENOTSUP -> "ENOTSUP"
else -> null
}
}
fun strerror(errno: Int): String? {
return when (errno) {
EPERM -> "Operation not permitted"
ENOENT -> "No such file or directory"
ESRCH -> "No such process"
EINTR -> "Interrupted system call"
EIO -> "Input/output error"
ENXIO -> "No such device or address"
E2BIG -> "Argument list too long"
ENOEXEC -> "Exec format error"
EBADF -> "Bad file descriptor"
ECHILD -> "No child processes"
EAGAIN -> "Resource temporarily unavailable"
ENOMEM -> "Cannot allocate memory"
EACCES -> "Permission denied"
EFAULT -> "Bad address"
ENOTBLK -> "Block device required"
EBUSY -> "Device or resource busy"
EEXIST -> "File exists"
EXDEV -> "Invalid cross-device link"
ENODEV -> "No such device"
ENOTDIR -> "Not a directory"
EISDIR -> "Is a directory"
EINVAL -> "Invalid argument"
ENFILE -> "Too many open files in system"
EMFILE -> "Too many open files"
ENOTTY -> "Inappropriate ioctl for device"
ETXTBSY -> "Text file busy"
EFBIG -> "File too large"
ENOSPC -> "No space left on device"
ESPIPE -> "Illegal seek"
EROFS -> "Read-only file system"
EMLINK -> "Too many links"
EPIPE -> "Broken pipe"
EDOM -> "Numerical argument out of domain"
ERANGE -> "Numerical result out of range"
EDEADLK -> "Resource deadlock avoided"
ENAMETOOLONG -> "File name too long"
ENOLCK -> "No locks available"
ENOSYS -> "Function not implemented"
ENOTEMPTY -> "Directory not empty"
ELOOP -> "Too many levels of symbolic links"
EWOULDBLOCK -> "Resource temporarily unavailable"
ENOMSG -> "No message of desired type"
EIDRM -> "Identifier removed"
ECHRNG -> "Channel number out of range"
EL2NSYNC -> "Level 2 not synchronized"
EL3HLT -> "Level 3 halted"
EL3RST -> "Level 3 reset"
ELNRNG -> "Link number out of range"
EUNATCH -> "Protocol driver not attached"
ENOCSI -> "No CSI structure available"
EL2HLT -> "Level 2 halted"
EBADE -> "Invalid exchange"
EBADR -> "Invalid request descriptor"
EXFULL -> "Exchange full"
ENOANO -> "No anode"
EBADRQC -> "Invalid request code"
EBADSLT -> "Invalid slot"
EDEADLOCK -> "Resource deadlock avoided"
EBFONT -> "Bad font file format"
ENOSTR -> "Device not a stream"
ENODATA -> "No data available"
ETIME -> "Timer expired"
ENOSR -> "Out of streams resources"
ENONET -> "Machine is not on the network"
ENOPKG -> "Package not installed"
EREMOTE -> "Object is remote"
ENOLINK -> "Link has been severed"
EADV -> "Advertise error"
ESRMNT -> "Srmount error"
ECOMM -> "Communication error on send"
EPROTO -> "Protocol error"
EMULTIHOP -> "Multihop attempted"
EDOTDOT -> "RFS specific error"
EBADMSG -> "Bad message"
EOVERFLOW -> "Value too large for defined data type"
ENOTUNIQ -> "Name not unique on network"
EBADFD -> "File descriptor in bad state"
EREMCHG -> "Remote address changed"
ELIBACC -> "Can not access a needed shared library"
ELIBBAD -> "Accessing a corrupted shared library"
ELIBSCN -> ".lib section in a.out corrupted"
ELIBMAX -> "Attempting to link in too many shared libraries"
ELIBEXEC -> "Cannot exec a shared library directly"
EILSEQ -> "Invalid or incomplete multibyte or wide character"
ERESTART -> "Interrupted system call should be restarted"
ESTRPIPE -> "Streams pipe error"
EUSERS -> "Too many users"
ENOTSOCK -> "Socket operation on non-socket"
EDESTADDRREQ -> "Destination address required"
EMSGSIZE -> "Message too long"
EPROTOTYPE -> "Protocol wrong type for socket"
ENOPROTOOPT -> "Protocol not available"
EPROTONOSUPPORT -> "Protocol not supported"
ESOCKTNOSUPPORT -> "Socket type not supported"
EOPNOTSUPP -> "Operation not supported"
EPFNOSUPPORT -> "Protocol family not supported"
EAFNOSUPPORT -> "Address family not supported by protocol"
EADDRINUSE -> "Address already in use"
EADDRNOTAVAIL -> "Cannot assign requested address"
ENETDOWN -> "Network is down"
ENETUNREACH -> "Network is unreachable"
ENETRESET -> "Network dropped connection on reset"
ECONNABORTED -> "Software caused connection abort"
ECONNRESET -> "Connection reset by peer"
ENOBUFS -> "No buffer space available"
EISCONN -> "Transport endpoint is already connected"
ENOTCONN -> "Transport endpoint is not connected"
ESHUTDOWN -> "Cannot send after transport endpoint shutdown"
ETOOMANYREFS -> "Too many references: cannot splice"
ETIMEDOUT -> "Connection timed out"
ECONNREFUSED -> "Connection refused"
EHOSTDOWN -> "Host is down"
EHOSTUNREACH -> "No route to host"
EALREADY -> "Operation already in progress"
EINPROGRESS -> "Operation now in progress"
ESTALE -> "Stale file handle"
EUCLEAN -> "Structure needs cleaning"
ENOTNAM -> "Not a XENIX named type file"
ENAVAIL -> "No XENIX semaphores available"
EISNAM -> "Is a named type file"
EREMOTEIO -> "Remote I/O error"
EDQUOT -> "Disk quota exceeded"
ENOMEDIUM -> "No medium found"
EMEDIUMTYPE -> "Wrong medium type"
ECANCELED -> "Operation canceled"
ENOKEY -> "Required key not available"
EKEYEXPIRED -> "Key has expired"
EKEYREVOKED -> "Key has been revoked"
EKEYREJECTED -> "Key was rejected by service"
EOWNERDEAD -> "Owner died"
ENOTRECOVERABLE -> "State not recoverable"
ERFKILL -> "Operation not possible due to RF-kill"
EHWPOISON -> "Memory page has hardware error"
ENOTSUP -> "Operation not supported"
else -> null
}
}
}
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package libcore.io;
public final class ErrnoException extends Exception {
public final int errno;
private final String functionName;
public ErrnoException(String functionName, int errno) {
this.functionName = functionName;
this.errno = errno;
}
public ErrnoException(String functionName, int errno, Throwable cause) {
super(cause);
this.functionName = functionName;
this.errno = errno;
}
}
......@@ -39,4 +39,9 @@
<code>%1$s</code><br/>
ist nicht gültig für %2$s.</p>
]]></string>
<string name="label_error_unknown_host">Host nicht gefunden: %1$s</string>
<string name="label_error_invalid_protocol_version">Unbekanntes Protokoll: %1$d</string>
<string name="label_error_connection">Fehler beim Herstellen der Verbindung: %1$s (%2$s)</string>
<string name="label_error_connection_closed">Fehler: Verbindung wurde unerwartet getrennt</string>
</resources>
......@@ -38,4 +38,5 @@
<code>%1$s</code><br/>
n\'est pas valide pour %2$s.</p>
]]></string>
</resources>
......@@ -38,4 +38,5 @@
<code>%1$s</code><br/>
negalioja %2$s.</p>
]]></string>
</resources>
......@@ -38,4 +38,5 @@
<code>%1$s</code><br/>
não é válido para %2$s.</p>
]]></string>
</resources>
......@@ -38,4 +38,5 @@
<code>%1$s</code><br/>
nije važeći za %2$s.</p>
]]></string>
</resources>
......@@ -38,4 +38,9 @@
<code>%1$s</code><br/>
is not valid for %2$s.</p>
]]></string>
<string name="label_error_unknown_host">Host not found: %1$s</string>
<string name="label_error_invalid_protocol_version">Invalid protocol: %1$d</string>
<string name="label_error_connection">Error encountered during connection: %1$s (%2$s)</string>
<string name="label_error_connection_closed">Error: Connection was unexpectedly closed</string>
</resources>
......@@ -56,7 +56,8 @@ class CoreConnection(
private val hostnameVerifier: HostnameVerifier,
private val address: SocketAddress,
private val handlerService: HandlerService,
private val securityExceptionCallback: (QuasselSecurityException) -> Unit
private val securityExceptionCallback: (QuasselSecurityException) -> Unit,
private val exceptionCallback: (Throwable) -> Unit
) : Thread(), Closeable {
companion object {
private const val TAG = "CoreConnection"
......@@ -146,7 +147,7 @@ class CoreConnection(
)
}
else -> {
throw IllegalArgumentException("Invalid Protocol Version: $protocol")
throw ProtocolVersionException(protocol)
}
}
}
......@@ -241,6 +242,7 @@ class CoreConnection(
log(WARN, TAG, "Error encountered in connection", e)
log(WARN, TAG, "Last sent message: ${MessageRunnable.lastSent.get()}")
close()
exceptionCallback(e)
}
}
}
......
package de.kuschku.libquassel.connection
import de.kuschku.libquassel.quassel.ProtocolInfo
import java.net.ConnectException
class ProtocolVersionException(val protocol: ProtocolInfo) : ConnectException() {
override val message: String?
get() = "Invalid Protocol Version: $protocol"
}
......@@ -61,6 +61,7 @@ interface ISession : Closeable {
val proxy: SignalProxy
val error: Flowable<Error>
val connectionError: Flowable<Throwable>
val lag: Observable<Long>
fun login(user: String, pass: String)
......@@ -69,6 +70,8 @@ interface ISession : Closeable {
val NULL = object : ISession {
override val proxy: SignalProxy = SignalProxy.NULL
override val error = BehaviorSubject.create<Error>().toFlowable(BackpressureStrategy.BUFFER)
override val connectionError = BehaviorSubject.create<Throwable>().toFlowable(
BackpressureStrategy.BUFFER)
override val state = BehaviorSubject.createDefault(ConnectionState.DISCONNECTED)
override val features: Features = Features(
QuasselFeatures.empty(),
......
......@@ -58,13 +58,24 @@ class Session(
get() = coreConnection.sslSession
private val coreConnection = CoreConnection(
this, clientData, features, trustManager, hostnameVerifier, address, handlerService, ::handle
this,
clientData,
features,
trustManager,
hostnameVerifier,
address,
handlerService,
::handle,
::handleConnectionError
)
override val state = coreConnection.state
private val _error = PublishSubject.create<Error>()
override val error = _error.toFlowable(BackpressureStrategy.BUFFER)
private val _connectionError = PublishSubject.create<Throwable>()
override val connectionError = _connectionError.toFlowable(BackpressureStrategy.LATEST)
override val aliasManager = AliasManager(this)
override val backlogManager = BacklogManager(this, backlogStorage)
override val bufferViewManager = BufferViewManager(this)
......@@ -148,6 +159,10 @@ class Session(
_error.onNext(Error.SslError(f))
}
fun handleConnectionError(f: Throwable) {
_connectionError.onNext(f)
}
fun addNetwork(networkId: NetworkId) {
val network = Network(networkId, this)
networks[networkId] = network
......
......@@ -74,6 +74,11 @@ class SessionManager(
.toFlowable(BackpressureStrategy.LATEST)
.switchMap(ISession::error)
val connectionError: Flowable<Throwable>
get() = inProgressSession
.toFlowable(BackpressureStrategy.LATEST)
.switchMap(ISession::connectionError)
val connectionProgress: Observable<Triple<ConnectionState, Int, Int>> = Observable.combineLatest(
state, initStatus,
BiFunction<ConnectionState, Pair<Int, Int>, Triple<ConnectionState, Int, Int>> { t1, t2 ->
......
......@@ -99,6 +99,10 @@ class QuasselViewModel : ViewModel() {
it.orNull()?.error ?: Flowable.empty()
}
val connectionErrors = sessionManager.toFlowable(BackpressureStrategy.LATEST).switchMap {
it.orNull()?.connectionError ?: Flowable.empty()
}
val sslSession = session.flatMapSwitchMap(ISession::sslSession)
val coreInfo = session.mapMapNullable(ISession::coreInfo).mapSwitchMap(CoreInfo::liveInfo)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment