From 1486121b77c2f067aaf55d27a6e07372ba735ab6 Mon Sep 17 00:00:00 2001 From: callebtc <93376500+callebtc@users.noreply.github.com> Date: Sun, 12 Oct 2025 20:59:37 +0200 Subject: [PATCH] Extract constants (#469) * extract constants * refactor constants --- .../mesh/BluetoothConnectionTracker.kt | 8 +- .../mesh/BluetoothGattClientManager.kt | 2 +- .../android/mesh/BluetoothMeshService.kt | 6 +- .../mesh/BluetoothPacketBroadcaster.kt | 2 +- .../bitchat/android/mesh/FragmentManager.kt | 8 +- .../bitchat/android/mesh/MessageHandler.kt | 26 ++-- .../com/bitchat/android/mesh/PeerManager.kt | 5 +- .../com/bitchat/android/mesh/PowerManager.kt | 24 ++-- .../bitchat/android/mesh/SecurityManager.kt | 8 +- .../android/mesh/StoreForwardManager.kt | 8 +- .../com/bitchat/android/net/TorManager.kt | 10 +- .../android/noise/NoiseEncryptionService.kt | 4 +- .../com/bitchat/android/noise/NoiseSession.kt | 8 +- .../android/nostr/NostrEmbeddedBitChat.kt | 8 +- .../android/nostr/NostrEventDeduplicator.kt | 2 +- .../android/nostr/NostrRelayManager.kt | 10 +- .../bitchat/android/nostr/NostrTransport.kt | 2 +- .../android/protocol/BinaryProtocol.kt | 2 +- .../android/protocol/CompressionUtil.kt | 2 +- .../android/services/SeenMessageStore.kt | 3 +- .../bitchat/android/sync/GossipSyncManager.kt | 17 ++- .../com/bitchat/android/ui/ChatUIConstants.kt | 5 +- .../bitchat/android/ui/MediaSendingManager.kt | 2 +- .../com/bitchat/android/ui/MessageManager.kt | 4 +- .../bitchat/android/ui/NotificationManager.kt | 2 +- .../bitchat/android/ui/theme/Typography.kt | 2 +- .../com/bitchat/android/util/AppConstants.kt | 115 +++++++++++++++++- 27 files changed, 199 insertions(+), 96 deletions(-) diff --git a/app/src/main/java/com/bitchat/android/mesh/BluetoothConnectionTracker.kt b/app/src/main/java/com/bitchat/android/mesh/BluetoothConnectionTracker.kt index 3494d1b2..0f0bdd86 100644 --- a/app/src/main/java/com/bitchat/android/mesh/BluetoothConnectionTracker.kt +++ b/app/src/main/java/com/bitchat/android/mesh/BluetoothConnectionTracker.kt @@ -20,10 +20,10 @@ class BluetoothConnectionTracker( companion object { private const val TAG = "BluetoothConnectionTracker" - private const val CONNECTION_RETRY_DELAY = 5000L - private const val MAX_CONNECTION_ATTEMPTS = 3 - private const val CLEANUP_DELAY = 500L - private const val CLEANUP_INTERVAL = 30000L // 30 seconds + private const val CONNECTION_RETRY_DELAY = com.bitchat.android.util.AppConstants.Mesh.CONNECTION_RETRY_DELAY_MS + private const val MAX_CONNECTION_ATTEMPTS = com.bitchat.android.util.AppConstants.Mesh.MAX_CONNECTION_ATTEMPTS + private const val CLEANUP_DELAY = com.bitchat.android.util.AppConstants.Mesh.CONNECTION_CLEANUP_DELAY_MS + private const val CLEANUP_INTERVAL = com.bitchat.android.util.AppConstants.Mesh.CONNECTION_CLEANUP_INTERVAL_MS // 30 seconds } // Connection tracking - reduced memory footprint diff --git a/app/src/main/java/com/bitchat/android/mesh/BluetoothGattClientManager.kt b/app/src/main/java/com/bitchat/android/mesh/BluetoothGattClientManager.kt index bd36c8ce..f263b068 100644 --- a/app/src/main/java/com/bitchat/android/mesh/BluetoothGattClientManager.kt +++ b/app/src/main/java/com/bitchat/android/mesh/BluetoothGattClientManager.kt @@ -37,7 +37,7 @@ class BluetoothGattClientManager( private val DESCRIPTOR_UUID = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb") // RSSI monitoring constants - private const val RSSI_UPDATE_INTERVAL = 5000L // 5 seconds + private const val RSSI_UPDATE_INTERVAL = com.bitchat.android.util.AppConstants.Mesh.RSSI_UPDATE_INTERVAL_MS // 5 seconds } // Core Bluetooth components diff --git a/app/src/main/java/com/bitchat/android/mesh/BluetoothMeshService.kt b/app/src/main/java/com/bitchat/android/mesh/BluetoothMeshService.kt index 98d7a622..56c640df 100644 --- a/app/src/main/java/com/bitchat/android/mesh/BluetoothMeshService.kt +++ b/app/src/main/java/com/bitchat/android/mesh/BluetoothMeshService.kt @@ -36,7 +36,7 @@ class BluetoothMeshService(private val context: Context) { companion object { private const val TAG = "BluetoothMeshService" - private const val MAX_TTL: UByte = 7u + private val MAX_TTL: UByte = com.bitchat.android.util.AppConstants.MESSAGE_TTL_HOPS } // Core components - each handling specific responsibilities @@ -694,7 +694,7 @@ class BluetoothMeshService(private val context: Context) { timestamp = System.currentTimeMillis().toULong(), payload = encrypted, signature = null, - ttl = 7u + ttl = com.bitchat.android.util.AppConstants.MESSAGE_TTL_HOPS ) // Sign and send the encrypted packet @@ -840,7 +840,7 @@ class BluetoothMeshService(private val context: Context) { timestamp = System.currentTimeMillis().toULong(), payload = encrypted, signature = null, - ttl = 7u // Same TTL as iOS messageTTL + ttl = com.bitchat.android.util.AppConstants.MESSAGE_TTL_HOPS // Same TTL as iOS messageTTL ) // Sign the packet before broadcasting diff --git a/app/src/main/java/com/bitchat/android/mesh/BluetoothPacketBroadcaster.kt b/app/src/main/java/com/bitchat/android/mesh/BluetoothPacketBroadcaster.kt index 5110279d..b3474217 100644 --- a/app/src/main/java/com/bitchat/android/mesh/BluetoothPacketBroadcaster.kt +++ b/app/src/main/java/com/bitchat/android/mesh/BluetoothPacketBroadcaster.kt @@ -47,7 +47,7 @@ class BluetoothPacketBroadcaster( companion object { private const val TAG = "BluetoothPacketBroadcaster" - private const val CLEANUP_DELAY = 500L + private const val CLEANUP_DELAY = com.bitchat.android.util.AppConstants.Mesh.BROADCAST_CLEANUP_DELAY_MS } // Optional nickname resolver injected by higher layer (peerID -> nickname?) diff --git a/app/src/main/java/com/bitchat/android/mesh/FragmentManager.kt b/app/src/main/java/com/bitchat/android/mesh/FragmentManager.kt index 4ab5f45f..714aedb2 100644 --- a/app/src/main/java/com/bitchat/android/mesh/FragmentManager.kt +++ b/app/src/main/java/com/bitchat/android/mesh/FragmentManager.kt @@ -22,10 +22,10 @@ class FragmentManager { companion object { private const val TAG = "FragmentManager" // iOS values: 512 MTU threshold, 469 max fragment size (512 MTU - headers) - private const val FRAGMENT_SIZE_THRESHOLD = 512 // Matches iOS: if data.count > 512 - private const val MAX_FRAGMENT_SIZE = 469 // Matches iOS: maxFragmentSize = 469 - private const val FRAGMENT_TIMEOUT = 30000L // Matches iOS: 30 seconds cleanup - private const val CLEANUP_INTERVAL = 10000L // 10 seconds cleanup check + private const val FRAGMENT_SIZE_THRESHOLD = com.bitchat.android.util.AppConstants.Fragmentation.FRAGMENT_SIZE_THRESHOLD // Matches iOS: if data.count > 512 + private const val MAX_FRAGMENT_SIZE = com.bitchat.android.util.AppConstants.Fragmentation.MAX_FRAGMENT_SIZE // Matches iOS: maxFragmentSize = 469 + private const val FRAGMENT_TIMEOUT = com.bitchat.android.util.AppConstants.Fragmentation.FRAGMENT_TIMEOUT_MS // Matches iOS: 30 seconds cleanup + private const val CLEANUP_INTERVAL = com.bitchat.android.util.AppConstants.Fragmentation.CLEANUP_INTERVAL_MS // 10 seconds cleanup check } // Fragment storage - iOS equivalent: incomingFragments: [String: [Int: Data]] diff --git a/app/src/main/java/com/bitchat/android/mesh/MessageHandler.kt b/app/src/main/java/com/bitchat/android/mesh/MessageHandler.kt index 98bb7fd8..d016dd37 100644 --- a/app/src/main/java/com/bitchat/android/mesh/MessageHandler.kt +++ b/app/src/main/java/com/bitchat/android/mesh/MessageHandler.kt @@ -183,16 +183,16 @@ class MessageHandler(private val myPeerID: String, private val appContext: andro } // Create NOISE_ENCRYPTED packet exactly like iOS - val packet = BitchatPacket( - version = 1u, - type = MessageType.NOISE_ENCRYPTED.value, - senderID = hexStringToByteArray(myPeerID), - recipientID = hexStringToByteArray(senderPeerID), - timestamp = System.currentTimeMillis().toULong(), - payload = encryptedPayload, - signature = null, - ttl = 7u // Same TTL as iOS messageTTL - ) + val packet = BitchatPacket( + version = 1u, + type = MessageType.NOISE_ENCRYPTED.value, + senderID = hexStringToByteArray(myPeerID), + recipientID = hexStringToByteArray(senderPeerID), + timestamp = System.currentTimeMillis().toULong(), + payload = encryptedPayload, + signature = null, + ttl = com.bitchat.android.util.AppConstants.MESSAGE_TTL_HOPS // Same TTL as iOS messageTTL + ) delegate?.sendPacket(packet) Log.d(TAG, "📤 Sent delivery ACK to $senderPeerID for message $messageID") @@ -214,8 +214,8 @@ class MessageHandler(private val myPeerID: String, private val appContext: andro // Ignore stale announcements older than STALE_PEER_TIMEOUT val now = System.currentTimeMillis() val age = now - packet.timestamp.toLong() - if (age > com.bitchat.android.util.AppConstants.STALE_PEER_TIMEOUT_MS) { - Log.w(TAG, "Ignoring stale ANNOUNCE from ${peerID.take(8)} (age=${age}ms > ${com.bitchat.android.util.AppConstants.STALE_PEER_TIMEOUT_MS}ms)") + if (age > com.bitchat.android.util.AppConstants.Mesh.STALE_PEER_TIMEOUT_MS) { + Log.w(TAG, "Ignoring stale ANNOUNCE from ${peerID.take(8)} (age=${age}ms > ${com.bitchat.android.util.AppConstants.Mesh.STALE_PEER_TIMEOUT_MS}ms)") return false } @@ -318,7 +318,7 @@ class MessageHandler(private val myPeerID: String, private val appContext: andro timestamp = System.currentTimeMillis().toULong(), payload = response, signature = null, - ttl = 7u // Same TTL as iOS + ttl = com.bitchat.android.util.AppConstants.MESSAGE_TTL_HOPS // Same TTL as iOS ) delegate?.sendPacket(responsePacket) diff --git a/app/src/main/java/com/bitchat/android/mesh/PeerManager.kt b/app/src/main/java/com/bitchat/android/mesh/PeerManager.kt index d61beee0..4c279d4a 100644 --- a/app/src/main/java/com/bitchat/android/mesh/PeerManager.kt +++ b/app/src/main/java/com/bitchat/android/mesh/PeerManager.kt @@ -67,11 +67,10 @@ class PeerManager { companion object { private const val TAG = "PeerManager" - private const val CLEANUP_INTERVAL = 60000L // 1 minute } // Centralized timeout from AppConstants - private val stalePeerTimeoutMs: Long = com.bitchat.android.util.AppConstants.STALE_PEER_TIMEOUT_MS + private val stalePeerTimeoutMs: Long = com.bitchat.android.util.AppConstants.Mesh.STALE_PEER_TIMEOUT_MS // Peer tracking data - enhanced with verification status private val peers = ConcurrentHashMap() // peerID -> PeerInfo @@ -416,7 +415,7 @@ class PeerManager { private fun startPeriodicCleanup() { managerScope.launch { while (isActive) { - delay(CLEANUP_INTERVAL) + delay(com.bitchat.android.util.AppConstants.Mesh.PEER_CLEANUP_INTERVAL_MS) cleanupStalePeers() } } diff --git a/app/src/main/java/com/bitchat/android/mesh/PowerManager.kt b/app/src/main/java/com/bitchat/android/mesh/PowerManager.kt index 5b974575..9db444e6 100644 --- a/app/src/main/java/com/bitchat/android/mesh/PowerManager.kt +++ b/app/src/main/java/com/bitchat/android/mesh/PowerManager.kt @@ -21,22 +21,22 @@ class PowerManager(private val context: Context) { private const val TAG = "PowerManager" // Battery thresholds - private const val CRITICAL_BATTERY = 10 - private const val LOW_BATTERY = 20 - private const val MEDIUM_BATTERY = 50 + private const val CRITICAL_BATTERY = com.bitchat.android.util.AppConstants.Power.CRITICAL_BATTERY_PERCENT + private const val LOW_BATTERY = com.bitchat.android.util.AppConstants.Power.LOW_BATTERY_PERCENT + private const val MEDIUM_BATTERY = com.bitchat.android.util.AppConstants.Power.MEDIUM_BATTERY_PERCENT // Scan duty cycle periods (ms) - private const val SCAN_ON_DURATION_NORMAL = 8000L // 8 seconds on - private const val SCAN_OFF_DURATION_NORMAL = 2000L // 2 seconds off - private const val SCAN_ON_DURATION_POWER_SAVE = 2000L // 2 seconds on - private const val SCAN_OFF_DURATION_POWER_SAVE = 8000L // 8 seconds off - private const val SCAN_ON_DURATION_ULTRA_LOW = 1000L // 1 second on - private const val SCAN_OFF_DURATION_ULTRA_LOW = 10000L // 10 seconds off + private const val SCAN_ON_DURATION_NORMAL = com.bitchat.android.util.AppConstants.Power.SCAN_ON_DURATION_NORMAL_MS // 8 seconds on + private const val SCAN_OFF_DURATION_NORMAL = com.bitchat.android.util.AppConstants.Power.SCAN_OFF_DURATION_NORMAL_MS // 2 seconds off + private const val SCAN_ON_DURATION_POWER_SAVE = com.bitchat.android.util.AppConstants.Power.SCAN_ON_DURATION_POWER_SAVE_MS // 2 seconds on + private const val SCAN_OFF_DURATION_POWER_SAVE = com.bitchat.android.util.AppConstants.Power.SCAN_OFF_DURATION_POWER_SAVE_MS // 8 seconds off + private const val SCAN_ON_DURATION_ULTRA_LOW = com.bitchat.android.util.AppConstants.Power.SCAN_ON_DURATION_ULTRA_LOW_MS // 1 second on + private const val SCAN_OFF_DURATION_ULTRA_LOW = com.bitchat.android.util.AppConstants.Power.SCAN_OFF_DURATION_ULTRA_LOW_MS // 10 seconds off // Connection limits - private const val MAX_CONNECTIONS_NORMAL = 8 - private const val MAX_CONNECTIONS_POWER_SAVE = 4 - private const val MAX_CONNECTIONS_ULTRA_LOW = 2 + private const val MAX_CONNECTIONS_NORMAL = com.bitchat.android.util.AppConstants.Power.MAX_CONNECTIONS_NORMAL + private const val MAX_CONNECTIONS_POWER_SAVE = com.bitchat.android.util.AppConstants.Power.MAX_CONNECTIONS_POWER_SAVE + private const val MAX_CONNECTIONS_ULTRA_LOW = com.bitchat.android.util.AppConstants.Power.MAX_CONNECTIONS_ULTRA_LOW } enum class PowerMode { diff --git a/app/src/main/java/com/bitchat/android/mesh/SecurityManager.kt b/app/src/main/java/com/bitchat/android/mesh/SecurityManager.kt index 42f6e356..476ead73 100644 --- a/app/src/main/java/com/bitchat/android/mesh/SecurityManager.kt +++ b/app/src/main/java/com/bitchat/android/mesh/SecurityManager.kt @@ -19,10 +19,10 @@ class SecurityManager(private val encryptionService: EncryptionService, private companion object { private const val TAG = "SecurityManager" - private const val MESSAGE_TIMEOUT = 300000L // 5 minutes (same as iOS) - private const val CLEANUP_INTERVAL = 300000L // 5 minutes - private const val MAX_PROCESSED_MESSAGES = 10000 - private const val MAX_PROCESSED_KEY_EXCHANGES = 1000 + private const val MESSAGE_TIMEOUT = com.bitchat.android.util.AppConstants.Security.MESSAGE_TIMEOUT_MS // 5 minutes (same as iOS) + private const val CLEANUP_INTERVAL = com.bitchat.android.util.AppConstants.Security.CLEANUP_INTERVAL_MS // 5 minutes + private const val MAX_PROCESSED_MESSAGES = com.bitchat.android.util.AppConstants.Security.MAX_PROCESSED_MESSAGES + private const val MAX_PROCESSED_KEY_EXCHANGES = com.bitchat.android.util.AppConstants.Security.MAX_PROCESSED_KEY_EXCHANGES } // Security tracking diff --git a/app/src/main/java/com/bitchat/android/mesh/StoreForwardManager.kt b/app/src/main/java/com/bitchat/android/mesh/StoreForwardManager.kt index 98830bea..d9dd18d0 100644 --- a/app/src/main/java/com/bitchat/android/mesh/StoreForwardManager.kt +++ b/app/src/main/java/com/bitchat/android/mesh/StoreForwardManager.kt @@ -16,10 +16,10 @@ class StoreForwardManager { companion object { private const val TAG = "StoreForwardManager" - private const val MESSAGE_CACHE_TIMEOUT = 43200000L // 12 hours for regular peers - private const val MAX_CACHED_MESSAGES = 100 // For regular peers - private const val MAX_CACHED_MESSAGES_FAVORITES = 1000 // For favorites - private const val CLEANUP_INTERVAL = 600000L // 10 minutes + private const val MESSAGE_CACHE_TIMEOUT = com.bitchat.android.util.AppConstants.StoreForward.MESSAGE_CACHE_TIMEOUT_MS // 12 hours for regular peers + private const val MAX_CACHED_MESSAGES = com.bitchat.android.util.AppConstants.StoreForward.MAX_CACHED_MESSAGES // For regular peers + private const val MAX_CACHED_MESSAGES_FAVORITES = com.bitchat.android.util.AppConstants.StoreForward.MAX_CACHED_MESSAGES_FAVORITES // For favorites + private const val CLEANUP_INTERVAL = com.bitchat.android.util.AppConstants.StoreForward.CLEANUP_INTERVAL_MS // 10 minutes } /** diff --git a/app/src/main/java/com/bitchat/android/net/TorManager.kt b/app/src/main/java/com/bitchat/android/net/TorManager.kt index 4acebf73..b7c2230d 100644 --- a/app/src/main/java/com/bitchat/android/net/TorManager.kt +++ b/app/src/main/java/com/bitchat/android/net/TorManager.kt @@ -29,11 +29,11 @@ import java.util.concurrent.atomic.AtomicLong */ object TorManager { private const val TAG = "TorManager" - private const val DEFAULT_SOCKS_PORT = 9060 - private const val RESTART_DELAY_MS = 2000L // 2 seconds between stop/start - private const val INACTIVITY_TIMEOUT_MS = 5000L // 5 seconds of no activity before restart - private const val MAX_RETRY_ATTEMPTS = 5 - private const val STOP_TIMEOUT_MS = 7000L + private const val DEFAULT_SOCKS_PORT = com.bitchat.android.util.AppConstants.Tor.DEFAULT_SOCKS_PORT + private const val RESTART_DELAY_MS = com.bitchat.android.util.AppConstants.Tor.RESTART_DELAY_MS // 2 seconds between stop/start + private const val INACTIVITY_TIMEOUT_MS = com.bitchat.android.util.AppConstants.Tor.INACTIVITY_TIMEOUT_MS // 5 seconds of no activity before restart + private const val MAX_RETRY_ATTEMPTS = com.bitchat.android.util.AppConstants.Tor.MAX_RETRY_ATTEMPTS + private const val STOP_TIMEOUT_MS = com.bitchat.android.util.AppConstants.Tor.STOP_TIMEOUT_MS private val appScope = CoroutineScope(Dispatchers.IO + SupervisorJob()) diff --git a/app/src/main/java/com/bitchat/android/noise/NoiseEncryptionService.kt b/app/src/main/java/com/bitchat/android/noise/NoiseEncryptionService.kt index a3d469be..f9e969d3 100644 --- a/app/src/main/java/com/bitchat/android/noise/NoiseEncryptionService.kt +++ b/app/src/main/java/com/bitchat/android/noise/NoiseEncryptionService.kt @@ -24,8 +24,8 @@ class NoiseEncryptionService(private val context: Context) { private const val TAG = "NoiseEncryptionService" // Session limits for performance and security - private const val REKEY_TIME_LIMIT = 3600000L // 1 hour (same as iOS) - private const val REKEY_MESSAGE_LIMIT = 1000L // 1k messages (matches iOS) (same as iOS) + private const val REKEY_TIME_LIMIT = com.bitchat.android.util.AppConstants.Noise.REKEY_TIME_LIMIT_MS // 1 hour (same as iOS) + private const val REKEY_MESSAGE_LIMIT = com.bitchat.android.util.AppConstants.Noise.REKEY_MESSAGE_LIMIT_ENCRYPTION // 1k messages (matches iOS) (same as iOS) } // Static identity key (persistent across app restarts) - loaded from secure storage diff --git a/app/src/main/java/com/bitchat/android/noise/NoiseSession.kt b/app/src/main/java/com/bitchat/android/noise/NoiseSession.kt index b9760a14..dc4a3d50 100644 --- a/app/src/main/java/com/bitchat/android/noise/NoiseSession.kt +++ b/app/src/main/java/com/bitchat/android/noise/NoiseSession.kt @@ -25,8 +25,8 @@ class NoiseSession( private const val PROTOCOL_NAME = "Noise_XX_25519_ChaChaPoly_SHA256" // Rekey thresholds (same as iOS) - private const val REKEY_TIME_LIMIT = 3600000L // 1 hour - private const val REKEY_MESSAGE_LIMIT = 10000L // 10k messages + private const val REKEY_TIME_LIMIT = com.bitchat.android.util.AppConstants.Noise.REKEY_TIME_LIMIT_MS // 1 hour + private const val REKEY_MESSAGE_LIMIT = com.bitchat.android.util.AppConstants.Noise.REKEY_MESSAGE_LIMIT_SESSION // 10k messages // XX Pattern Message Sizes (exactly matching iOS implementation) private const val XX_MESSAGE_1_SIZE = 32 // -> e (ephemeral key only) @@ -34,13 +34,13 @@ class NoiseSession( private const val XX_MESSAGE_3_SIZE = 48 // -> s, se (encrypted static key) // Maximum payload size for safety - private const val MAX_PAYLOAD_SIZE = 256 + private const val MAX_PAYLOAD_SIZE = com.bitchat.android.util.AppConstants.Noise.MAX_PAYLOAD_SIZE_BYTES // Constants for replay protection (matching iOS implementation) private const val NONCE_SIZE_BYTES = 4 private const val REPLAY_WINDOW_SIZE = 1024 private const val REPLAY_WINDOW_BYTES = REPLAY_WINDOW_SIZE / 8 // 128 bytes - private const val HIGH_NONCE_WARNING_THRESHOLD = 1_000_000_000L + private const val HIGH_NONCE_WARNING_THRESHOLD = com.bitchat.android.util.AppConstants.Noise.HIGH_NONCE_WARNING_THRESHOLD // MARK: - Sliding Window Replay Protection diff --git a/app/src/main/java/com/bitchat/android/nostr/NostrEmbeddedBitChat.kt b/app/src/main/java/com/bitchat/android/nostr/NostrEmbeddedBitChat.kt index 968bec16..3f70bbb7 100644 --- a/app/src/main/java/com/bitchat/android/nostr/NostrEmbeddedBitChat.kt +++ b/app/src/main/java/com/bitchat/android/nostr/NostrEmbeddedBitChat.kt @@ -46,7 +46,7 @@ object NostrEmbeddedBitChat { timestamp = System.currentTimeMillis().toULong(), payload = payload, signature = null, - ttl = 7u + ttl = com.bitchat.android.util.AppConstants.MESSAGE_TTL_HOPS ) val data = packet.toBinaryData() ?: return null @@ -86,7 +86,7 @@ object NostrEmbeddedBitChat { timestamp = System.currentTimeMillis().toULong(), payload = payload, signature = null, - ttl = 7u + ttl = com.bitchat.android.util.AppConstants.MESSAGE_TTL_HOPS ) val data = packet.toBinaryData() ?: return null @@ -123,7 +123,7 @@ object NostrEmbeddedBitChat { timestamp = System.currentTimeMillis().toULong(), payload = payload, signature = null, - ttl = 7u + ttl = com.bitchat.android.util.AppConstants.MESSAGE_TTL_HOPS ) val data = packet.toBinaryData() ?: return null @@ -158,7 +158,7 @@ object NostrEmbeddedBitChat { timestamp = System.currentTimeMillis().toULong(), payload = payload, signature = null, - ttl = 7u + ttl = com.bitchat.android.util.AppConstants.MESSAGE_TTL_HOPS ) val data = packet.toBinaryData() ?: return null diff --git a/app/src/main/java/com/bitchat/android/nostr/NostrEventDeduplicator.kt b/app/src/main/java/com/bitchat/android/nostr/NostrEventDeduplicator.kt index ca54462d..0638eafd 100644 --- a/app/src/main/java/com/bitchat/android/nostr/NostrEventDeduplicator.kt +++ b/app/src/main/java/com/bitchat/android/nostr/NostrEventDeduplicator.kt @@ -22,7 +22,7 @@ class NostrEventDeduplicator( ) { companion object { private const val TAG = "NostrDeduplicator" - private const val DEFAULT_CAPACITY = 10000 + private const val DEFAULT_CAPACITY = com.bitchat.android.util.AppConstants.Nostr.DEFAULT_DEDUP_CAPACITY @Volatile private var INSTANCE: NostrEventDeduplicator? = null diff --git a/app/src/main/java/com/bitchat/android/nostr/NostrRelayManager.kt b/app/src/main/java/com/bitchat/android/nostr/NostrRelayManager.kt index ace6e57b..eb5806bb 100644 --- a/app/src/main/java/com/bitchat/android/nostr/NostrRelayManager.kt +++ b/app/src/main/java/com/bitchat/android/nostr/NostrRelayManager.kt @@ -41,10 +41,10 @@ class NostrRelayManager private constructor() { ) // Exponential backoff configuration (same as iOS) - private const val INITIAL_BACKOFF_INTERVAL = 1000L // 1 second - private const val MAX_BACKOFF_INTERVAL = 300000L // 5 minutes - private const val BACKOFF_MULTIPLIER = 2.0 - private const val MAX_RECONNECT_ATTEMPTS = 10 + private const val INITIAL_BACKOFF_INTERVAL = com.bitchat.android.util.AppConstants.Nostr.INITIAL_BACKOFF_INTERVAL_MS // 1 second + private const val MAX_BACKOFF_INTERVAL = com.bitchat.android.util.AppConstants.Nostr.MAX_BACKOFF_INTERVAL_MS // 5 minutes + private const val BACKOFF_MULTIPLIER = com.bitchat.android.util.AppConstants.Nostr.BACKOFF_MULTIPLIER + private const val MAX_RECONNECT_ATTEMPTS = com.bitchat.android.util.AppConstants.Nostr.MAX_RECONNECT_ATTEMPTS // Track gift-wraps we initiated for logging private val pendingGiftWrapIDs = ConcurrentHashMap.newKeySet() @@ -111,7 +111,7 @@ class NostrRelayManager private constructor() { // Subscription validation timer private var subscriptionValidationJob: Job? = null - private val SUBSCRIPTION_VALIDATION_INTERVAL = 30000L // 30 seconds + private val SUBSCRIPTION_VALIDATION_INTERVAL = com.bitchat.android.util.AppConstants.Nostr.SUBSCRIPTION_VALIDATION_INTERVAL_MS // 30 seconds // OkHttp client for WebSocket connections (via provider to honor Tor) private val httpClient: OkHttpClient diff --git a/app/src/main/java/com/bitchat/android/nostr/NostrTransport.kt b/app/src/main/java/com/bitchat/android/nostr/NostrTransport.kt index a7c49818..26ba8369 100644 --- a/app/src/main/java/com/bitchat/android/nostr/NostrTransport.kt +++ b/app/src/main/java/com/bitchat/android/nostr/NostrTransport.kt @@ -19,7 +19,7 @@ class NostrTransport( companion object { private const val TAG = "NostrTransport" - private const val READ_ACK_INTERVAL = 350L // ~3 per second (0.35s interval like iOS) + private const val READ_ACK_INTERVAL = com.bitchat.android.util.AppConstants.Nostr.READ_ACK_INTERVAL_MS // ~3 per second (0.35s interval like iOS) @Volatile private var INSTANCE: NostrTransport? = null diff --git a/app/src/main/java/com/bitchat/android/protocol/BinaryProtocol.kt b/app/src/main/java/com/bitchat/android/protocol/BinaryProtocol.kt index 692d9513..2d15b86e 100644 --- a/app/src/main/java/com/bitchat/android/protocol/BinaryProtocol.kt +++ b/app/src/main/java/com/bitchat/android/protocol/BinaryProtocol.kt @@ -97,7 +97,7 @@ data class BitchatPacket( timestamp = timestamp, payload = payload, signature = null, // Remove signature for signing - ttl = 0u // Use fixed TTL=0 for signing to ensure relay compatibility + ttl = com.bitchat.android.util.AppConstants.SYNC_TTL_HOPS // Use fixed TTL=0 for signing to ensure relay compatibility ) return BinaryProtocol.encode(unsignedPacket) } diff --git a/app/src/main/java/com/bitchat/android/protocol/CompressionUtil.kt b/app/src/main/java/com/bitchat/android/protocol/CompressionUtil.kt index d6096e10..e8b59254 100644 --- a/app/src/main/java/com/bitchat/android/protocol/CompressionUtil.kt +++ b/app/src/main/java/com/bitchat/android/protocol/CompressionUtil.kt @@ -10,7 +10,7 @@ import java.util.zip.Inflater * Uses the same zlib algorithm as iOS CompressionUtil.swift */ object CompressionUtil { - private const val COMPRESSION_THRESHOLD = 100 // bytes - same as iOS + private const val COMPRESSION_THRESHOLD = com.bitchat.android.util.AppConstants.Protocol.COMPRESSION_THRESHOLD_BYTES // bytes - same as iOS /** * Helper to check if compression is worth it - exact same logic as iOS diff --git a/app/src/main/java/com/bitchat/android/services/SeenMessageStore.kt b/app/src/main/java/com/bitchat/android/services/SeenMessageStore.kt index 469525d7..a6cd2378 100644 --- a/app/src/main/java/com/bitchat/android/services/SeenMessageStore.kt +++ b/app/src/main/java/com/bitchat/android/services/SeenMessageStore.kt @@ -13,7 +13,7 @@ class SeenMessageStore private constructor(private val context: Context) { companion object { private const val TAG = "SeenMessageStore" private const val STORAGE_KEY = "seen_message_store_v1" - private const val MAX_IDS = 10_000 + private const val MAX_IDS = com.bitchat.android.util.AppConstants.Services.SEEN_MESSAGE_MAX_IDS @Volatile private var INSTANCE: SeenMessageStore? = null fun getInstance(appContext: Context): SeenMessageStore { @@ -86,4 +86,3 @@ class SeenMessageStore private constructor(private val context: Context) { val read: List = emptyList() ) } - diff --git a/app/src/main/java/com/bitchat/android/sync/GossipSyncManager.kt b/app/src/main/java/com/bitchat/android/sync/GossipSyncManager.kt index 05601bfc..6e29aa79 100644 --- a/app/src/main/java/com/bitchat/android/sync/GossipSyncManager.kt +++ b/app/src/main/java/com/bitchat/android/sync/GossipSyncManager.kt @@ -33,7 +33,6 @@ class GossipSyncManager( companion object { private const val TAG = "GossipSyncManager" - private const val CLEANUP_INTERVAL = 60_000L // 1 minute } var delegate: Delegate? = null @@ -67,7 +66,7 @@ class GossipSyncManager( cleanupJob = scope.launch(Dispatchers.IO) { while (isActive) { try { - delay(CLEANUP_INTERVAL) + delay(com.bitchat.android.util.AppConstants.Sync.CLEANUP_INTERVAL_MS) pruneStaleAnnouncements() } catch (e: CancellationException) { throw e } catch (e: Exception) { Log.e(TAG, "Periodic cleanup error: ${e.message}") } @@ -118,8 +117,8 @@ class GossipSyncManager( // Ignore stale announcements older than STALE_PEER_TIMEOUT val now = System.currentTimeMillis() val age = now - packet.timestamp.toLong() - if (age > com.bitchat.android.util.AppConstants.STALE_PEER_TIMEOUT_MS) { - Log.d(TAG, "Ignoring stale ANNOUNCE (age=${age}ms > ${com.bitchat.android.util.AppConstants.STALE_PEER_TIMEOUT_MS}ms)") + if (age > com.bitchat.android.util.AppConstants.Mesh.STALE_PEER_TIMEOUT_MS) { + Log.d(TAG, "Ignoring stale ANNOUNCE (age=${age}ms > ${com.bitchat.android.util.AppConstants.Mesh.STALE_PEER_TIMEOUT_MS}ms)") return } // senderID is fixed-size 8 bytes; map to hex string for key @@ -142,7 +141,7 @@ class GossipSyncManager( senderID = hexStringToByteArray(myPeerID), timestamp = System.currentTimeMillis().toULong(), payload = payload, - ttl = 0u // neighbors only + ttl = com.bitchat.android.util.AppConstants.SYNC_TTL_HOPS // neighbors only ) // Sign and broadcast val signed = delegate?.signPacketForBroadcast(packet) ?: packet @@ -158,7 +157,7 @@ class GossipSyncManager( recipientID = hexStringToByteArray(peerID), timestamp = System.currentTimeMillis().toULong(), payload = payload, - ttl = 0u // neighbor only + ttl = com.bitchat.android.util.AppConstants.SYNC_TTL_HOPS // neighbor only ) Log.d(TAG, "Sending sync request to $peerID (${payload.size} bytes)") // Sign and send directly to peer @@ -186,7 +185,7 @@ class GossipSyncManager( val idBytes = hexToBytes(id) if (!mightContain(idBytes)) { // Send original packet unchanged to requester only (keep local TTL) - val toSend = pkt.copy(ttl = 0u) + val toSend = pkt.copy(ttl = com.bitchat.android.util.AppConstants.SYNC_TTL_HOPS) delegate?.sendPacketToPeer(fromPeerID, toSend) Log.d(TAG, "Sent sync announce: Type ${toSend.type} from ${toSend.senderID.toHexString()} to $fromPeerID packet id ${idBytes.toHexString()}") } @@ -197,7 +196,7 @@ class GossipSyncManager( for (pkt in toSendMsgs) { val idBytes = PacketIdUtil.computeIdBytes(pkt) if (!mightContain(idBytes)) { - val toSend = pkt.copy(ttl = 0u) + val toSend = pkt.copy(ttl = com.bitchat.android.util.AppConstants.SYNC_TTL_HOPS) delegate?.sendPacketToPeer(fromPeerID, toSend) Log.d(TAG, "Sent sync message: Type ${toSend.type} to $fromPeerID packet id ${idBytes.toHexString()}") } @@ -268,7 +267,7 @@ class GossipSyncManager( for ((peerID, pair) in latestAnnouncementByPeer.entries) { val pkt = pair.second val age = now - pkt.timestamp.toLong() - if (age > com.bitchat.android.util.AppConstants.STALE_PEER_TIMEOUT_MS) { + if (age > com.bitchat.android.util.AppConstants.Mesh.STALE_PEER_TIMEOUT_MS) { stalePeers.add(peerID) } } diff --git a/app/src/main/java/com/bitchat/android/ui/ChatUIConstants.kt b/app/src/main/java/com/bitchat/android/ui/ChatUIConstants.kt index 30f9a894..f00d650e 100644 --- a/app/src/main/java/com/bitchat/android/ui/ChatUIConstants.kt +++ b/app/src/main/java/com/bitchat/android/ui/ChatUIConstants.kt @@ -3,10 +3,7 @@ package com.bitchat.android.ui /** * UI constants/utilities for nickname rendering. */ -const val MAX_NICKNAME_LENGTH: Int = 15 - -fun truncateNickname(name: String, maxLen: Int = MAX_NICKNAME_LENGTH): String { +fun truncateNickname(name: String, maxLen: Int = com.bitchat.android.util.AppConstants.UI.MAX_NICKNAME_LENGTH): String { return if (name.length <= maxLen) name else name.take(maxLen) } - diff --git a/app/src/main/java/com/bitchat/android/ui/MediaSendingManager.kt b/app/src/main/java/com/bitchat/android/ui/MediaSendingManager.kt index e9befa4e..0a6be528 100644 --- a/app/src/main/java/com/bitchat/android/ui/MediaSendingManager.kt +++ b/app/src/main/java/com/bitchat/android/ui/MediaSendingManager.kt @@ -20,7 +20,7 @@ class MediaSendingManager( ) { companion object { private const val TAG = "MediaSendingManager" - private const val MAX_FILE_SIZE = 50 * 1024 * 1024 // 50MB limit + private const val MAX_FILE_SIZE = com.bitchat.android.util.AppConstants.Media.MAX_FILE_SIZE_BYTES // 50MB limit } // Track in-flight transfer progress: transferId -> messageId and reverse diff --git a/app/src/main/java/com/bitchat/android/ui/MessageManager.kt b/app/src/main/java/com/bitchat/android/ui/MessageManager.kt index 75d6b7a2..f35689e7 100644 --- a/app/src/main/java/com/bitchat/android/ui/MessageManager.kt +++ b/app/src/main/java/com/bitchat/android/ui/MessageManager.kt @@ -13,8 +13,8 @@ class MessageManager(private val state: ChatState) { // Message deduplication - FIXED: Prevent duplicate messages from dual connection paths private val processedUIMessages = Collections.synchronizedSet(mutableSetOf()) private val recentSystemEvents = Collections.synchronizedMap(mutableMapOf()) - private val MESSAGE_DEDUP_TIMEOUT = 30000L // 30 seconds - private val SYSTEM_EVENT_DEDUP_TIMEOUT = 5000L // 5 seconds + private val MESSAGE_DEDUP_TIMEOUT = com.bitchat.android.util.AppConstants.UI.MESSAGE_DEDUP_TIMEOUT_MS // 30 seconds + private val SYSTEM_EVENT_DEDUP_TIMEOUT = com.bitchat.android.util.AppConstants.UI.SYSTEM_EVENT_DEDUP_TIMEOUT_MS // 5 seconds // MARK: - Public Message Management diff --git a/app/src/main/java/com/bitchat/android/ui/NotificationManager.kt b/app/src/main/java/com/bitchat/android/ui/NotificationManager.kt index 11a90fdb..622800ca 100644 --- a/app/src/main/java/com/bitchat/android/ui/NotificationManager.kt +++ b/app/src/main/java/com/bitchat/android/ui/NotificationManager.kt @@ -42,7 +42,7 @@ class NotificationManager( private const val SUMMARY_NOTIFICATION_ID = 999 private const val GEOHASH_SUMMARY_NOTIFICATION_ID = 998 private const val ACTIVE_PEERS_NOTIFICATION_ID = 997 - private const val ACTIVE_PEERS_NOTIFICATION_TIME_INTERVAL = 300_000L + private const val ACTIVE_PEERS_NOTIFICATION_TIME_INTERVAL = com.bitchat.android.util.AppConstants.UI.ACTIVE_PEERS_NOTIFICATION_INTERVAL_MS // Intent extras for notification handling const val EXTRA_OPEN_PRIVATE_CHAT = "open_private_chat" diff --git a/app/src/main/java/com/bitchat/android/ui/theme/Typography.kt b/app/src/main/java/com/bitchat/android/ui/theme/Typography.kt index 04a0b14c..a8c68a4b 100644 --- a/app/src/main/java/com/bitchat/android/ui/theme/Typography.kt +++ b/app/src/main/java/com/bitchat/android/ui/theme/Typography.kt @@ -7,7 +7,7 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.sp // Base font size for consistent scaling across the app -const val BASE_FONT_SIZE = 15 // sp - increased from 14sp for better readability +internal const val BASE_FONT_SIZE = com.bitchat.android.util.AppConstants.UI.BASE_FONT_SIZE_SP // sp - increased from 14sp for better readability // Typography matching the iOS monospace design - using BASE_FONT_SIZE for consistency val Typography = Typography( diff --git a/app/src/main/java/com/bitchat/android/util/AppConstants.kt b/app/src/main/java/com/bitchat/android/util/AppConstants.kt index 18c8e269..ce396b9a 100644 --- a/app/src/main/java/com/bitchat/android/util/AppConstants.kt +++ b/app/src/main/java/com/bitchat/android/util/AppConstants.kt @@ -4,7 +4,116 @@ package com.bitchat.android.util * Centralized application-wide constants. */ object AppConstants { - // Peer staleness threshold (ms). Keep consistent across mesh and sync layers. - const val STALE_PEER_TIMEOUT_MS: Long = 180_000L // 3 minutes -} + // Packet time-to-live (hops) + val MESSAGE_TTL_HOPS: UByte = 7u // Default TTL for regular packets + val SYNC_TTL_HOPS: UByte = 0u // TTL for neighbor-only sync packets + object Mesh { + // Peer lifecycle + const val STALE_PEER_TIMEOUT_MS: Long = 180_000L // 3 minutes + const val PEER_CLEANUP_INTERVAL_MS: Long = 60_000L + + // BLE connection tracking + const val CONNECTION_RETRY_DELAY_MS: Long = 5_000L + const val MAX_CONNECTION_ATTEMPTS: Int = 3 + const val CONNECTION_CLEANUP_DELAY_MS: Long = 500L + const val CONNECTION_CLEANUP_INTERVAL_MS: Long = 30_000L + const val BROADCAST_CLEANUP_DELAY_MS: Long = 500L + + // GATT client RSSI updates + const val RSSI_UPDATE_INTERVAL_MS: Long = 5_000L + } + + object Sync { + const val CLEANUP_INTERVAL_MS: Long = 60_000L + } + + object Fragmentation { + const val FRAGMENT_SIZE_THRESHOLD: Int = 512 + const val MAX_FRAGMENT_SIZE: Int = 469 + const val FRAGMENT_TIMEOUT_MS: Long = 30_000L + const val CLEANUP_INTERVAL_MS: Long = 10_000L + } + + object Security { + const val MESSAGE_TIMEOUT_MS: Long = 300_000L + const val CLEANUP_INTERVAL_MS: Long = 300_000L + const val MAX_PROCESSED_MESSAGES: Int = 10_000 + const val MAX_PROCESSED_KEY_EXCHANGES: Int = 1_000 + } + + object Noise { + const val REKEY_TIME_LIMIT_MS: Long = 3_600_000L // 1 hour + const val REKEY_MESSAGE_LIMIT_ENCRYPTION: Long = 1_000L // per session, encryption service policy + const val REKEY_MESSAGE_LIMIT_SESSION: Long = 10_000L // session-level ceiling + const val MAX_PAYLOAD_SIZE_BYTES: Int = 256 + const val HIGH_NONCE_WARNING_THRESHOLD: Long = 1_000_000_000L + } + + object Protocol { + const val COMPRESSION_THRESHOLD_BYTES: Int = 100 + } + + object StoreForward { + const val MESSAGE_CACHE_TIMEOUT_MS: Long = 43_200_000L // 12h + const val MAX_CACHED_MESSAGES: Int = 100 + const val MAX_CACHED_MESSAGES_FAVORITES: Int = 1_000 + const val CLEANUP_INTERVAL_MS: Long = 600_000L + } + + object Power { + const val CRITICAL_BATTERY_PERCENT: Int = 10 + const val LOW_BATTERY_PERCENT: Int = 20 + const val MEDIUM_BATTERY_PERCENT: Int = 50 + const val SCAN_ON_DURATION_NORMAL_MS: Long = 8_000L + const val SCAN_OFF_DURATION_NORMAL_MS: Long = 2_000L + const val SCAN_ON_DURATION_POWER_SAVE_MS: Long = 2_000L + const val SCAN_OFF_DURATION_POWER_SAVE_MS: Long = 8_000L + const val SCAN_ON_DURATION_ULTRA_LOW_MS: Long = 1_000L + const val SCAN_OFF_DURATION_ULTRA_LOW_MS: Long = 10_000L + const val MAX_CONNECTIONS_NORMAL: Int = 8 + const val MAX_CONNECTIONS_POWER_SAVE: Int = 4 + const val MAX_CONNECTIONS_ULTRA_LOW: Int = 2 + } + + object Nostr { + // Relay backoff + const val INITIAL_BACKOFF_INTERVAL_MS: Long = 1_000L + const val MAX_BACKOFF_INTERVAL_MS: Long = 300_000L + const val BACKOFF_MULTIPLIER: Double = 2.0 + const val MAX_RECONNECT_ATTEMPTS: Int = 10 + + // Transport + const val READ_ACK_INTERVAL_MS: Long = 350L + + // Deduplicator + const val DEFAULT_DEDUP_CAPACITY: Int = 10_000 + + // Relay subscription validation + const val SUBSCRIPTION_VALIDATION_INTERVAL_MS: Long = 30_000L + } + + object Tor { + const val DEFAULT_SOCKS_PORT: Int = 9060 + const val RESTART_DELAY_MS: Long = 2_000L + const val INACTIVITY_TIMEOUT_MS: Long = 5_000L + const val MAX_RETRY_ATTEMPTS: Int = 5 + const val STOP_TIMEOUT_MS: Long = 7_000L + } + + object UI { + const val MAX_NICKNAME_LENGTH: Int = 15 + const val BASE_FONT_SIZE_SP: Int = 15 + const val MESSAGE_DEDUP_TIMEOUT_MS: Long = 30_000L + const val SYSTEM_EVENT_DEDUP_TIMEOUT_MS: Long = 5_000L + const val ACTIVE_PEERS_NOTIFICATION_INTERVAL_MS: Long = 300_000L + } + + object Media { + const val MAX_FILE_SIZE_BYTES: Long = 50L * 1024 * 1024 + } + + object Services { + const val SEEN_MESSAGE_MAX_IDS: Int = 10_000 + } +}