Add some stats to homepage (#51)
This commit is contained in:
parent
96608718a0
commit
1ff55f4b30
@ -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)
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
4
main.go
4
main.go
@ -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
|
||||
|
||||
@ -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>
|
||||
@ -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 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", gin.H{
|
||||
"Message": "Welcome to dcrvsp!",
|
||||
})
|
||||
c.HTML(http.StatusOK, "homepage.html", homepageData)
|
||||
}
|
||||
|
||||
func sendJSONResponse(resp interface{}, c *gin.Context) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user