aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--coroutine-utils/build.gradle.kts1
-rw-r--r--coroutine-utils/src/main/kotlin/dev/msfjarvis/aps/util/coroutines/RunSuspendCatching.kt48
-rw-r--r--crypto-pgpainless/build.gradle.kts1
-rw-r--r--crypto-pgpainless/src/main/kotlin/dev/msfjarvis/aps/crypto/PGPKeyManager.kt14
4 files changed, 57 insertions, 7 deletions
diff --git a/coroutine-utils/build.gradle.kts b/coroutine-utils/build.gradle.kts
index 2a20df08..78f1e8c2 100644
--- a/coroutine-utils/build.gradle.kts
+++ b/coroutine-utils/build.gradle.kts
@@ -10,4 +10,5 @@ plugins {
dependencies {
implementation(libs.kotlin.coroutines.core)
implementation(libs.dagger.hilt.core)
+ api(libs.thirdparty.kotlinResult)
}
diff --git a/coroutine-utils/src/main/kotlin/dev/msfjarvis/aps/util/coroutines/RunSuspendCatching.kt b/coroutine-utils/src/main/kotlin/dev/msfjarvis/aps/util/coroutines/RunSuspendCatching.kt
new file mode 100644
index 00000000..7e5b906c
--- /dev/null
+++ b/coroutine-utils/src/main/kotlin/dev/msfjarvis/aps/util/coroutines/RunSuspendCatching.kt
@@ -0,0 +1,48 @@
+@file:OptIn(ExperimentalContracts::class)
+@file:Suppress("RedundantSuspendModifier")
+
+package dev.msfjarvis.aps.util.coroutines
+
+import com.github.michaelbull.result.Err
+import com.github.michaelbull.result.Ok
+import com.github.michaelbull.result.Result
+import kotlin.contracts.ExperimentalContracts
+import kotlin.contracts.InvocationKind
+import kotlin.contracts.contract
+import kotlinx.coroutines.CancellationException
+
+/**
+ * Calls the specified function [block] with [this] value as its receiver and returns its
+ * encapsulated result if invocation was successful, catching any [Throwable] except
+ * [CancellationException] that was thrown from the [block] function execution and encapsulating it
+ * as a failure.
+ */
+public suspend inline fun <V> runSuspendCatching(block: () -> V): Result<V, Throwable> {
+ contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
+
+ return try {
+ Ok(block())
+ } catch (e: Throwable) {
+ if (e is CancellationException) throw e
+ Err(e)
+ }
+}
+
+/**
+ * Calls the specified function [block] with [this] value as its receiver and returns its
+ * encapsulated result if invocation was successful, catching any [Throwable] except
+ * [CancellationException] that was thrown from the [block] function execution and encapsulating it
+ * as a failure.
+ */
+public suspend inline infix fun <T, V> T.runSuspendCatching(
+ block: T.() -> V
+): Result<V, Throwable> {
+ contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
+
+ return try {
+ Ok(block())
+ } catch (e: Throwable) {
+ if (e is CancellationException) throw e
+ Err(e)
+ }
+}
diff --git a/crypto-pgpainless/build.gradle.kts b/crypto-pgpainless/build.gradle.kts
index ee55f349..b3ace3d9 100644
--- a/crypto-pgpainless/build.gradle.kts
+++ b/crypto-pgpainless/build.gradle.kts
@@ -10,6 +10,7 @@ plugins {
dependencies {
api(projects.cryptoCommon)
+ implementation(projects.coroutineUtils)
implementation(libs.androidx.annotation)
implementation(libs.dagger.hilt.core)
implementation(libs.kotlin.coroutines.core)
diff --git a/crypto-pgpainless/src/main/kotlin/dev/msfjarvis/aps/crypto/PGPKeyManager.kt b/crypto-pgpainless/src/main/kotlin/dev/msfjarvis/aps/crypto/PGPKeyManager.kt
index adcce22b..8c54d516 100644
--- a/crypto-pgpainless/src/main/kotlin/dev/msfjarvis/aps/crypto/PGPKeyManager.kt
+++ b/crypto-pgpainless/src/main/kotlin/dev/msfjarvis/aps/crypto/PGPKeyManager.kt
@@ -8,9 +8,9 @@ package dev.msfjarvis.aps.crypto
import androidx.annotation.VisibleForTesting
import com.github.michaelbull.result.Result
-import com.github.michaelbull.result.runCatching
import dev.msfjarvis.aps.crypto.KeyUtils.tryGetId
import dev.msfjarvis.aps.crypto.KeyUtils.tryParseKeyring
+import dev.msfjarvis.aps.util.coroutines.runSuspendCatching
import java.io.File
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
@@ -28,7 +28,7 @@ constructor(
override suspend fun addKey(key: PGPKey, replace: Boolean): Result<PGPKey, Throwable> =
withContext(dispatcher) {
- runCatching {
+ runSuspendCatching {
if (!keyDirExists()) throw KeyManagerException.KeyDirectoryUnavailableException
if (tryParseKeyring(key) == null) throw KeyManagerException.InvalidKeyException
val keyFile = File(keyDir, "${tryGetId(key)}.$KEY_EXTENSION")
@@ -49,7 +49,7 @@ constructor(
override suspend fun removeKey(key: PGPKey): Result<PGPKey, Throwable> =
withContext(dispatcher) {
- runCatching {
+ runSuspendCatching {
if (!keyDirExists()) throw KeyManagerException.KeyDirectoryUnavailableException
if (tryParseKeyring(key) == null) throw KeyManagerException.InvalidKeyException
val keyFile = File(keyDir, "${tryGetId(key)}.$KEY_EXTENSION")
@@ -63,7 +63,7 @@ constructor(
override suspend fun getKeyById(id: GpgIdentifier): Result<PGPKey, Throwable> =
withContext(dispatcher) {
- runCatching {
+ runSuspendCatching {
if (!keyDirExists()) throw KeyManagerException.KeyDirectoryUnavailableException
val keyFiles = keyDir.listFiles()
if (keyFiles.isNullOrEmpty()) throw KeyManagerException.NoKeysAvailableException
@@ -89,7 +89,7 @@ constructor(
}
if (matchResult != null) {
- return@runCatching matchResult
+ return@runSuspendCatching matchResult
}
throw KeyManagerException.KeyNotFoundException("$id")
@@ -98,10 +98,10 @@ constructor(
override suspend fun getAllKeys(): Result<List<PGPKey>, Throwable> =
withContext(dispatcher) {
- runCatching {
+ runSuspendCatching {
if (!keyDirExists()) throw KeyManagerException.KeyDirectoryUnavailableException
val keyFiles = keyDir.listFiles()
- if (keyFiles.isNullOrEmpty()) return@runCatching emptyList()
+ if (keyFiles.isNullOrEmpty()) return@runSuspendCatching emptyList()
keyFiles.map { keyFile -> PGPKey(keyFile.readBytes()) }.toList()
}
}