chore(updater): create resolver in provider updater

- Pass min servers to resolve call
- Set settings when constructing resolver
- Construct resolver in each provider updater
- No more common resolver for all providers
This commit is contained in:
Quentin McGaw
2022-06-09 02:54:39 +00:00
parent e37f557cd5
commit 415cb7a945
53 changed files with 155 additions and 483 deletions

View File

@@ -1,16 +1,12 @@
package cyberghost
import (
"context"
"net"
"time"
"github.com/qdm12/gluetun/internal/updater/resolver"
)
func resolveHosts(ctx context.Context, presolver resolver.Parallel,
possibleHosts []string, minServers int) (
hostToIPs map[string][]net.IP, err error) {
func newParallelResolver() (parallelResolver resolver.Parallel) {
const (
maxFailRatio = 1
maxDuration = 20 * time.Second
@@ -20,7 +16,6 @@ func resolveHosts(ctx context.Context, presolver resolver.Parallel,
)
settings := resolver.ParallelSettings{
MaxFailRatio: maxFailRatio,
MinFound: minServers,
Repeat: resolver.RepeatSettings{
MaxDuration: maxDuration,
BetweenDuration: betweenDuration,
@@ -29,10 +24,5 @@ func resolveHosts(ctx context.Context, presolver resolver.Parallel,
SortIPs: true,
},
}
hostToIPs, _, err = presolver.Resolve(ctx, possibleHosts, settings)
if err != nil {
return nil, err
}
return hostToIPs, nil
return resolver.NewParallelResolver(settings)
}

View File

@@ -14,7 +14,7 @@ func (u *Updater) FetchServers(ctx context.Context, minServers int) (
possibleServers := getPossibleServers()
possibleHosts := possibleServers.hostsSlice()
hostToIPs, err := resolveHosts(ctx, u.presolver, possibleHosts, minServers)
hostToIPs, _, err := u.presolver.Resolve(ctx, possibleHosts, minServers)
if err != nil {
return nil, err
}

View File

@@ -6,8 +6,8 @@ type Updater struct {
presolver resolver.Parallel
}
func New(presolver resolver.Parallel) *Updater {
func New() *Updater {
return &Updater{
presolver: presolver,
presolver: newParallelResolver(),
}
}

View File

@@ -1,16 +1,12 @@
package expressvpn
import (
"context"
"net"
"time"
"github.com/qdm12/gluetun/internal/updater/resolver"
)
func resolveHosts(ctx context.Context, presolver resolver.Parallel,
hosts []string, minServers int) (hostToIPs map[string][]net.IP,
warnings []string, err error) {
func newParallelResolver() resolver.Parallel {
const (
maxFailRatio = 0.1
maxNoNew = 1
@@ -18,7 +14,6 @@ func resolveHosts(ctx context.Context, presolver resolver.Parallel,
)
settings := resolver.ParallelSettings{
MaxFailRatio: maxFailRatio,
MinFound: minServers,
Repeat: resolver.RepeatSettings{
MaxDuration: time.Second,
MaxNoNew: maxNoNew,
@@ -26,5 +21,5 @@ func resolveHosts(ctx context.Context, presolver resolver.Parallel,
SortIPs: true,
},
}
return presolver.Resolve(ctx, hosts, settings)
return resolver.NewParallelResolver(settings)
}

View File

@@ -21,7 +21,7 @@ func (u *Updater) FetchServers(ctx context.Context, minServers int) (
hosts[i] = servers[i].Hostname
}
hostToIPs, warnings, err := resolveHosts(ctx, u.presolver, hosts, minServers)
hostToIPs, warnings, err := u.presolver.Resolve(ctx, hosts, minServers)
for _, warning := range warnings {
u.warner.Warn(warning)
}

View File

@@ -15,11 +15,10 @@ type Warner interface {
Warn(s string)
}
func New(unzipper unzip.Unzipper, presolver resolver.Parallel,
warner Warner) *Updater {
func New(unzipper unzip.Unzipper, warner Warner) *Updater {
return &Updater{
unzipper: unzipper,
presolver: presolver,
presolver: newParallelResolver(),
warner: warner,
}
}

View File

@@ -1,16 +1,12 @@
package fastestvpn
import (
"context"
"net"
"time"
"github.com/qdm12/gluetun/internal/updater/resolver"
)
func resolveHosts(ctx context.Context, presolver resolver.Parallel,
hosts []string, minServers int) (hostToIPs map[string][]net.IP,
warnings []string, err error) {
func newParallelResolver() resolver.Parallel {
const (
maxFailRatio = 0.1
maxNoNew = 1
@@ -18,7 +14,6 @@ func resolveHosts(ctx context.Context, presolver resolver.Parallel,
)
settings := resolver.ParallelSettings{
MaxFailRatio: maxFailRatio,
MinFound: minServers,
Repeat: resolver.RepeatSettings{
MaxDuration: time.Second,
MaxNoNew: maxNoNew,
@@ -26,5 +21,5 @@ func resolveHosts(ctx context.Context, presolver resolver.Parallel,
SortIPs: true,
},
}
return presolver.Resolve(ctx, hosts, settings)
return resolver.NewParallelResolver(settings)
}

View File

@@ -56,7 +56,7 @@ func (u *Updater) FetchServers(ctx context.Context, minServers int) (
}
hosts := hts.toHostsSlice()
hostToIPs, warnings, err := resolveHosts(ctx, u.presolver, hosts, minServers)
hostToIPs, warnings, err := u.presolver.Resolve(ctx, hosts, minServers)
for _, warning := range warnings {
u.warner.Warn(warning)
}

View File

@@ -15,11 +15,10 @@ type Warner interface {
Warn(s string)
}
func New(unzipper unzip.Unzipper, presolver resolver.Parallel,
warner Warner) *Updater {
func New(unzipper unzip.Unzipper, warner Warner) *Updater {
return &Updater{
unzipper: unzipper,
presolver: presolver,
presolver: newParallelResolver(),
warner: warner,
}
}

View File

@@ -1,16 +1,12 @@
package hidemyass
import (
"context"
"net"
"time"
"github.com/qdm12/gluetun/internal/updater/resolver"
)
func resolveHosts(ctx context.Context, presolver resolver.Parallel,
hosts []string, minServers int) (
hostToIPs map[string][]net.IP, warnings []string, err error) {
func newParallelResolver() resolver.Parallel {
const (
maxFailRatio = 0.1
maxDuration = 15 * time.Second
@@ -20,7 +16,6 @@ func resolveHosts(ctx context.Context, presolver resolver.Parallel,
)
settings := resolver.ParallelSettings{
MaxFailRatio: maxFailRatio,
MinFound: minServers,
Repeat: resolver.RepeatSettings{
MaxDuration: maxDuration,
BetweenDuration: betweenDuration,
@@ -29,5 +24,5 @@ func resolveHosts(ctx context.Context, presolver resolver.Parallel,
SortIPs: true,
},
}
return presolver.Resolve(ctx, hosts, settings)
return resolver.NewParallelResolver(settings)
}

View File

@@ -26,7 +26,7 @@ func (u *Updater) FetchServers(ctx context.Context, minServers int) (
common.ErrNotEnoughServers, len(hosts), minServers)
}
hostToIPs, warnings, err := resolveHosts(ctx, u.presolver, hosts, minServers)
hostToIPs, warnings, err := u.presolver.Resolve(ctx, hosts, minServers)
for _, warning := range warnings {
u.warner.Warn(warning)
}

View File

@@ -16,11 +16,10 @@ type Warner interface {
Warn(s string)
}
func New(client *http.Client, presolver resolver.Parallel,
warner Warner) *Updater {
func New(client *http.Client, warner Warner) *Updater {
return &Updater{
client: client,
presolver: presolver,
presolver: newParallelResolver(),
warner: warner,
}
}

View File

@@ -1,14 +1,12 @@
package ipvanish
import (
"context"
"net"
"time"
"github.com/qdm12/gluetun/internal/updater/resolver"
)
func getResolveSettings(minServers int) (settings resolver.ParallelSettings) {
func newParallelResolver() (parallelResolver resolver.Parallel) {
const (
maxFailRatio = 0.1
maxDuration = 20 * time.Second
@@ -16,9 +14,8 @@ func getResolveSettings(minServers int) (settings resolver.ParallelSettings) {
maxNoNew = 2
maxFails = 2
)
return resolver.ParallelSettings{
settings := resolver.ParallelSettings{
MaxFailRatio: maxFailRatio,
MinFound: minServers,
Repeat: resolver.RepeatSettings{
MaxDuration: maxDuration,
BetweenDuration: betweenDuration,
@@ -27,11 +24,5 @@ func getResolveSettings(minServers int) (settings resolver.ParallelSettings) {
SortIPs: true,
},
}
}
func resolveHosts(ctx context.Context, presolver resolver.Parallel,
hosts []string, minServers int) (hostToIPs map[string][]net.IP,
warnings []string, err error) {
settings := getResolveSettings(minServers)
return presolver.Resolve(ctx, hosts, settings)
return resolver.NewParallelResolver(settings)
}

View File

@@ -1,57 +0,0 @@
package ipvanish
import (
"context"
"errors"
"net"
"testing"
"time"
"github.com/golang/mock/gomock"
"github.com/qdm12/gluetun/internal/updater/resolver"
"github.com/qdm12/gluetun/internal/updater/resolver/mock_resolver"
"github.com/stretchr/testify/assert"
)
func Test_resolveHosts(t *testing.T) {
t.Parallel()
ctrl := gomock.NewController(t)
ctx := context.Background()
presolver := mock_resolver.NewMockParallel(ctrl)
hosts := []string{"host1", "host2"}
const minServers = 10
expectedHostToIPs := map[string][]net.IP{
"host1": {{1, 2, 3, 4}},
"host2": {{2, 3, 4, 5}},
}
expectedWarnings := []string{"warning1", "warning2"}
expectedErr := errors.New("dummy")
const (
maxFailRatio = 0.1
maxDuration = 20 * time.Second
betweenDuration = time.Second
maxNoNew = 2
maxFails = 2
)
expectedSettings := resolver.ParallelSettings{
MaxFailRatio: maxFailRatio,
MinFound: minServers,
Repeat: resolver.RepeatSettings{
MaxDuration: maxDuration,
BetweenDuration: betweenDuration,
MaxNoNew: maxNoNew,
MaxFails: maxFails,
SortIPs: true,
},
}
presolver.EXPECT().Resolve(ctx, hosts, expectedSettings).
Return(expectedHostToIPs, expectedWarnings, expectedErr)
hostToIPs, warnings, err := resolveHosts(ctx, presolver, hosts, minServers)
assert.Equal(t, expectedHostToIPs, hostToIPs)
assert.Equal(t, expectedWarnings, warnings)
assert.Equal(t, expectedErr, err)
}

View File

@@ -67,7 +67,7 @@ func (u *Updater) FetchServers(ctx context.Context, minServers int) (
}
hosts := hts.toHostsSlice()
hostToIPs, warnings, err := resolveHosts(ctx, u.presolver, hosts, minServers)
hostToIPs, warnings, err := u.presolver.Resolve(ctx, hosts, minServers)
for _, warning := range warnings {
u.warner.Warn(warning)
}

View File

@@ -9,7 +9,6 @@ import (
"github.com/golang/mock/gomock"
"github.com/qdm12/gluetun/internal/constants/vpn"
"github.com/qdm12/gluetun/internal/models"
"github.com/qdm12/gluetun/internal/updater/resolver"
"github.com/qdm12/gluetun/internal/updater/resolver/mock_resolver"
"github.com/qdm12/gluetun/internal/updater/unzip/mock_unzip"
"github.com/stretchr/testify/assert"
@@ -32,7 +31,6 @@ func Test_Updater_GetServers(t *testing.T) {
// Resolution
expectResolve bool
hostsToResolve []string
resolveSettings resolver.ParallelSettings
hostToIPs map[string][]net.IP
resolveWarnings []string
resolveErr error
@@ -90,7 +88,6 @@ func Test_Updater_GetServers(t *testing.T) {
},
expectResolve: true,
hostsToResolve: []string{"hosta"},
resolveSettings: getResolveSettings(1),
err: errors.New("not enough servers found: 0 and expected at least 1"),
},
"resolve error": {
@@ -104,7 +101,6 @@ func Test_Updater_GetServers(t *testing.T) {
},
expectResolve: true,
hostsToResolve: []string{"hosta"},
resolveSettings: getResolveSettings(0),
resolveWarnings: []string{"resolve warning"},
resolveErr: errors.New("dummy"),
err: errors.New("dummy"),
@@ -134,7 +130,6 @@ func Test_Updater_GetServers(t *testing.T) {
},
expectResolve: true,
hostsToResolve: []string{"hosta", "hostb"},
resolveSettings: getResolveSettings(1),
hostToIPs: map[string][]net.IP{
"hosta": {{1, 1, 1, 1}, {2, 2, 2, 2}},
"hostb": {{3, 3, 3, 3}, {4, 4, 4, 4}},
@@ -175,13 +170,15 @@ func Test_Updater_GetServers(t *testing.T) {
presolver := mock_resolver.NewMockParallel(ctrl)
if testCase.expectResolve {
presolver.EXPECT().Resolve(ctx, testCase.hostsToResolve, testCase.resolveSettings).
presolver.EXPECT().Resolve(ctx, testCase.hostsToResolve, testCase.minServers).
Return(testCase.hostToIPs, testCase.resolveWarnings, testCase.resolveErr)
}
warner := testCase.warnerBuilder(ctrl)
updater := New(unzipper, presolver, warner)
updater := &Updater{
unzipper: unzipper,
warner: testCase.warnerBuilder(ctrl),
presolver: presolver,
}
servers, err := updater.FetchServers(ctx, testCase.minServers)

View File

@@ -7,19 +7,18 @@ import (
type Updater struct {
unzipper unzip.Unzipper
presolver resolver.Parallel
warner Warner
presolver resolver.Parallel
}
type Warner interface {
Warn(s string)
}
func New(unzipper unzip.Unzipper, presolver resolver.Parallel,
warner Warner) *Updater {
func New(unzipper unzip.Unzipper, warner Warner) *Updater {
return &Updater{
unzipper: unzipper,
presolver: presolver,
warner: warner,
presolver: newParallelResolver(),
}
}

View File

@@ -1,14 +1,12 @@
package ivpn
import (
"context"
"net"
"time"
"github.com/qdm12/gluetun/internal/updater/resolver"
)
func getResolveSettings(minServers int) (settings resolver.ParallelSettings) {
func newParallelResolver() (parallelResolver resolver.Parallel) {
const (
maxFailRatio = 0.1
maxDuration = 20 * time.Second
@@ -16,9 +14,8 @@ func getResolveSettings(minServers int) (settings resolver.ParallelSettings) {
maxNoNew = 2
maxFails = 2
)
return resolver.ParallelSettings{
settings := resolver.ParallelSettings{
MaxFailRatio: maxFailRatio,
MinFound: minServers,
Repeat: resolver.RepeatSettings{
MaxDuration: maxDuration,
BetweenDuration: betweenDuration,
@@ -27,11 +24,5 @@ func getResolveSettings(minServers int) (settings resolver.ParallelSettings) {
SortIPs: true,
},
}
}
func resolveHosts(ctx context.Context, presolver resolver.Parallel,
hosts []string, minServers int) (hostToIPs map[string][]net.IP,
warnings []string, err error) {
settings := getResolveSettings(minServers)
return presolver.Resolve(ctx, hosts, settings)
return resolver.NewParallelResolver(settings)
}

View File

@@ -1,57 +0,0 @@
package ivpn
import (
"context"
"errors"
"net"
"testing"
"time"
"github.com/golang/mock/gomock"
"github.com/qdm12/gluetun/internal/updater/resolver"
"github.com/qdm12/gluetun/internal/updater/resolver/mock_resolver"
"github.com/stretchr/testify/assert"
)
func Test_resolveHosts(t *testing.T) {
t.Parallel()
ctrl := gomock.NewController(t)
ctx := context.Background()
presolver := mock_resolver.NewMockParallel(ctrl)
hosts := []string{"host1", "host2"}
const minServers = 10
expectedHostToIPs := map[string][]net.IP{
"host1": {{1, 2, 3, 4}},
"host2": {{2, 3, 4, 5}},
}
expectedWarnings := []string{"warning1", "warning2"}
expectedErr := errors.New("dummy")
const (
maxFailRatio = 0.1
maxDuration = 20 * time.Second
betweenDuration = time.Second
maxNoNew = 2
maxFails = 2
)
expectedSettings := resolver.ParallelSettings{
MaxFailRatio: maxFailRatio,
MinFound: minServers,
Repeat: resolver.RepeatSettings{
MaxDuration: maxDuration,
BetweenDuration: betweenDuration,
MaxNoNew: maxNoNew,
MaxFails: maxFails,
SortIPs: true,
},
}
presolver.EXPECT().Resolve(ctx, hosts, expectedSettings).
Return(expectedHostToIPs, expectedWarnings, expectedErr)
hostToIPs, warnings, err := resolveHosts(ctx, presolver, hosts, minServers)
assert.Equal(t, expectedHostToIPs, hostToIPs)
assert.Equal(t, expectedWarnings, warnings)
assert.Equal(t, expectedErr, err)
}

View File

@@ -38,7 +38,7 @@ func (u *Updater) FetchServers(ctx context.Context, minServers int) (
common.ErrNotEnoughServers, len(hosts), minServers)
}
hostToIPs, warnings, err := resolveHosts(ctx, u.presolver, hosts, minServers)
hostToIPs, warnings, err := u.presolver.Resolve(ctx, hosts, minServers)
for _, warning := range warnings {
u.warner.Warn(warning)
}

View File

@@ -12,7 +12,6 @@ import (
"github.com/golang/mock/gomock"
"github.com/qdm12/gluetun/internal/constants/vpn"
"github.com/qdm12/gluetun/internal/models"
"github.com/qdm12/gluetun/internal/updater/resolver"
"github.com/qdm12/gluetun/internal/updater/resolver/mock_resolver"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -35,7 +34,6 @@ func Test_Updater_GetServers(t *testing.T) {
// Resolution
expectResolve bool
hostsToResolve []string
resolveSettings resolver.ParallelSettings
hostToIPs map[string][]net.IP
resolveWarnings []string
resolveErr error
@@ -61,7 +59,6 @@ func Test_Updater_GetServers(t *testing.T) {
responseStatus: http.StatusOK,
expectResolve: true,
hostsToResolve: []string{"hosta"},
resolveSettings: getResolveSettings(0),
resolveWarnings: []string{"resolve warning"},
resolveErr: errors.New("dummy"),
err: errors.New("dummy"),
@@ -90,7 +87,6 @@ func Test_Updater_GetServers(t *testing.T) {
responseStatus: http.StatusOK,
expectResolve: true,
hostsToResolve: []string{"hosta", "hostb", "hostc"},
resolveSettings: getResolveSettings(1),
hostToIPs: map[string][]net.IP{
"hosta": {{1, 1, 1, 1}, {2, 2, 2, 2}},
"hostb": {{3, 3, 3, 3}, {4, 4, 4, 4}},
@@ -134,13 +130,17 @@ func Test_Updater_GetServers(t *testing.T) {
presolver := mock_resolver.NewMockParallel(ctrl)
if testCase.expectResolve {
presolver.EXPECT().Resolve(ctx, testCase.hostsToResolve, testCase.resolveSettings).
presolver.EXPECT().Resolve(ctx, testCase.hostsToResolve, testCase.minServers).
Return(testCase.hostToIPs, testCase.resolveWarnings, testCase.resolveErr)
}
warner := testCase.warnerBuilder(ctrl)
updater := New(client, presolver, warner)
updater := &Updater{
client: client,
presolver: presolver,
warner: warner,
}
servers, err := updater.FetchServers(ctx, testCase.minServers)

View File

@@ -16,11 +16,10 @@ type Warner interface {
Warn(s string)
}
func New(client *http.Client, presolver resolver.Parallel,
warner Warner) *Updater {
func New(client *http.Client, warner Warner) *Updater {
return &Updater{
client: client,
presolver: presolver,
presolver: newParallelResolver(),
warner: warner,
}
}

View File

@@ -1,25 +1,20 @@
package privado
import (
"context"
"net"
"time"
"github.com/qdm12/gluetun/internal/updater/resolver"
)
func resolveHosts(ctx context.Context, presolver resolver.Parallel,
hosts []string, minServers int) (hostToIPs map[string][]net.IP,
warnings []string, err error) {
func newParallelResolver() (parallelResolver resolver.Parallel) {
const (
maxFailRatio = 0.1
maxDuration = 30 * time.Second
maxNoNew = 1
maxFails = 5
maxNoNew = 2
maxFails = 2
)
settings := resolver.ParallelSettings{
MaxFailRatio: maxFailRatio,
MinFound: minServers,
Repeat: resolver.RepeatSettings{
MaxDuration: maxDuration,
MaxNoNew: maxNoNew,
@@ -27,5 +22,5 @@ func resolveHosts(ctx context.Context, presolver resolver.Parallel,
SortIPs: true,
},
}
return presolver.Resolve(ctx, hosts, settings)
return resolver.NewParallelResolver(settings)
}

View File

@@ -50,7 +50,7 @@ func (u *Updater) FetchServers(ctx context.Context, minServers int) (
}
hosts := hts.toHostsSlice()
hostToIPs, warnings, err := resolveHosts(ctx, u.presolver, hosts, minServers)
hostToIPs, warnings, err := u.presolver.Resolve(ctx, hosts, minServers)
for _, warning := range warnings {
u.warner.Warn(warning)
}

View File

@@ -19,11 +19,11 @@ type Warner interface {
}
func New(client *http.Client, unzipper unzip.Unzipper,
presolver resolver.Parallel, warner Warner) *Updater {
warner Warner) *Updater {
return &Updater{
client: client,
unzipper: unzipper,
presolver: presolver,
presolver: newParallelResolver(),
warner: warner,
}
}

View File

@@ -1,16 +1,12 @@
package privatevpn
import (
"context"
"net"
"time"
"github.com/qdm12/gluetun/internal/updater/resolver"
)
func resolveHosts(ctx context.Context, presolver resolver.Parallel,
hosts []string, minServers int) (hostToIPs map[string][]net.IP,
warnings []string, err error) {
func newParallelResolver() (parallelResolver resolver.Parallel) {
const (
maxFailRatio = 0.1
maxDuration = 6 * time.Second
@@ -20,7 +16,6 @@ func resolveHosts(ctx context.Context, presolver resolver.Parallel,
)
settings := resolver.ParallelSettings{
MaxFailRatio: maxFailRatio,
MinFound: minServers,
Repeat: resolver.RepeatSettings{
MaxDuration: maxDuration,
BetweenDuration: betweenDuration,
@@ -29,5 +24,5 @@ func resolveHosts(ctx context.Context, presolver resolver.Parallel,
SortIPs: true,
},
}
return presolver.Resolve(ctx, hosts, settings)
return resolver.NewParallelResolver(settings)
}

View File

@@ -82,7 +82,7 @@ func (u *Updater) FetchServers(ctx context.Context, minServers int) (
hosts := hts.toHostsSlice()
hostToIPs, warnings, err := resolveHosts(ctx, u.presolver, hosts, minServers)
hostToIPs, warnings, err := u.presolver.Resolve(ctx, hosts, minServers)
for _, warning := range warnings {
u.warner.Warn(warning)
}

View File

@@ -15,11 +15,10 @@ type Warner interface {
Warn(s string)
}
func New(unzipper unzip.Unzipper, presolver resolver.Parallel,
warner Warner) *Updater {
func New(unzipper unzip.Unzipper, warner Warner) *Updater {
return &Updater{
unzipper: unzipper,
presolver: presolver,
presolver: newParallelResolver(),
warner: warner,
}
}

View File

@@ -1,16 +1,12 @@
package purevpn
import (
"context"
"net"
"time"
"github.com/qdm12/gluetun/internal/updater/resolver"
)
func resolveHosts(ctx context.Context, presolver resolver.Parallel,
hosts []string, minServers int) (hostToIPs map[string][]net.IP,
warnings []string, err error) {
func newParallelResolver() (parallelResolver resolver.Parallel) {
const (
maxFailRatio = 0.1
maxDuration = 20 * time.Second
@@ -20,7 +16,6 @@ func resolveHosts(ctx context.Context, presolver resolver.Parallel,
)
settings := resolver.ParallelSettings{
MaxFailRatio: maxFailRatio,
MinFound: minServers,
Repeat: resolver.RepeatSettings{
MaxDuration: maxDuration,
BetweenDuration: betweenDuration,
@@ -29,5 +24,5 @@ func resolveHosts(ctx context.Context, presolver resolver.Parallel,
SortIPs: true,
},
}
return presolver.Resolve(ctx, hosts, settings)
return resolver.NewParallelResolver(settings)
}

View File

@@ -60,7 +60,7 @@ func (u *Updater) FetchServers(ctx context.Context, minServers int) (
}
hosts := hts.toHostsSlice()
hostToIPs, warnings, err := resolveHosts(ctx, u.presolver, hosts, minServers)
hostToIPs, warnings, err := u.presolver.Resolve(ctx, hosts, minServers)
for _, warning := range warnings {
u.warner.Warn(warning)
}

View File

@@ -19,11 +19,11 @@ type Warner interface {
}
func New(client *http.Client, unzipper unzip.Unzipper,
presolver resolver.Parallel, warner Warner) *Updater {
warner Warner) *Updater {
return &Updater{
client: client,
unzipper: unzipper,
presolver: presolver,
presolver: newParallelResolver(),
warner: warner,
}
}

View File

@@ -1,16 +1,12 @@
package surfshark
import (
"context"
"net"
"time"
"github.com/qdm12/gluetun/internal/updater/resolver"
)
func resolveHosts(ctx context.Context, presolver resolver.Parallel,
hosts []string, minServers int) (hostToIPs map[string][]net.IP,
warnings []string, err error) {
func newParallelResolver() (parallelResolver resolver.Parallel) {
const (
maxFailRatio = 0.1
maxDuration = 20 * time.Second
@@ -20,7 +16,6 @@ func resolveHosts(ctx context.Context, presolver resolver.Parallel,
)
settings := resolver.ParallelSettings{
MaxFailRatio: maxFailRatio,
MinFound: minServers,
Repeat: resolver.RepeatSettings{
MaxDuration: maxDuration,
BetweenDuration: betweenDuration,
@@ -29,5 +24,5 @@ func resolveHosts(ctx context.Context, presolver resolver.Parallel,
SortIPs: true,
},
}
return presolver.Resolve(ctx, hosts, settings)
return resolver.NewParallelResolver(settings)
}

View File

@@ -1,57 +0,0 @@
package surfshark
import (
"context"
"errors"
"net"
"testing"
"time"
"github.com/golang/mock/gomock"
"github.com/qdm12/gluetun/internal/updater/resolver"
"github.com/qdm12/gluetun/internal/updater/resolver/mock_resolver"
"github.com/stretchr/testify/assert"
)
func Test_resolveHosts(t *testing.T) {
t.Parallel()
ctrl := gomock.NewController(t)
ctx := context.Background()
presolver := mock_resolver.NewMockParallel(ctrl)
hosts := []string{"host1", "host2"}
const minServers = 10
expectedHostToIPs := map[string][]net.IP{
"host1": {{1, 2, 3, 4}},
"host2": {{2, 3, 4, 5}},
}
expectedWarnings := []string{"warning1", "warning2"}
expectedErr := errors.New("dummy")
const (
maxFailRatio = 0.1
maxDuration = 20 * time.Second
betweenDuration = time.Second
maxNoNew = 2
maxFails = 2
)
expectedSettings := resolver.ParallelSettings{
MaxFailRatio: maxFailRatio,
MinFound: minServers,
Repeat: resolver.RepeatSettings{
MaxDuration: maxDuration,
BetweenDuration: betweenDuration,
MaxNoNew: maxNoNew,
MaxFails: maxFails,
SortIPs: true,
},
}
presolver.EXPECT().Resolve(ctx, hosts, expectedSettings).
Return(expectedHostToIPs, expectedWarnings, expectedErr)
hostToIPs, warnings, err := resolveHosts(ctx, presolver, hosts, minServers)
assert.Equal(t, expectedHostToIPs, hostToIPs)
assert.Equal(t, expectedWarnings, warnings)
assert.Equal(t, expectedErr, err)
}

View File

@@ -31,7 +31,7 @@ func (u *Updater) FetchServers(ctx context.Context, minServers int) (
getRemainingServers(hts)
hosts := hts.toHostsSlice()
hostToIPs, warnings, err := resolveHosts(ctx, u.presolver, hosts, minServers)
hostToIPs, warnings, err := u.presolver.Resolve(ctx, hosts, minServers)
for _, warning := range warnings {
u.warner.Warn(warning)
}

View File

@@ -19,11 +19,11 @@ type Warner interface {
}
func New(client *http.Client, unzipper unzip.Unzipper,
presolver resolver.Parallel, warner Warner) *Updater {
warner Warner) *Updater {
return &Updater{
client: client,
unzipper: unzipper,
presolver: presolver,
presolver: newParallelResolver(),
warner: warner,
}
}

View File

@@ -1,16 +1,12 @@
package torguard
import (
"context"
"net"
"time"
"github.com/qdm12/gluetun/internal/updater/resolver"
)
func resolveHosts(ctx context.Context, presolver resolver.Parallel,
hosts []string, minServers int) (hostToIPs map[string][]net.IP,
warnings []string, err error) {
func newParallelResolver() (parallelResolver resolver.Parallel) {
const (
maxFailRatio = 0.1
maxDuration = 20 * time.Second
@@ -20,7 +16,6 @@ func resolveHosts(ctx context.Context, presolver resolver.Parallel,
)
settings := resolver.ParallelSettings{
MaxFailRatio: maxFailRatio,
MinFound: minServers,
Repeat: resolver.RepeatSettings{
MaxDuration: maxDuration,
BetweenDuration: betweenDuration,
@@ -29,5 +24,5 @@ func resolveHosts(ctx context.Context, presolver resolver.Parallel,
SortIPs: true,
},
}
return presolver.Resolve(ctx, hosts, settings)
return resolver.NewParallelResolver(settings)
}

View File

@@ -50,7 +50,7 @@ func (u *Updater) FetchServers(ctx context.Context, minServers int) (
}
hosts := hts.toHostsSlice()
hostToIPs, warnings, err := resolveHosts(ctx, u.presolver, hosts, minServers)
hostToIPs, warnings, err := u.presolver.Resolve(ctx, hosts, minServers)
u.warnWarnings(warnings)
if err != nil {
return nil, err

View File

@@ -15,11 +15,10 @@ type Warner interface {
Warn(s string)
}
func New(unzipper unzip.Unzipper, presolver resolver.Parallel,
warner Warner) *Updater {
func New(unzipper unzip.Unzipper, warner Warner) *Updater {
return &Updater{
unzipper: unzipper,
presolver: presolver,
presolver: newParallelResolver(),
warner: warner,
}
}

View File

@@ -1,16 +1,12 @@
package vpnunlimited
import (
"context"
"net"
"time"
"github.com/qdm12/gluetun/internal/updater/resolver"
)
func resolveHosts(ctx context.Context, presolver resolver.Parallel,
hosts []string, minServers int) (hostToIPs map[string][]net.IP,
warnings []string, err error) {
func newParallelResolver() (parallelResolver resolver.Parallel) {
const (
maxFailRatio = 0.1
maxDuration = 20 * time.Second
@@ -20,7 +16,6 @@ func resolveHosts(ctx context.Context, presolver resolver.Parallel,
)
settings := resolver.ParallelSettings{
MaxFailRatio: maxFailRatio,
MinFound: minServers,
Repeat: resolver.RepeatSettings{
MaxDuration: maxDuration,
BetweenDuration: betweenDuration,
@@ -29,5 +24,5 @@ func resolveHosts(ctx context.Context, presolver resolver.Parallel,
SortIPs: true,
},
}
return presolver.Resolve(ctx, hosts, settings)
return resolver.NewParallelResolver(settings)
}

View File

@@ -20,7 +20,7 @@ func (u *Updater) FetchServers(ctx context.Context, minServers int) (
}
hosts := hts.toHostsSlice()
hostToIPs, warnings, err := resolveHosts(ctx, u.presolver, hosts, minServers)
hostToIPs, warnings, err := u.presolver.Resolve(ctx, hosts, minServers)
for _, warning := range warnings {
u.warner.Warn(warning)
}

View File

@@ -15,11 +15,10 @@ type Warner interface {
Warn(s string)
}
func New(unzipper unzip.Unzipper, presolver resolver.Parallel,
warner Warner) *Updater {
func New(unzipper unzip.Unzipper, warner Warner) *Updater {
return &Updater{
unzipper: unzipper,
presolver: presolver,
presolver: newParallelResolver(),
warner: warner,
}
}

View File

@@ -1,30 +1,28 @@
package vyprvpn
import (
"context"
"net"
"time"
"github.com/qdm12/gluetun/internal/updater/resolver"
)
func resolveHosts(ctx context.Context, presolver resolver.Parallel,
hosts []string, minServers int) (hostToIPs map[string][]net.IP,
warnings []string, err error) {
func newParallelResolver() (parallelResolver resolver.Parallel) {
const (
maxFailRatio = 0.1
maxDuration = 5 * time.Second
betweenDuration = time.Second
maxNoNew = 2
maxFails = 2
)
settings := resolver.ParallelSettings{
MaxFailRatio: maxFailRatio,
MinFound: minServers,
Repeat: resolver.RepeatSettings{
MaxDuration: time.Second,
MaxDuration: maxDuration,
BetweenDuration: betweenDuration,
MaxNoNew: maxNoNew,
MaxFails: maxFails,
SortIPs: true,
},
}
return presolver.Resolve(ctx, hosts, settings)
return resolver.NewParallelResolver(settings)
}

View File

@@ -64,7 +64,7 @@ func (u *Updater) FetchServers(ctx context.Context, minServers int) (
}
hosts := hts.toHostsSlice()
hostToIPs, warnings, err := resolveHosts(ctx, u.presolver, hosts, minServers)
hostToIPs, warnings, err := u.presolver.Resolve(ctx, hosts, minServers)
for _, warning := range warnings {
u.warner.Warn(warning)
}

View File

@@ -15,11 +15,10 @@ type Warner interface {
Warn(s string)
}
func New(unzipper unzip.Unzipper, presolver resolver.Parallel,
warner Warner) *Updater {
func New(unzipper unzip.Unzipper, warner Warner) *Updater {
return &Updater{
unzipper: unzipper,
presolver: presolver,
presolver: newParallelResolver(),
warner: warner,
}
}

View File

@@ -1,16 +1,12 @@
package wevpn
import (
"context"
"net"
"time"
"github.com/qdm12/gluetun/internal/updater/resolver"
)
func resolveHosts(ctx context.Context, presolver resolver.Parallel,
hosts []string, minServers int) (hostToIPs map[string][]net.IP,
warnings []string, err error) {
func newParallelResolver() (parallelResolver resolver.Parallel) {
const (
maxFailRatio = 0.1
maxDuration = 20 * time.Second
@@ -20,7 +16,6 @@ func resolveHosts(ctx context.Context, presolver resolver.Parallel,
)
settings := resolver.ParallelSettings{
MaxFailRatio: maxFailRatio,
MinFound: minServers,
Repeat: resolver.RepeatSettings{
MaxDuration: maxDuration,
BetweenDuration: betweenDuration,
@@ -29,5 +24,5 @@ func resolveHosts(ctx context.Context, presolver resolver.Parallel,
SortIPs: true,
},
}
return presolver.Resolve(ctx, hosts, settings)
return resolver.NewParallelResolver(settings)
}

View File

@@ -1,57 +0,0 @@
package wevpn
import (
"context"
"errors"
"net"
"testing"
"time"
"github.com/golang/mock/gomock"
"github.com/qdm12/gluetun/internal/updater/resolver"
"github.com/qdm12/gluetun/internal/updater/resolver/mock_resolver"
"github.com/stretchr/testify/assert"
)
func Test_resolveHosts(t *testing.T) {
t.Parallel()
ctrl := gomock.NewController(t)
ctx := context.Background()
presolver := mock_resolver.NewMockParallel(ctrl)
hosts := []string{"host1", "host2"}
const minServers = 10
expectedHostToIPs := map[string][]net.IP{
"host1": {{1, 2, 3, 4}},
"host2": {{2, 3, 4, 5}},
}
expectedWarnings := []string{"warning1", "warning2"}
expectedErr := errors.New("dummy")
const (
maxFailRatio = 0.1
maxDuration = 20 * time.Second
betweenDuration = time.Second
maxNoNew = 2
maxFails = 2
)
expectedSettings := resolver.ParallelSettings{
MaxFailRatio: maxFailRatio,
MinFound: minServers,
Repeat: resolver.RepeatSettings{
MaxDuration: maxDuration,
BetweenDuration: betweenDuration,
MaxNoNew: maxNoNew,
MaxFails: maxFails,
SortIPs: true,
},
}
presolver.EXPECT().Resolve(ctx, hosts, expectedSettings).
Return(expectedHostToIPs, expectedWarnings, expectedErr)
hostToIPs, warnings, err := resolveHosts(ctx, presolver, hosts, minServers)
assert.Equal(t, expectedHostToIPs, hostToIPs)
assert.Equal(t, expectedWarnings, warnings)
assert.Equal(t, expectedErr, err)
}

View File

@@ -31,7 +31,7 @@ func (u *Updater) FetchServers(ctx context.Context, minServers int) (
hostnameToCity[hostname] = city
}
hostnameToIPs, warnings, err := resolveHosts(ctx, u.presolver, hostnames, minServers)
hostnameToIPs, warnings, err := u.presolver.Resolve(ctx, hostnames, minServers)
for _, warning := range warnings {
u.warner.Warn(warning)
}

View File

@@ -13,9 +13,9 @@ type Warner interface {
Warn(s string)
}
func New(presolver resolver.Parallel, warner Warner) *Updater {
func New(warner Warner) *Updater {
return &Updater{
presolver: presolver,
presolver: newParallelResolver(),
warner: warner,
}
}

View File

@@ -60,17 +60,17 @@ func (u *Updater) fetchServers(ctx context.Context, provider string,
case providers.Custom:
panic("cannot update custom provider")
case providers.Cyberghost:
providerUpdater = cyberghost.New(u.presolver)
providerUpdater = cyberghost.New()
case providers.Expressvpn:
providerUpdater = expressvpn.New(u.unzipper, u.presolver, u.logger)
providerUpdater = expressvpn.New(u.unzipper, u.logger)
case providers.Fastestvpn:
providerUpdater = fastestvpn.New(u.unzipper, u.presolver, u.logger)
providerUpdater = fastestvpn.New(u.unzipper, u.logger)
case providers.HideMyAss:
providerUpdater = hidemyass.New(u.client, u.presolver, u.logger)
providerUpdater = hidemyass.New(u.client, u.logger)
case providers.Ipvanish:
providerUpdater = ipvanish.New(u.unzipper, u.presolver, u.logger)
providerUpdater = ipvanish.New(u.unzipper, u.logger)
case providers.Ivpn:
providerUpdater = ivpn.New(u.client, u.presolver, u.logger)
providerUpdater = ivpn.New(u.client, u.logger)
case providers.Mullvad:
providerUpdater = mullvad.New(u.client)
case providers.Nordvpn:
@@ -78,25 +78,25 @@ func (u *Updater) fetchServers(ctx context.Context, provider string,
case providers.Perfectprivacy:
providerUpdater = perfectprivacy.New(u.unzipper, u.logger)
case providers.Privado:
providerUpdater = privado.New(u.client, u.unzipper, u.presolver, u.logger)
providerUpdater = privado.New(u.client, u.unzipper, u.logger)
case providers.PrivateInternetAccess:
providerUpdater = privateinternetaccess.New(u.client)
case providers.Privatevpn:
providerUpdater = privatevpn.New(u.unzipper, u.presolver, u.logger)
providerUpdater = privatevpn.New(u.unzipper, u.logger)
case providers.Protonvpn:
providerUpdater = protonvpn.New(u.client, u.logger)
case providers.Purevpn:
providerUpdater = purevpn.New(u.client, u.unzipper, u.presolver, u.logger)
providerUpdater = purevpn.New(u.client, u.unzipper, u.logger)
case providers.Surfshark:
providerUpdater = surfshark.New(u.client, u.unzipper, u.presolver, u.logger)
providerUpdater = surfshark.New(u.client, u.unzipper, u.logger)
case providers.Torguard:
providerUpdater = torguard.New(u.unzipper, u.presolver, u.logger)
providerUpdater = torguard.New(u.unzipper, u.logger)
case providers.VPNUnlimited:
providerUpdater = vpnunlimited.New(u.unzipper, u.presolver, u.logger)
providerUpdater = vpnunlimited.New(u.unzipper, u.logger)
case providers.Vyprvpn:
providerUpdater = vyprvpn.New(u.unzipper, u.presolver, u.logger)
providerUpdater = vyprvpn.New(u.unzipper, u.logger)
case providers.Wevpn:
providerUpdater = wevpn.New(u.presolver, u.logger)
providerUpdater = wevpn.New(u.logger)
case providers.Windscribe:
providerUpdater = windscribe.New(u.client, u.logger)
default:

View File

@@ -10,7 +10,6 @@ import (
reflect "reflect"
gomock "github.com/golang/mock/gomock"
resolver "github.com/qdm12/gluetun/internal/updater/resolver"
)
// MockParallel is a mock of Parallel interface.
@@ -37,7 +36,7 @@ func (m *MockParallel) EXPECT() *MockParallelMockRecorder {
}
// Resolve mocks base method.
func (m *MockParallel) Resolve(arg0 context.Context, arg1 []string, arg2 resolver.ParallelSettings) (map[string][]net.IP, []string, error) {
func (m *MockParallel) Resolve(arg0 context.Context, arg1 []string, arg2 int) (map[string][]net.IP, []string, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Resolve", arg0, arg1, arg2)
ret0, _ := ret[0].(map[string][]net.IP)

View File

@@ -10,17 +10,19 @@ import (
//go:generate mockgen -destination=mock_$GOPACKAGE/$GOFILE . Parallel
type Parallel interface {
Resolve(ctx context.Context, hosts []string, settings ParallelSettings) (
Resolve(ctx context.Context, hosts []string, minToFind int) (
hostToIPs map[string][]net.IP, warnings []string, err error)
}
type parallel struct {
repeatResolver Repeat
settings ParallelSettings
}
func NewParallelResolver(address string) Parallel {
func NewParallelResolver(settings ParallelSettings) Parallel {
return &parallel{
repeatResolver: NewRepeat(address),
repeatResolver: NewRepeat(settings.Repeat),
settings: settings,
}
}
@@ -32,10 +34,6 @@ type ParallelSettings struct {
// This value is between 0 and 1. Note this is only
// applicable if FailEarly is not set to true.
MaxFailRatio float64
// MinFound is the minimum number of hosts to be found.
// If it is bigger than the number of hosts given, it
// is set to the number of hosts given.
MinFound int
}
type parallelResult struct {
@@ -48,13 +46,8 @@ var (
ErrMaxFailRatio = errors.New("maximum failure ratio reached")
)
func (pr *parallel) Resolve(ctx context.Context, hosts []string,
settings ParallelSettings) (hostToIPs map[string][]net.IP, warnings []string, err error) {
minFound := settings.MinFound
if minFound > len(hosts) {
minFound = len(hosts)
}
func (pr *parallel) Resolve(ctx context.Context, hosts []string, minToFind int) (
hostToIPs map[string][]net.IP, warnings []string, err error) {
ctx, cancel := context.WithCancel(ctx)
defer cancel()
@@ -64,16 +57,16 @@ func (pr *parallel) Resolve(ctx context.Context, hosts []string,
defer close(errors)
for _, host := range hosts {
go pr.resolveAsync(ctx, host, settings.Repeat, results, errors)
go pr.resolveAsync(ctx, host, results, errors)
}
hostToIPs = make(map[string][]net.IP, len(hosts))
maxFails := int(settings.MaxFailRatio * float64(len(hosts)))
maxFails := int(pr.settings.MaxFailRatio * float64(len(hosts)))
for range hosts {
select {
case newErr := <-errors:
if settings.FailEarly {
if pr.settings.FailEarly {
if err == nil {
// only set the error to the first error encountered
// and not the context canceled errors coming after.
@@ -100,14 +93,14 @@ func (pr *parallel) Resolve(ctx context.Context, hosts []string,
return nil, warnings, err
}
if len(hostToIPs) < minFound {
if len(hostToIPs) < minToFind {
return nil, warnings,
fmt.Errorf("%w: found %d hosts but expected at least %d",
ErrMinFound, len(hostToIPs), minFound)
ErrMinFound, len(hostToIPs), minToFind)
}
failureRatio := float64(len(warnings)) / float64(len(hosts))
if failureRatio > settings.MaxFailRatio {
if failureRatio > pr.settings.MaxFailRatio {
return hostToIPs, warnings,
fmt.Errorf("%w: %.2f failure ratio reached", ErrMaxFailRatio, failureRatio)
}
@@ -116,8 +109,8 @@ func (pr *parallel) Resolve(ctx context.Context, hosts []string,
}
func (pr *parallel) resolveAsync(ctx context.Context, host string,
settings RepeatSettings, results chan<- parallelResult, errors chan<- error) {
IPs, err := pr.repeatResolver.Resolve(ctx, host, settings)
results chan<- parallelResult, errors chan<- error) {
IPs, err := pr.repeatResolver.Resolve(ctx, host)
if err != nil {
errors <- err
return

View File

@@ -11,20 +11,23 @@ import (
)
type Repeat interface {
Resolve(ctx context.Context, host string, settings RepeatSettings) (IPs []net.IP, err error)
Resolve(ctx context.Context, host string) (IPs []net.IP, err error)
}
type repeat struct {
resolver *net.Resolver
settings RepeatSettings
}
func NewRepeat(address string) Repeat {
func NewRepeat(settings RepeatSettings) Repeat {
return &repeat{
resolver: newResolver(address),
resolver: newResolver(settings.Address),
settings: settings,
}
}
type RepeatSettings struct {
Address string
MaxDuration time.Duration
BetweenDuration time.Duration
MaxNoNew int
@@ -33,8 +36,8 @@ type RepeatSettings struct {
SortIPs bool
}
func (r *repeat) Resolve(ctx context.Context, host string, settings RepeatSettings) (ips []net.IP, err error) {
timedCtx, cancel := context.WithTimeout(ctx, settings.MaxDuration)
func (r *repeat) Resolve(ctx context.Context, host string) (ips []net.IP, err error) {
timedCtx, cancel := context.WithTimeout(ctx, r.settings.MaxDuration)
defer cancel()
noNewCounter := 0
@@ -45,7 +48,7 @@ func (r *repeat) Resolve(ctx context.Context, host string, settings RepeatSettin
// TODO
// - one resolving every 100ms for round robin DNS responses
// - one every second for time based DNS cycling responses
noNewCounter, failCounter, err = r.resolveOnce(ctx, timedCtx, host, settings, uniqueIPs, noNewCounter, failCounter)
noNewCounter, failCounter, err = r.resolveOnce(ctx, timedCtx, host, r.settings, uniqueIPs, noNewCounter, failCounter)
}
if len(uniqueIPs) == 0 {
@@ -54,7 +57,7 @@ func (r *repeat) Resolve(ctx context.Context, host string, settings RepeatSettin
ips = uniqueIPsToSlice(uniqueIPs)
if settings.SortIPs {
if r.settings.SortIPs {
sort.Slice(ips, func(i, j int) bool {
return bytes.Compare(ips[i], ips[j]) < 1
})

View File

@@ -8,7 +8,6 @@ import (
"github.com/qdm12/gluetun/internal/configuration/settings"
"github.com/qdm12/gluetun/internal/models"
"github.com/qdm12/gluetun/internal/updater/resolver"
"github.com/qdm12/gluetun/internal/updater/unzip"
"golang.org/x/text/cases"
"golang.org/x/text/language"
@@ -24,7 +23,6 @@ type Updater struct {
// Functions for tests
logger Logger
timeNow func() time.Time
presolver resolver.Parallel
client *http.Client
unzipper unzip.Unzipper
}
@@ -49,7 +47,6 @@ func New(settings settings.Updater, httpClient *http.Client,
storage: storage,
logger: logger,
timeNow: time.Now,
presolver: resolver.NewParallelResolver(settings.DNSAddress.String()),
client: httpClient,
unzipper: unzipper,
}