Extract constants (#469)

* extract constants

* refactor constants
This commit is contained in:
callebtc
2025-10-12 20:59:37 +02:00
committed by GitHub
parent c61347defe
commit 1486121b77
27 changed files with 199 additions and 96 deletions
@@ -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
@@ -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
@@ -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
@@ -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?)
@@ -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]]
@@ -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)
@@ -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<String, PeerInfo>() // 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()
}
}
@@ -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 {
@@ -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
@@ -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
}
/**
@@ -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())
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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<String>()
@@ -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
@@ -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
@@ -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)
}
@@ -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
@@ -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<String> = emptyList()
)
}
@@ -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)
}
}
@@ -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)
}
@@ -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
@@ -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<String>())
private val recentSystemEvents = Collections.synchronizedMap(mutableMapOf<String, Long>())
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
@@ -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"
@@ -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(
@@ -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
}
}