OSDN Git Service

:sparkles: Add version notification (#1258)
[bytom/bytom.git] / version / version.go
1 package version
2
3 import (
4         gover "github.com/hashicorp/go-version"
5         log "github.com/sirupsen/logrus"
6         "gopkg.in/fatih/set.v0"
7         "sync"
8 )
9
10 const (
11         noUpdate uint16 = iota
12         hasUpdate
13         hasMUpdate
14 )
15
16 var (
17         // The full version string
18         Version = "1.0.4"
19         // GitCommit is set with --ldflags "-X main.gitCommit=$(git rev-parse HEAD)"
20         GitCommit string
21         Status    *UpdateStatus
22 )
23
24 func init() {
25         if GitCommit != "" {
26                 Version += "-" + GitCommit[:8]
27         }
28         Status = &UpdateStatus{
29                 notified:      false,
30                 versionStatus: noUpdate,
31                 seedSet:       set.New(),
32         }
33 }
34
35 type UpdateStatus struct {
36         sync.RWMutex
37         notified      bool
38         versionStatus uint16
39         seedSet       *set.Set
40 }
41
42 func (s *UpdateStatus) AddSeed(seedAddr string) {
43         s.Lock()
44         defer s.Unlock()
45         s.seedSet.Add(seedAddr)
46 }
47
48 // CheckUpdate checks whether there is a newer version to update.
49 // If there is, it set the "Status" variable to a proper value.
50 //      params:
51 //              localVerStr: the version of the node itself
52 //              remoteVerStr: the version received from a seed node.
53 //              remoteAddr: the version received from a seed node.
54 // current rule:
55 //              1. small update: seed version is higher than the node itself
56 //              2. significant update: seed mojor version is higher than the node itself
57 func (s *UpdateStatus) CheckUpdate(localVerStr string, remoteVerStr string, remoteAddr string) error {
58         s.Lock()
59         defer s.Unlock()
60
61         if s.notified || !s.seedSet.Has(remoteAddr) {
62                 return nil
63         }
64
65         localVersion, err := gover.NewVersion(localVerStr)
66         if err != nil {
67                 return err
68         }
69         remoteVersion, err := gover.NewVersion(remoteVerStr)
70         if err != nil {
71                 return err
72         }
73         if remoteVersion.GreaterThan(localVersion) {
74                 s.versionStatus = hasUpdate
75         }
76         if remoteVersion.Segments()[0] > localVersion.Segments()[0] {
77                 s.versionStatus = hasMUpdate
78         }
79         if s.versionStatus != noUpdate {
80                 log.WithFields(log.Fields{
81                         "Current version": localVerStr,
82                         "Newer version":   remoteVerStr,
83                         "seed":            remoteAddr,
84                 }).Warn("Please update your bytomd via https://github.com/Bytom/bytom/releases/ or http://bytom.io/wallet/")
85                 s.notified = true
86         }
87         return nil
88 }
89
90 func (s *UpdateStatus) VersionStatus() uint16 {
91         s.RLock()
92         defer s.RUnlock()
93         return s.versionStatus
94 }
95
96 // CompatibleWith checks whether the remote peer version is compatible with the
97 // node itself.
98 // RULES:
99 // | local |           remote           |
100 // |   -   |             -              |
101 // | 1.0.3 | same major&moinor version. |
102 // | 1.0.4 |     same major version.    |
103 func CompatibleWith(remoteVerStr string) (bool, error) {
104         localVersion, err := gover.NewVersion(Version)
105         if err != nil {
106                 return false, err
107         }
108         remoteVersion, err := gover.NewVersion(remoteVerStr)
109         if err != nil {
110                 return false, err
111         }
112         return (localVersion.Segments()[0] == remoteVersion.Segments()[0]), nil
113 }