mirror of
https://github.com/qdm12/gluetun.git
synced 2026-07-27 12:56:24 +02:00
chore(updater): move updater packages to pkg/updaters/<name>
This commit is contained in:
@@ -5,7 +5,8 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/constants/providers"
|
||||
"github.com/qdm12/gluetun/internal/constants/vpn"
|
||||
"github.com/qdm12/gluetun/pkg/updaters/constants"
|
||||
"github.com/qdm12/gluetun/pkg/updaters/models"
|
||||
)
|
||||
|
||||
func boolToMarkdown(b bool) string {
|
||||
@@ -42,7 +43,7 @@ const (
|
||||
vpnHeader = "VPN"
|
||||
)
|
||||
|
||||
func (s *Server) ToMarkdown(headers ...string) (markdown string) {
|
||||
func serverToMarkdown(s models.Server, headers ...string) (markdown string) {
|
||||
if len(headers) == 0 {
|
||||
return ""
|
||||
}
|
||||
@@ -81,7 +82,7 @@ func (s *Server) ToMarkdown(headers ...string) (markdown string) {
|
||||
case tcpHeader:
|
||||
fields[i] = boolToMarkdown(s.TCP)
|
||||
case udpHeader:
|
||||
fields[i] = boolToMarkdown(s.UDP || s.VPN == vpn.Wireguard)
|
||||
fields[i] = boolToMarkdown(s.UDP || s.VPN == constants.Wireguard)
|
||||
case vpnHeader:
|
||||
fields[i] = s.VPN
|
||||
}
|
||||
@@ -90,7 +91,7 @@ func (s *Server) ToMarkdown(headers ...string) (markdown string) {
|
||||
return "| " + strings.Join(fields, " | ") + " |"
|
||||
}
|
||||
|
||||
func (s *Servers) toMarkdown(vpnProvider string) (formatted string, err error) {
|
||||
func serversToMarkdown(s models.Servers, vpnProvider string) (formatted string, err error) {
|
||||
headers, err := getMarkdownHeaders(vpnProvider)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("getting markdown headers: %w", err)
|
||||
@@ -100,7 +101,7 @@ func (s *Servers) toMarkdown(vpnProvider string) (formatted string, err error) {
|
||||
|
||||
entries := make([]string, len(s.Servers))
|
||||
for i, server := range s.Servers {
|
||||
entries[i] = server.ToMarkdown(headers...)
|
||||
entries[i] = serverToMarkdown(server, headers...)
|
||||
}
|
||||
|
||||
formatted = legend + "\n" +
|
||||
|
||||
@@ -4,16 +4,17 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/constants/providers"
|
||||
"github.com/qdm12/gluetun/internal/constants/vpn"
|
||||
"github.com/qdm12/gluetun/pkg/updaters/constants"
|
||||
"github.com/qdm12/gluetun/pkg/updaters/models"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func Test_Servers_ToMarkdown(t *testing.T) {
|
||||
func Test_serversToMarkdown(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
testCases := map[string]struct {
|
||||
provider string
|
||||
servers Servers
|
||||
servers models.Servers
|
||||
formatted string
|
||||
errMessage string
|
||||
}{
|
||||
@@ -23,8 +24,8 @@ func Test_Servers_ToMarkdown(t *testing.T) {
|
||||
},
|
||||
providers.Cyberghost: {
|
||||
provider: providers.Cyberghost,
|
||||
servers: Servers{
|
||||
Servers: []Server{
|
||||
servers: models.Servers{
|
||||
Servers: []models.Server{
|
||||
{Country: "a", UDP: true, Hostname: "xa"},
|
||||
{Country: "b", TCP: true, Hostname: "xb"},
|
||||
},
|
||||
@@ -36,10 +37,10 @@ func Test_Servers_ToMarkdown(t *testing.T) {
|
||||
},
|
||||
providers.Fastestvpn: {
|
||||
provider: providers.Fastestvpn,
|
||||
servers: Servers{
|
||||
Servers: []Server{
|
||||
{Country: "a", Hostname: "xa", VPN: vpn.OpenVPN, TCP: true},
|
||||
{Country: "b", Hostname: "xb", VPN: vpn.OpenVPN, UDP: true},
|
||||
servers: models.Servers{
|
||||
Servers: []models.Server{
|
||||
{Country: "a", Hostname: "xa", VPN: constants.OpenVPN, TCP: true},
|
||||
{Country: "b", Hostname: "xb", VPN: constants.OpenVPN, UDP: true},
|
||||
},
|
||||
},
|
||||
formatted: "| Country | Hostname | VPN | TCP | UDP |\n" +
|
||||
@@ -53,7 +54,7 @@ func Test_Servers_ToMarkdown(t *testing.T) {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
markdown, err := testCase.servers.toMarkdown(testCase.provider)
|
||||
markdown, err := serversToMarkdown(testCase.servers, testCase.provider)
|
||||
|
||||
assert.Equal(t, testCase.formatted, markdown)
|
||||
if testCase.errMessage != "" {
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"net/netip"
|
||||
)
|
||||
|
||||
type PublicIP struct {
|
||||
IP netip.Addr `json:"public_ip"`
|
||||
Region string `json:"region,omitempty"`
|
||||
Country string `json:"country,omitempty"`
|
||||
City string `json:"city,omitempty"`
|
||||
Hostname string `json:"hostname,omitempty"`
|
||||
Location string `json:"location,omitempty"`
|
||||
Organization string `json:"organization,omitempty"`
|
||||
PostalCode string `json:"postal_code,omitempty"`
|
||||
Timezone string `json:"timezone,omitempty"`
|
||||
}
|
||||
|
||||
func (p *PublicIP) Copy() (publicIPCopy PublicIP) {
|
||||
publicIPCopy = PublicIP{
|
||||
IP: p.IP,
|
||||
Region: p.Region,
|
||||
Country: p.Country,
|
||||
City: p.City,
|
||||
Hostname: p.Hostname,
|
||||
Location: p.Location,
|
||||
Organization: p.Organization,
|
||||
PostalCode: p.PostalCode,
|
||||
Timezone: p.Timezone,
|
||||
}
|
||||
return publicIPCopy
|
||||
}
|
||||
@@ -1,93 +0,0 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/netip"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/constants/vpn"
|
||||
)
|
||||
|
||||
type Server struct {
|
||||
VPN string `json:"vpn,omitempty"`
|
||||
// Surfshark: country is also used for multi-hop
|
||||
Country string `json:"country,omitempty"`
|
||||
Region string `json:"region,omitempty"`
|
||||
City string `json:"city,omitempty"`
|
||||
ISP string `json:"isp,omitempty"`
|
||||
Categories []string `json:"categories,omitempty"`
|
||||
Owned bool `json:"owned,omitempty"`
|
||||
Number uint16 `json:"number,omitempty"`
|
||||
ServerName string `json:"server_name,omitempty"`
|
||||
Hostname string `json:"hostname,omitempty"`
|
||||
TCP bool `json:"tcp,omitempty"`
|
||||
UDP bool `json:"udp,omitempty"`
|
||||
OvpnX509 string `json:"x509,omitempty"`
|
||||
RetroLoc string `json:"retroloc,omitempty"` // TODO remove in v4
|
||||
MultiHop bool `json:"multihop,omitempty"`
|
||||
WgPubKey string `json:"wgpubkey,omitempty"`
|
||||
Free bool `json:"free,omitempty"` // TODO v4 create a SubscriptionTier struct
|
||||
Premium bool `json:"premium,omitempty"`
|
||||
Stream bool `json:"stream,omitempty"` // TODO v4 create a Features struct
|
||||
SecureCore bool `json:"secure_core,omitempty"`
|
||||
Tor bool `json:"tor,omitempty"`
|
||||
PortForward bool `json:"port_forward,omitempty"`
|
||||
Keep bool `json:"keep,omitempty"`
|
||||
IPs []netip.Addr `json:"ips,omitempty"`
|
||||
}
|
||||
|
||||
func (s *Server) HasMinimumInformation() (err error) {
|
||||
switch {
|
||||
case s.VPN == "":
|
||||
return errors.New("vpn field is empty")
|
||||
case len(s.IPs) == 0:
|
||||
return errors.New("ips field is empty")
|
||||
case s.VPN == vpn.Wireguard && (s.TCP || s.UDP):
|
||||
return errors.New("no network protocol should be set")
|
||||
case s.VPN == vpn.OpenVPN && !s.TCP && !s.UDP:
|
||||
return errors.New("both TCP and UDP fields are false for OpenVPN")
|
||||
case s.VPN == vpn.Wireguard && s.WgPubKey == "":
|
||||
return errors.New("wireguard public key field is empty")
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) Equal(other Server) (equal bool) {
|
||||
if !ipsAreEqual(s.IPs, other.IPs) {
|
||||
return false
|
||||
}
|
||||
|
||||
serverCopy := *s
|
||||
serverCopy.IPs = nil
|
||||
other.IPs = nil
|
||||
return reflect.DeepEqual(serverCopy, other)
|
||||
}
|
||||
|
||||
func ipsAreEqual(a, b []netip.Addr) (equal bool) {
|
||||
if len(a) != len(b) {
|
||||
return false
|
||||
}
|
||||
|
||||
for i := range a {
|
||||
if a[i].Compare(b[i]) != 0 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *Server) Key() (key string) {
|
||||
var protocols []string
|
||||
if s.TCP {
|
||||
protocols = append(protocols, "tcp")
|
||||
}
|
||||
if s.UDP {
|
||||
protocols = append(protocols, "udp")
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%s-%s-%s", s.VPN, strings.Join(protocols, "-"), s.Hostname)
|
||||
}
|
||||
@@ -1,125 +0,0 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"net/netip"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func Test_Server_Equal(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
testCases := map[string]struct {
|
||||
a *Server
|
||||
b Server
|
||||
equal bool
|
||||
}{
|
||||
"same IPs": {
|
||||
a: &Server{
|
||||
IPs: []netip.Addr{netip.AddrFrom4([4]byte{1, 2, 3, 4})},
|
||||
},
|
||||
b: Server{
|
||||
IPs: []netip.Addr{netip.AddrFrom4([4]byte{1, 2, 3, 4})},
|
||||
},
|
||||
equal: true,
|
||||
},
|
||||
"same IP strings": {
|
||||
a: &Server{
|
||||
IPs: []netip.Addr{netip.AddrFrom4([4]byte{1, 2, 3, 4})},
|
||||
},
|
||||
b: Server{
|
||||
IPs: []netip.Addr{netip.AddrFrom4([4]byte{1, 2, 3, 4})},
|
||||
},
|
||||
equal: true,
|
||||
},
|
||||
"different IPs": {
|
||||
a: &Server{
|
||||
IPs: []netip.Addr{netip.AddrFrom4([4]byte{1, 2, 3, 4}), netip.AddrFrom4([4]byte{2, 3, 4, 5})},
|
||||
},
|
||||
b: Server{
|
||||
IPs: []netip.Addr{netip.AddrFrom4([4]byte{1, 2, 3, 4}), netip.AddrFrom4([4]byte{1, 2, 3, 4})},
|
||||
},
|
||||
},
|
||||
"all fields equal": {
|
||||
a: &Server{
|
||||
VPN: "vpn",
|
||||
Country: "country",
|
||||
Region: "region",
|
||||
City: "city",
|
||||
ISP: "isp",
|
||||
Owned: true,
|
||||
Number: 1,
|
||||
ServerName: "server_name",
|
||||
Hostname: "hostname",
|
||||
TCP: true,
|
||||
UDP: true,
|
||||
OvpnX509: "x509",
|
||||
RetroLoc: "retroloc",
|
||||
MultiHop: true,
|
||||
WgPubKey: "wgpubkey",
|
||||
Free: true,
|
||||
Stream: true,
|
||||
SecureCore: true,
|
||||
Tor: true,
|
||||
PortForward: true,
|
||||
IPs: []netip.Addr{netip.AddrFrom4([4]byte{1, 2, 3, 4})},
|
||||
Keep: true,
|
||||
},
|
||||
b: Server{
|
||||
VPN: "vpn",
|
||||
Country: "country",
|
||||
Region: "region",
|
||||
City: "city",
|
||||
ISP: "isp",
|
||||
Owned: true,
|
||||
Number: 1,
|
||||
ServerName: "server_name",
|
||||
Hostname: "hostname",
|
||||
TCP: true,
|
||||
UDP: true,
|
||||
OvpnX509: "x509",
|
||||
RetroLoc: "retroloc",
|
||||
MultiHop: true,
|
||||
WgPubKey: "wgpubkey",
|
||||
Free: true,
|
||||
Stream: true,
|
||||
SecureCore: true,
|
||||
Tor: true,
|
||||
PortForward: true,
|
||||
IPs: []netip.Addr{netip.AddrFrom4([4]byte{1, 2, 3, 4})},
|
||||
Keep: true,
|
||||
},
|
||||
equal: true,
|
||||
},
|
||||
"different field": {
|
||||
a: &Server{
|
||||
VPN: "vpn",
|
||||
},
|
||||
b: Server{
|
||||
VPN: "other vpn",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for name, testCase := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
ipsOfANotNil := testCase.a.IPs != nil
|
||||
ipsOfBNotNil := testCase.b.IPs != nil
|
||||
|
||||
equal := testCase.a.Equal(testCase.b)
|
||||
|
||||
assert.Equal(t, testCase.equal, equal)
|
||||
|
||||
// Ensure IPs field is not modified
|
||||
if ipsOfANotNil {
|
||||
assert.NotNil(t, testCase.a)
|
||||
}
|
||||
if ipsOfBNotNil {
|
||||
assert.NotNil(t, testCase.b)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -9,11 +9,12 @@ import (
|
||||
"sort"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/constants/providers"
|
||||
"github.com/qdm12/gluetun/pkg/updaters/models"
|
||||
)
|
||||
|
||||
type AllServers struct {
|
||||
Version uint16 // used for migration of the top level scheme
|
||||
ProviderToServers map[string]Servers
|
||||
ProviderToServers map[string]models.Servers
|
||||
}
|
||||
|
||||
var _ json.Marshaler = (*AllServers)(nil)
|
||||
@@ -110,7 +111,7 @@ func (a *AllServers) UnmarshalJSON(data []byte) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
a.ProviderToServers = make(map[string]Servers, len(keyValues))
|
||||
a.ProviderToServers = make(map[string]models.Servers, len(keyValues))
|
||||
|
||||
allProviders := providers.All()
|
||||
allProvidersSet := make(map[string]struct{}, len(allProviders))
|
||||
@@ -131,7 +132,7 @@ func (a *AllServers) UnmarshalJSON(data []byte) (err error) {
|
||||
key, err)
|
||||
}
|
||||
|
||||
var servers Servers
|
||||
var servers models.Servers
|
||||
err = json.Unmarshal(jsonValue, &servers)
|
||||
if err != nil {
|
||||
return fmt.Errorf("decoding %s servers: %w",
|
||||
@@ -151,24 +152,18 @@ func (a *AllServers) Count() (count int) {
|
||||
return count
|
||||
}
|
||||
|
||||
type Servers struct {
|
||||
Version uint16 `json:"version"`
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
Servers []Server `json:"servers,omitempty"`
|
||||
}
|
||||
|
||||
func (s *Servers) Format(vpnProvider, format string) (formatted string, err error) {
|
||||
func FormatServers(s models.Servers, vpnProvider, format string) (formatted string, err error) {
|
||||
switch format {
|
||||
case "markdown":
|
||||
return s.toMarkdown(vpnProvider)
|
||||
return serversToMarkdown(s, vpnProvider)
|
||||
case "json":
|
||||
return s.toJSON()
|
||||
return serversToJSON(s)
|
||||
default:
|
||||
return "", fmt.Errorf("servers format not supported: %s", format)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Servers) toJSON() (formatted string, err error) {
|
||||
func serversToJSON(s models.Servers) (formatted string, err error) {
|
||||
buffer := bytes.NewBuffer(nil)
|
||||
encoder := json.NewEncoder(buffer)
|
||||
encoder.SetIndent("", " ")
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/constants/providers"
|
||||
"github.com/qdm12/gluetun/pkg/updaters/models"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
@@ -20,18 +21,18 @@ func Test_AllServers_MarshalJSON(t *testing.T) {
|
||||
}{
|
||||
"no provider": {
|
||||
allServers: &AllServers{
|
||||
ProviderToServers: map[string]Servers{},
|
||||
ProviderToServers: map[string]models.Servers{},
|
||||
},
|
||||
dataString: `{"version":0}`,
|
||||
},
|
||||
"two providers": {
|
||||
allServers: &AllServers{
|
||||
Version: 1,
|
||||
ProviderToServers: map[string]Servers{
|
||||
ProviderToServers: map[string]models.Servers{
|
||||
providers.Cyberghost: {
|
||||
Version: 1,
|
||||
Timestamp: 1000,
|
||||
Servers: []Server{
|
||||
Servers: []models.Server{
|
||||
{Country: "A"},
|
||||
{Country: "B"},
|
||||
},
|
||||
@@ -39,7 +40,7 @@ func Test_AllServers_MarshalJSON(t *testing.T) {
|
||||
providers.Privado: {
|
||||
Version: 2,
|
||||
Timestamp: 2000,
|
||||
Servers: []Server{
|
||||
Servers: []models.Server{
|
||||
{City: "C"},
|
||||
{City: "D"},
|
||||
},
|
||||
@@ -100,11 +101,11 @@ func Test_AllServers_UnmarshalJSON(t *testing.T) {
|
||||
`"privado":{"version":2,"timestamp":2000,"servers":[{"city":"C"},{"city":"D"}]}}`,
|
||||
allServers: AllServers{
|
||||
Version: 1,
|
||||
ProviderToServers: map[string]Servers{
|
||||
ProviderToServers: map[string]models.Servers{
|
||||
providers.Cyberghost: {
|
||||
Version: 1,
|
||||
Timestamp: 1000,
|
||||
Servers: []Server{
|
||||
Servers: []models.Server{
|
||||
{Country: "A"},
|
||||
{Country: "B"},
|
||||
},
|
||||
@@ -112,7 +113,7 @@ func Test_AllServers_UnmarshalJSON(t *testing.T) {
|
||||
providers.Privado: {
|
||||
Version: 2,
|
||||
Timestamp: 2000,
|
||||
Servers: []Server{
|
||||
Servers: []models.Server{
|
||||
{City: "C"},
|
||||
{City: "D"},
|
||||
},
|
||||
@@ -146,11 +147,11 @@ func Test_AllServers_JSON_Marshal_Unmarshal(t *testing.T) {
|
||||
|
||||
allServers := &AllServers{
|
||||
Version: 1,
|
||||
ProviderToServers: map[string]Servers{
|
||||
ProviderToServers: map[string]models.Servers{
|
||||
providers.Cyberghost: {
|
||||
Version: 1,
|
||||
Timestamp: 1000,
|
||||
Servers: []Server{
|
||||
Servers: []models.Server{
|
||||
{Country: "A"},
|
||||
{Country: "B"},
|
||||
},
|
||||
@@ -158,7 +159,7 @@ func Test_AllServers_JSON_Marshal_Unmarshal(t *testing.T) {
|
||||
providers.Privado: {
|
||||
Version: 2,
|
||||
Timestamp: 2000,
|
||||
Servers: []Server{
|
||||
Servers: []models.Server{
|
||||
{City: "C"},
|
||||
{City: "D"},
|
||||
},
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
package models
|
||||
|
||||
import "sort"
|
||||
|
||||
var _ sort.Interface = (*SortableServers)(nil)
|
||||
|
||||
type SortableServers []Server
|
||||
|
||||
func (s SortableServers) Len() int {
|
||||
return len(s)
|
||||
}
|
||||
|
||||
func (s SortableServers) Swap(i, j int) {
|
||||
s[i], s[j] = s[j], s[i]
|
||||
}
|
||||
|
||||
func (s SortableServers) Less(i, j int) bool {
|
||||
a, b := s[i], s[j]
|
||||
|
||||
if a.Country == b.Country { //nolint:nestif
|
||||
if a.Region == b.Region {
|
||||
if a.City == b.City {
|
||||
if a.ServerName == b.ServerName {
|
||||
if a.Number == b.Number {
|
||||
if a.Hostname == b.Hostname {
|
||||
if a.ISP == b.ISP {
|
||||
return a.VPN < b.VPN
|
||||
}
|
||||
return a.ISP < b.ISP
|
||||
}
|
||||
return a.Hostname < b.Hostname
|
||||
}
|
||||
return a.Number < b.Number
|
||||
}
|
||||
return a.ServerName < b.ServerName
|
||||
}
|
||||
return a.City < b.City
|
||||
}
|
||||
return a.Region < b.Region
|
||||
}
|
||||
return a.Country < b.Country
|
||||
}
|
||||
Reference in New Issue
Block a user