forked from decred/dcrvotingweb
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathweb.go
263 lines (234 loc) · 8.78 KB
/
web.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
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
package main
import (
"bytes"
"fmt"
"html/template"
"net/http"
"os"
"os/signal"
"path/filepath"
"regexp"
"github.com/decred/dcrd/dcrjson"
)
// Agenda embeds the Agenda returned by getvoteinfo with several fields to
// facilitate the html template programming.
type Agenda struct {
dcrjson.Agenda `storm:"inline"`
QuorumExpirationDate string
QuorumVotedPercentage float64
QuorumAbstainedPercentage float64
ChoiceIDs []string
ChoicePercentages []float64
ChoiceIDsActing []string
ChoicePercentagesActing []float64
StartHeight int64
}
var dcpRE = regexp.MustCompile(`(?i)DCP\-?(\d{4})`)
// Agenda status may be: started, defined, lockedin, failed, active
// IsActive indicates if the agenda is active
func (a *Agenda) IsActive() bool {
return a.Status == "active"
}
// IsStarted indicates if the agenda is started
func (a *Agenda) IsStarted() bool {
return a.Status == "started"
}
// IsDefined indicates if the agenda is defined
func (a *Agenda) IsDefined() bool {
return a.Status == "defined"
}
// IsLockedIn indicates if the agenda is lockedin
func (a *Agenda) IsLockedIn() bool {
return a.Status == "lockedin"
}
// IsFailed indicates if the agenda is failed
func (a *Agenda) IsFailed() bool {
return a.Status == "failed"
}
// IsDCP indicates if agenda has a DCP paper
func (a *Agenda) IsDCP() bool {
return dcpRE.MatchString(a.Description)
}
// DCPNumber gets the DCP number as a string with any leading zeros
func (a *Agenda) DCPNumber() string {
if a.IsDCP() {
matches := dcpRE.FindStringSubmatch(a.Description)
if len(matches) > 1 {
return matches[1]
}
}
return ""
}
// DescriptionWithDCPURL writes a new description with an link to any DCP that
// is detected in the text. It is written to a template.HTML type so the link
// is not escaped when the template is executed.
func (a *Agenda) DescriptionWithDCPURL() template.HTML {
subst := `<a href="https://github.com/decred/dcps/blob/master/dcp-${1}/dcp-${1}.mediawiki" target="_blank">${0}</a>`
return template.HTML(dcpRE.ReplaceAllString(a.Description, subst))
}
// Overall data structure given to the template to render.
type templateFields struct {
// Network
Network string
// Basic information
BlockHeight uint32
// Link to current block on explorer
BlockExplorerLink string
// BlockVersion Information
//
// BlockVersions is the data after it has been prepared for graphing.
BlockVersions map[int32]*blockVersions
// BlockVersionHeights is an array of Block heights for graph's x axis.
BlockVersionsHeights []int64
// BlockVersionSuccess is a bool whether or not BlockVersion has
// successfully tripped over to the new version.
BlockVersionSuccess bool
// BlockVersionWindowLength is the activeNetParams of BlockUpgradeNumToCheck
// rolling window length.
BlockVersionWindowLength uint64
// BlockVersionEnforceThreshold is the activeNetParams of BlockEnforceNumRequired.
BlockVersionEnforceThreshold int
// BlockVersionRejectThreshold is the activeNetParams of BlockRejectNumRequired.
BlockVersionRejectThreshold int
// BlockVersionCurrent is the currently calculated block version based on the rolling window.
BlockVersionCurrent int32
// BlockVersionMostPopular is the calculated most popular block version that is NOT current version.
BlockVersionMostPopular int32
// BlockVersionMostPopularPercentage is the percentage of the most popular block version
BlockVersionMostPopularPercentage float64
// BlockVersionNext is teh next block version.
BlockVersionNext int32
// BlockVersionNextPercentage is the share of the next block version in the current rolling window.
BlockVersionNextPercentage float64
// StakeVersion Information
//
// StakeVersionThreshold is the activeNetParams of StakeVersion threshold made into a float for display
StakeVersionThreshold float64
// StakeVersionWindowLength is the activeNetParams of StakeVersionInterval
StakeVersionWindowLength int64
// StakeVersionIntervalBlocks shows the actual blocks for the current window
StakeVersionIntervalBlocks string
// StakeVersionWindowVoteTotal is the number of total possible votes in the windows.
// It is reduced by number of observed missed votes thus far in the window.
StakeVersionWindowVoteTotal int64
// StakeVersionIntervalLabels are labels for the bar graph for each of the past 4 fixed stake version intervals.
StakeVersionIntervalLabels []string
// StakeVersionVotesRemaining is the calculated number of votes possibly remaining in the current stake version interval.
StakeVersionVotesRemaining int64
// StakeVersionsIntervals is the data received from GetStakeVersionInfo json-rpc call to dcrd.
StakeVersionsIntervals []dcrjson.VersionInterval
// StakeVersionIntervalResults is the data after being analyzed for graph displaying.
StakeVersionIntervalResults []intervalVersionCounts
// StakeVersionSuccess is a bool for whether or not the StakeVersion has rolled over in this window.
StakeVersionSuccess bool
// StakeVersionCurrent is the StakeVersion that has been seen in the recent block header.
StakeVersionCurrent uint32
// StakeVersionMostPopular is the most popular stake version that is NOT the current stake version.
StakeVersionMostPopular uint32
// StakeVersionMostPopularCount is the count of most popular stake versions.
StakeVersionMostPopularCount uint32
// StakeVersionMostPopularPercentage is the percentage of most popular stake versions out of possible votes.
StakeVersionMostPopularPercentage float64
// StakeVersionRequiredVotes is the number of stake version votes required for the stake version to change.
StakeVersionRequiredVotes int32
// StakeVersionTimeRemaining is a string to show how much estimated time is remaining in the stake version interval.
StakeVersionTimeRemaining string
// Quorum and Rule Change Information
// RuleChangeActivationQuorum is the activeNetParams of RuleChangeActivationQuorum
RuleChangeActivationQuorum uint32
// Quorum is a bool that is true if needed number of yes/nos were
// received (>10%).
Quorum bool
// QuorumThreshold is the percentage required for the RuleChange to become active.
QuorumThreshold float64
// LockedinPercentage is the percent of the voing window remaining
LockedinPercentage float64
// Length of the static rule change interval
RuleChangeActivationInterval int64
// Agendas contains all the agendas and their statuses
Agendas []Agenda
// Phase Upgrading or Voting
IsUpgrading bool
// GetVoteInfoResult has all the raw data returned from getvoteinfo json-rpc command.
GetVoteInfoResult *dcrjson.GetVoteInfoResult
}
var funcMap = template.FuncMap{
"plus": plus,
"minus": minus,
"minus64": minus64,
"modiszero": modiszero,
}
func plus(a, b int) int {
return a + b
}
func minus(a, b int) int {
return a - b
}
func minus64(a, b int64) int64 {
return a - b
}
func modiszero(a, b int) bool {
return (a % b) == 0
}
// TemplateExecToString executes the specified template with given data, writing
// the output into a string.
func TemplateExecToString(t *template.Template, name string, data interface{}) (string, error) {
var page bytes.Buffer
err := t.ExecuteTemplate(&page, name, data)
return page.String(), err
}
// renders the 'home' template that is current located at "design_sketch.html".
func (td *WebUI) demoPage(w http.ResponseWriter, r *http.Request) {
err := td.templ.Execute(w, td.TemplateData)
if err != nil {
panic(err)
}
// TODO: Use TemplateExecToString only when the template data is updated
// (i.e. block notification).
}
// WebUI represents the html web interface. It includes the template related
// data, methods for parsing the templates, and the http.HandlerFuncs registered
// with URL paths by the http router.
type WebUI struct {
TemplateData *templateFields
templ *template.Template
templFiles []string
}
// NewWebUI is the constructor for WebUI. It creates a html/template.Template,
// loads the function map, and parses the template files.
func NewWebUI() *WebUI {
fp := filepath.Join("public", "views", "start.html")
tmpl, err := template.New("home").Funcs(funcMap).ParseFiles(fp)
if err != nil {
panic(err)
}
// may have multiple template files eventually
templFiles := []string{fp}
return &WebUI{
templ: tmpl,
templFiles: templFiles,
}
}
// ParseTemplates parses the html templates into a new html/template.Temlate.
func (td *WebUI) ParseTemplates() (err error) {
td.templ, err = template.New("home").ParseFiles(td.templFiles...)
return
}
// See reloadsig*.go for an exported method
func (td *WebUI) reloadTemplatesSig(sig os.Signal) {
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, sig)
go func() {
for {
sigr := <-sigChan
fmt.Printf("Received %s", sig)
if sigr == sig {
if err := td.ParseTemplates(); err != nil {
fmt.Println(err)
continue
}
fmt.Println("Web UI html templates reparsed.")
}
}
}()
}