165 lines
3.8 KiB
Go
165 lines
3.8 KiB
Go
package app
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
)
|
|
|
|
type vpnLocationChoice struct {
|
|
ISO string
|
|
Label string
|
|
RawTarget string
|
|
Name string
|
|
Connect string
|
|
}
|
|
|
|
func resolveVPNLocationSelection(
|
|
reqTarget string,
|
|
reqISO string,
|
|
reqLabel string,
|
|
locs []vpnLocationItem,
|
|
) (target string, iso string, label string, validated bool, err error) {
|
|
targetReq := strings.TrimSpace(reqTarget)
|
|
isoReq := strings.ToUpper(strings.TrimSpace(reqISO))
|
|
labelReq := strings.TrimSpace(reqLabel)
|
|
|
|
choices := buildVPNLocationChoices(locs)
|
|
if len(choices) == 0 {
|
|
if isISO2(isoReq) {
|
|
return isoReq, isoReq, "", false, nil
|
|
}
|
|
if isISO2(targetReq) {
|
|
t := strings.ToUpper(strings.TrimSpace(targetReq))
|
|
return t, t, "", false, nil
|
|
}
|
|
return "", "", "", false, fmt.Errorf("location catalog unavailable; use ISO code")
|
|
}
|
|
|
|
findBy := func(pred func(vpnLocationChoice) bool) *vpnLocationChoice {
|
|
for i := range choices {
|
|
if pred(choices[i]) {
|
|
return &choices[i]
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
var chosen *vpnLocationChoice
|
|
|
|
if labelReq != "" {
|
|
chosen = findBy(func(it vpnLocationChoice) bool {
|
|
return equalsFoldTrim(labelReq, it.Label)
|
|
})
|
|
}
|
|
|
|
if chosen == nil && targetReq != "" {
|
|
chosen = findBy(func(it vpnLocationChoice) bool {
|
|
return equalsFoldTrim(targetReq, it.Connect) ||
|
|
equalsFoldTrim(targetReq, it.Name) ||
|
|
equalsFoldTrim(targetReq, it.RawTarget) ||
|
|
equalsFoldTrim(targetReq, it.Label)
|
|
})
|
|
}
|
|
|
|
if chosen == nil && isISO2(isoReq) {
|
|
chosen = findBy(func(it vpnLocationChoice) bool {
|
|
return it.ISO == isoReq
|
|
})
|
|
}
|
|
|
|
if chosen == nil && isISO2(targetReq) {
|
|
isoByTarget := strings.ToUpper(strings.TrimSpace(targetReq))
|
|
chosen = findBy(func(it vpnLocationChoice) bool {
|
|
return it.ISO == isoByTarget
|
|
})
|
|
}
|
|
|
|
if chosen == nil {
|
|
return "", "", "", false, fmt.Errorf("location not recognized; current connection kept")
|
|
}
|
|
|
|
connectArg := strings.TrimSpace(chosen.Connect)
|
|
if connectArg == "" {
|
|
connectArg = chosen.ISO
|
|
}
|
|
|
|
isValidated := true
|
|
if targetReq != "" &&
|
|
!equalsFoldTrim(targetReq, connectArg) &&
|
|
!equalsFoldTrim(targetReq, chosen.ISO) &&
|
|
!equalsFoldTrim(targetReq, chosen.Name) &&
|
|
!equalsFoldTrim(targetReq, chosen.RawTarget) &&
|
|
!equalsFoldTrim(targetReq, chosen.Label) {
|
|
isValidated = false
|
|
}
|
|
|
|
return connectArg, chosen.ISO, chosen.Label, isValidated, nil
|
|
}
|
|
|
|
func buildVPNLocationChoices(locs []vpnLocationItem) []vpnLocationChoice {
|
|
choices := make([]vpnLocationChoice, 0, len(locs))
|
|
namesByISO := map[string][][]string{}
|
|
countByISO := map[string]int{}
|
|
|
|
for _, it := range locs {
|
|
iso := strings.ToUpper(strings.TrimSpace(it.ISO))
|
|
if !isISO2(iso) {
|
|
continue
|
|
}
|
|
label := strings.TrimSpace(it.Label)
|
|
rawTarget := strings.TrimSpace(it.Target)
|
|
|
|
name := inferVPNLocationTargetFromLabel(label, iso)
|
|
if name == "" {
|
|
name = rawTarget
|
|
}
|
|
if name == "" {
|
|
name = iso
|
|
}
|
|
|
|
namesByISO[iso] = append(namesByISO[iso], strings.Fields(name))
|
|
countByISO[iso]++
|
|
choices = append(choices, vpnLocationChoice{
|
|
ISO: iso,
|
|
Label: label,
|
|
RawTarget: rawTarget,
|
|
Name: name,
|
|
})
|
|
}
|
|
|
|
commonByISO := map[string][]string{}
|
|
for iso, names := range namesByISO {
|
|
if len(names) < 2 {
|
|
continue
|
|
}
|
|
pfx := commonPrefixTokens(names)
|
|
if len(pfx) > 0 {
|
|
commonByISO[iso] = pfx
|
|
}
|
|
}
|
|
|
|
for i := range choices {
|
|
iso := choices[i].ISO
|
|
if countByISO[iso] <= 1 {
|
|
choices[i].Connect = iso
|
|
continue
|
|
}
|
|
tokens := strings.Fields(choices[i].Name)
|
|
pfx := commonByISO[iso]
|
|
if len(pfx) > 0 && len(tokens) > len(pfx) {
|
|
choices[i].Connect = strings.TrimSpace(strings.Join(tokens[len(pfx):], " "))
|
|
} else if choices[i].Name != "" {
|
|
choices[i].Connect = choices[i].Name
|
|
}
|
|
if choices[i].Connect == "" {
|
|
choices[i].Connect = iso
|
|
}
|
|
}
|
|
|
|
return choices
|
|
}
|
|
|
|
func equalsFoldTrim(a, b string) bool {
|
|
return strings.EqualFold(strings.TrimSpace(a), strings.TrimSpace(b))
|
|
}
|