-
Notifications
You must be signed in to change notification settings - Fork 1
/
web.go
133 lines (112 loc) · 3.3 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
// Copyright (c) 2017, Jonathan Chappelow
// See LICENSE for details.
package main
import (
"bytes"
"html/template"
"io"
"net/http"
"os"
"os/signal"
"path/filepath"
"sync"
"time"
"github.com/dcrdata/dcrdata/blockdata"
apitypes "github.com/dcrdata/dcrdata/dcrdataapi"
"github.com/dcrdata/dcrdata/mempool"
"github.com/decred/dcrd/chaincfg"
)
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
}
type WebTemplateData struct {
BlockSummary apitypes.BlockDataBasic
StakeSummary apitypes.StakeInfoExtendedEstimates
MempoolFeeInfo apitypes.MempoolTicketFeeInfo
MempoolFees apitypes.MempoolTicketFees
}
type WebUI struct {
MPC mempool.MempoolDataCache
TemplateData WebTemplateData
templateDataMtx sync.RWMutex
templ *template.Template
templFiles []string
params *chaincfg.Params
}
func NewWebUI() *WebUI {
fp := filepath.Join("views", "root.tmpl")
tmpl, err := template.New("home").ParseFiles(fp)
if err != nil {
return nil
}
//var templFiles []string
templFiles := []string{fp}
return &WebUI{
templ: tmpl,
templFiles: templFiles,
params: activeChain,
}
}
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
log.Infof("Received %s", sig)
if sigr == sig {
if err := td.ParseTemplates(); err != nil {
log.Error(err)
continue
}
log.Infof("Web UI html templates reparsed.")
}
}
}()
}
func (td *WebUI) Store(blockData *blockdata.BlockData) error {
td.templateDataMtx.Lock()
defer td.templateDataMtx.Unlock()
td.TemplateData.BlockSummary = blockData.ToBlockSummary()
td.TemplateData.StakeSummary = blockData.ToStakeInfoExtendedEstimates()
return nil
}
func (td *WebUI) StoreMPData(data *mempool.MempoolData, timestamp time.Time) error {
td.MPC.StoreMPData(data, timestamp)
td.MPC.RLock()
defer td.MPC.RUnlock()
_, fie := td.MPC.GetFeeInfoExtra()
td.templateDataMtx.Lock()
defer td.templateDataMtx.Unlock()
td.TemplateData.MempoolFeeInfo = *fie
// LowestMineable is the lowest fee of those in the top 20 (mainnet), but
// for the web interface, we want to interpret "lowest mineable" as the
// lowest fee the user needs to get a new ticket purchase mined right away.
if td.TemplateData.MempoolFeeInfo.Number < uint32(td.params.MaxFreshStakePerBlock) {
td.TemplateData.MempoolFeeInfo.LowestMineable = 0.01
}
mpf := &td.TemplateData.MempoolFees
mpf.Height, mpf.Time, _, mpf.FeeRates = td.MPC.GetFeeRates(25)
mpf.Length = uint32(len(mpf.FeeRates))
return nil
}
func (td *WebUI) RootPage(w http.ResponseWriter, r *http.Request) {
td.templateDataMtx.RLock()
//err := td.templ.Execute(w, td.TemplateData)
str, err := TemplateExecToString(td.templ, "home", td.TemplateData)
td.templateDataMtx.RUnlock()
if err != nil {
http.Error(w, "template execute failure", http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "text/html")
w.WriteHeader(http.StatusOK)
io.WriteString(w, str)
}