-
-
Notifications
You must be signed in to change notification settings - Fork 327
/
servers.go
150 lines (131 loc) · 4.06 KB
/
servers.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
package updater
import (
"context"
"errors"
"fmt"
"sort"
"github.com/qdm12/gluetun/internal/constants/vpn"
"github.com/qdm12/gluetun/internal/models"
"github.com/qdm12/gluetun/internal/provider/common"
)
var (
ErrNotIPv4 = errors.New("IP address is not IPv4")
)
func (u *Updater) FetchServers(ctx context.Context, minServers int) (
servers []models.Server, err error) {
const limit = 0
data, err := fetchAPI(ctx, u.client, limit)
if err != nil {
return nil, err
}
servers = make([]models.Server, 0, len(data.Servers))
groups, services, locations, technologies := data.idToData()
for _, jsonServer := range data.Servers {
newServers, warnings := extractServers(jsonServer, groups, services, locations, technologies)
for _, warning := range warnings {
u.warner.Warn(warning)
}
servers = append(servers, newServers...)
}
if len(servers) < minServers {
return nil, fmt.Errorf("%w: %d and expected at least %d",
common.ErrNotEnoughServers, len(servers), minServers)
}
sort.Sort(models.SortableServers(servers))
return servers, nil
}
func extractServers(jsonServer serverData, groups map[uint32]groupData,
services map[uint32]serviceData, locations map[uint32]locationData,
technologies map[uint32]technologyData) (servers []models.Server,
warnings []string) {
ignoreReason := ""
switch {
case jsonServer.Status != "online":
ignoreReason = "status is " + jsonServer.Status
case len(jsonServer.LocationIDs) == 0:
ignoreReason = "no location"
case len(jsonServer.IPs) == 0:
ignoreReason = "no IP address"
case !jsonServer.hasVPNService(services):
ignoreReason = "no VPN service"
}
if ignoreReason != "" {
warning := fmt.Sprintf("ignoring server %s: %s", jsonServer.Name, ignoreReason)
return nil, []string{warning}
}
location, ok := locations[jsonServer.LocationIDs[0]]
if !ok {
warning := fmt.Sprintf("location with id %d not found in %v",
jsonServer.LocationIDs[0], locations)
return nil, []string{warning}
}
region := jsonServer.region(groups)
if region == "" {
warning := fmt.Sprintf("no region found for server %s", jsonServer.Name)
return nil, []string{warning}
}
server := models.Server{
Country: location.Country.Name,
Region: jsonServer.region(groups),
City: location.Country.City.Name,
Categories: jsonServer.categories(groups),
Hostname: jsonServer.Hostname,
IPs: jsonServer.ips(),
}
number, err := parseServerName(jsonServer.Name)
switch {
case errors.Is(err, ErrNoIDInServerName):
warning := fmt.Sprintf("%s - leaving server number as 0", err)
warnings = append(warnings, warning)
case err != nil:
warning := fmt.Sprintf("failed parsing server name: %s", err)
return nil, []string{warning}
default: // no error
server.Number = number
}
var wireguardFound, openvpnFound bool
wireguardServer := server
wireguardServer.VPN = vpn.Wireguard
openVPNServer := server // accumulate UDP+TCP technologies
openVPNServer.VPN = vpn.OpenVPN
for _, technology := range jsonServer.Technologies {
if technology.Status != "online" {
continue
}
technologyData, ok := technologies[technology.ID]
if !ok {
warning := fmt.Sprintf("technology with id %d not found in %v",
technology.ID, technologies)
warnings = append(warnings, warning)
continue
}
switch technologyData.Identifier {
case "openvpn_udp", "openvpn_dedicated_udp":
openvpnFound = true
openVPNServer.UDP = true
case "openvpn_tcp", "openvpn_dedicated_tcp":
openvpnFound = true
openVPNServer.TCP = true
case "wireguard_udp":
wireguardFound = true
wireguardServer.WgPubKey, err = jsonServer.wireguardPublicKey(technologies)
if err != nil {
warning := fmt.Sprintf("ignoring Wireguard server %s: %s", jsonServer.Name, err)
warnings = append(warnings, warning)
wireguardFound = false
continue
}
default: // Ignore other technologies
continue
}
}
const maxServers = 2
servers = make([]models.Server, 0, maxServers)
if openvpnFound {
servers = append(servers, openVPNServer)
}
if wireguardFound {
servers = append(servers, wireguardServer)
}
return servers, warnings
}