fix(debug): Harden debug session recording and sharing

This commit is contained in:
darken
2026-03-09 16:39:56 +00:00
committed by Matthias Urhahn
parent 0cdd2a4f7a
commit 00083707c6
3 changed files with 21 additions and 15 deletions
@@ -15,6 +15,8 @@ import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.CancellationException
@@ -57,21 +59,20 @@ class DebugSessionManager @Inject constructor(
activeDir = recorderState.currentLogDir,
recordingStartedAt = recorderState.recordingStartedAt,
)
val overlaid = applyOverlays(raw, zipping, failedZips)
applyOverlays(raw, zipping, failedZips)
}.replayingShare(appScope)
val orphans = findOrphans(overlaid, zipping)
if (orphans.isNotEmpty()) {
orphans.forEach { (id, _) -> pendingAutoZips.add(id) }
appScope.launch {
orphans.forEach { (id, dir) ->
init {
sessions.onEach { allSessions ->
val orphans = findOrphans(allSessions, zippingIds.value)
orphans.forEach { (id, dir) ->
if (pendingAutoZips.add(id)) {
log(TAG, INFO) { "Orphan session detected, auto-zipping: $id" }
zipSessionAsync(id, dir)
}
}
}
overlaid
}.replayingShare(appScope)
}.launchIn(appScope)
}
private fun applyOverlays(
sessions: List<DebugSession>,
@@ -226,6 +227,7 @@ class DebugSessionManager @Inject constructor(
}
}
failedZipIds.update { emptySet() }
pendingAutoZips.clear()
log(TAG) { "All stored logs deleted" }
refresh()
}
@@ -76,7 +76,7 @@ class RecorderModule @Inject constructor(
recordingStartedAt = System.currentTimeMillis(),
)
} else if (!shouldRecord && isRecording) {
recorder!!.stop()
requireNotNull(recorder) { "Recorder is null despite isRecording" }.stop()
if (triggerFile.exists() && !triggerFile.delete()) {
log(TAG, ERROR) { "Failed to delete trigger file" }
@@ -133,7 +133,8 @@ class RecorderModule @Inject constructor(
internalState.updateBlocking {
copy(shouldRecord = true)
}
return internalState.flow.filter { it.isRecording }.first().currentLogDir!!
val state = internalState.flow.filter { it.isRecording }.first()
return requireNotNull(state.currentLogDir) { "Recording state has no logDir" }
}
suspend fun stopRecorder(): File? {
@@ -9,6 +9,7 @@ import eu.darken.capod.R
import eu.darken.capod.common.PrivacyPolicy
import eu.darken.capod.common.WebpageTool
import eu.darken.capod.common.coroutine.DispatcherProvider
import eu.darken.capod.common.debug.logging.Logging.Priority.WARN
import eu.darken.capod.common.debug.logging.log
import eu.darken.capod.common.debug.logging.logTag
import eu.darken.capod.common.debug.recording.core.DebugSession
@@ -132,8 +133,6 @@ class RecorderActivityVM @Inject constructor(
}
fun share() = launch {
val currentState = stater.flow.first()
val dir = currentState.logDir ?: return@launch
val sid = sessionId ?: return@launch
stater.updateBlocking { copy(isWorking = true) }
@@ -141,17 +140,21 @@ class RecorderActivityVM @Inject constructor(
try {
val uri = sessionManager.getZipUri(sid)
val displayName = stater.flow.first().logDir?.name ?: sid
val intent = Intent(Intent.ACTION_SEND).apply {
putExtra(Intent.EXTRA_STREAM, uri)
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
type = "application/zip"
addCategory(Intent.CATEGORY_DEFAULT)
putExtra(Intent.EXTRA_SUBJECT, "CAPod DebugLog - ${dir.name}")
putExtra(Intent.EXTRA_SUBJECT, "CAPod DebugLog - $displayName")
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
}
val chooserIntent = Intent.createChooser(intent, context.getString(R.string.support_debuglog_label))
events.tryEmit(Event.ShareIntent(chooserIntent))
} catch (e: Exception) {
log(TAG, WARN) { "Failed to share session $sid: ${e.message}" }
} finally {
stater.updateBlocking { copy(isWorking = false) }
}