Files

168 lines
7.9 KiB
Swift

import Foundation
// MARK: - 国内分省三网
/// 国内三大运营商
public enum ChinaCarrier: String, Sendable, CaseIterable, Codable {
case telecom = "ct", unicom = "cu", mobile = "cm"
public var name: String {
switch self {
case .telecom: "电信"
case .unicom: "联通"
case .mobile: "移动"
}
}
public var nameEnglish: String {
switch self {
case .telecom: "Telecom"
case .unicom: "Unicom"
case .mobile: "Mobile"
}
}
}
/// 国内测速节点:zstaticcdn.com 的省级 TCPPing 节点,每省电信、联通、移动各一个。
/// 该站点只允许用于连通性与延迟参考,所以这里只做 TCP 建连计时,不下载任何数据
public struct ChinaNode: Sendable, Hashable, Identifiable {
public let province: String
public let provinceEnglish: String
/// 节点域名里的省份代码,如 bj、gd
public let code: String
public let carrier: ChinaCarrier
public var id: String { "\(code)-\(carrier.rawValue)" }
public var host: String { "\(code)-\(carrier.rawValue)-v4.ip.zstaticcdn.com" }
public var port: UInt16 { 80 }
/// 31 个省级行政区 × 三网 = 93 个节点
public static let all: [ChinaNode] = provinces.flatMap { province in
ChinaCarrier.allCases.map {
ChinaNode(province: province.name, provinceEnglish: province.english, code: province.code, carrier: $0)
}
}
public static let provinces: [(code: String, name: String, english: String)] = [
("bj", "北京", "Beijing"), ("tj", "天津", "Tianjin"), ("he", "河北", "Hebei"), ("sx", "山西", "Shanxi"),
("nm", "内蒙古", "Inner Mongolia"), ("ln", "辽宁", "Liaoning"), ("jl", "吉林", "Jilin"),
("hl", "黑龙江", "Heilongjiang"), ("sh", "上海", "Shanghai"), ("js", "江苏", "Jiangsu"),
("zj", "浙江", "Zhejiang"), ("ah", "安徽", "Anhui"), ("fj", "福建", "Fujian"), ("jx", "江西", "Jiangxi"),
("sd", "山东", "Shandong"), ("ha", "河南", "Henan"), ("hb", "湖北", "Hubei"), ("hn", "湖南", "Hunan"),
("gd", "广东", "Guangdong"), ("gx", "广西", "Guangxi"), ("hi", "海南", "Hainan"),
("cq", "重庆", "Chongqing"), ("sc", "四川", "Sichuan"), ("gz", "贵州", "Guizhou"), ("yn", "云南", "Yunnan"),
("xz", "西藏", "Tibet"), ("sn", "陕西", "Shaanxi"), ("gs", "甘肃", "Gansu"), ("qh", "青海", "Qinghai"),
("nx", "宁夏", "Ningxia"), ("xj", "新疆", "Xinjiang"),
]
}
// MARK: - 全球节点
/// 全球测速节点所在的大区,界面按此分组
public enum GlobalRegion: String, Sendable, CaseIterable, Codable {
case asiaPacific, europe, northAmerica, other
public var name: String {
switch self {
case .asiaPacific: "亚太"
case .europe: "欧洲"
case .northAmerica: "北美"
case .other: "其他地区"
}
}
public var nameEnglish: String {
switch self {
case .asiaPacific: "Asia-Pacific"
case .europe: "Europe"
case .northAmerica: "North America"
case .other: "Other"
}
}
}
/// 全球测速节点:各家云厂商公开提供的测速文件。
/// 延迟用 TCP 建连计时;下载测速按用户设定的时长与流量上限截断,不会整份下载
public struct GlobalNode: Sendable, Hashable, Identifiable {
public let id: String
public let city: String
public let cityEnglish: String
/// 两位国家代码,界面上显示国旗
public let countryCode: String
public let region: GlobalRegion
/// 提供测速文件的服务商
public let provider: String
public let downloadURL: URL
public var host: String { downloadURL.host ?? "" }
public var port: UInt16 { 443 }
init(_ id: String, _ city: String, _ cityEnglish: String, _ countryCode: String,
_ region: GlobalRegion, _ provider: String, _ url: String) {
self.id = id
self.city = city
self.cityEnglish = cityEnglish
self.countryCode = countryCode
self.region = region
self.provider = provider
// 清单写死在代码里,地址不合法属于编码错误
downloadURL = URL(string: url)!
}
/// 24 个节点,四家服务商,逐个验证过可用
public static let all: [GlobalNode] = [
// 亚太
.init("tokyo", "东京", "Tokyo", "JP", .asiaPacific, "Linode",
"https://speedtest.tokyo2.linode.com/100MB-tokyo2.bin"),
.init("osaka", "大阪", "Osaka", "JP", .asiaPacific, "Linode",
"https://speedtest.osaka.linode.com/100MB-osaka.bin"),
.init("seoul", "首尔", "Seoul", "KR", .asiaPacific, "DataPacket",
"https://seo.download.datapacket.com/100mb.bin"),
.init("hongkong", "香港", "Hong Kong", "HK", .asiaPacific, "DataPacket",
"https://hkg.download.datapacket.com/100mb.bin"),
.init("singapore", "新加坡", "Singapore", "SG", .asiaPacific, "Linode",
"https://speedtest.singapore.linode.com/100MB-singapore.bin"),
.init("mumbai", "孟买", "Mumbai", "IN", .asiaPacific, "Linode",
"https://speedtest.mumbai1.linode.com/100MB-mumbai1.bin"),
.init("sydney", "悉尼", "Sydney", "AU", .asiaPacific, "Linode",
"https://speedtest.sydney.linode.com/100MB-sydney.bin"),
// 欧洲
.init("frankfurt", "法兰克福", "Frankfurt", "DE", .europe, "Linode",
"https://speedtest.frankfurt.linode.com/100MB-frankfurt.bin"),
.init("london", "伦敦", "London", "GB", .europe, "Linode",
"https://speedtest.london.linode.com/100MB-london.bin"),
.init("amsterdam", "阿姆斯特丹", "Amsterdam", "NL", .europe, "Vultr",
"https://ams-nl-ping.vultr.com/vultr.com.100MB.bin"),
.init("paris", "巴黎", "Paris", "FR", .europe, "Linode",
"https://speedtest.paris.linode.com/100MB-paris.bin"),
.init("stockholm", "斯德哥尔摩", "Stockholm", "SE", .europe, "Linode",
"https://speedtest.stockholm.linode.com/100MB-stockholm.bin"),
.init("madrid", "马德里", "Madrid", "ES", .europe, "Linode",
"https://speedtest.madrid.linode.com/100MB-madrid.bin"),
.init("warsaw", "华沙", "Warsaw", "PL", .europe, "Vultr",
"https://waw-pl-ping.vultr.com/vultr.com.100MB.bin"),
// 北美
.init("newark", "纽瓦克", "Newark", "US", .northAmerica, "Linode",
"https://speedtest.newark.linode.com/100MB-newark.bin"),
.init("chicago", "芝加哥", "Chicago", "US", .northAmerica, "DataPacket",
"https://chi.download.datapacket.com/100mb.bin"),
.init("miami", "迈阿密", "Miami", "US", .northAmerica, "DataPacket",
"https://mia.download.datapacket.com/100mb.bin"),
.init("dallas", "达拉斯", "Dallas", "US", .northAmerica, "Linode",
"https://speedtest.dallas.linode.com/100MB-dallas.bin"),
.init("seattle", "西雅图", "Seattle", "US", .northAmerica, "Linode",
"https://speedtest.seattle.linode.com/100MB-seattle.bin"),
.init("losangeles", "洛杉矶", "Los Angeles", "US", .northAmerica, "Vultr",
"https://lax-ca-us-ping.vultr.com/vultr.com.100MB.bin"),
.init("toronto", "多伦多", "Toronto", "CA", .northAmerica, "Linode",
"https://speedtest.toronto1.linode.com/100MB-toronto1.bin"),
// 其他地区
.init("saopaulo", "圣保罗", "São Paulo", "BR", .other, "Linode",
"https://speedtest.sao-paulo.linode.com/100MB-sao-paulo.bin"),
.init("mexicocity", "墨西哥城", "Mexico City", "MX", .other, "Vultr",
"https://mex-mx-ping.vultr.com/vultr.com.100MB.bin"),
.init("johannesburg", "约翰内斯堡", "Johannesburg", "ZA", .other, "Vultr",
"https://jnb-za-ping.vultr.com/vultr.com.100MB.bin"),
]
}