From 0cfc324d87d07b98f02aaf02df84ee89662df85f Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Mon, 15 Jun 2026 10:41:40 -0400 Subject: [PATCH] Removes Threading checks on Commons since Main Threads don't exist over there. Remove warnings --- commons/ARCHITECTURE.md | 6 +-- commons/build.gradle.kts | 4 +- .../commons/threading/Threading.android.kt | 37 ------------------- .../amethyst/commons/model/Note.kt | 2 - .../amethyst/commons/model/ThreadAssembler.kt | 3 -- .../amethyst/commons/threading/Threading.kt | 36 ------------------ .../commons/ui/feeds/FeedContentState.kt | 3 -- .../src/commonTest/kotlin/android/util/Log.kt | 13 +++++++ .../amethyst/commons/ThumbHashTest.kt | 11 +----- .../namecoin/NamecoinSettingsTest.kt | 12 +++--- .../commons/threading/Threading.ios.kt | 28 -------------- .../service/lnurl/LightningAddressResolver.kt | 4 +- .../lnurl/OkHttpLnurlEndpointResolver.kt | 2 +- .../commons/service/upload/BlossomClient.kt | 8 ++-- .../commons/threading/Threading.jvm.kt | 32 ---------------- .../inlineMetadata/Nip54InlineMetadata.kt | 2 - .../metadata/BirthdayTolerantSerializer.kt | 2 + .../nip01Core/relay/client/pool/PoolCounts.kt | 2 - .../relay/client/pool/PoolRequests.kt | 2 - .../definition/AppDefinitionEvent.kt | 2 +- .../nip89AppHandlers/definition/EventExt.kt | 23 ------------ 21 files changed, 36 insertions(+), 198 deletions(-) delete mode 100644 commons/src/androidMain/kotlin/com/vitorpamplona/amethyst/commons/threading/Threading.android.kt delete mode 100644 commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/threading/Threading.kt delete mode 100644 commons/src/iosMain/kotlin/com/vitorpamplona/amethyst/commons/threading/Threading.ios.kt delete mode 100644 commons/src/jvmMain/kotlin/com/vitorpamplona/amethyst/commons/threading/Threading.jvm.kt delete mode 100644 quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/definition/EventExt.kt diff --git a/commons/ARCHITECTURE.md b/commons/ARCHITECTURE.md index 31c18cf334..b86c122c6f 100644 --- a/commons/ARCHITECTURE.md +++ b/commons/ARCHITECTURE.md @@ -109,7 +109,6 @@ they are shared across the GUI apps. Treat as GUI-shared, not strictly headless. |----------------|-----|---------| | `util` | no | KMP primitives: `KmpLock`, `WeakReference`, number/URL/codepoint helpers, list/debug helpers. **This is the only general-utility package** — there is no `utils`. | | `keystorage` | no | Secure key storage interface (Keystore / keychain / keyring actuals). | -| `threading` | no | `checkNotInMainThread` assertion. | | `tor` | no | Tor manager interface + settings. | | `service` | no | Cross-cutting services: `BundledUpdate` batching (common); `service/upload` (JVM), `service/nwc`, `service/lnurl` (jvmAndroid). **Singular `service`** — there is no `services`. | @@ -203,8 +202,7 @@ compiles: `commonMain` → `jvmAndroid` → platform-specific. See `` if feature-scoped). Keep it CLI-safe where practical. 4. **Relay subscription / filter assembly**? → `relayClient`. 5. **A domain model or per-NIP event wrapper**? → `model` (`model/nipNN…`). -6. **A platform capability behind `expect`/`actual`** (storage, crypto, - threading)? → the matching abstraction package + actuals in platform sets. +6. **A platform capability behind `expect`/`actual`** (storage, crypto)? → the matching abstraction package + actuals in platform sets. 7. **A generic helper**? → `util`. (Resist creating a new top-level package for one file.) @@ -229,7 +227,7 @@ These are intentionally *documented*, not silently tolerated. Fix opportunistica low-level EOSE bookkeeping, `relayClient` is the subscription client. Keep the distinction in mind when adding files. - Several **single-file feature packages** (`account`, `marmot`, - `nip53LiveActivities`, `keystorage`, `threading`) are kept as feature/abstraction + `nip53LiveActivities`, `keystorage`) are kept as feature/abstraction namespaces expected to grow; do not fold them into `util` just for size. - **`onchain`** (on-chain zap splitting) is `quartz`-adjacent but un-numbered; leave readable unless a clear NIP number lands. diff --git a/commons/build.gradle.kts b/commons/build.gradle.kts index 8def899ef0..b7119dcc77 100644 --- a/commons/build.gradle.kts +++ b/commons/build.gradle.kts @@ -37,7 +37,9 @@ kotlin { androidResources.enable = true - withHostTest {} + withHostTest { + isReturnDefaultValues = true + } withDeviceTest { instrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" diff --git a/commons/src/androidMain/kotlin/com/vitorpamplona/amethyst/commons/threading/Threading.android.kt b/commons/src/androidMain/kotlin/com/vitorpamplona/amethyst/commons/threading/Threading.android.kt deleted file mode 100644 index 551c4ea03a..0000000000 --- a/commons/src/androidMain/kotlin/com/vitorpamplona/amethyst/commons/threading/Threading.android.kt +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2025 Vitor Pamplona - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to use, - * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the - * Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -package com.vitorpamplona.amethyst.commons.threading - -import android.os.Looper - -/** - * Android implementation of checkNotInMainThread. - * Uses Looper to detect if running on main thread. - */ -actual fun checkNotInMainThread() { - // BuildConfig check removed - commons doesn't have BuildConfig - // Enable this check in debug builds at the app level if needed - if (isMainThread()) { - throw OnMainThreadException("It should not be in the MainThread") - } -} - -private fun isMainThread() = Looper.myLooper() == Looper.getMainLooper() diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/Note.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/Note.kt index 3f0de80179..bb5a045ee5 100644 --- a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/Note.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/Note.kt @@ -23,7 +23,6 @@ package com.vitorpamplona.amethyst.commons.model import androidx.compose.runtime.Immutable import androidx.compose.runtime.Stable import com.vitorpamplona.amethyst.commons.model.nip88Polls.PollResponsesCache -import com.vitorpamplona.amethyst.commons.threading.checkNotInMainThread import com.vitorpamplona.amethyst.commons.util.KmpLock import com.vitorpamplona.amethyst.commons.util.firstFullCharOrEmoji import com.vitorpamplona.amethyst.commons.util.replace @@ -723,7 +722,6 @@ open class Note( zapPaymentRequest: Note, zapPayment: Note?, ) { - checkNotInMainThread() if (zapPayments[zapPaymentRequest] == null) { val inserted = innerAddZapPayment(zapPaymentRequest, zapPayment) if (inserted) { diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/ThreadAssembler.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/ThreadAssembler.kt index 485069cbb9..fa37cf253b 100644 --- a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/ThreadAssembler.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/ThreadAssembler.kt @@ -22,7 +22,6 @@ package com.vitorpamplona.amethyst.commons.model import androidx.compose.runtime.Stable import com.vitorpamplona.amethyst.commons.model.cache.ICacheProvider -import com.vitorpamplona.amethyst.commons.threading.checkNotInMainThread import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.AddressableEvent import com.vitorpamplona.quartz.nip01Core.core.Event @@ -110,8 +109,6 @@ class ThreadAssembler( } fun findThreadFor(noteId: String): ThreadInfo? { - checkNotInMainThread() - val note = cache.checkGetOrCreateNote(noteId) ?: return null return if (note.event != null) { diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/threading/Threading.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/threading/Threading.kt deleted file mode 100644 index 1a7ec1e9be..0000000000 --- a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/threading/Threading.kt +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2025 Vitor Pamplona - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to use, - * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the - * Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -package com.vitorpamplona.amethyst.commons.threading - -/** - * Checks that the current code is not running on the main thread. - * Throws an exception in debug builds if called from the main thread. - * - * Platform-specific: Android uses Looper, Desktop may use different mechanism or no-op. - */ -expect fun checkNotInMainThread() - -/** - * Exception thrown when code expected to run on a background thread is executed on the main thread. - */ -class OnMainThreadException( - str: String, -) : RuntimeException(str) diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/feeds/FeedContentState.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/feeds/FeedContentState.kt index d6a4e8bd57..013840ea1b 100644 --- a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/feeds/FeedContentState.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/feeds/FeedContentState.kt @@ -27,7 +27,6 @@ import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.ICacheProvider import com.vitorpamplona.amethyst.commons.service.BasicBundledInsert import com.vitorpamplona.amethyst.commons.service.BasicBundledUpdate -import com.vitorpamplona.amethyst.commons.threading.checkNotInMainThread import com.vitorpamplona.amethyst.commons.util.equalImmutableLists import com.vitorpamplona.quartz.nip09Deletions.DeletionEvent import com.vitorpamplona.quartz.utils.flattenToSet @@ -87,8 +86,6 @@ class FeedContentState( fun lastNoteCreatedAtIfFilled() = lastNoteCreatedAtWhenFullyLoaded.value fun refreshSuspended() { - checkNotInMainThread() - isRefreshing.value = true try { lastFeedKey = localFilter.feedKey() diff --git a/commons/src/commonTest/kotlin/android/util/Log.kt b/commons/src/commonTest/kotlin/android/util/Log.kt index d0c09ca3af..bb65a7d1b7 100644 --- a/commons/src/commonTest/kotlin/android/util/Log.kt +++ b/commons/src/commonTest/kotlin/android/util/Log.kt @@ -20,13 +20,21 @@ */ package android.util +import kotlin.jvm.JvmStatic + class Log { + // @JvmStatic so the methods compile to real static methods on android.util.Log. Code compiled + // against the Android SDK (e.g. quartz's PlatformLog) emits `invokestatic Log.d(...)`; without + // @JvmStatic the companion methods would be instance methods and resolve to NoSuchMethodError + // when this fake shadows the SDK stub under :commons:testAndroidHostTest. companion object { + @JvmStatic fun isLoggable( tag: String?, msg: Int?, ): Boolean = true + @JvmStatic fun d( tag: String?, msg: String?, @@ -35,6 +43,7 @@ class Log { return 0 } + @JvmStatic fun i( tag: String?, msg: String?, @@ -43,6 +52,7 @@ class Log { return 0 } + @JvmStatic fun w( tag: String?, msg: String?, @@ -51,6 +61,7 @@ class Log { return 0 } + @JvmStatic fun w( tag: String?, msg: String?, @@ -61,6 +72,7 @@ class Log { return 0 } + @JvmStatic fun e( tag: String?, msg: String?, @@ -69,6 +81,7 @@ class Log { return 0 } + @JvmStatic fun e( tag: String?, msg: String?, diff --git a/commons/src/commonTest/kotlin/com/vitorpamplona/amethyst/commons/ThumbHashTest.kt b/commons/src/commonTest/kotlin/com/vitorpamplona/amethyst/commons/ThumbHashTest.kt index cddc9872db..63f3b32a22 100644 --- a/commons/src/commonTest/kotlin/com/vitorpamplona/amethyst/commons/ThumbHashTest.kt +++ b/commons/src/commonTest/kotlin/com/vitorpamplona/amethyst/commons/ThumbHashTest.kt @@ -41,7 +41,6 @@ class ThumbHashTest { val decoded = ThumbHashDecoder.decode(hashBytes) assertNotNull(decoded) - decoded!! assertTrue(decoded.width > 0, "decoded width should be positive") assertTrue(decoded.height > 0, "decoded height should be positive") @@ -74,11 +73,9 @@ class ThumbHashTest { val viaBase64 = ThumbHashDecoder.decode(encoded) assertNotNull(viaBase64) - viaBase64!! val viaBytes = ThumbHashDecoder.decode(ThumbHashEncoder.encode(pixels, w, h)) assertNotNull(viaBytes) - viaBytes!! assertEquals(viaBytes.width, viaBase64.width, "base64 path and raw path should agree on width") assertEquals(viaBytes.height, viaBase64.height, "base64 path and raw path should agree on height") @@ -98,7 +95,6 @@ class ThumbHashTest { val pixels = IntArray(w * h) { 0xFF8080FF.toInt() } // opaque cornflower-ish val decoded = ThumbHashDecoder.decode(ThumbHashEncoder.encode(pixels, w, h)) assertNotNull(decoded) - decoded!! for (p in decoded.pixels) { val a = (p ushr 24) and 0xff assertEquals(255, a, "alpha should be 255 for opaque encode") @@ -113,7 +109,6 @@ class ThumbHashTest { val pixels = IntArray(w * h) { 0x00000000 } val decoded = ThumbHashDecoder.decode(ThumbHashEncoder.encode(pixels, w, h)) assertNotNull(decoded) - decoded!! // The average alpha is 0, so every decoded alpha should be at or near 0. var maxAlpha = 0 for (p in decoded.pixels) { @@ -134,7 +129,6 @@ class ThumbHashTest { } val decoded = ThumbHashDecoder.decode(ThumbHashEncoder.encode(pixels, w, h)) assertNotNull(decoded) - decoded!! var sumR = 0 var sumG = 0 @@ -163,7 +157,7 @@ class ThumbHashTest { val hash = ThumbHashEncoder.encode(pixels, w, h) val ratio = ThumbHashDecoder.aspectRatio(hash) assertNotNull(ratio) - assertTrue(ratio!! > 1f, "landscape ratio should be > 1, got $ratio") + assertTrue(ratio > 1f, "landscape ratio should be > 1, got $ratio") } @Test @@ -174,7 +168,7 @@ class ThumbHashTest { val hash = ThumbHashEncoder.encode(pixels, w, h) val ratio = ThumbHashDecoder.aspectRatio(hash) assertNotNull(ratio) - assertTrue(ratio!! < 1f, "portrait ratio should be < 1, got $ratio") + assertTrue(ratio < 1f, "portrait ratio should be < 1, got $ratio") } @Test @@ -237,7 +231,6 @@ class ThumbHashTest { } val decoded = ThumbHashDecoder.decode(ThumbHashEncoder.encode(pixels, w, h)) assertNotNull(decoded) - decoded!! assertTrue( decoded.width in 1..32 && decoded.height in 1..32, "expected output to fit in 32x32, got ${decoded.width}x${decoded.height}", diff --git a/commons/src/commonTest/kotlin/com/vitorpamplona/amethyst/commons/model/nip05DnsIdentifiers/namecoin/NamecoinSettingsTest.kt b/commons/src/commonTest/kotlin/com/vitorpamplona/amethyst/commons/model/nip05DnsIdentifiers/namecoin/NamecoinSettingsTest.kt index 77a7b54748..1613e1c6ff 100644 --- a/commons/src/commonTest/kotlin/com/vitorpamplona/amethyst/commons/model/nip05DnsIdentifiers/namecoin/NamecoinSettingsTest.kt +++ b/commons/src/commonTest/kotlin/com/vitorpamplona/amethyst/commons/model/nip05DnsIdentifiers/namecoin/NamecoinSettingsTest.kt @@ -37,7 +37,7 @@ class NamecoinSettingsTest { fun `parses host colon port as TLS`() { val s = NamecoinSettings.parseServerString("example.com:50006") assertNotNull(s) - assertEquals("example.com", s!!.host) + assertEquals("example.com", s.host) assertEquals(50006, s.port) assertTrue(s.useSsl) } @@ -46,7 +46,7 @@ class NamecoinSettingsTest { fun `parses host colon port colon tcp as plaintext`() { val s = NamecoinSettings.parseServerString("example.com:50001:tcp") assertNotNull(s) - assertEquals("example.com", s!!.host) + assertEquals("example.com", s.host) assertEquals(50001, s.port) assertFalse(s.useSsl) } @@ -55,7 +55,7 @@ class NamecoinSettingsTest { fun `parses onion address`() { val s = NamecoinSettings.parseServerString("abc123def.onion:50001:tcp") assertNotNull(s) - assertEquals("abc123def.onion", s!!.host) + assertEquals("abc123def.onion", s.host) assertEquals(50001, s.port) assertFalse(s.useSsl) assertTrue(s.usePinnedTrustStore) @@ -65,7 +65,7 @@ class NamecoinSettingsTest { fun `trims whitespace`() { val s = NamecoinSettings.parseServerString(" example.com : 50006 ") assertNotNull(s) - assertEquals("example.com", s!!.host) + assertEquals("example.com", s.host) assertEquals(50006, s.port) } @@ -128,7 +128,7 @@ class NamecoinSettingsTest { ) val servers = settings.toElectrumxServers() assertNotNull(servers) - assertEquals(2, servers!!.size) + assertEquals(2, servers.size) assertEquals("server1.com", servers[0].host) assertTrue(servers[0].useSsl) assertEquals("server2.onion", servers[1].host) @@ -149,7 +149,7 @@ class NamecoinSettingsTest { ) val servers = settings.toElectrumxServers() assertNotNull(servers) - assertEquals(1, servers!!.size) + assertEquals(1, servers.size) assertEquals("valid.com", servers[0].host) } diff --git a/commons/src/iosMain/kotlin/com/vitorpamplona/amethyst/commons/threading/Threading.ios.kt b/commons/src/iosMain/kotlin/com/vitorpamplona/amethyst/commons/threading/Threading.ios.kt deleted file mode 100644 index 7eff5bb65b..0000000000 --- a/commons/src/iosMain/kotlin/com/vitorpamplona/amethyst/commons/threading/Threading.ios.kt +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2025 Vitor Pamplona - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to use, - * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the - * Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -package com.vitorpamplona.amethyst.commons.threading - -// Mirrors the jvmMain no-op. The iosApp module (Phase 3) can swap this for an -// `NSThread.isMainThread` check if iOS-specific main-thread restrictions need -// enforcement; today there are none. -actual fun checkNotInMainThread() { - // No-op -} diff --git a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/service/lnurl/LightningAddressResolver.kt b/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/service/lnurl/LightningAddressResolver.kt index c88762532a..55ef95738a 100644 --- a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/service/lnurl/LightningAddressResolver.kt +++ b/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/service/lnurl/LightningAddressResolver.kt @@ -193,7 +193,7 @@ class LightningAddressResolver( val request = Request.Builder().url(url).build() httpClient.newCall(request).execute().use { response -> if (response.isSuccessful) { - response.body?.string() + response.body.string() } else { null } @@ -224,7 +224,7 @@ class LightningAddressResolver( val request = Request.Builder().url(url).build() httpClient.newCall(request).execute().use { response -> // Return body even on error — caller extracts "reason" or "message" from JSON - response.body?.string() + response.body.string() } } catch (e: Exception) { if (e is CancellationException) throw e diff --git a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/service/lnurl/OkHttpLnurlEndpointResolver.kt b/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/service/lnurl/OkHttpLnurlEndpointResolver.kt index b9332d2470..86bd02a720 100644 --- a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/service/lnurl/OkHttpLnurlEndpointResolver.kt +++ b/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/service/lnurl/OkHttpLnurlEndpointResolver.kt @@ -60,7 +60,7 @@ class OkHttpLnurlEndpointResolver( val request = Request.Builder().url(url).build() client.newCall(request).execute().use { response -> if (!response.isSuccessful) return@use null - val body = response.body?.string() ?: return@use null + val body = response.body.string() val root = mapper.readTree(body) ?: return@use null LnurlEndpointInfo( nostrPubkey = root.get("nostrPubkey")?.asText()?.ifBlank { null }, diff --git a/commons/src/jvmMain/kotlin/com/vitorpamplona/amethyst/commons/service/upload/BlossomClient.kt b/commons/src/jvmMain/kotlin/com/vitorpamplona/amethyst/commons/service/upload/BlossomClient.kt index 2ce416f5fe..295165d7e5 100644 --- a/commons/src/jvmMain/kotlin/com/vitorpamplona/amethyst/commons/service/upload/BlossomClient.kt +++ b/commons/src/jvmMain/kotlin/com/vitorpamplona/amethyst/commons/service/upload/BlossomClient.kt @@ -76,8 +76,8 @@ open class BlossomClient( val reason = it.headers["X-Reason"] ?: it.code.toString() throw RuntimeException("Upload failed ($serverBaseUrl): $reason") } - val body = it.body ?: throw RuntimeException("Upload to $serverBaseUrl returned no body") - JsonMapper.fromJson(body.string()) + val body = it.body.string().ifBlank { throw RuntimeException("Upload to $serverBaseUrl returned no body") } + JsonMapper.fromJson(body) } } @@ -108,8 +108,8 @@ open class BlossomClient( val reason = it.headers["X-Reason"] ?: it.code.toString() throw RuntimeException("Upload failed ($serverBaseUrl): $reason") } - val body = it.body ?: throw RuntimeException("Upload to $serverBaseUrl returned no body") - JsonMapper.fromJson(body.string()) + val body = it.body.string().ifBlank { throw RuntimeException("Upload to $serverBaseUrl returned no body") } + JsonMapper.fromJson(body) } } } diff --git a/commons/src/jvmMain/kotlin/com/vitorpamplona/amethyst/commons/threading/Threading.jvm.kt b/commons/src/jvmMain/kotlin/com/vitorpamplona/amethyst/commons/threading/Threading.jvm.kt deleted file mode 100644 index 6e0dab73b8..0000000000 --- a/commons/src/jvmMain/kotlin/com/vitorpamplona/amethyst/commons/threading/Threading.jvm.kt +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2025 Vitor Pamplona - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to use, - * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the - * Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -package com.vitorpamplona.amethyst.commons.threading - -/** - * Desktop JVM implementation of checkNotInMainThread. - * Currently a no-op as Desktop Compose doesn't have the same main thread restrictions as Android. - * Could be enhanced to check Swing EDT if needed. - */ -actual fun checkNotInMainThread() { - // No-op for Desktop - different threading model - // Could check for Swing EDT with: javax.swing.SwingUtilities.isEventDispatchThread() - // but Compose Desktop doesn't have the same restrictions as Android -} diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/inlineMetadata/Nip54InlineMetadata.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/inlineMetadata/Nip54InlineMetadata.kt index 40ba19e9f7..99961214a9 100644 --- a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/inlineMetadata/Nip54InlineMetadata.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/inlineMetadata/Nip54InlineMetadata.kt @@ -43,8 +43,6 @@ class Nip54InlineMetadata { append(it.key) append("=") append(UrlEncoder.encode(value)) - } else { - null } } } diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/BirthdayTolerantSerializer.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/BirthdayTolerantSerializer.kt index 5e04867275..ce22d04127 100644 --- a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/BirthdayTolerantSerializer.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/BirthdayTolerantSerializer.kt @@ -21,6 +21,7 @@ package com.vitorpamplona.quartz.nip01Core.metadata import com.vitorpamplona.quartz.utils.Log +import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.KSerializer import kotlinx.serialization.descriptors.SerialDescriptor import kotlinx.serialization.descriptors.nullable @@ -73,6 +74,7 @@ object BirthdayTolerantSerializer : KSerializer { } } + @OptIn(ExperimentalSerializationApi::class) override fun serialize( encoder: Encoder, value: Birthday?, diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/pool/PoolCounts.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/pool/PoolCounts.kt index 75b8ff0a49..2d9a44ea31 100644 --- a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/pool/PoolCounts.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/pool/PoolCounts.kt @@ -109,8 +109,6 @@ class PoolCounts { val filters = filters[relay] if (!filters.isNullOrEmpty()) { sync(CountCmd(subId, filters)) - } else { - null } } } diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/pool/PoolRequests.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/pool/PoolRequests.kt index fce7019694..5bf4dff727 100644 --- a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/pool/PoolRequests.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/pool/PoolRequests.kt @@ -251,8 +251,6 @@ class PoolRequests { val filters = filters[relay] if (!filters.isNullOrEmpty()) { sync(ReqCmd(subId, filters)) - } else { - null } } } diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/definition/AppDefinitionEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/definition/AppDefinitionEvent.kt index 260ef53494..d2f4bc68dd 100644 --- a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/definition/AppDefinitionEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/definition/AppDefinitionEvent.kt @@ -81,7 +81,7 @@ class AppDefinitionEvent( fun includeKind(kind: Int) = tags.isTaggedKind(kind) - fun platformLinks() = tags.mapNotNull(PlatformLinkTag::parse) + fun platformLinks() = tags.platformLinks() override fun publishedAt(): Long? { val publishedAt = tags.firstNotNullOfOrNull(PublishedAtTag::parse) diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/definition/EventExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/definition/EventExt.kt deleted file mode 100644 index 6b6505ba6e..0000000000 --- a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/definition/EventExt.kt +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2025 Vitor Pamplona - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to use, - * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the - * Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -package com.vitorpamplona.quartz.nip89AppHandlers.definition - -fun AppDefinitionEvent.platformLinks() = tags.platformLinks()