From 6039e20879cacbbf8829f8c822ac3895c1bfb235 Mon Sep 17 00:00:00 2001 From: davotoula Date: Fri, 8 May 2026 07:38:55 +0200 Subject: [PATCH 1/3] reduce lint errors --- .../service/scheduledposts/ScheduledPostWorker.kt | 7 +++---- .../loggedIn/scheduledposts/ScheduledPostsScreen.kt | 11 +++++++---- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/scheduledposts/ScheduledPostWorker.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/scheduledposts/ScheduledPostWorker.kt index d32293035..f104116d0 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/scheduledposts/ScheduledPostWorker.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/scheduledposts/ScheduledPostWorker.kt @@ -198,15 +198,14 @@ class ScheduledPostWorker( ): Int { val deadline = System.currentTimeMillis() + OK_TIMEOUT_SEC * 1000 while (System.currentTimeMillis() < deadline) { - val pending = client.pendingPublishRelaysFor(eventId) // null means the outbox dropped the entry — every relay either OK'd // or hit the discard cap (replaced/pow/deleted/invalid). Treat as full ack. - if (pending == null) return totalRelays + val pending = client.pendingPublishRelaysFor(eventId) ?: return totalRelays val acked = totalRelays - pending.size if (acked > 0) return acked delay(OK_POLL_MS) } - val pending = client.pendingPublishRelaysFor(eventId) - return if (pending == null) totalRelays else totalRelays - pending.size + val pending = client.pendingPublishRelaysFor(eventId) ?: return totalRelays + return totalRelays - pending.size } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/scheduledposts/ScheduledPostsScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/scheduledposts/ScheduledPostsScreen.kt index ee383a362..26d972ac8 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/scheduledposts/ScheduledPostsScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/scheduledposts/ScheduledPostsScreen.kt @@ -66,6 +66,7 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.produceState import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -77,12 +78,11 @@ import androidx.compose.ui.geometry.Size import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.compositeOver -import androidx.compose.ui.platform.LocalClipboardManager +import androidx.compose.ui.platform.LocalClipboard import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.pluralStringResource import androidx.compose.ui.semantics.semantics -import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow @@ -97,6 +97,7 @@ import com.vitorpamplona.amethyst.service.scheduledposts.ScheduledPost import com.vitorpamplona.amethyst.service.scheduledposts.ScheduledPostStatus import com.vitorpamplona.amethyst.service.scheduledposts.ScheduledPostWorker import com.vitorpamplona.amethyst.ui.components.SwipeToDeleteWithConfirmation +import com.vitorpamplona.amethyst.ui.components.util.setText import com.vitorpamplona.amethyst.ui.navigation.navs.INav import com.vitorpamplona.amethyst.ui.navigation.routes.Route import com.vitorpamplona.amethyst.ui.navigation.topbars.ShorterTopAppBar @@ -107,6 +108,7 @@ import com.vitorpamplona.amethyst.ui.note.timeAheadNoDot import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.stringRes import kotlinx.coroutines.delay +import kotlinx.coroutines.launch import java.time.Instant import java.time.LocalDate import java.time.ZoneId @@ -373,7 +375,8 @@ private fun ScheduledPostCardExpandedPanel( onDelete: () -> Unit, ) { val context = LocalContext.current - val clipboard = LocalClipboardManager.current + val clipboardManager = LocalClipboard.current + val scope = rememberCoroutineScope() val eventId = remember(post.id) { extractEventId(post) } Column( @@ -410,7 +413,7 @@ private fun ScheduledPostCardExpandedPanel( .combinedClickable( onClick = {}, onLongClick = { - clipboard.setText(AnnotatedString(eventId)) + scope.launch { clipboardManager.setText(eventId) } Toast .makeText( context, From 9bdef97dd0806c405f277753df76e2b329773065 Mon Sep 17 00:00:00 2001 From: davotoula Date: Fri, 8 May 2026 09:02:50 +0200 Subject: [PATCH 2/3] Log when File.delete() fails in ScheduledPostStore.persist() --- .../service/scheduledposts/ScheduledPostStore.kt | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/scheduledposts/ScheduledPostStore.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/scheduledposts/ScheduledPostStore.kt index 325ad10ab..1f2a38614 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/scheduledposts/ScheduledPostStore.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/scheduledposts/ScheduledPostStore.kt @@ -253,15 +253,21 @@ class ScheduledPostStore( try { mapper.writeValue(tmp, ScheduledPostFile(version = 1, posts = snapshot)) if (!tmp.renameTo(storageFile)) { - storageFile.delete() + if (!storageFile.delete()) { + Log.w(TAG) { "Failed to delete existing $storageFile before rename retry" } + } if (!tmp.renameTo(storageFile)) { Log.e(TAG, "Failed to rename $tmp to $storageFile") - tmp.delete() + if (!tmp.delete()) { + Log.w(TAG) { "Failed to clean up temp file $tmp after rename failure" } + } } } } catch (e: Exception) { Log.e(TAG, "Failed to persist scheduled posts to $storageFile", e) - tmp.delete() + if (!tmp.delete()) { + Log.w(TAG) { "Failed to clean up temp file $tmp after persist exception" } + } } } From 9565411e3d2c5b01c133d7123d5fe8cf0a924372 Mon Sep 17 00:00:00 2001 From: davotoula Date: Fri, 8 May 2026 11:02:19 +0200 Subject: [PATCH 3/3] Extract UNSET_LABEL and ALPN_HQ_INTEROP constants in InteropClient --- .../quic/interop/runner/InteropClient.kt | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/quic/interop/src/main/kotlin/com/vitorpamplona/quic/interop/runner/InteropClient.kt b/quic/interop/src/main/kotlin/com/vitorpamplona/quic/interop/runner/InteropClient.kt index a2469c68d..0ef119cd7 100644 --- a/quic/interop/src/main/kotlin/com/vitorpamplona/quic/interop/runner/InteropClient.kt +++ b/quic/interop/src/main/kotlin/com/vitorpamplona/quic/interop/runner/InteropClient.kt @@ -56,6 +56,12 @@ private const val EXIT_OK = 0 private const val EXIT_FAIL = 1 private const val EXIT_UNSUPPORTED = 127 +// Sentinel rendered for null/empty env-var values in boot-line logging. +private const val UNSET_LABEL = "(unset)" + +// IANA ALPN identifier for HTTP/0.9-over-QUIC used by quic-interop-runner. +private const val ALPN_HQ_INTEROP = "hq-interop" + private const val HANDSHAKE_TIMEOUT_SEC = 10L // Multiconnect's per-iteration handshake timeout. The runner's @@ -120,11 +126,11 @@ fun main() { System.err.println( "[boot] DEBUG=1; writerDebugEnabled=true; build_id=" + "${com.vitorpamplona.quic.connection.WRITER_DEBUG_BUILD_ID}; " + - "TESTCASE=${System.getenv("TESTCASE") ?: "(unset)"}; " + - "ROLE=${System.getenv("ROLE") ?: "(unset)"}", + "TESTCASE=${System.getenv("TESTCASE") ?: UNSET_LABEL}; " + + "ROLE=${System.getenv("ROLE") ?: UNSET_LABEL}", ) } else { - System.err.println("[boot] DEBUG=${debugEnv ?: "(unset)"} writerDebugEnabled=false") + System.err.println("[boot] DEBUG=${debugEnv ?: UNSET_LABEL} writerDebugEnabled=false") } val role = System.getenv("ROLE") ?: "client" @@ -150,8 +156,8 @@ fun main() { System.err.println("testcase: $testcase") System.err.println("requests: $requests") System.err.println("downloads dir: ${downloadsDir.absolutePath} (exists=${downloadsDir.isDirectory})") - System.err.println("sslkeylogfile: ${keyLogPath ?: "(unset)"}") - System.err.println("qlogdir: ${qlogDir?.absolutePath ?: "(unset)"}") + System.err.println("sslkeylogfile: ${keyLogPath ?: UNSET_LABEL}") + System.err.println("qlogdir: ${qlogDir?.absolutePath ?: UNSET_LABEL}") } val cipherSuites = @@ -367,7 +373,7 @@ internal enum class Alpn( * on a fresh bidi stream, server returns the body, FIN both sides. No * control stream, no QPACK, no SETTINGS. Used for handshake / chacha20 / * transfer / loss-variant testcases. */ - HQ_INTEROP("hq-interop".encodeToByteArray()), + HQ_INTEROP(ALPN_HQ_INTEROP.encodeToByteArray()), } private fun runTransferTest( @@ -478,7 +484,7 @@ private fun runTransferTest( Http3GetClient(conn, driver).also { it.init(scope) } } - "hq-interop" -> { + ALPN_HQ_INTEROP -> { HqInteropGetClient(conn, driver) } @@ -934,7 +940,7 @@ private suspend fun runOneResumptionConnection( Http3GetClient(conn, driver).also { it.init(scope) } } - "hq-interop" -> { + ALPN_HQ_INTEROP -> { HqInteropGetClient(conn, driver) } @@ -1111,7 +1117,7 @@ private fun runMulticonnectTest( Http3GetClient(conn, driver).also { it.init(scope) } } - "hq-interop" -> { + ALPN_HQ_INTEROP -> { HqInteropGetClient(conn, driver) }