1

I'm newbie with RxJava2.

I have next code:

fun signIn(): Completable = getCredentials() // get saved token
        .onErrorResumeNext { makeLockSignInRequest() } // if token not saved then get it
        .flatMap { refreshToken(it) } // refresh token
        .doOnSuccess { credentialsManager.saveCredentials(it) } // save updated token
        .doFinally { lock?.onDestroy(context) }!!
        .toCompletable()

private fun getCredentials() = Single.create(SingleOnSubscribe<Credentials> {
    credentialsManager.getCredentials(object : BaseCallback<Credentials, CredentialsManagerException> {
        override fun onSuccess(payload: Credentials?) = it.onSuccess(payload!!)
        override fun onFailure(error: CredentialsManagerException?) = it.onError(error!!)
    })
})

private fun makeLockSignInRequest() = Single.create(SingleOnSubscribe<Credentials> {
    lock = Lock.newBuilder(auth0, object : AuthenticationCallback() {
        override fun onAuthentication(credentials: Credentials?) = it.onSuccess(credentials!!)
        override fun onCanceled() { }
        override fun onError(error: LockException?) = it.onError(error!!)
    })
            .withScheme("demo")
            .withScope("email openid offline_access")
            .withAudience(ApiServiceProvider.DOMAIN + "/api/")
            .closable(true)
            .build(context)

    context.startActivity(lock!!.newIntent(context))
})

private fun refreshToken(storedCredentials: Credentials) = Single.create(SingleOnSubscribe<Credentials> {
    apiClient.renewAuth(storedCredentials.refreshToken!!)
            .addParameter("scope", "openid email offline_access")
            .start(object : BaseCallback<Credentials, AuthenticationException> {
                override fun onSuccess(receivedCredentials: Credentials?) {
                    val newCredentials = Credentials(receivedCredentials!!.idToken, receivedCredentials.accessToken, receivedCredentials.type, storedCredentials.refreshToken, receivedCredentials.expiresAt, receivedCredentials.scope)
                    it.onSuccess(newCredentials)
                }

                override fun onFailure(error: AuthenticationException?) {
                    it.onError(Exception("Error refresh token: ${error!!.description!!}"))
                }
            })
})

This code gets saved token and refresh it. Also if user just logged in it refresh token.

I want to add filter like follows:

fun signIn(): Completable = getCredentials()
        .onErrorResumeNext { makeLockSignInRequest() }
        .filter { OffsetDateTime.now(ZoneOffset.UTC).toEpochSecond() > it.expiresAt!!.time } // if token alive then do nothing
        .flatMapSingle { refreshToken(it) }
        .doOnSuccess { credentialsManager.saveCredentials(it) }
        .doFinally { lock?.onDestroy(context) }!!
        .toCompletable()

This code will fail with error: NoSuchElementException So how can I filter token?

Milind Mevada
  • 3,145
  • 1
  • 14
  • 22
Max Polkovnik
  • 319
  • 1
  • 5
  • 18

1 Answers1

5

.filter changes your Single to Maybe. If there is no item in Maybe (because filter requirements are not met) after transforming it with flatMapSingle your code will return error with NoSuchElementException exception.

What I would do with it is:

fun signIn(): Completable = getCredentials()
    .onErrorResumeNext { makeLockSignInRequest() }
    .filter { OffsetDateTime.now(ZoneOffset.UTC).toEpochSecond() > it.expiresAt!!.time } // if token alive then do nothing
    .flatMapCompletable { refreshToken(it).doAfterSuccess{credentialsManager.saveCredentials(it)}.toCompletable() }
    .doFinally { lock?.onDestroy(context) }!!
RadekJ
  • 2,835
  • 1
  • 19
  • 25