Add some stats to homepage (#51)

This commit is contained in:
Jamie Holdstock 2020-05-22 18:43:41 +01:00 committed by GitHub
parent 96608718a0
commit 1ff55f4b30
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 91 additions and 8 deletions

View File

@ -31,7 +31,7 @@ var (
privateKeyK = []byte("privatekey")
)
// Open initialises and returns an open database. If no database file is found
// Open initializes and returns an open database. If no database file is found
// at the provided path, a new one will be created.
func Open(ctx context.Context, shutdownWg *sync.WaitGroup, dbFile string) (*VspDatabase, error) {
@ -61,14 +61,14 @@ func Open(ctx context.Context, shutdownWg *sync.WaitGroup, dbFile string) (*VspD
// Create all storage buckets of the VSP if they don't already exist.
err = db.Update(func(tx *bolt.Tx) error {
if tx.Bucket(vspBktK) == nil {
log.Debug("Initialising new database")
log.Debug("Initializing new database")
// Create parent bucket.
vspBkt, err := tx.CreateBucket(vspBktK)
if err != nil {
return fmt.Errorf("failed to create %s bucket: %v", string(vspBktK), err)
}
// Initialise with database version 1.
// Initialize with database version 1.
vbytes := make([]byte, 4)
binary.LittleEndian.PutUint32(vbytes, uint32(1))
err = vspBkt.Put(versionK, vbytes)

View File

@ -155,3 +155,31 @@ func (vdb *VspDatabase) UpdateExpireAndFee(ticketHash string, expiration int64,
return ticketBkt.Put(hashBytes, ticketBytes)
})
}
func (vdb *VspDatabase) CountTickets() (int, int, error) {
var total, feePaid int
err := vdb.db.View(func(tx *bolt.Tx) error {
ticketBkt := tx.Bucket(vspBktK).Bucket(ticketBktK)
return ticketBkt.ForEach(func(k, v []byte) error {
total++
var ticket Ticket
err := json.Unmarshal(v, &ticket)
if err != nil {
return fmt.Errorf("could not unmarshal ticket: %v", err)
}
if ticket.FeeTxHash != "" {
feePaid++
}
return nil
})
})
if err != nil {
return 0, 0, err
}
return total, feePaid, nil
}

View File

@ -39,7 +39,7 @@ func run(ctx context.Context) error {
// Load config file and parse CLI args.
cfg, err := loadConfig()
if err != nil {
// Don't use logger here because it may not be initialised.
// Don't use logger here because it may not be initialized.
fmt.Fprintf(os.Stderr, "Config error: %v\n", err)
return err
}
@ -120,7 +120,7 @@ func run(ctx context.Context) error {
}
err = webapi.Start(ctx, shutdownRequestChannel, &shutdownWg, cfg.Listen, db, feeWalletConnect, votingWalletConnect, cfg.WebServerDebug, apiCfg)
if err != nil {
log.Errorf("Failed to initialise webapi: %v", err)
log.Errorf("Failed to initialize webapi: %v", err)
requestShutdown()
shutdownWg.Wait()
return err

View File

@ -11,5 +11,12 @@
<body>
<img src="/public/images/decred-logo.svg" />
<h1>{{ .Message }}</h1>
<table>
<tr><td>Total tickets:</td><td>{{ .TotalTickets }}</td></tr>
<tr><td>FeePaid tickets:</td><td>{{ .FeePaidTickets }}</td></tr>
<tr><td>VSP Fee:</td><td>{{ .VSPFee }}</td></tr>
<tr><td>Network:</td><td>{{ .Network }}</td></tr>
</table>
<p>Last updated: {{.UpdateTime}}</p>
</body>
</html>

View File

@ -5,6 +5,7 @@ import (
"crypto/ed25519"
"encoding/hex"
"encoding/json"
"fmt"
"net"
"net/http"
"sync"
@ -26,6 +27,8 @@ type Config struct {
FeeAddressExpiration time.Duration
}
var homepageData *gin.H
var cfg Config
var db *database.VspDatabase
var feeWalletConnect rpc.Connect
@ -34,6 +37,13 @@ var votingWalletConnect rpc.Connect
func Start(ctx context.Context, requestShutdownChan chan struct{}, shutdownWg *sync.WaitGroup,
listen string, vdb *database.VspDatabase, fWalletConnect rpc.Connect, vWalletConnect rpc.Connect, debugMode bool, config Config) error {
// Populate template data before starting webserver.
var err error
homepageData, err = updateHomepageData(vdb, config)
if err != nil {
return fmt.Errorf("could not initialize homepage data: %v", err)
}
// Create TCP listener.
var listenConfig net.ListenConfig
listener, err := listenConfig.Listen(ctx, "tcp", listen)
@ -78,6 +88,31 @@ func Start(ctx context.Context, requestShutdownChan chan struct{}, shutdownWg *s
}
}()
// Use a ticker to update template data.
var refresh time.Duration
if debugMode {
refresh = 1 * time.Second
} else {
refresh = 5 * time.Minute
}
shutdownWg.Add(1)
go func() {
ticker := time.NewTicker(refresh)
for {
select {
case <-ctx.Done():
ticker.Stop()
shutdownWg.Done()
return
case <-ticker.C:
homepageData, err = updateHomepageData(db, cfg)
if err != nil {
log.Errorf("Failed to update homepage data: %v", err)
}
}
}
}()
cfg = config
db = vdb
feeWalletConnect = fWalletConnect
@ -125,10 +160,23 @@ func router(debugMode bool) *gin.Engine {
return router
}
func homepage(c *gin.Context) {
c.HTML(http.StatusOK, "homepage.html", gin.H{
func updateHomepageData(db *database.VspDatabase, cfg Config) (*gin.H, error) {
total, feePaid, err := db.CountTickets()
if err != nil {
return nil, err
}
return &gin.H{
"Message": "Welcome to dcrvsp!",
})
"TotalTickets": total,
"FeePaidTickets": feePaid,
"VSPFee": cfg.VSPFee,
"Network": cfg.NetParams.Name,
"UpdateTime": time.Now().Format("Mon Jan _2 15:04:05 2006"),
}, nil
}
func homepage(c *gin.Context) {
c.HTML(http.StatusOK, "homepage.html", homepageData)
}
func sendJSONResponse(resp interface{}, c *gin.Context) {