chore(updater): incorporate FetchServers method in Provider interface
- Each provider interface can now fetch updated servers data - Rename each provider updater subpackage name to `updater` - Updater constructor does not take a settings struct - Updater update method takes in a slice of provider strings
This commit is contained in:
@@ -23,7 +23,7 @@ type Looper interface {
|
||||
}
|
||||
|
||||
type Updater interface {
|
||||
UpdateServers(ctx context.Context) (err error)
|
||||
UpdateServers(ctx context.Context, providers []string) (err error)
|
||||
}
|
||||
|
||||
type looper struct {
|
||||
@@ -46,26 +46,20 @@ type looper struct {
|
||||
|
||||
const defaultBackoffTime = 5 * time.Second
|
||||
|
||||
type Storage interface {
|
||||
SetServers(provider string, servers []models.Server) (err error)
|
||||
GetServersCount(provider string) (count int)
|
||||
ServersAreEqual(provider string, servers []models.Server) (equal bool)
|
||||
}
|
||||
|
||||
type Logger interface {
|
||||
Info(s string)
|
||||
Warn(s string)
|
||||
Error(s string)
|
||||
}
|
||||
|
||||
func NewLooper(settings settings.Updater, storage Storage,
|
||||
func NewLooper(settings settings.Updater, storage updater.Storage,
|
||||
client *http.Client, logger Logger) Looper {
|
||||
return &looper{
|
||||
state: state{
|
||||
status: constants.Stopped,
|
||||
settings: settings,
|
||||
},
|
||||
updater: updater.New(settings, client, storage, logger),
|
||||
updater: updater.New(client, storage, logger),
|
||||
logger: logger,
|
||||
start: make(chan struct{}),
|
||||
running: make(chan models.LoopStatus),
|
||||
@@ -106,12 +100,14 @@ func (l *looper) Run(ctx context.Context, done chan<- struct{}) {
|
||||
for ctx.Err() == nil {
|
||||
updateCtx, updateCancel := context.WithCancel(ctx)
|
||||
|
||||
settings := l.GetSettings()
|
||||
|
||||
errorCh := make(chan error)
|
||||
runWg := &sync.WaitGroup{}
|
||||
runWg.Add(1)
|
||||
go func() {
|
||||
defer runWg.Done()
|
||||
err := l.updater.UpdateServers(updateCtx)
|
||||
err := l.updater.UpdateServers(updateCtx, settings.Providers)
|
||||
if err != nil {
|
||||
if updateCtx.Err() == nil {
|
||||
errorCh <- err
|
||||
|
||||
@@ -4,39 +4,24 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/constants/providers"
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
cyberghost "github.com/qdm12/gluetun/internal/provider/cyberghost/updater"
|
||||
expressvpn "github.com/qdm12/gluetun/internal/provider/expressvpn/updater"
|
||||
fastestvpn "github.com/qdm12/gluetun/internal/provider/fastestvpn/updater"
|
||||
hidemyass "github.com/qdm12/gluetun/internal/provider/hidemyass/updater"
|
||||
ipvanish "github.com/qdm12/gluetun/internal/provider/ipvanish/updater"
|
||||
ivpn "github.com/qdm12/gluetun/internal/provider/ivpn/updater"
|
||||
mullvad "github.com/qdm12/gluetun/internal/provider/mullvad/updater"
|
||||
nordvpn "github.com/qdm12/gluetun/internal/provider/nordvpn/updater"
|
||||
perfectprivacy "github.com/qdm12/gluetun/internal/provider/perfectprivacy/updater"
|
||||
privado "github.com/qdm12/gluetun/internal/provider/privado/updater"
|
||||
privateinternetaccess "github.com/qdm12/gluetun/internal/provider/privateinternetaccess/updater"
|
||||
privatevpn "github.com/qdm12/gluetun/internal/provider/privatevpn/updater"
|
||||
protonvpn "github.com/qdm12/gluetun/internal/provider/protonvpn/updater"
|
||||
purevpn "github.com/qdm12/gluetun/internal/provider/purevpn/updater"
|
||||
surfshark "github.com/qdm12/gluetun/internal/provider/surfshark/updater"
|
||||
torguard "github.com/qdm12/gluetun/internal/provider/torguard/updater"
|
||||
vpnunlimited "github.com/qdm12/gluetun/internal/provider/vpnunlimited/updater"
|
||||
vyprvpn "github.com/qdm12/gluetun/internal/provider/vyprvpn/updater"
|
||||
wevpn "github.com/qdm12/gluetun/internal/provider/wevpn/updater"
|
||||
windscribe "github.com/qdm12/gluetun/internal/provider/windscribe/updater"
|
||||
)
|
||||
|
||||
func (u *Updater) updateProvider(ctx context.Context, provider string) (err error) {
|
||||
existingServersCount := u.storage.GetServersCount(provider)
|
||||
type Provider interface {
|
||||
Name() string
|
||||
FetchServers(ctx context.Context, minServers int) (servers []models.Server, err error)
|
||||
}
|
||||
|
||||
func (u *Updater) updateProvider(ctx context.Context, provider Provider) (err error) {
|
||||
providerName := provider.Name()
|
||||
existingServersCount := u.storage.GetServersCount(providerName)
|
||||
minServers := getMinServers(existingServersCount)
|
||||
servers, err := u.fetchServers(ctx, provider, minServers)
|
||||
servers, err := provider.FetchServers(ctx, minServers)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot get servers: %w", err)
|
||||
}
|
||||
|
||||
if u.storage.ServersAreEqual(provider, servers) {
|
||||
if u.storage.ServersAreEqual(providerName, servers) {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -44,68 +29,13 @@ func (u *Updater) updateProvider(ctx context.Context, provider string) (err erro
|
||||
// since the implementation does not deep copy the servers.
|
||||
// TODO set in storage in provider updater directly, server by server,
|
||||
// to avoid accumulating server data in memory.
|
||||
err = u.storage.SetServers(provider, servers)
|
||||
err = u.storage.SetServers(providerName, servers)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot set servers to storage: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *Updater) fetchServers(ctx context.Context, provider string,
|
||||
minServers int) (servers []models.Server, err error) {
|
||||
var providerUpdater interface {
|
||||
FetchServers(ctx context.Context, minServers int) (servers []models.Server, err error)
|
||||
}
|
||||
switch provider {
|
||||
case providers.Custom:
|
||||
panic("cannot update custom provider")
|
||||
case providers.Cyberghost:
|
||||
providerUpdater = cyberghost.New()
|
||||
case providers.Expressvpn:
|
||||
providerUpdater = expressvpn.New(u.unzipper, u.logger)
|
||||
case providers.Fastestvpn:
|
||||
providerUpdater = fastestvpn.New(u.unzipper, u.logger)
|
||||
case providers.HideMyAss:
|
||||
providerUpdater = hidemyass.New(u.client, u.logger)
|
||||
case providers.Ipvanish:
|
||||
providerUpdater = ipvanish.New(u.unzipper, u.logger)
|
||||
case providers.Ivpn:
|
||||
providerUpdater = ivpn.New(u.client, u.logger)
|
||||
case providers.Mullvad:
|
||||
providerUpdater = mullvad.New(u.client)
|
||||
case providers.Nordvpn:
|
||||
providerUpdater = nordvpn.New(u.client, u.logger)
|
||||
case providers.Perfectprivacy:
|
||||
providerUpdater = perfectprivacy.New(u.unzipper, u.logger)
|
||||
case providers.Privado:
|
||||
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.logger)
|
||||
case providers.Protonvpn:
|
||||
providerUpdater = protonvpn.New(u.client, u.logger)
|
||||
case providers.Purevpn:
|
||||
providerUpdater = purevpn.New(u.client, u.unzipper, u.logger)
|
||||
case providers.Surfshark:
|
||||
providerUpdater = surfshark.New(u.client, u.unzipper, u.logger)
|
||||
case providers.Torguard:
|
||||
providerUpdater = torguard.New(u.unzipper, u.logger)
|
||||
case providers.VPNUnlimited:
|
||||
providerUpdater = vpnunlimited.New(u.unzipper, u.logger)
|
||||
case providers.Vyprvpn:
|
||||
providerUpdater = vyprvpn.New(u.unzipper, u.logger)
|
||||
case providers.Wevpn:
|
||||
providerUpdater = wevpn.New(u.logger)
|
||||
case providers.Windscribe:
|
||||
providerUpdater = windscribe.New(u.client, u.logger)
|
||||
default:
|
||||
panic("provider " + provider + " is unknown")
|
||||
}
|
||||
|
||||
return providerUpdater.FetchServers(ctx, minServers)
|
||||
}
|
||||
|
||||
func getMinServers(existingServersCount int) (minServers int) {
|
||||
const minRatio = 0.8
|
||||
return int(minRatio * float64(existingServersCount))
|
||||
|
||||
@@ -8,15 +8,13 @@ import (
|
||||
|
||||
"github.com/qdm12/gluetun/internal/configuration/settings"
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/qdm12/gluetun/internal/provider"
|
||||
"github.com/qdm12/gluetun/internal/updater/unzip"
|
||||
"golang.org/x/text/cases"
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
type Updater struct {
|
||||
// configuration
|
||||
options settings.Updater
|
||||
|
||||
// state
|
||||
storage Storage
|
||||
|
||||
@@ -31,6 +29,9 @@ type Storage interface {
|
||||
SetServers(provider string, servers []models.Server) (err error)
|
||||
GetServersCount(provider string) (count int)
|
||||
ServersAreEqual(provider string, servers []models.Server) (equal bool)
|
||||
// Extra methods to match the provider.New storage interface
|
||||
FilterServers(provider string, selection settings.ServerSelection) (filtered []models.Server, err error)
|
||||
GetServerByName(provider string, name string) (server models.Server, ok bool)
|
||||
}
|
||||
|
||||
type Logger interface {
|
||||
@@ -39,11 +40,10 @@ type Logger interface {
|
||||
Error(s string)
|
||||
}
|
||||
|
||||
func New(settings settings.Updater, httpClient *http.Client,
|
||||
func New(httpClient *http.Client,
|
||||
storage Storage, logger Logger) *Updater {
|
||||
unzipper := unzip.New(httpClient)
|
||||
return &Updater{
|
||||
options: settings,
|
||||
storage: storage,
|
||||
logger: logger,
|
||||
timeNow: time.Now,
|
||||
@@ -52,19 +52,23 @@ func New(settings settings.Updater, httpClient *http.Client,
|
||||
}
|
||||
}
|
||||
|
||||
func (u *Updater) UpdateServers(ctx context.Context) (err error) {
|
||||
func (u *Updater) UpdateServers(ctx context.Context, providers []string) (err error) {
|
||||
caser := cases.Title(language.English)
|
||||
for _, provider := range u.options.Providers {
|
||||
u.logger.Info("updating " + caser.String(provider) + " servers...")
|
||||
for _, providerName := range providers {
|
||||
u.logger.Info("updating " + caser.String(providerName) + " servers...")
|
||||
|
||||
fetcherStorage := (Storage)(nil) // unused
|
||||
fetcher := provider.New(providerName, fetcherStorage, u.timeNow,
|
||||
u.logger, u.client, u.unzipper)
|
||||
// TODO support servers offering only TCP or only UDP
|
||||
// for NordVPN and PureVPN
|
||||
err := u.updateProvider(ctx, provider)
|
||||
err := u.updateProvider(ctx, fetcher)
|
||||
if err == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// return the only error for the single provider.
|
||||
if len(u.options.Providers) == 1 {
|
||||
if len(providers) == 1 {
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user