import Foundation /// What your home machine is doing right now, which sets the upload-priority tier. public enum BandwidthMode: String, Sendable, Equatable { /// You're actively pulling content TO yourself (Travel Mode / offline fetch). /// Your experience dominates — public + friends yield all upload to you. case userFetch /// You're actively using the machine (streaming, browsing) but not fetching. case userActive /// You're away / the machine is idle — serve friends generously, public as leftover. case idle } /// Configurable knobs for the priority tiers (your 3rd boundary's "options"). public struct BandwidthOptions: Sendable, Equatable { /// Tier 2: prioritize friends' streaming experiences while you're idle. public var serveFriendsWhenIdle: Bool /// Tier 3: be a good public-swarm citizen while you're idle. public var seedPublicWhenIdle: Bool /// Your home upload capacity in KB/s, used to split idle bandwidth. nil = unmetered. public var totalUploadKBps: Int? public init(serveFriendsWhenIdle: Bool = true, seedPublicWhenIdle: Bool = true, totalUploadKBps: Int? = nil) { self.serveFriendsWhenIdle = serveFriendsWhenIdle self.seedPublicWhenIdle = seedPublicWhenIdle self.totalUploadKBps = totalUploadKBps } } /// Upload allocation across the three tiers. `nil` KB/s = unlimited; `0` = blocked. public struct BandwidthAllocation: Sendable, Equatable { public var userKBps: Int? // upload dedicated to your own fetch public var friendsKBps: Int? // upload for friends' streams (mesh / F2F custody) public var publicKBps: Int? // upload for the public swarm public init(userKBps: Int?, friendsKBps: Int?, publicKBps: Int?) { self.userKBps = userKBps; self.friendsKBps = friendsKBps; self.publicKBps = publicKBps } } /// The bandwidth-arbitration brain: allocate upload across **you > friends > public**. /// Pure decision logic (the governor actuates it onto transmission). This is what /// makes Travel Mode work: in `.userFetch`, public + friends drop to 0 so home's /// whole upload pipe is dedicated to your fetch (which the laptop further augments /// from public peers — UX over public good). public enum BandwidthPolicy { public static func allocate(mode: BandwidthMode, options: BandwidthOptions) -> BandwidthAllocation { switch mode { case .userFetch: // Travel Mode: everything to you; stop seeding public AND friends. return BandwidthAllocation(userKBps: nil, friendsKBps: 0, publicKBps: 0) case .userActive: // You're using the pipe — don't fight it; trickle others (friends > public). let total = options.totalUploadKBps return BandwidthAllocation(userKBps: nil, friendsKBps: options.serveFriendsWhenIdle ? total.map { max(1, $0 / 8) } ?? nil : 0, publicKBps: 0) case .idle: // Tier 2 (friends) ahead of tier 3 (public). Split the pipe when both on. let total = options.totalUploadKBps let friends = options.serveFriendsWhenIdle ? total : 0 let pub: Int? if !options.seedPublicWhenIdle { pub = 0 } else if options.serveFriendsWhenIdle { pub = total.map { max(0, $0 / 4) } // friends get the lion's share } else { pub = total // no friends → public gets it all } return BandwidthAllocation(userKBps: 0, friendsKBps: friends, publicKBps: pub) } } }