mirror of
https://github.com/permissionlesstech/bitchat.git
synced 2026-07-25 23:25:20 +00:00
* Run local packages’ tests as well on CI * BitFoundation module to centralize shared components
97 lines
3.2 KiB
Swift
97 lines
3.2 KiB
Swift
//
|
|
// ReadReceipt.swift
|
|
// bitchat
|
|
//
|
|
// This is free and unencumbered software released into the public domain.
|
|
// For more information, see <https://unlicense.org>
|
|
//
|
|
|
|
import Foundation
|
|
import BitFoundation
|
|
|
|
struct ReadReceipt: Codable {
|
|
let originalMessageID: String
|
|
let receiptID: String
|
|
var readerID: PeerID // Who read it
|
|
let readerNickname: String
|
|
let timestamp: Date
|
|
|
|
init(originalMessageID: String, readerID: PeerID, 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: PeerID, 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.id
|
|
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 = PeerID(hexData: readerIDData)
|
|
guard readerID.isValid 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)
|
|
}
|
|
}
|