package updater import ( "context" "fmt" "sort" "strings" "github.com/qdm12/gluetun/internal/models" "github.com/qdm12/gluetun/internal/provider/common" "github.com/qdm12/gluetun/internal/updater/openvpn" "golang.org/x/text/cases" "golang.org/x/text/language" ) func (u *Updater) FetchServers(ctx context.Context, minServers int) ( servers []models.Server, err error) { const tcpURL = "https://torguard.net/downloads/OpenVPN-TCP-Linux.zip" tcpContents, err := u.unzipper.FetchAndExtract(ctx, tcpURL) if err != nil { return nil, err } const udpURL = "https://torguard.net/downloads/OpenVPN-UDP-Linux.zip" udpContents, err := u.unzipper.FetchAndExtract(ctx, udpURL) if err != nil { return nil, err } hts := make(hostToServer) titleCaser := cases.Title(language.English) for fileName, content := range tcpContents { const tcp, udp = true, false warnings := addServerFromOvpn(fileName, content, hts, tcp, udp, titleCaser) u.warnWarnings(warnings) } for fileName, content := range udpContents { const tcp, udp = false, true warnings := addServerFromOvpn(fileName, content, hts, tcp, udp, titleCaser) u.warnWarnings(warnings) } if len(hts) < minServers { return nil, fmt.Errorf("%w: %d and expected at least %d", common.ErrNotEnoughServers, len(hts), minServers) } hosts := hts.toHostsSlice() resolveSettings := parallelResolverSettings(hosts) hostToIPs, warnings, err := u.parallelResolver.Resolve(ctx, resolveSettings) u.warnWarnings(warnings) if err != nil { return nil, err } if len(hostToIPs) < minServers { return nil, fmt.Errorf("%w: %d and expected at least %d", common.ErrNotEnoughServers, len(servers), minServers) } hts.adaptWithIPs(hostToIPs) servers = hts.toServersSlice() 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 addServerFromOvpn(fileName string, content []byte, hts hostToServer, tcp, udp bool, titleCaser cases.Caser) (warnings []string) { if !strings.HasSuffix(fileName, ".ovpn") { return nil // not an OpenVPN file } country, city := parseFilename(fileName, titleCaser) host, warning, err := openvpn.ExtractHost(content) if warning != "" { warnings = append(warnings, warning) } if err != nil { // treat error as warning and go to next file warning := err.Error() + " in " + fileName warnings = append(warnings, warning) return warnings } ips, err := openvpn.ExtractIPs(content) if err != nil { // treat error as warning and go to next file warning := err.Error() + " in " + fileName warnings = append(warnings, warning) return warnings } hts.add(host, country, city, tcp, udp, ips) return warnings } func (u *Updater) warnWarnings(warnings []string) { for _, warning := range warnings { u.warner.Warn(warning) } }