mirror of
https://github.com/permissionlesstech/bitchat.git
synced 2026-07-25 10:45:20 +00:00
* docs(plans): add refactor plan; chore(config): introduce TransportConfig and use in BLEService/ChatViewModel/PrivateChatManager; feat: add PeerDisplayNameResolver and apply in BLEService; chore: make TransportPeerSnapshot Equatable/Hashable; perf: simplify read-receipt persistence (no synchronize) * project: add TransportConfig.swift and PeerDisplayNameResolver.swift to iOS/macOS targets (no xcodegen) * chore: remove unnecessary UserDefaults.synchronize() calls (extension/app/VM) * project: fix TransportConfig reference path; remove recovered reference; hook correct fileRef in iOS/macOS sources * chore(BLE): move connect/duty/announce constants to TransportConfig and reference them * chore(NostrTransport): factor recipient npub resolution into helper; reduce duplication * chore(BLE): trim raw hex dump on central decode failure to length+prefix * project: remove duplicate TransportConfig.swift entries from Sources build phases * chore: centralize more constants in TransportConfig (BLE thresholds, Nostr read-ack, UI caps) and adopt in BLEService/ChatViewModel/NostrTransport * chore: centralize location + geohash constants (filters, lookback, relay count) and adopt in LocationChannelManager/ChatViewModel * chore: centralize compression, dedup, verification QR, relay backoff, georelay fetch constants; adopt across modules * chore: centralize more BLE/Nostr delays; tighten NostrRelayManager logs to concise summaries; adopt config for location/geohash/relays * refactor(config): centralize remaining magic numbers and finalize log hygiene Add comprehensive TransportConfig constants for UI, Nostr, and BLE; adopt across ChatViewModel, ContentView, BLEService, ShareViewController, and BitchatApp to remove scattered literals. Standardize Nostr lookbacks/limits, UI delays/animations, and BLE announce/duty-cycle/candidate caps. Preserve behavior while making tuning explicit and safe. Highlights:\n- UI: animations, scroll throttle, long-message thresholds, batch stagger, color hue tuning, rate-limit buckets, read-receipt debounce, startup delays, share accept/dismiss windows, migration cutoff.\n- Nostr: short display length (8), conv-key prefix length (16), DM lookback (24h), geohash sample lookback/limits; consistent use throughout ChatViewModel.\n- BLE: dynamic RSSI defaults, announce intervals/base+jitter, duty cycles (dense/sparse), fragment/ingress lifetimes, expected write timings/spacing, recent packet window (30s/100), peer inactivity timeout; unified candidate caps (100).\n- Share: use constant dismiss delay; App: use constant share accept window.\n\nRisk/impact: behavior-equivalent with centralized knobs; easier to tune without code edits. * project: add TransportConfig.swift to Share Extension target to fix build --------- Co-authored-by: jack <jackjackbits@users.noreply.github.com>
76 lines
2.9 KiB
Swift
76 lines
2.9 KiB
Swift
//
|
|
// CompressionUtil.swift
|
|
// bitchat
|
|
//
|
|
// This is free and unencumbered software released into the public domain.
|
|
// For more information, see <https://unlicense.org>
|
|
//
|
|
|
|
import Foundation
|
|
import Compression
|
|
|
|
struct CompressionUtil {
|
|
// Compression threshold - don't compress if data is smaller than this
|
|
static let compressionThreshold = TransportConfig.compressionThresholdBytes // bytes
|
|
|
|
// Compress data using zlib algorithm (most compatible)
|
|
static func compress(_ data: Data) -> Data? {
|
|
// Skip compression for small data
|
|
guard data.count >= compressionThreshold else { return nil }
|
|
|
|
let maxCompressedSize = data.count + (data.count / 255) + 16
|
|
let destinationBuffer = UnsafeMutablePointer<UInt8>.allocate(capacity: maxCompressedSize)
|
|
defer { destinationBuffer.deallocate() }
|
|
|
|
let compressedSize = data.withUnsafeBytes { sourceBuffer in
|
|
guard let sourcePtr = sourceBuffer.bindMemory(to: UInt8.self).baseAddress else { return 0 }
|
|
return compression_encode_buffer(
|
|
destinationBuffer, data.count,
|
|
sourcePtr, data.count,
|
|
nil, COMPRESSION_ZLIB
|
|
)
|
|
}
|
|
|
|
guard compressedSize > 0 && compressedSize < data.count else { return nil }
|
|
|
|
return Data(bytes: destinationBuffer, count: compressedSize)
|
|
}
|
|
|
|
// Decompress zlib compressed data
|
|
static func decompress(_ compressedData: Data, originalSize: Int) -> Data? {
|
|
let destinationBuffer = UnsafeMutablePointer<UInt8>.allocate(capacity: originalSize)
|
|
defer { destinationBuffer.deallocate() }
|
|
|
|
let decompressedSize = compressedData.withUnsafeBytes { sourceBuffer in
|
|
guard let sourcePtr = sourceBuffer.bindMemory(to: UInt8.self).baseAddress else { return 0 }
|
|
return compression_decode_buffer(
|
|
destinationBuffer, originalSize,
|
|
sourcePtr, compressedData.count,
|
|
nil, COMPRESSION_ZLIB
|
|
)
|
|
}
|
|
|
|
guard decompressedSize > 0 else { return nil }
|
|
|
|
return Data(bytes: destinationBuffer, count: decompressedSize)
|
|
}
|
|
|
|
// Helper to check if compression is worth it
|
|
static func shouldCompress(_ data: Data) -> Bool {
|
|
// Don't compress if:
|
|
// 1. Data is too small
|
|
// 2. Data appears to be already compressed (high entropy)
|
|
guard data.count >= compressionThreshold else { return false }
|
|
|
|
// Simple entropy check - count unique bytes
|
|
var byteFrequency = [UInt8: Int]()
|
|
for byte in data {
|
|
byteFrequency[byte, default: 0] += 1
|
|
}
|
|
|
|
// If we have very high byte diversity, data is likely already compressed
|
|
let uniqueByteRatio = Double(byteFrequency.count) / Double(min(data.count, 256))
|
|
return uniqueByteRatio < 0.9 // Compress if less than 90% unique bytes
|
|
}
|
|
}
|