forked from BytomDAO/bytom
/
version.go
166 lines (149 loc) · 4.66 KB
/
version.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
// package version provide the version info for the node, and also provide
// support for version compatibility check and update notification.
//
// The version format should follow Semantic Versioning (https://semver.org/):
// MAJOR.MINOR.PATCH
// 1. MAJOR version when you make incompatible API changes,
// 2. MINOR version when you add functionality in a backwards-compatible manner, and
// 3. PATCH version when you make backwards-compatible bug fixes.
//
// A pre-release version MAY be denoted by appending a hyphen and a series of
// dot separated identifiers immediately following the patch version.
// Examples:
// 1.0.0-alpha, 1.0.0-alpha.1, 1.0.0-0.3.7, 1.0.0-x.7.z.92.
// Precedence:
// 1. Pre-release versions have a lower precedence than the associated normal version!
// Numeric identifiers always have lower precedence than non-numeric identifiers.
// 2. A larger set of pre-release fields has a higher precedence than a smaller set,
// if all of the preceding identifiers are equal.
// 3. Example:
// 1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-alpha.beta < 1.0.0-beta < 1.0.0-beta.2 < 1.0.0-beta.11 < 1.0.0-rc.1 < 1.0.0.
//
// Build metadata MAY be denoted by appending a plus sign and a series of dot
// separated identifiers immediately following the patch or pre-release version.
// Build metadata SHOULD be ignored when determining version precedence. Thus
// two versions that differ only in the build metadata, have the same precedence.
package version
import (
"sync"
gover "github.com/hashicorp/go-version"
log "github.com/sirupsen/logrus"
"gopkg.in/fatih/set.v0"
)
const (
// If needing to edit the iota, please ensure the following:
// noUpdate = 0
// hasUpdate = 1
// hasMUpdate = 2
noUpdate uint16 = iota
hasUpdate
hasMUpdate
logModule = "version"
)
var (
// The full version string
Version = "2.0.6"
// GitCommit is set with --ldflags "-X main.gitCommit=$(git rev-parse HEAD)"
GitCommit string
Status *UpdateStatus
)
func init() {
if GitCommit != "" {
Version += "+" + GitCommit[:8]
}
Status = &UpdateStatus{
maxVerSeen: Version,
notified: false,
seedSet: set.New(),
versionStatus: noUpdate,
}
}
type UpdateStatus struct {
sync.RWMutex
maxVerSeen string
notified bool
seedSet *set.Set
versionStatus uint16
}
func (s *UpdateStatus) AddSeed(seedAddr string) {
s.Lock()
defer s.Unlock()
s.seedSet.Add(seedAddr)
}
// CheckUpdate checks whether there is a newer version to update.
// If there is, it set the "Status" variable to a proper value.
// params:
// localVerStr: the version of the node itself
// remoteVerStr: the version received from a seed node.
// remoteAddr: the version received from a seed node.
// current rule:
// 1. small update: seed version is higher than the node itself
// 2. significant update: seed mojor version is higher than the node itself
func (s *UpdateStatus) CheckUpdate(localVerStr string, remoteVerStr string, remoteAddr string) error {
s.Lock()
defer s.Unlock()
if !s.seedSet.Has(remoteAddr) {
return nil
}
localVersion, err := gover.NewVersion(localVerStr)
if err != nil {
return err
}
remoteVersion, err := gover.NewVersion(remoteVerStr)
if err != nil {
return err
}
if remoteVersion.GreaterThan(localVersion) {
if s.versionStatus == noUpdate {
s.versionStatus = hasUpdate
}
maxVersion, err := gover.NewVersion(s.maxVerSeen)
if err != nil {
return err
}
if remoteVersion.GreaterThan(maxVersion) {
s.maxVerSeen = remoteVerStr
}
}
if remoteVersion.Segments()[0] > localVersion.Segments()[0] {
s.versionStatus = hasMUpdate
}
if s.versionStatus != noUpdate {
log.WithFields(log.Fields{
"module": logModule,
"Current version": localVerStr,
"Newer version": remoteVerStr,
"seed": remoteAddr,
}).Warn("Please update your bytomd via https://github.com/Bytom/bytom/releases/ or http://bytom.io/wallet/")
s.notified = true
}
return nil
}
func (s *UpdateStatus) MaxVerSeen() string {
s.RLock()
defer s.RUnlock()
return s.maxVerSeen
}
func (s *UpdateStatus) VersionStatus() uint16 {
s.RLock()
defer s.RUnlock()
return s.versionStatus
}
// CompatibleWith checks whether the remote peer version is compatible with the
// node itself.
// RULES:
// | local | remote |
// | - | - |
// | 1.0.3 | same major&moinor version. |
// | 1.0.4 | same major version. |
func CompatibleWith(remoteVerStr string) (bool, error) {
localVersion, err := gover.NewVersion(Version)
if err != nil {
return false, err
}
remoteVersion, err := gover.NewVersion(remoteVerStr)
if err != nil {
return false, err
}
return (localVersion.Segments()[0] == remoteVersion.Segments()[0]), nil
}