Merge remote-tracking branch 'refs/remotes/origin/master'
This commit is contained in:
@@ -69,6 +69,9 @@ class Protocol(
|
||||
private var lastPublicKey: String? = null
|
||||
private var lastPrivateHash: String? = null
|
||||
|
||||
// Heartbeat
|
||||
private var heartbeatJob: Job? = null
|
||||
|
||||
// Supported packets
|
||||
private val supportedPackets = mapOf(
|
||||
0x00 to { PacketHandshake() },
|
||||
@@ -92,6 +95,30 @@ class Protocol(
|
||||
handshakeComplete = true
|
||||
_state.value = ProtocolState.AUTHENTICATED
|
||||
flushPacketQueue()
|
||||
|
||||
// Start heartbeat with interval from server
|
||||
startHeartbeat(packet.heartbeatInterval)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start heartbeat to keep connection alive
|
||||
*/
|
||||
private fun startHeartbeat(intervalSeconds: Int) {
|
||||
heartbeatJob?.cancel()
|
||||
|
||||
val intervalMs = (intervalSeconds * 1000L) / 2 // Send at half the interval
|
||||
log("💓 Starting heartbeat with interval: ${intervalSeconds}s (sending every ${intervalMs}ms)")
|
||||
|
||||
heartbeatJob = scope.launch {
|
||||
while (isActive) {
|
||||
delay(intervalMs)
|
||||
if (webSocket?.send("heartbeat") == true) {
|
||||
log("💓 Heartbeat sent")
|
||||
} else {
|
||||
log("💔 Heartbeat failed to send")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -100,13 +127,19 @@ class Protocol(
|
||||
* Initialize connection to server
|
||||
*/
|
||||
fun connect() {
|
||||
if (_state.value == ProtocolState.CONNECTING || _state.value == ProtocolState.CONNECTED) {
|
||||
log("Already connecting or connected")
|
||||
if (_state.value == ProtocolState.CONNECTING) {
|
||||
log("Already connecting, skipping...")
|
||||
return
|
||||
}
|
||||
|
||||
// Allow reconnection even if connected (for manual reconnect)
|
||||
if (_state.value == ProtocolState.CONNECTED || _state.value == ProtocolState.AUTHENTICATED) {
|
||||
log("Already connected/authenticated, skipping...")
|
||||
return
|
||||
}
|
||||
|
||||
isManuallyClosed = false
|
||||
reconnectAttempts = 0 // Reset reconnect attempts on new connection
|
||||
// Don't reset reconnectAttempts here - it's reset on successful connection in onOpen
|
||||
_state.value = ProtocolState.CONNECTING
|
||||
_lastError.value = null
|
||||
|
||||
@@ -266,6 +299,7 @@ class Protocol(
|
||||
_state.value = ProtocolState.DISCONNECTED
|
||||
handshakeComplete = false
|
||||
handshakeJob?.cancel()
|
||||
heartbeatJob?.cancel()
|
||||
|
||||
if (!isManuallyClosed && reconnectAttempts < MAX_RECONNECT_ATTEMPTS) {
|
||||
reconnectAttempts++
|
||||
@@ -302,6 +336,7 @@ class Protocol(
|
||||
log("Disconnecting...")
|
||||
isManuallyClosed = true
|
||||
handshakeJob?.cancel()
|
||||
heartbeatJob?.cancel()
|
||||
webSocket?.close(1000, "User disconnected")
|
||||
webSocket = null
|
||||
_state.value = ProtocolState.DISCONNECTED
|
||||
@@ -332,6 +367,7 @@ class Protocol(
|
||||
*/
|
||||
fun destroy() {
|
||||
disconnect()
|
||||
heartbeatJob?.cancel()
|
||||
scope.cancel()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -175,7 +175,13 @@ class AuthStateManager(
|
||||
|
||||
loadAccounts()
|
||||
|
||||
// Step 8: Authenticate with protocol
|
||||
// Step 8: Connect and authenticate with protocol
|
||||
Log.d(TAG, "🌐 Connecting to protocol server...")
|
||||
ProtocolManager.connect()
|
||||
|
||||
// Give WebSocket time to connect before authenticating
|
||||
kotlinx.coroutines.delay(500)
|
||||
|
||||
Log.d(TAG, "🌐 Authenticating with protocol server...")
|
||||
ProtocolManager.authenticate(keyPair.publicKey, privateKeyHash)
|
||||
|
||||
@@ -236,7 +242,13 @@ class AuthStateManager(
|
||||
status = AuthStatus.Authenticated(decryptedAccount)
|
||||
)}
|
||||
|
||||
// Authenticate with protocol
|
||||
// Connect and authenticate with protocol
|
||||
Log.d(TAG, "🌐 Connecting to protocol server...")
|
||||
ProtocolManager.connect()
|
||||
|
||||
// Give WebSocket time to connect before authenticating
|
||||
kotlinx.coroutines.delay(500)
|
||||
|
||||
Log.d(TAG, "🌐 Authenticating with protocol server...")
|
||||
ProtocolManager.authenticate(decryptedAccount.publicKey, decryptedAccount.privateKeyHash)
|
||||
|
||||
|
||||
@@ -130,7 +130,7 @@ fun AuthFlow(
|
||||
currentScreen = AuthScreen.CONFIRM_SEED
|
||||
}
|
||||
},
|
||||
onAccountCreated = { onAuthComplete(null) }
|
||||
onAccountCreated = { account -> onAuthComplete(account) }
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.rosetta.messenger.crypto.CryptoManager
|
||||
import com.rosetta.messenger.data.AccountManager
|
||||
import com.rosetta.messenger.data.DecryptedAccount
|
||||
import com.rosetta.messenger.data.EncryptedAccount
|
||||
import com.rosetta.messenger.network.ProtocolManager
|
||||
import com.rosetta.messenger.ui.onboarding.PrimaryBlue
|
||||
@@ -38,7 +39,7 @@ fun SetPasswordScreen(
|
||||
seedPhrase: List<String>,
|
||||
isDarkTheme: Boolean,
|
||||
onBack: () -> Unit,
|
||||
onAccountCreated: () -> Unit
|
||||
onAccountCreated: (DecryptedAccount) -> Unit
|
||||
) {
|
||||
val themeAnimSpec = tween<Color>(durationMillis = 500, easing = CubicBezierEasing(0.4f, 0f, 0.2f, 1f))
|
||||
val backgroundColor by animateColorAsState(if (isDarkTheme) AuthBackground else AuthBackgroundLight, animationSpec = themeAnimSpec)
|
||||
@@ -497,9 +498,21 @@ fun SetPasswordScreen(
|
||||
// 🔌 Connect to server and authenticate
|
||||
val privateKeyHash = CryptoManager.generatePrivateKeyHash(keyPair.privateKey)
|
||||
Log.d("SetPasswordScreen", "🔌 Connecting to server...")
|
||||
ProtocolManager.connect()
|
||||
// Give WebSocket time to connect before authenticating
|
||||
kotlinx.coroutines.delay(500)
|
||||
ProtocolManager.authenticate(keyPair.publicKey, privateKeyHash)
|
||||
|
||||
onAccountCreated()
|
||||
// Create DecryptedAccount to pass to callback
|
||||
val decryptedAccount = DecryptedAccount(
|
||||
publicKey = keyPair.publicKey,
|
||||
privateKey = keyPair.privateKey,
|
||||
seedPhrase = seedPhrase,
|
||||
privateKeyHash = privateKeyHash,
|
||||
name = truncatedKey
|
||||
)
|
||||
|
||||
onAccountCreated(decryptedAccount)
|
||||
} catch (e: Exception) {
|
||||
error = "Failed to create account: ${e.message}"
|
||||
isCreating = false
|
||||
|
||||
@@ -581,6 +581,9 @@ fun UnlockScreen(
|
||||
|
||||
// Connect to server and authenticate
|
||||
Log.d("UnlockScreen", "Connecting to server...")
|
||||
ProtocolManager.connect()
|
||||
// Give WebSocket time to connect before authenticating
|
||||
kotlinx.coroutines.delay(500)
|
||||
ProtocolManager.authenticate(account.publicKey, privateKeyHash)
|
||||
|
||||
accountManager.setCurrentAccount(account.publicKey)
|
||||
|
||||
Reference in New Issue
Block a user