Files
bitchat-android/app/src/main/java/com/bitchat/android/model/DeliveryAck.kt
T
callebtcandGitHub 565e4ab33c Fix delivery acks and read receipts (#186)
* delivery ack and read receipt

* handle deliveryack

* fix uppercase id

* fix read receipts too
2025-07-25 17:54:12 +02:00

107 lines
3.4 KiB
Kotlin

package com.bitchat.android.model
import android.os.Parcelable
import kotlinx.parcelize.Parcelize
import com.bitchat.android.util.*
import java.util.*
/**
* Delivery acknowledgment structure - exact same as iOS version
* Uses binary encoding for efficient protocol communication
*/
@Parcelize
data class DeliveryAck(
val originalMessageID: String,
val ackID: String = UUID.randomUUID().toString(),
val recipientID: String,
val recipientNickname: String,
val timestamp: Date = Date(),
val hopCount: UByte
) : Parcelable {
// Primary constructor for creating new acks
constructor(originalMessageID: String, recipientID: String, recipientNickname: String, hopCount: UByte) : this(
originalMessageID = originalMessageID,
ackID = UUID.randomUUID().toString(),
recipientID = recipientID,
recipientNickname = recipientNickname,
timestamp = Date(),
hopCount = hopCount
)
/**
* Encode to binary data matching iOS toBinaryData implementation
*/
fun encode(): ByteArray {
val builder = BinaryDataBuilder()
// Append original message UUID
builder.appendUUID(originalMessageID)
// Append ack ID UUID
builder.appendUUID(ackID)
// Append recipient ID as 8-byte hex string
val recipientData = ByteArray(8) { 0 }
var tempID = recipientID
var index = 0
while (tempID.length >= 2 && index < 8) {
val hexByte = tempID.substring(0, 2)
val byte = hexByte.toIntOrNull(16)?.toByte()
if (byte != null) {
recipientData[index] = byte
}
tempID = tempID.substring(2)
index++
}
builder.buffer.addAll(recipientData.toList())
// Append hop count (UInt8)
builder.appendUInt8(hopCount)
// Append timestamp
builder.appendDate(timestamp)
// Append recipient nickname as string
builder.appendString(recipientNickname)
return builder.toByteArray()
}
companion object {
/**
* Decode from binary data matching iOS fromBinaryData implementation
*/
fun decode(data: ByteArray): DeliveryAck? {
// Create defensive copy
val dataCopy = data.copyOf()
// Minimum size: 2 UUIDs (32) + recipientID (8) + hopCount (1) + timestamp (8) + min nickname
if (dataCopy.size < 50) return null
val offset = intArrayOf(0)
val originalMessageID = dataCopy.readUUID(offset) ?: return null
val ackID = dataCopy.readUUID(offset) ?: return null
val recipientIDData = dataCopy.readFixedBytes(offset, 8) ?: return null
val recipientID = recipientIDData.hexEncodedString()
val hopCount = dataCopy.readUInt8(offset) ?: return null
val timestamp = dataCopy.readDate(offset) ?: return null
val recipientNickname = dataCopy.readString(offset) ?: return null
return DeliveryAck(
originalMessageID = originalMessageID,
ackID = ackID,
recipientID = recipientID,
recipientNickname = recipientNickname,
timestamp = timestamp,
hopCount = hopCount
)
}
}
}