Add some stats to homepage (#51)
This commit is contained in:
parent
96608718a0
commit
1ff55f4b30
@ -31,7 +31,7 @@ var (
|
|||||||
privateKeyK = []byte("privatekey")
|
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.
|
// at the provided path, a new one will be created.
|
||||||
func Open(ctx context.Context, shutdownWg *sync.WaitGroup, dbFile string) (*VspDatabase, error) {
|
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.
|
// Create all storage buckets of the VSP if they don't already exist.
|
||||||
err = db.Update(func(tx *bolt.Tx) error {
|
err = db.Update(func(tx *bolt.Tx) error {
|
||||||
if tx.Bucket(vspBktK) == nil {
|
if tx.Bucket(vspBktK) == nil {
|
||||||
log.Debug("Initialising new database")
|
log.Debug("Initializing new database")
|
||||||
// Create parent bucket.
|
// Create parent bucket.
|
||||||
vspBkt, err := tx.CreateBucket(vspBktK)
|
vspBkt, err := tx.CreateBucket(vspBktK)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to create %s bucket: %v", string(vspBktK), err)
|
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)
|
vbytes := make([]byte, 4)
|
||||||
binary.LittleEndian.PutUint32(vbytes, uint32(1))
|
binary.LittleEndian.PutUint32(vbytes, uint32(1))
|
||||||
err = vspBkt.Put(versionK, vbytes)
|
err = vspBkt.Put(versionK, vbytes)
|
||||||
|
|||||||
@ -155,3 +155,31 @@ func (vdb *VspDatabase) UpdateExpireAndFee(ticketHash string, expiration int64,
|
|||||||
return ticketBkt.Put(hashBytes, ticketBytes)
|
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.
|
// Load config file and parse CLI args.
|
||||||
cfg, err := loadConfig()
|
cfg, err := loadConfig()
|
||||||
if err != nil {
|
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)
|
fmt.Fprintf(os.Stderr, "Config error: %v\n", err)
|
||||||
return 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)
|
err = webapi.Start(ctx, shutdownRequestChannel, &shutdownWg, cfg.Listen, db, feeWalletConnect, votingWalletConnect, cfg.WebServerDebug, apiCfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("Failed to initialise webapi: %v", err)
|
log.Errorf("Failed to initialize webapi: %v", err)
|
||||||
requestShutdown()
|
requestShutdown()
|
||||||
shutdownWg.Wait()
|
shutdownWg.Wait()
|
||||||
return err
|
return err
|
||||||
|
|||||||
@ -11,5 +11,12 @@
|
|||||||
<body>
|
<body>
|
||||||
<img src="/public/images/decred-logo.svg" />
|
<img src="/public/images/decred-logo.svg" />
|
||||||
<h1>{{ .Message }}</h1>
|
<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>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@ -5,6 +5,7 @@ import (
|
|||||||
"crypto/ed25519"
|
"crypto/ed25519"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"sync"
|
"sync"
|
||||||
@ -26,6 +27,8 @@ type Config struct {
|
|||||||
FeeAddressExpiration time.Duration
|
FeeAddressExpiration time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var homepageData *gin.H
|
||||||
|
|
||||||
var cfg Config
|
var cfg Config
|
||||||
var db *database.VspDatabase
|
var db *database.VspDatabase
|
||||||
var feeWalletConnect rpc.Connect
|
var feeWalletConnect rpc.Connect
|
||||||
@ -34,6 +37,13 @@ var votingWalletConnect rpc.Connect
|
|||||||
func Start(ctx context.Context, requestShutdownChan chan struct{}, shutdownWg *sync.WaitGroup,
|
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 {
|
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.
|
// Create TCP listener.
|
||||||
var listenConfig net.ListenConfig
|
var listenConfig net.ListenConfig
|
||||||
listener, err := listenConfig.Listen(ctx, "tcp", listen)
|
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
|
cfg = config
|
||||||
db = vdb
|
db = vdb
|
||||||
feeWalletConnect = fWalletConnect
|
feeWalletConnect = fWalletConnect
|
||||||
@ -125,10 +160,23 @@ func router(debugMode bool) *gin.Engine {
|
|||||||
return router
|
return router
|
||||||
}
|
}
|
||||||
|
|
||||||
func homepage(c *gin.Context) {
|
func updateHomepageData(db *database.VspDatabase, cfg Config) (*gin.H, error) {
|
||||||
c.HTML(http.StatusOK, "homepage.html", gin.H{
|
total, feePaid, err := db.CountTickets()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &gin.H{
|
||||||
"Message": "Welcome to dcrvsp!",
|
"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) {
|
func sendJSONResponse(resp interface{}, c *gin.Context) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user