Randomize provider server (#263)
* Pick random server within location * Add toggle to provider section in profile
This commit is contained in:
parent
c85f3d894e
commit
17ae9793df
|
@ -77,7 +77,7 @@ class DefaultLightProfileManager: LightProfileManager {
|
|||
$0.header < $1.header
|
||||
}.map {
|
||||
let server: ProviderServer?
|
||||
if let serverId = $0.providerServerId() {
|
||||
if let serverId = $0.providerServerId {
|
||||
server = providerManager.server(withId: serverId)
|
||||
} else {
|
||||
server = nil
|
||||
|
|
|
@ -92,13 +92,13 @@ extension EndpointView {
|
|||
}
|
||||
_customEndpoint = .init {
|
||||
if currentProfile.value.isProvider {
|
||||
return currentProfile.value.providerCustomEndpoint()
|
||||
return currentProfile.value.providerCustomEndpoint
|
||||
} else {
|
||||
return currentProfile.value.hostOpenVPNSettings?.customEndpoint
|
||||
}
|
||||
} set: {
|
||||
if currentProfile.value.isProvider {
|
||||
currentProfile.value.setProviderCustomEndpoint($0)
|
||||
currentProfile.value.providerCustomEndpoint = $0
|
||||
} else {
|
||||
currentProfile.value.hostOpenVPNSettings?.customEndpoint = $0
|
||||
}
|
||||
|
|
|
@ -35,16 +35,6 @@ extension ProfileView {
|
|||
}
|
||||
|
||||
var body: some View {
|
||||
if currentProfile.value.isProvider {
|
||||
Section {
|
||||
Toggle(
|
||||
L10n.Profile.Items.VpnResolvesHostname.caption,
|
||||
isOn: $currentProfile.value.networkSettings.resolvesHostname
|
||||
)
|
||||
} footer: {
|
||||
Text(L10n.Profile.Sections.VpnResolvesHostname.footer)
|
||||
}
|
||||
}
|
||||
Section {
|
||||
Toggle(
|
||||
L10n.Profile.Items.VpnSurvivesSleep.caption,
|
||||
|
|
|
@ -77,6 +77,18 @@ extension ProfileView {
|
|||
} footer: {
|
||||
currentProviderServerDescription.map(Text.init)
|
||||
}
|
||||
Section {
|
||||
Toggle(
|
||||
L10n.Profile.Items.RandomizesServer.caption,
|
||||
isOn: $currentProfile.value.providerRandomizesServer ?? false
|
||||
)
|
||||
Toggle(
|
||||
L10n.Profile.Items.VpnResolvesHostname.caption,
|
||||
isOn: $currentProfile.value.networkSettings.resolvesHostname
|
||||
)
|
||||
} footer: {
|
||||
Text(L10n.Profile.Sections.VpnResolvesHostname.footer)
|
||||
}
|
||||
Section {
|
||||
NavigationLink {
|
||||
ProviderPresetView(currentProfile: currentProfile)
|
||||
|
@ -107,7 +119,14 @@ extension ProfileView {
|
|||
}
|
||||
|
||||
private var currentProviderServerDescription: String? {
|
||||
profile.providerServer(providerManager)?.localizedLongDescription(withCategory: true)
|
||||
guard let server = profile.providerServer(providerManager) else {
|
||||
return nil
|
||||
}
|
||||
if currentProfile.value.providerRandomizesServer ?? false {
|
||||
return server.localizedCountry(withCategory: true)
|
||||
} else {
|
||||
return server.localizedLongDescription(withCategory: true)
|
||||
}
|
||||
}
|
||||
|
||||
private var currentProviderCountryImage: Image? {
|
||||
|
|
|
@ -71,7 +71,7 @@ struct ProviderLocationView: View, ProviderProfileAvailability {
|
|||
self.isEditable = isEditable
|
||||
|
||||
_selectedServer = .init {
|
||||
guard let serverId = currentProfile.value.providerServerId() else {
|
||||
guard let serverId = currentProfile.value.providerServerId else {
|
||||
return nil
|
||||
}
|
||||
return providerManager.server(withId: serverId)
|
||||
|
@ -84,9 +84,9 @@ struct ProviderLocationView: View, ProviderProfileAvailability {
|
|||
isPresented.wrappedValue = false
|
||||
}
|
||||
_favoriteLocationIds = .init {
|
||||
currentProfile.value.providerFavoriteLocationIds()
|
||||
currentProfile.value.providerFavoriteLocationIds
|
||||
} set: {
|
||||
currentProfile.value.setProviderFavoriteLocationIds($0)
|
||||
currentProfile.value.providerFavoriteLocationIds = $0
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -151,6 +151,8 @@ struct ProviderLocationView: View, ProviderProfileAvailability {
|
|||
private func locationRow(_ location: ProviderLocation) -> some View {
|
||||
if let onlyServer = location.onlyServer {
|
||||
singleServerRow(location, onlyServer)
|
||||
} else if profile.providerRandomizesServer ?? false {
|
||||
singleServerRow(location, nil)
|
||||
} else {
|
||||
multipleServersRow(location)
|
||||
}
|
||||
|
@ -170,9 +172,9 @@ struct ProviderLocationView: View, ProviderProfileAvailability {
|
|||
})
|
||||
}
|
||||
|
||||
private func singleServerRow(_ location: ProviderLocation, _ server: ProviderServer) -> some View {
|
||||
private func singleServerRow(_ location: ProviderLocation, _ server: ProviderServer?) -> some View {
|
||||
Button {
|
||||
selectedServer = server
|
||||
selectedServer = server ?? location.servers?.randomElement()
|
||||
} label: {
|
||||
LocationRow(
|
||||
location: location,
|
||||
|
|
|
@ -46,7 +46,7 @@ struct ProviderPresetView: View {
|
|||
|
||||
server = currentProfile.value.providerServer(providerManager)
|
||||
_selectedPreset = .init {
|
||||
guard let serverId = currentProfile.value.providerServerId() else {
|
||||
guard let serverId = currentProfile.value.providerServerId else {
|
||||
return nil
|
||||
}
|
||||
guard let server = providerManager.server(withId: serverId) else {
|
||||
|
|
|
@ -795,6 +795,10 @@ internal enum L10n {
|
|||
internal static let caption = L10n.tr("Localizable", "profile.items.provider.refresh.caption", fallback: "Refresh infrastructure")
|
||||
}
|
||||
}
|
||||
internal enum RandomizesServer {
|
||||
/// Randomize server
|
||||
internal static let caption = L10n.tr("Localizable", "profile.items.randomizes_server.caption", fallback: "Randomize server")
|
||||
}
|
||||
internal enum UseProfile {
|
||||
/// Use this profile
|
||||
internal static let caption = L10n.tr("Localizable", "profile.items.use_profile.caption", fallback: "Use this profile")
|
||||
|
|
|
@ -70,6 +70,14 @@ extension ProviderServer {
|
|||
countryCode.localizedAsCountryCode
|
||||
}
|
||||
|
||||
func localizedCountry(withCategory: Bool) -> String {
|
||||
let desc = localizedCountry
|
||||
if withCategory, !categoryName.isEmpty {
|
||||
return "\(categoryName.uppercased()): \(desc)"
|
||||
}
|
||||
return desc
|
||||
}
|
||||
|
||||
var localizedShortDescription: String? {
|
||||
var comps = localizedName.map { [$0] } ?? []
|
||||
if let serverIndex = serverIndex {
|
||||
|
|
|
@ -152,6 +152,7 @@
|
|||
"profile.items.vpn.turn_off.caption" = "Disable VPN";
|
||||
"profile.items.connection_status.caption" = "Status";
|
||||
"profile.items.data_count.caption" = "Exchanged data";
|
||||
"profile.items.randomizes_server.caption" = "Randomize server";
|
||||
"profile.items.provider.refresh.caption" = "Refresh infrastructure";
|
||||
"profile.items.category.caption" = "Category";
|
||||
"profile.items.only_shows_favorites.caption" = "Only show favorite locations";
|
||||
|
|
|
@ -27,23 +27,24 @@ import Foundation
|
|||
import TunnelKitCore
|
||||
|
||||
extension Profile {
|
||||
public func hostAccount() -> Profile.Account? {
|
||||
switch currentVPNProtocol {
|
||||
case .openVPN:
|
||||
return host?.ovpnSettings?.account
|
||||
public var hostAccount: Profile.Account? {
|
||||
get {
|
||||
switch currentVPNProtocol {
|
||||
case .openVPN:
|
||||
return host?.ovpnSettings?.account
|
||||
|
||||
case .wireGuard:
|
||||
return nil
|
||||
case .wireGuard:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
set {
|
||||
switch currentVPNProtocol {
|
||||
case .openVPN:
|
||||
host?.ovpnSettings?.account = newValue
|
||||
|
||||
public mutating func setHostAccount(_ account: Profile.Account?) {
|
||||
switch currentVPNProtocol {
|
||||
case .openVPN:
|
||||
host?.ovpnSettings?.account = account
|
||||
|
||||
case .wireGuard:
|
||||
break
|
||||
case .wireGuard:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -41,16 +41,16 @@ extension Profile {
|
|||
public var account: Profile.Account {
|
||||
get {
|
||||
if isProvider {
|
||||
return providerAccount() ?? .init()
|
||||
return providerAccount ?? .init()
|
||||
} else {
|
||||
return hostAccount() ?? .init()
|
||||
return hostAccount ?? .init()
|
||||
}
|
||||
}
|
||||
set {
|
||||
if isProvider {
|
||||
setProviderAccount(newValue)
|
||||
providerAccount = newValue
|
||||
} else {
|
||||
setHostAccount(newValue)
|
||||
hostAccount = newValue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ extension Profile {
|
|||
provider?.name
|
||||
}
|
||||
|
||||
public func providerServerId() -> String? {
|
||||
public var providerServerId: String? {
|
||||
provider?.vpnSettings[currentVPNProtocol]?.serverId
|
||||
}
|
||||
|
||||
|
@ -71,28 +71,40 @@ extension Profile {
|
|||
provider?.vpnSettings[currentVPNProtocol]?.presetId = preset.id
|
||||
}
|
||||
|
||||
public func providerFavoriteLocationIds() -> Set<String>? {
|
||||
provider?.vpnSettings[currentVPNProtocol]?.favoriteLocationIds
|
||||
public var providerFavoriteLocationIds: Set<String>? {
|
||||
get {
|
||||
provider?.vpnSettings[currentVPNProtocol]?.favoriteLocationIds
|
||||
}
|
||||
set {
|
||||
provider?.vpnSettings[currentVPNProtocol]?.favoriteLocationIds = newValue
|
||||
}
|
||||
}
|
||||
|
||||
public mutating func setProviderFavoriteLocationIds(_ ids: Set<String>?) {
|
||||
provider?.vpnSettings[currentVPNProtocol]?.favoriteLocationIds = ids
|
||||
public var providerCustomEndpoint: Endpoint? {
|
||||
get {
|
||||
provider?.vpnSettings[currentVPNProtocol]?.customEndpoint
|
||||
}
|
||||
set {
|
||||
provider?.vpnSettings[currentVPNProtocol]?.customEndpoint = newValue
|
||||
}
|
||||
}
|
||||
|
||||
public func providerCustomEndpoint() -> Endpoint? {
|
||||
provider?.vpnSettings[currentVPNProtocol]?.customEndpoint
|
||||
public var providerAccount: Profile.Account? {
|
||||
get {
|
||||
provider?.vpnSettings[currentVPNProtocol]?.account
|
||||
}
|
||||
set {
|
||||
provider?.vpnSettings[currentVPNProtocol]?.account = newValue
|
||||
}
|
||||
}
|
||||
|
||||
public mutating func setProviderCustomEndpoint(_ endpoint: Endpoint?) {
|
||||
provider?.vpnSettings[currentVPNProtocol]?.customEndpoint = endpoint
|
||||
}
|
||||
|
||||
public func providerAccount() -> Profile.Account? {
|
||||
provider?.vpnSettings[currentVPNProtocol]?.account
|
||||
}
|
||||
|
||||
public mutating func setProviderAccount(_ account: Profile.Account?) {
|
||||
provider?.vpnSettings[currentVPNProtocol]?.account = account
|
||||
public var providerRandomizesServer: Bool? {
|
||||
get {
|
||||
provider?.randomizesServer
|
||||
}
|
||||
set {
|
||||
provider?.randomizesServer = newValue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -47,6 +47,8 @@ extension Profile {
|
|||
|
||||
public var vpnSettings: [VPNProtocolType: Settings] = [:]
|
||||
|
||||
public var randomizesServer: Bool?
|
||||
|
||||
public init(_ name: ProviderName) {
|
||||
self.name = name
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ extension Profile {
|
|||
|
||||
extension Profile {
|
||||
public func providerServer(_ providerManager: ProviderManager) -> ProviderServer? {
|
||||
guard let serverId = providerServerId() else {
|
||||
guard let serverId = providerServerId else {
|
||||
return nil
|
||||
}
|
||||
return providerManager.server(withId: serverId)
|
||||
|
@ -51,9 +51,21 @@ extension Profile {
|
|||
}
|
||||
|
||||
// infer remotes from preset + server
|
||||
guard let server = providerServer(providerManager) else {
|
||||
guard let selectedServer = providerServer(providerManager) else {
|
||||
throw PassepartoutError.missingProviderServer
|
||||
}
|
||||
let server: ProviderServer
|
||||
if providerRandomizesServer ?? false {
|
||||
let location = selectedServer.location(withVPNProtocol: currentVPNProtocol)
|
||||
let servers = providerManager.servers(forLocation: location)
|
||||
guard let randomServerId = servers.randomElement()?.id,
|
||||
let randomServer = providerManager.server(withId: randomServerId) else {
|
||||
throw PassepartoutError.missingProviderServer
|
||||
}
|
||||
server = randomServer
|
||||
} else {
|
||||
server = selectedServer
|
||||
}
|
||||
guard let preset = providerPreset(server) else {
|
||||
throw PassepartoutError.missingProviderPreset
|
||||
}
|
||||
|
@ -68,8 +80,8 @@ extension Profile {
|
|||
// apply provider settings (username, custom endpoint)
|
||||
let cfg = builder.build()
|
||||
var settings = OpenVPNSettings(configuration: cfg)
|
||||
settings.account = providerAccount()
|
||||
settings.customEndpoint = providerCustomEndpoint()
|
||||
settings.account = providerAccount
|
||||
settings.customEndpoint = providerCustomEndpoint
|
||||
return settings
|
||||
}
|
||||
|
||||
|
|
|
@ -45,6 +45,16 @@ extension ProviderServer {
|
|||
public var locationId: String {
|
||||
"\(providerMetadata.name):\(categoryName):\(countryCode)"
|
||||
}
|
||||
|
||||
public func location(withVPNProtocol vpnProtocol: VPNProtocolType) -> ProviderLocation {
|
||||
ProviderLocation(
|
||||
providerMetadata: providerMetadata,
|
||||
vpnProtocol: vpnProtocol,
|
||||
categoryName: categoryName,
|
||||
countryCode: countryCode,
|
||||
servers: nil
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
extension ProviderServer {
|
||||
|
|
|
@ -85,7 +85,7 @@ extension VPNManager {
|
|||
try await profileManager.makeProfileReady(profile)
|
||||
}
|
||||
|
||||
let oldServerId = profile.providerServerId()
|
||||
let oldServerId = profile.providerServerId
|
||||
guard let newServer = providerManager.server(withId: newServerId) else {
|
||||
pp_log.warning("Server \(newServerId) not found")
|
||||
throw PassepartoutError.missingProviderServer
|
||||
|
|
|
@ -206,15 +206,15 @@ extension VPNManager {
|
|||
if newProfile.isProvider {
|
||||
|
||||
// server changed?
|
||||
if newProfile.providerServerId() != lastProfile.providerServerId() {
|
||||
pp_log.info("Provider server changed: \(newProfile.providerServerId()?.description ?? "nil")")
|
||||
if newProfile.providerServerId != lastProfile.providerServerId {
|
||||
pp_log.info("Provider server changed: \(newProfile.providerServerId?.description ?? "nil")")
|
||||
isHandled = true
|
||||
shouldReconnect = notDisconnected
|
||||
}
|
||||
|
||||
// endpoint changed?
|
||||
else if newProfile.providerCustomEndpoint() != lastProfile.providerCustomEndpoint() {
|
||||
pp_log.info("Provider endpoint changed: \(newProfile.providerCustomEndpoint()?.description ?? "automatic")")
|
||||
else if newProfile.providerCustomEndpoint != lastProfile.providerCustomEndpoint {
|
||||
pp_log.info("Provider endpoint changed: \(newProfile.providerCustomEndpoint?.description ?? "automatic")")
|
||||
isHandled = true
|
||||
shouldReconnect = notDisconnected
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue