Refactor: Extract types from BitchatProtocol (#611)

* Extract BitchatMessage into a separate file

* Convert `fromBinaryPayload` to `convenience init?`

* Extract message dedup into an extension

* Remove dead `formatMessageContent`

* Minor refactor of timestamp and username formatting

* Remove dead `getSenderColor`

* Extract MessagePadding into a separate file

* Extract BitchatPacket into a separate file

* Extract ReadReceipt into a separate file

* Extract NoisePayload into a separate file

* Remove unnecessary import
This commit is contained in:
Islam
2025-09-15 15:21:03 +02:00
committed by GitHub
parent ea8d51a36b
commit 6a6504c6f2
5 changed files with 288 additions and 270 deletions
+95
View File
@@ -0,0 +1,95 @@
//
// ReadReceipt.swift
// bitchat
//
// This is free and unencumbered software released into the public domain.
// For more information, see <https://unlicense.org>
//
import Foundation
struct ReadReceipt: Codable {
let originalMessageID: String
let receiptID: String
var readerID: String // Who read it
let readerNickname: String
let timestamp: Date
init(originalMessageID: String, readerID: String, readerNickname: String) {
self.originalMessageID = originalMessageID
self.receiptID = UUID().uuidString
self.readerID = readerID
self.readerNickname = readerNickname
self.timestamp = Date()
}
// For binary decoding
private init(originalMessageID: String, receiptID: String, readerID: String, readerNickname: String, timestamp: Date) {
self.originalMessageID = originalMessageID
self.receiptID = receiptID
self.readerID = readerID
self.readerNickname = readerNickname
self.timestamp = timestamp
}
func encode() -> Data? {
try? JSONEncoder().encode(self)
}
static func decode(from data: Data) -> ReadReceipt? {
try? JSONDecoder().decode(ReadReceipt.self, from: data)
}
// MARK: - Binary Encoding
func toBinaryData() -> Data {
var data = Data()
data.appendUUID(originalMessageID)
data.appendUUID(receiptID)
// ReaderID as 8-byte hex string
var readerData = Data()
var tempID = readerID
while tempID.count >= 2 && readerData.count < 8 {
let hexByte = String(tempID.prefix(2))
if let byte = UInt8(hexByte, radix: 16) {
readerData.append(byte)
}
tempID = String(tempID.dropFirst(2))
}
while readerData.count < 8 {
readerData.append(0)
}
data.append(readerData)
data.appendDate(timestamp)
data.appendString(readerNickname)
return data
}
static func fromBinaryData(_ data: Data) -> ReadReceipt? {
// Create defensive copy
let dataCopy = Data(data)
// Minimum size: 2 UUIDs (32) + readerID (8) + timestamp (8) + min nickname
guard dataCopy.count >= 49 else { return nil }
var offset = 0
guard let originalMessageID = dataCopy.readUUID(at: &offset),
let receiptID = dataCopy.readUUID(at: &offset) else { return nil }
guard let readerIDData = dataCopy.readFixedBytes(at: &offset, count: 8) else { return nil }
let readerID = readerIDData.hexEncodedString()
guard InputValidator.validatePeerID(readerID) else { return nil }
guard let timestamp = dataCopy.readDate(at: &offset),
InputValidator.validateTimestamp(timestamp),
let readerNicknameRaw = dataCopy.readString(at: &offset),
let readerNickname = InputValidator.validateNickname(readerNicknameRaw) else { return nil }
return ReadReceipt(originalMessageID: originalMessageID,
receiptID: receiptID,
readerID: readerID,
readerNickname: readerNickname,
timestamp: timestamp)
}
}