Maintenance: use native HTTP client for updater
This commit is contained in:
8
internal/updater/errors.go
Normal file
8
internal/updater/errors.go
Normal file
@@ -0,0 +1,8 @@
|
||||
package updater
|
||||
|
||||
import "errors"
|
||||
|
||||
var (
|
||||
ErrHTTPStatusCodeNotOK = errors.New("HTTP status code not OK")
|
||||
ErrUnmarshalResponseBody = errors.New("cannot unmarshal response body")
|
||||
)
|
||||
@@ -10,7 +10,6 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/qdm12/golibs/network"
|
||||
)
|
||||
|
||||
func (u *updater) updateMullvad(ctx context.Context) (err error) {
|
||||
@@ -26,15 +25,25 @@ func (u *updater) updateMullvad(ctx context.Context) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
func findMullvadServers(ctx context.Context, client network.Client) (servers []models.MullvadServer, err error) {
|
||||
func findMullvadServers(ctx context.Context, client *http.Client) (servers []models.MullvadServer, err error) {
|
||||
const url = "https://api.mullvad.net/www/relays/openvpn/"
|
||||
bytes, status, err := client.Get(ctx, url)
|
||||
|
||||
request, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if status != http.StatusOK {
|
||||
return nil, fmt.Errorf("HTTP status code %d", status)
|
||||
|
||||
response, err := client.Do(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer response.Body.Close()
|
||||
|
||||
if response.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("%w: %s for %s", ErrHTTPStatusCodeNotOK, response.Status, url)
|
||||
}
|
||||
|
||||
decoder := json.NewDecoder(response.Body)
|
||||
var data []struct {
|
||||
Country string `json:"country_name"`
|
||||
City string `json:"city_name"`
|
||||
@@ -44,9 +53,14 @@ func findMullvadServers(ctx context.Context, client network.Client) (servers []m
|
||||
IPv4 string `json:"ipv4_addr_in"`
|
||||
IPv6 string `json:"ipv6_addr_in"`
|
||||
}
|
||||
if err := json.Unmarshal(bytes, &data); err != nil {
|
||||
if err := decoder.Decode(&data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := response.Body.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
serversByKey := map[string]models.MullvadServer{}
|
||||
for _, jsonServer := range data {
|
||||
if !jsonServer.Active {
|
||||
|
||||
@@ -12,7 +12,6 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/qdm12/golibs/network"
|
||||
)
|
||||
|
||||
func (u *updater) updateNordvpn(ctx context.Context) (err error) {
|
||||
@@ -38,16 +37,26 @@ var (
|
||||
ErrInvalidIDInServerName = errors.New("invalid ID in server name")
|
||||
)
|
||||
|
||||
func findNordvpnServers(ctx context.Context, client network.Client) (
|
||||
func findNordvpnServers(ctx context.Context, client *http.Client) (
|
||||
servers []models.NordvpnServer, warnings []string, err error) {
|
||||
const url = "https://nordvpn.com/api/server"
|
||||
bytes, status, err := client.Get(ctx, url)
|
||||
|
||||
request, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if status != http.StatusOK {
|
||||
return nil, nil, fmt.Errorf("HTTP status code %d", status)
|
||||
|
||||
response, err := client.Do(request)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
defer response.Body.Close()
|
||||
|
||||
if response.StatusCode != http.StatusOK {
|
||||
return nil, nil, fmt.Errorf("%w: %s for %s", ErrHTTPStatusCodeNotOK, response.Status, url)
|
||||
}
|
||||
|
||||
decoder := json.NewDecoder(response.Body)
|
||||
var data []struct {
|
||||
IPAddress string `json:"ip_address"`
|
||||
Name string `json:"name"`
|
||||
@@ -57,9 +66,14 @@ func findNordvpnServers(ctx context.Context, client network.Client) (
|
||||
TCP bool `json:"openvpn_tcp"`
|
||||
} `json:"features"`
|
||||
}
|
||||
if err := json.Unmarshal(bytes, &data); err != nil {
|
||||
if err := decoder.Decode(&data); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if err := response.Body.Close(); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
sort.Slice(data, func(i, j int) bool {
|
||||
if data[i].Country == data[j].Country {
|
||||
return data[i].Name < data[j].Name
|
||||
|
||||
@@ -5,22 +5,39 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
)
|
||||
|
||||
func (u *updater) updatePIA(ctx context.Context) (err error) {
|
||||
const url = "https://serverlist.piaservers.net/vpninfo/servers/v5"
|
||||
b, status, err := u.client.Get(ctx, url)
|
||||
|
||||
request, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if status != http.StatusOK {
|
||||
return fmt.Errorf("HTTP status code %d: %s", status, strings.ReplaceAll(string(b), "\n", ""))
|
||||
|
||||
response, err := u.client.Do(request)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer response.Body.Close()
|
||||
|
||||
if response.StatusCode != http.StatusOK {
|
||||
return fmt.Errorf("%w: %s for %s", ErrHTTPStatusCodeNotOK, response.Status, url)
|
||||
}
|
||||
|
||||
b, err := ioutil.ReadAll(response.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := response.Body.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// remove key/signature at the bottom
|
||||
|
||||
@@ -3,10 +3,10 @@ package updater
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"sort"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/qdm12/golibs/network"
|
||||
)
|
||||
|
||||
func (u *updater) updatePrivado(ctx context.Context) (err error) {
|
||||
@@ -27,7 +27,7 @@ func (u *updater) updatePrivado(ctx context.Context) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
func findPrivadoServersFromZip(ctx context.Context, client network.Client, lookupIP lookupIPFunc) (
|
||||
func findPrivadoServersFromZip(ctx context.Context, client *http.Client, lookupIP lookupIPFunc) (
|
||||
servers []models.PrivadoServer, warnings []string, err error) {
|
||||
const zipURL = "https://privado.io/apps/ovpn_configs.zip"
|
||||
contents, err := fetchAndExtractFiles(ctx, client, zipURL)
|
||||
|
||||
@@ -10,7 +10,6 @@ import (
|
||||
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/qdm12/gluetun/internal/publicip"
|
||||
"github.com/qdm12/golibs/network"
|
||||
)
|
||||
|
||||
func (u *updater) updatePurevpn(ctx context.Context) (err error) {
|
||||
@@ -31,7 +30,7 @@ func (u *updater) updatePurevpn(ctx context.Context) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
func findPurevpnServers(ctx context.Context, client network.Client, lookupIP lookupIPFunc) (
|
||||
func findPurevpnServers(ctx context.Context, client *http.Client, lookupIP lookupIPFunc) (
|
||||
servers []models.PurevpnServer, warnings []string, err error) {
|
||||
const zipURL = "https://s3-us-west-1.amazonaws.com/heartbleed/windows/New+OVPN+Files.zip"
|
||||
contents, err := fetchAndExtractFiles(ctx, client, zipURL)
|
||||
@@ -70,10 +69,7 @@ func findPurevpnServers(ctx context.Context, client network.Client, lookupIP loo
|
||||
continue
|
||||
}
|
||||
|
||||
// TODO remove once we move away from network.Client
|
||||
const httpTimeout = 3 * time.Second
|
||||
httpClient := &http.Client{Timeout: httpTimeout}
|
||||
country, region, city, err := publicip.Info(ctx, httpClient, IPs[0])
|
||||
country, region, city, err := publicip.Info(ctx, client, IPs[0])
|
||||
if err != nil {
|
||||
return nil, warnings, err
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/qdm12/golibs/network"
|
||||
)
|
||||
|
||||
func (u *updater) updateSurfshark(ctx context.Context) (err error) {
|
||||
@@ -32,21 +31,36 @@ func (u *updater) updateSurfshark(ctx context.Context) (err error) {
|
||||
}
|
||||
|
||||
//nolint:deadcode,unused
|
||||
func findSurfsharkServersFromAPI(ctx context.Context, client network.Client, lookupIP lookupIPFunc) (
|
||||
func findSurfsharkServersFromAPI(ctx context.Context, client *http.Client, lookupIP lookupIPFunc) (
|
||||
servers []models.SurfsharkServer, warnings []string, err error) {
|
||||
const url = "https://my.surfshark.com/vpn/api/v4/server/clusters"
|
||||
b, status, err := client.Get(ctx, url)
|
||||
|
||||
request, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
} else if status != http.StatusOK {
|
||||
return nil, nil, fmt.Errorf("HTTP status code %d", status)
|
||||
}
|
||||
|
||||
response, err := client.Do(request)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
defer response.Body.Close()
|
||||
|
||||
if response.StatusCode != http.StatusOK {
|
||||
return nil, nil, fmt.Errorf("%w: %s for %s", ErrHTTPStatusCodeNotOK, response.Status, url)
|
||||
}
|
||||
|
||||
decoder := json.NewDecoder(response.Body)
|
||||
var jsonServers []struct {
|
||||
Host string `json:"connectionName"`
|
||||
Country string `json:"country"`
|
||||
Location string `json:"location"`
|
||||
}
|
||||
if err := json.Unmarshal(b, &jsonServers); err != nil {
|
||||
if err := decoder.Decode(&jsonServers); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if err := response.Body.Close(); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
@@ -80,7 +94,7 @@ func findSurfsharkServersFromAPI(ctx context.Context, client network.Client, loo
|
||||
return servers, warnings, nil
|
||||
}
|
||||
|
||||
func findSurfsharkServersFromZip(ctx context.Context, client network.Client, lookupIP lookupIPFunc) (
|
||||
func findSurfsharkServersFromZip(ctx context.Context, client *http.Client, lookupIP lookupIPFunc) (
|
||||
servers []models.SurfsharkServer, warnings []string, err error) {
|
||||
const zipURL = "https://my.surfshark.com/vpn/api/v1/server/configurations"
|
||||
contents, err := fetchAndExtractFiles(ctx, client, zipURL)
|
||||
|
||||
@@ -4,12 +4,12 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/qdm12/golibs/network"
|
||||
)
|
||||
|
||||
func (u *updater) updateTorguard(ctx context.Context) (err error) {
|
||||
@@ -30,7 +30,7 @@ func (u *updater) updateTorguard(ctx context.Context) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
func findTorguardServersFromZip(ctx context.Context, client network.Client) (
|
||||
func findTorguardServersFromZip(ctx context.Context, client *http.Client) (
|
||||
servers []models.TorguardServer, warnings []string, err error) {
|
||||
// Note: all servers do both TCP and UDP
|
||||
const zipURL = "https://torguard.net/downloads/OpenVPN-TCP-Linux.zip"
|
||||
|
||||
@@ -10,7 +10,6 @@ import (
|
||||
"github.com/qdm12/gluetun/internal/configuration"
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/qdm12/golibs/logging"
|
||||
"github.com/qdm12/golibs/network"
|
||||
)
|
||||
|
||||
type Updater interface {
|
||||
@@ -29,7 +28,7 @@ type updater struct {
|
||||
timeNow func() time.Time
|
||||
println func(s string)
|
||||
lookupIP lookupIPFunc
|
||||
client network.Client
|
||||
client *http.Client
|
||||
}
|
||||
|
||||
func New(settings configuration.Updater, httpClient *http.Client,
|
||||
@@ -38,13 +37,12 @@ func New(settings configuration.Updater, httpClient *http.Client,
|
||||
settings.DNSAddress = "1.1.1.1"
|
||||
}
|
||||
resolver := newResolver(settings.DNSAddress)
|
||||
const clientTimeout = 10 * time.Second
|
||||
return &updater{
|
||||
logger: logger,
|
||||
timeNow: time.Now,
|
||||
println: func(s string) { fmt.Println(s) },
|
||||
lookupIP: newLookupIP(resolver),
|
||||
client: network.NewClient(clientTimeout),
|
||||
client: httpClient,
|
||||
options: settings,
|
||||
servers: currentServers,
|
||||
}
|
||||
|
||||
@@ -3,11 +3,11 @@ package updater
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/qdm12/golibs/network"
|
||||
)
|
||||
|
||||
func (u *updater) updateVyprvpn(ctx context.Context) (err error) {
|
||||
@@ -28,7 +28,7 @@ func (u *updater) updateVyprvpn(ctx context.Context) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
func findVyprvpnServers(ctx context.Context, client network.Client, lookupIP lookupIPFunc) (
|
||||
func findVyprvpnServers(ctx context.Context, client *http.Client, lookupIP lookupIPFunc) (
|
||||
servers []models.VyprvpnServer, warnings []string, err error) {
|
||||
const zipURL = "https://support.vyprvpn.com/hc/article_attachments/360052617332/Vypr_OpenVPN_20200320.zip"
|
||||
contents, err := fetchAndExtractFiles(ctx, client, zipURL)
|
||||
|
||||
@@ -10,7 +10,6 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/qdm12/golibs/network"
|
||||
)
|
||||
|
||||
func (u *updater) updateWindscribe(ctx context.Context) (err error) {
|
||||
@@ -26,16 +25,27 @@ func (u *updater) updateWindscribe(ctx context.Context) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
func findWindscribeServers(ctx context.Context, client network.Client) (servers []models.WindscribeServer, err error) {
|
||||
func findWindscribeServers(ctx context.Context, client *http.Client) (servers []models.WindscribeServer, err error) {
|
||||
const baseURL = "https://assets.windscribe.com/serverlist/mob-v2/1/"
|
||||
cacheBreaker := time.Now().Unix()
|
||||
url := fmt.Sprintf("%s%d", baseURL, cacheBreaker)
|
||||
content, status, err := client.Get(ctx, url)
|
||||
|
||||
request, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if status != http.StatusOK {
|
||||
return nil, fmt.Errorf(http.StatusText(status))
|
||||
}
|
||||
|
||||
response, err := client.Do(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer response.Body.Close()
|
||||
|
||||
if response.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("%w: %s", ErrHTTPStatusCodeNotOK, response.Status)
|
||||
}
|
||||
|
||||
decoder := json.NewDecoder(response.Body)
|
||||
var jsonData struct {
|
||||
Data []struct {
|
||||
Region string `json:"name"`
|
||||
@@ -48,9 +58,14 @@ func findWindscribeServers(ctx context.Context, client network.Client) (servers
|
||||
} `json:"groups"`
|
||||
} `json:"data"`
|
||||
}
|
||||
if err := json.Unmarshal(content, &jsonData); err != nil {
|
||||
if err := decoder.Decode(&jsonData); err != nil {
|
||||
return nil, fmt.Errorf("%w: %s", ErrUnmarshalResponseBody, err)
|
||||
}
|
||||
|
||||
if err := response.Body.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, regionBlock := range jsonData.Data {
|
||||
region := regionBlock.Region
|
||||
for _, group := range regionBlock.Groups {
|
||||
|
||||
@@ -4,31 +4,42 @@ import (
|
||||
"archive/zip"
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/qdm12/golibs/network"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrBadStatusCode = errors.New("bad HTTP status code")
|
||||
)
|
||||
|
||||
func fetchAndExtractFiles(ctx context.Context, client network.Client, urls ...string) (
|
||||
func fetchAndExtractFiles(ctx context.Context, client *http.Client, urls ...string) (
|
||||
contents map[string][]byte, err error) {
|
||||
contents = make(map[string][]byte)
|
||||
for _, url := range urls {
|
||||
zipBytes, status, err := client.Get(ctx, url)
|
||||
request, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if status != http.StatusOK {
|
||||
return nil, fmt.Errorf("%w: fetching url %s: %d", ErrBadStatusCode, url, status)
|
||||
}
|
||||
newContents, err := zipExtractAll(zipBytes)
|
||||
|
||||
response, err := client.Do(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer response.Body.Close()
|
||||
|
||||
if response.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("%w: %s for %s", ErrHTTPStatusCodeNotOK, response.Status, url)
|
||||
}
|
||||
|
||||
b, err := ioutil.ReadAll(response.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := response.Body.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
newContents, err := zipExtractAll(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user