fix(android): sign initiator event handling to match Electron flow
Changes: - Add sign initiator handling for participant_joined events in MainViewModel - Add sign initiator handling for session_started events in MainViewModel - Add sign initiator handling for all_joined events in MainViewModel - Set pendingSessionId in TssRepository.createSignSession for event matching - Refactor initiateSignSession to wait for session_started instead of starting immediately - Add PendingSignInitiatorInfo data class to store pending sign info - Add sessionAlreadyInProgress flag to SignSessionResult for immediate trigger case This fixes the issue where sign initiator couldn't detect when other parties joined the signing session, making Android flow 100% consistent with Electron. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
fd56de5c00
commit
16e1e9159c
|
|
@ -554,7 +554,8 @@
|
|||
"Bash(\"/c/Users/dong/go/bin/go1.22.10.exe\" mod tidy)",
|
||||
"Bash(adb devices:*)",
|
||||
"Bash(adb logcat:*)",
|
||||
"Bash(git commit -m \"$\\(cat <<''EOF''\nfeat\\(android\\): add 5-minute polling timeout mechanism for keygen/sign\n\nImplements Electron''s checkAndTriggerKeygen\\(\\) polling fallback:\n- Adds polling every 2 seconds with 5-minute timeout\n- Triggers keygen/sign via synthetic session_started event on in_progress status\n- Handles gRPC stream disconnection when app goes to background\n- Shows timeout error in UI via existing error mechanism\n\n🤖 Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nEOF\n\\)\")"
|
||||
"Bash(git commit -m \"$\\(cat <<''EOF''\nfeat\\(android\\): add 5-minute polling timeout mechanism for keygen/sign\n\nImplements Electron''s checkAndTriggerKeygen\\(\\) polling fallback:\n- Adds polling every 2 seconds with 5-minute timeout\n- Triggers keygen/sign via synthetic session_started event on in_progress status\n- Handles gRPC stream disconnection when app goes to background\n- Shows timeout error in UI via existing error mechanism\n\n🤖 Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nEOF\n\\)\")",
|
||||
"Bash(go list:*)"
|
||||
],
|
||||
"deny": [],
|
||||
"ask": []
|
||||
|
|
|
|||
|
|
@ -2015,6 +2015,11 @@ class TssRepository @Inject constructor(
|
|||
)
|
||||
}
|
||||
|
||||
// CRITICAL: Set pendingSessionId BEFORE any async operations to avoid race condition
|
||||
// This ensures session events can be matched even if they arrive before other state is set
|
||||
pendingSessionId = sessionId
|
||||
android.util.Log.d("TssRepository", "[CO-SIGN] Set pendingSessionId=$sessionId for event matching (sign initiator)")
|
||||
|
||||
// Update session state with complete participant list
|
||||
// Use original keygen thresholdN (matching Electron's share.threshold_n)
|
||||
val session = TssSession(
|
||||
|
|
@ -2074,7 +2079,8 @@ class TssRepository @Inject constructor(
|
|||
|
||||
Result.success(SignSessionResult(
|
||||
sessionId = sessionId,
|
||||
inviteCode = inviteCode
|
||||
inviteCode = inviteCode,
|
||||
sessionAlreadyInProgress = sessionAlreadyInProgress
|
||||
))
|
||||
} catch (e: Exception) {
|
||||
android.util.Log.e("TssRepository", "[CO-SIGN] Create sign session failed", e)
|
||||
|
|
@ -2386,7 +2392,8 @@ data class CreateKeygenSessionResult(
|
|||
*/
|
||||
data class SignSessionResult(
|
||||
val sessionId: String,
|
||||
val inviteCode: String
|
||||
val inviteCode: String,
|
||||
val sessionAlreadyInProgress: Boolean = false
|
||||
)
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -332,10 +332,10 @@ class MainViewModel @Inject constructor(
|
|||
|
||||
when (event.eventType) {
|
||||
"session_started" -> {
|
||||
// Check if this is for initiator (CreateWallet)
|
||||
// Check if this is for keygen initiator (CreateWallet)
|
||||
val currentSessionId = _currentSessionId.value
|
||||
if (currentSessionId != null && event.sessionId == currentSessionId) {
|
||||
android.util.Log.d("MainViewModel", "Session started event for initiator, triggering keygen")
|
||||
android.util.Log.d("MainViewModel", "Session started event for keygen initiator, triggering keygen")
|
||||
viewModelScope.launch {
|
||||
startKeygenAsInitiator(
|
||||
sessionId = currentSessionId,
|
||||
|
|
@ -359,6 +359,13 @@ class MainViewModel @Inject constructor(
|
|||
android.util.Log.d("MainViewModel", "Session started event for sign joiner, triggering sign")
|
||||
startSignAsJoiner()
|
||||
}
|
||||
|
||||
// Check if this is for sign initiator (TransferScreen - 发起签名)
|
||||
val signSessionId = _signSessionId.value
|
||||
if (signSessionId != null && event.sessionId == signSessionId) {
|
||||
android.util.Log.d("MainViewModel", "Session started event for sign initiator, triggering sign")
|
||||
startSignAsInitiator(event.selectedParties)
|
||||
}
|
||||
}
|
||||
"party_joined", "participant_joined" -> {
|
||||
android.util.Log.d("MainViewModel", "Processing participant_joined event...")
|
||||
|
|
@ -395,6 +402,18 @@ class MainViewModel @Inject constructor(
|
|||
current + newParticipant
|
||||
}
|
||||
}
|
||||
|
||||
// Update participant count for sign initiator's TransferScreen (SigningScreen)
|
||||
val signSessionId = _signSessionId.value
|
||||
android.util.Log.d("MainViewModel", " Checking for sign initiator: signSessionId=$signSessionId, eventSessionId=${event.sessionId}")
|
||||
if (signSessionId != null && event.sessionId == signSessionId) {
|
||||
android.util.Log.d("MainViewModel", " → Matched sign initiator session! Updating _signParticipants")
|
||||
_signParticipants.update { current ->
|
||||
val newParticipant = "参与方 ${current.size + 1}"
|
||||
android.util.Log.d("MainViewModel", " → Adding participant: $newParticipant, total now: ${current.size + 1}")
|
||||
current + newParticipant
|
||||
}
|
||||
}
|
||||
}
|
||||
"all_joined" -> {
|
||||
android.util.Log.d("MainViewModel", "All parties joined, starting session status polling as fallback")
|
||||
|
|
@ -405,6 +424,7 @@ class MainViewModel @Inject constructor(
|
|||
val currentSessionId = _currentSessionId.value
|
||||
val joinKeygenInfo = pendingJoinKeygenInfo
|
||||
val joinSignInfo = pendingJoinSignInfo
|
||||
val signSessionId = _signSessionId.value
|
||||
|
||||
when {
|
||||
// Initiator keygen session
|
||||
|
|
@ -417,11 +437,16 @@ class MainViewModel @Inject constructor(
|
|||
android.util.Log.d("MainViewModel", "Starting polling for joiner keygen session: ${joinKeygenInfo.sessionId}")
|
||||
repository.startSessionStatusPolling(joinKeygenInfo.sessionId, "keygen")
|
||||
}
|
||||
// Sign session
|
||||
// Sign joiner session
|
||||
joinSignInfo != null && event.sessionId == joinSignInfo.sessionId -> {
|
||||
android.util.Log.d("MainViewModel", "Starting polling for sign session: ${joinSignInfo.sessionId}")
|
||||
android.util.Log.d("MainViewModel", "Starting polling for sign joiner session: ${joinSignInfo.sessionId}")
|
||||
repository.startSessionStatusPolling(joinSignInfo.sessionId, "sign")
|
||||
}
|
||||
// Sign initiator session
|
||||
signSessionId != null && event.sessionId == signSessionId -> {
|
||||
android.util.Log.d("MainViewModel", "Starting polling for sign initiator session: $signSessionId")
|
||||
repository.startSessionStatusPolling(signSessionId, "sign")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1118,8 +1143,13 @@ class MainViewModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
// Store pending sign initiator info for when session_started event arrives
|
||||
private var pendingSignInitiatorInfo: PendingSignInitiatorInfo? = null
|
||||
|
||||
/**
|
||||
* Create sign session and start signing
|
||||
* Create sign session and wait for other participants
|
||||
* Matches Electron's cosign:createSession - does NOT start signing immediately
|
||||
* Signing is triggered when session_started event is received (via startSignAsInitiator)
|
||||
*/
|
||||
fun initiateSignSession(shareId: Long, password: String, initiatorName: String = "发起者") {
|
||||
viewModelScope.launch {
|
||||
|
|
@ -1145,8 +1175,22 @@ class MainViewModel @Inject constructor(
|
|||
_signParticipants.value = listOf(initiatorName)
|
||||
_uiState.update { it.copy(isLoading = false) }
|
||||
|
||||
// Start signing process
|
||||
startSigningProcess(sessionResult.sessionId, shareId, password)
|
||||
// Store pending info for when session_started event arrives
|
||||
// Matching Electron's behavior: don't start signing until session_started
|
||||
pendingSignInitiatorInfo = PendingSignInitiatorInfo(
|
||||
sessionId = sessionResult.sessionId,
|
||||
shareId = shareId,
|
||||
password = password
|
||||
)
|
||||
|
||||
android.util.Log.d("MainViewModel", "Sign session created, waiting for participants. sessionId=${sessionResult.sessionId}")
|
||||
|
||||
// Check if session already in_progress (all parties already joined)
|
||||
// This matches Electron's immediate trigger when status === 'in_progress'
|
||||
if (sessionResult.sessionAlreadyInProgress) {
|
||||
android.util.Log.d("MainViewModel", "Session already in_progress, triggering sign immediately")
|
||||
startSigningProcess(sessionResult.sessionId, shareId, password)
|
||||
}
|
||||
},
|
||||
onFailure = { e ->
|
||||
_uiState.update { it.copy(isLoading = false, error = e.message) }
|
||||
|
|
@ -1155,6 +1199,21 @@ class MainViewModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start sign as initiator (called when session_started event is received)
|
||||
* Matches Electron's handleCoSignStart for initiator
|
||||
*/
|
||||
private fun startSignAsInitiator(selectedParties: List<String>) {
|
||||
val info = pendingSignInitiatorInfo
|
||||
if (info == null) {
|
||||
android.util.Log.w("MainViewModel", "startSignAsInitiator called but no pending info")
|
||||
return
|
||||
}
|
||||
|
||||
android.util.Log.d("MainViewModel", "Starting sign as initiator: sessionId=${info.sessionId}, selectedParties=$selectedParties")
|
||||
startSigningProcess(info.sessionId, info.shareId, info.password)
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the TSS signing process
|
||||
*/
|
||||
|
|
@ -1223,6 +1282,9 @@ class MainViewModel @Inject constructor(
|
|||
_signCurrentRound.value = 0
|
||||
_signature.value = null
|
||||
_txHash.value = null
|
||||
pendingSignInitiatorInfo = null
|
||||
// Reset session status to WAITING for fresh start
|
||||
repository.resetSessionStatus()
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1336,3 +1398,13 @@ data class PendingJoinSignInfo(
|
|||
val shareId: Long,
|
||||
val password: String
|
||||
)
|
||||
|
||||
/**
|
||||
* Pending sign initiator info (stored when creating sign session, waiting for session_started)
|
||||
* Matches Electron's activeCoSignSession for initiator
|
||||
*/
|
||||
data class PendingSignInitiatorInfo(
|
||||
val sessionId: String,
|
||||
val shareId: Long,
|
||||
val password: String
|
||||
)
|
||||
|
|
|
|||
Loading…
Reference in New Issue