diff --git a/Gopkg.lock b/Gopkg.lock index 7a8f120..18b8f74 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -16,6 +16,12 @@ packages = ["."] revision = "2efee857e7cfd4f3d0138cc3cbb1b4966962b93a" +[[projects]] + name = "github.com/beevik/ntp" + packages = ["."] + revision = "62c80a04de2086884d8296004b6d74ee1846c582" + version = "v0.2.0" + [[projects]] name = "github.com/davecgh/go-spew" packages = ["spew"] @@ -77,6 +83,17 @@ revision = "eeedf312bc6c57391d84767a4cd413f02a917974" version = "v1.8.0" +[[projects]] + branch = "master" + name = "golang.org/x/net" + packages = [ + "bpf", + "internal/iana", + "internal/socket", + "ipv4" + ] + revision = "d0887baf81f4598189d4e12a37c6da86f0bba4d0" + [[projects]] name = "gopkg.in/alecthomas/kingpin.v2" packages = ["."] @@ -86,6 +103,6 @@ [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "c4fdd3664f683342ad0c2509f4a8bcfe5b267a6e8cdaf36f70d39536bbf89834" + inputs-digest = "f828340a30ea13c563829f9a37d0ff62974d4578411c9be02e61125dbdf98692" solver-name = "gps-cdcl" solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml index ec43ce8..f34b7d2 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -48,3 +48,7 @@ [[constraint]] branch = "master" name = "github.com/dustin/go-humanize" + +[[constraint]] + name = "github.com/beevik/ntp" + version = "0.2.0" diff --git a/main.go b/main.go index e7d8a16..7587613 100644 --- a/main.go +++ b/main.go @@ -4,20 +4,22 @@ package main import ( "encoding/json" + "fmt" "io" "math/rand" "os" "syscall" "time" + "github.com/juju/errors" "go.uber.org/zap" "go.uber.org/zap/zapcore" kingpin "gopkg.in/alecthomas/kingpin.v2" "github.com/9seconds/mtg/config" + "github.com/9seconds/mtg/ntp" "github.com/9seconds/mtg/proxy" "github.com/9seconds/mtg/stats" - "github.com/juju/errors" ) var ( @@ -120,6 +122,14 @@ func main() { if conf.UseMiddleProxy() { zap.S().Infow("Use middle proxy connection to Telegram") + if diff, err := ntp.Fetch(); err != nil { + zap.S().Warnw("Could not fetch time data from NTP") + } else { + if diff >= time.Second { + usage(fmt.Sprintf("You choose to use middle proxy but your clock drift (%s) is bigger than 1 second. Please, sync your time", diff)) + } + go ntp.AutoUpdate() + } } else { zap.S().Infow("Use direct connection to Telegram") } diff --git a/ntp/ntp.go b/ntp/ntp.go new file mode 100644 index 0000000..5aee499 --- /dev/null +++ b/ntp/ntp.go @@ -0,0 +1,60 @@ +package ntp + +import ( + "math/rand" + "time" + + "github.com/beevik/ntp" + "github.com/juju/errors" + "go.uber.org/zap" +) + +const autoUpdatePeriod = time.Minute + +var ntpEndpoints = []string{ + "0.pool.ntp.org", + "1.pool.ntp.org", + "2.pool.ntp.org", + "3.pool.ntp.org", +} + +// Fetch fetches the data on time drift. +func Fetch() (time.Duration, error) { + url := ntpEndpoints[rand.Intn(len(ntpEndpoints))] + resp, err := ntp.Query(url) + if err != nil { + return 0, errors.Annotatef(err, "Cannot fetch NTP server %s", url) + } + + offsetInt := int64(resp.ClockOffset) + if offsetInt < 0 { + offsetInt = -offsetInt + } + offset := time.Duration(offsetInt) + + return offset, nil +} + +// AutoUpdate runs periodic check of current time .drift state. +func AutoUpdate() { + logger := zap.S().Named("ntp") + + for range time.Tick(autoUpdatePeriod) { + diff, err := Fetch() + if err != nil { + logger.Debugw("Cannot fetch time from NTP", "error", err) + continue + } + + switch { + case diff < 400*time.Millisecond: + logger.Debugw("NTP time drift", "value", diff.String()) + case diff < 600*time.Millisecond: + logger.Infow("NTP time drift", "value", diff.String()) + case diff < 800*time.Millisecond: + logger.Warnw("NTP time drift", "value", diff.String()) + default: + logger.Errorw("NTP time drift", "value", diff.String()) + } + } +}