mirror of
https://github.com/warppipe/swift-torrent.git
synced 2026-05-28 15:27:20 +00:00
6c8c581517
Full BEP-3 peer wire protocol, BEP-5 DHT, BEP-15 UDP trackers, magnet link support, bencode serialization, rarest-first piece selection, and async session management using SwiftNIO and swift-crypto. Includes 64 passing unit tests. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
56 lines
1.6 KiB
Swift
56 lines
1.6 KiB
Swift
import Foundation
|
|
|
|
/// 160-bit DHT node identifier.
|
|
public struct NodeID: Hashable, Sendable, CustomStringConvertible {
|
|
public let bytes: Data // 20 bytes
|
|
|
|
public init(bytes: Data) {
|
|
precondition(bytes.count == 20)
|
|
self.bytes = bytes
|
|
}
|
|
|
|
/// Generate a random node ID.
|
|
public static func random() -> NodeID {
|
|
var data = Data(count: 20)
|
|
for i in 0..<20 {
|
|
data[i] = UInt8.random(in: 0...255)
|
|
}
|
|
return NodeID(bytes: data)
|
|
}
|
|
|
|
/// XOR distance between two node IDs.
|
|
public func distance(to other: NodeID) -> Data {
|
|
var result = Data(count: 20)
|
|
for i in 0..<20 {
|
|
result[i] = bytes[bytes.startIndex + i] ^ other.bytes[other.bytes.startIndex + i]
|
|
}
|
|
return result
|
|
}
|
|
|
|
/// The index of the highest set bit in the distance (0-159), used for bucket selection.
|
|
public func bucketIndex(relativeTo other: NodeID) -> Int {
|
|
let dist = distance(to: other)
|
|
for i in 0..<20 {
|
|
let byte = dist[i]
|
|
if byte != 0 {
|
|
let bit = 7 - byte.leadingZeroBitCount
|
|
return (19 - i) * 8 + bit
|
|
}
|
|
}
|
|
return 0
|
|
}
|
|
|
|
public var description: String {
|
|
bytes.map { String(format: "%02x", $0) }.joined()
|
|
}
|
|
}
|
|
|
|
/// Compare distances: returns true if d1 < d2.
|
|
public func distanceLessThan(_ d1: Data, _ d2: Data) -> Bool {
|
|
for i in 0..<min(d1.count, d2.count) {
|
|
if d1[d1.startIndex + i] < d2[d2.startIndex + i] { return true }
|
|
if d1[d1.startIndex + i] > d2[d2.startIndex + i] { return false }
|
|
}
|
|
return false
|
|
}
|