Skip to content

Commit

Permalink
Add in routine that checks internet connectivity for bot services (th…
Browse files Browse the repository at this point in the history
…rasher-corp#287)

* Add in routine that checks internet connectivity for bot services

* Packaged connection checker
  • Loading branch information
shazbert authored and thrasher- committed May 2, 2019
1 parent 2f1405e commit 6e2cba5
Show file tree
Hide file tree
Showing 3 changed files with 180 additions and 21 deletions.
53 changes: 41 additions & 12 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"sync"
"time"

"github.com/thrasher-/gocryptotrader/connchecker"
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/currency"
"github.com/thrasher-/gocryptotrader/currency/forexprovider"
Expand Down Expand Up @@ -104,18 +105,19 @@ type CurrencyPairFormatConfig struct {
// prestart management of Portfolio, Communications, Webserver and Enabled
// Exchanges
type Config struct {
Name string `json:"name"`
EncryptConfig int `json:"encryptConfig"`
GlobalHTTPTimeout time.Duration `json:"globalHTTPTimeout"`
Logging log.Logging `json:"logging"`
Profiler ProfilerConfig `json:"profiler"`
NTPClient NTPClientConfig `json:"ntpclient"`
Currency CurrencyConfig `json:"currencyConfig"`
Communications CommunicationsConfig `json:"communications"`
Portfolio portfolio.Base `json:"portfolioAddresses"`
Webserver WebserverConfig `json:"webserver"`
Exchanges []ExchangeConfig `json:"exchanges"`
BankAccounts []BankAccount `json:"bankAccounts"`
Name string `json:"name"`
EncryptConfig int `json:"encryptConfig"`
GlobalHTTPTimeout time.Duration `json:"globalHTTPTimeout"`
Logging log.Logging `json:"logging"`
Profiler ProfilerConfig `json:"profiler"`
NTPClient NTPClientConfig `json:"ntpclient"`
Currency CurrencyConfig `json:"currencyConfig"`
Communications CommunicationsConfig `json:"communications"`
Portfolio portfolio.Base `json:"portfolioAddresses"`
Webserver WebserverConfig `json:"webserver"`
Exchanges []ExchangeConfig `json:"exchanges"`
BankAccounts []BankAccount `json:"bankAccounts"`
ConnectionMonitor ConnectionMonitorConfig `json:"connectionMonitor"`

// Deprecated config settings, will be removed at a future date
CurrencyPairFormat *CurrencyPairFormatConfig `json:"currencyPairFormat,omitempty"`
Expand All @@ -124,6 +126,14 @@ type Config struct {
SMS *SMSGlobalConfig `json:"smsGlobal,omitempty"`
}

// ConnectionMonitorConfig defines the connection monitor variables to ensure
// that there is internet connectivity
type ConnectionMonitorConfig struct {
DNSList []string `json:"preferredDNSList"`
PublicDomainList []string `json:"preferredDomainList"`
CheckInterval time.Duration `json:"checkInterval"`
}

// ProfilerConfig defines the profiler configuration to enable pprof
type ProfilerConfig struct {
Enabled bool `json:"enabled"`
Expand Down Expand Up @@ -1158,6 +1168,24 @@ func (c *Config) DisableNTPCheck(input io.Reader) (string, error) {
return "", errors.New("something went wrong NTPCheck should never make it this far")
}

// CheckConnectionMonitorConfig checks and if zero value assigns default values
func (c *Config) CheckConnectionMonitorConfig() {
m.Lock()
defer m.Unlock()

if c.ConnectionMonitor.CheckInterval == 0 {
c.ConnectionMonitor.CheckInterval = connchecker.DefaultCheckInterval
}

if len(c.ConnectionMonitor.DNSList) == 0 {
c.ConnectionMonitor.DNSList = connchecker.DefaultDNSList
}

if len(c.ConnectionMonitor.PublicDomainList) == 0 {
c.ConnectionMonitor.PublicDomainList = connchecker.DefaultDomainList
}
}

// GetFilePath returns the desired config file or the default config file name
// based on if the application is being run under test or normal mode.
func GetFilePath(file string) (string, error) {
Expand Down Expand Up @@ -1351,6 +1379,7 @@ func (c *Config) CheckConfig() error {
return fmt.Errorf(ErrCheckingConfigValues, err)
}

c.CheckConnectionMonitorConfig()
c.CheckCommunicationsConfig()

if c.Webserver.Enabled {
Expand Down
121 changes: 121 additions & 0 deletions connchecker/connchecker.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
package connchecker

import (
"net"
"sync"
"time"

log "github.com/thrasher-/gocryptotrader/logger"
)

// DefaultCheckInterval is a const that defines the amount of time between
// checking if the connection is lost
const DefaultCheckInterval = time.Second

// Default check lists
var (
DefaultDNSList = []string{"8.8.8.8", "8.8.4.4", "1.1.1.1", "1.0.0.1"}
DefaultDomainList = []string{"www.google.com", "www.cloudflare.com", "www.facebook.com"}
)

// New returns a new connection checker, if no values set it will default it out
func New(dnsList, domainList []string, checkInterval time.Duration) *Checker {
c := &Checker{}
if len(dnsList) == 0 {
c.DNSList = DefaultDNSList
} else {
c.DNSList = dnsList
}

if len(domainList) == 0 {
c.DomainList = DefaultDomainList
} else {
c.DomainList = domainList
}

if checkInterval == 0 {
c.CheckInterval = DefaultCheckInterval
} else {
c.CheckInterval = checkInterval
}

go c.Monitor()
return c
}

// Checker defines a struct to determine connectivity to the interwebs
type Checker struct {
DNSList []string
DomainList []string
CheckInterval time.Duration
shutdown chan struct{}
wg sync.WaitGroup
connected bool
sync.Mutex
}

// Shutdown cleanly shutsdown monitor routine
func (c *Checker) Shutdown() {
c.shutdown <- struct{}{}
c.wg.Wait()
}

// Monitor determines internet connectivity via a DNS lookup
func (c *Checker) Monitor() {
c.wg.Add(1)
tick := time.NewTicker(time.Second)
defer func() { tick.Stop(); c.wg.Done() }()
c.connectionTest()
for {
select {
case <-tick.C:
c.connectionTest()
case <-c.shutdown:
return
}
}
}

// ConnectionTest determines if a connection to the internet is available by
// iterating over a set list of dns ip and popular domains
func (c *Checker) connectionTest() {
for i := range c.DNSList {
_, err := net.LookupAddr(c.DNSList[i])
if err == nil {
c.Lock()
if !c.connected {
log.Warnf("Internet connectivity re-established")
c.connected = true
}
c.Unlock()
return
}
}

for i := range c.DomainList {
_, err := net.LookupHost(c.DomainList[i])
if err == nil {
c.Lock()
if !c.connected {
log.Warnf("Internet connectivity re-established")
c.connected = true
}
c.Unlock()
return
}
}

c.Lock()
if c.connected {
log.Warnf("Internet connectivity lost")
c.connected = false
}
c.Unlock()
}

// IsConnected returns if there is internet connectivity
func (c *Checker) IsConnected() bool {
c.Lock()
defer c.Unlock()
return c.connected
}
27 changes: 18 additions & 9 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@ import (
"os/signal"
"runtime"
"strconv"
"sync"
"syscall"
"time"

"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/communications"
"github.com/thrasher-/gocryptotrader/config"
"github.com/thrasher-/gocryptotrader/connchecker"
"github.com/thrasher-/gocryptotrader/currency"
"github.com/thrasher-/gocryptotrader/currency/coinmarketcap"
exchange "github.com/thrasher-/gocryptotrader/exchanges"
Expand All @@ -25,14 +27,16 @@ import (
// Bot contains configuration, portfolio, exchange & ticker data and is the
// overarching type across this code base.
type Bot struct {
config *config.Config
portfolio *portfolio.Base
exchanges []exchange.IBotExchange
comms *communications.Communications
shutdown chan bool
dryRun bool
configFile string
dataDir string
config *config.Config
portfolio *portfolio.Base
exchanges []exchange.IBotExchange
comms *communications.Communications
shutdown chan bool
dryRun bool
configFile string
dataDir string
connectivity *connchecker.Checker
sync.Mutex
}

const banner = `
Expand Down Expand Up @@ -129,6 +133,11 @@ func main() {
}
}

// Sets up internet connectivity monitor
bot.connectivity = connchecker.New(bot.config.ConnectionMonitor.DNSList,
bot.config.ConnectionMonitor.PublicDomainList,
bot.config.ConnectionMonitor.CheckInterval)

AdjustGoMaxProcs()
log.Debugf("Bot '%s' started.\n", bot.config.Name)
log.Debugf("Bot dry run mode: %v.\n", common.IsEnabled(bot.dryRun))
Expand Down Expand Up @@ -243,7 +252,7 @@ func HandleInterrupt() {
go func() {
sig := <-c
log.Debugf("Captured %v, shutdown requested.", sig)
bot.shutdown <- true
close(bot.shutdown)
}()
}

Expand Down

0 comments on commit 6e2cba5

Please sign in to comment.