72 lines
3.6 KiB
Swift
72 lines
3.6 KiB
Swift
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)
|
|
}
|
|
}
|
|
}
|