2020-07-01 10:58:49 +00:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2020 Proton Technologies AG
|
|
|
|
* This file is part of Proton Technologies AG and ProtonCore.
|
|
|
|
*
|
|
|
|
* ProtonCore is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* ProtonCore is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with ProtonCore. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
package me.proton.core.network.domain
|
|
|
|
|
|
|
|
import kotlinx.coroutines.CoroutineScope
|
|
|
|
import kotlinx.coroutines.withTimeoutOrNull
|
2020-07-07 11:47:26 +00:00
|
|
|
import java.lang.Exception
|
2020-07-01 10:58:49 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Result of the safe API call.
|
|
|
|
*
|
|
|
|
* @param T value type of the successful call result.
|
|
|
|
*/
|
|
|
|
sealed class ApiResult<out T> {
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Successful call result.
|
|
|
|
*
|
|
|
|
* @param T Value type.
|
|
|
|
* @property value Value.
|
|
|
|
*/
|
|
|
|
class Success<T>(val value: T) : ApiResult<T>() {
|
|
|
|
override val valueOrNull get() = value
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Base class for error result.
|
2020-07-07 11:47:26 +00:00
|
|
|
* @param cause [Exception] exception that caused this error for debugging purposes.
|
2020-07-01 10:58:49 +00:00
|
|
|
*/
|
2020-07-07 11:47:26 +00:00
|
|
|
sealed class Error(val cause: Exception?) : ApiResult<Nothing>() {
|
2020-07-01 10:58:49 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* HTTP error.
|
|
|
|
*
|
|
|
|
* @property httpCode HTTP code.
|
|
|
|
* @property message HTTP message.
|
2020-07-01 12:39:58 +00:00
|
|
|
* @property proton Proton-specific HTTP error data.
|
2020-07-01 10:58:49 +00:00
|
|
|
*/
|
2020-07-07 11:47:26 +00:00
|
|
|
open class Http(val httpCode: Int, val message: String, val proton: ProtonData? = null) : Error(null)
|
2020-07-01 12:39:58 +00:00
|
|
|
class ProtonData(val code: Int, val error: String)
|
2020-07-01 10:58:49 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Parsing error. Should not normally happen.
|
|
|
|
*/
|
2020-07-07 11:47:26 +00:00
|
|
|
class Parse(cause: Exception?) : Error(cause)
|
2020-07-01 10:58:49 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Base class for connection errors (no response available)
|
|
|
|
*
|
|
|
|
* @property potentialBlock [true] if our API might have been blocked.
|
|
|
|
*/
|
2020-07-07 11:47:26 +00:00
|
|
|
open class Connection(val potentialBlock: Boolean, cause: Exception? = null) : Error(cause) {
|
2020-07-01 10:58:49 +00:00
|
|
|
override val isPotentialBlocking get() = potentialBlock
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Connection timed out.
|
|
|
|
*
|
|
|
|
* @param potentialBlock [true] if our API might have been blocked.
|
|
|
|
*/
|
2020-07-07 11:47:26 +00:00
|
|
|
class Timeout(potentialBlock: Boolean, cause: Exception? = null) : Connection(potentialBlock, cause)
|
2020-07-01 10:58:49 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Certificate verification failed.
|
|
|
|
*/
|
2020-07-07 11:47:26 +00:00
|
|
|
class Certificate(cause: Exception) : Connection(true, cause)
|
2020-07-01 10:58:49 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* No connectivity.
|
|
|
|
*/
|
2020-07-07 11:47:26 +00:00
|
|
|
object NoInternet : Connection(false, null)
|
2020-07-01 10:58:49 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* 429 "Too Many Requests"
|
|
|
|
*
|
|
|
|
* @property retryAfterSeconds Number of seconds to hold all requests (network layer will
|
|
|
|
* automatically fail requests that don't comply)
|
|
|
|
*/
|
2020-07-01 12:39:58 +00:00
|
|
|
class TooManyRequest(val retryAfterSeconds: Int, proton: ProtonData? = null) :
|
|
|
|
Http(HTTP_TOO_MANY_REQUESTS, "Too Many Requests", proton)
|
2020-07-01 10:58:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Value for successful calls or [null].
|
|
|
|
*/
|
|
|
|
open val valueOrNull: T? get() = null
|
|
|
|
|
|
|
|
/**
|
|
|
|
* [true] for failed calls potentially caused by blocking.
|
|
|
|
*/
|
|
|
|
open val isPotentialBlocking: Boolean get() = false
|
|
|
|
|
|
|
|
companion object {
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Introduce timeout for given block returning [ApiResult].
|
|
|
|
*
|
|
|
|
* @param T Value type for successful call.
|
|
|
|
* @param timeoutMs Timeout in milliseconds.
|
|
|
|
* @param block potentially long-running lambda producing [ApiResult].
|
|
|
|
* @return block [ApiResult] or [ApiResult.Error.Timeout] on timeout.
|
|
|
|
*/
|
|
|
|
suspend fun <T> withTimeout(timeoutMs: Long, block: suspend CoroutineScope.() -> ApiResult<T>) =
|
2020-07-07 11:47:26 +00:00
|
|
|
withTimeoutOrNull(timeoutMs, block) ?: Error.Timeout(true, null)
|
2020-07-01 10:58:49 +00:00
|
|
|
|
|
|
|
const val HTTP_TOO_MANY_REQUESTS = 429
|
|
|
|
}
|
|
|
|
}
|