From 1c351d02ec76b1cbd9ab7882aa3c287a6acd3811 Mon Sep 17 00:00:00 2001 From: jholdstock Date: Mon, 6 Jul 2020 10:43:46 +0100 Subject: [PATCH] Add voting wallet status to admin page --- rpc/dcrwallet.go | 9 ++++++ webapi/admin.go | 55 +++++++++++++++++++++++++++++++-- webapi/middleware.go | 1 + webapi/public/css/vspd.css | 22 ++++++++++++- webapi/templates/admin.html | 61 +++++++++++++++++++++++++++++++++++-- webapi/webapi.go | 2 +- 6 files changed, 143 insertions(+), 7 deletions(-) diff --git a/rpc/dcrwallet.go b/rpc/dcrwallet.go index dcf3c6f..fd34407 100644 --- a/rpc/dcrwallet.go +++ b/rpc/dcrwallet.go @@ -155,3 +155,12 @@ func (c *WalletRPC) AddTicketForVoting(votingWIF, blockHash, txHex string) error func (c *WalletRPC) SetVoteChoice(agenda, choice, ticketHash string) error { return c.Call(c.ctx, "setvotechoice", nil, agenda, choice, ticketHash) } + +func (c *WalletRPC) GetBestBlockHeight() (int64, error) { + var block dcrdtypes.GetBestBlockResult + err := c.Call(c.ctx, "getbestblock", &block) + if err != nil { + return 0, err + } + return block.Height, nil +} diff --git a/webapi/admin.go b/webapi/admin.go index 4fa9496..bba0125 100644 --- a/webapi/admin.go +++ b/webapi/admin.go @@ -3,14 +3,64 @@ package webapi import ( "net/http" + "github.com/decred/vspd/rpc" "github.com/gin-gonic/gin" "github.com/gorilla/sessions" ) +// WalletStatus describes the current status of a single voting wallet. +type WalletStatus struct { + Connected bool + InfoError bool + DaemonConnected bool + VoteVersion uint32 + Unlocked bool + Voting bool + BestBlockError bool + BestBlockHeight int64 +} + +func walletStatus(c *gin.Context) map[string]WalletStatus { + walletClients := c.MustGet("WalletClients").([]*rpc.WalletRPC) + failedWalletClients := c.MustGet("FailedWalletClients").([]string) + + walletStatus := make(map[string]WalletStatus) + for _, v := range walletClients { + ws := WalletStatus{Connected: true} + + walletInfo, err := v.WalletInfo() + if err != nil { + log.Errorf("dcrwallet.WalletInfo error (wallet=%s): %v", v.String(), err) + ws.InfoError = true + } else { + ws.DaemonConnected = walletInfo.DaemonConnected + ws.VoteVersion = walletInfo.VoteVersion + ws.Unlocked = walletInfo.Unlocked + ws.Voting = walletInfo.Voting + } + + height, err := v.GetBestBlockHeight() + if err != nil { + log.Errorf("dcrwallet.GetBestBlockHeight error (wallet=%s): %v", v.String(), err) + ws.BestBlockError = true + } else { + ws.BestBlockHeight = height + } + + walletStatus[v.String()] = ws + } + for _, v := range failedWalletClients { + ws := WalletStatus{Connected: false} + walletStatus[v] = ws + } + return walletStatus +} + // adminPage is the handler for "GET /admin". func adminPage(c *gin.Context) { c.HTML(http.StatusOK, "admin.html", gin.H{ - "VspStats": getVSPStats(), + "VspStats": getVSPStats(), + "WalletStatus": walletStatus(c), }) } @@ -32,7 +82,8 @@ func ticketSearch(c *gin.Context) { "Found": found, "Ticket": ticket, }, - "VspStats": getVSPStats(), + "VspStats": getVSPStats(), + "WalletStatus": walletStatus(c), }) } diff --git a/webapi/middleware.go b/webapi/middleware.go index f7ba06d..8cb67cd 100644 --- a/webapi/middleware.go +++ b/webapi/middleware.go @@ -105,6 +105,7 @@ func withWalletClients(wallets rpc.WalletConnect) gin.HandlerFunc { len(failedConnections), len(clients)) } c.Set("WalletClients", clients) + c.Set("FailedWalletClients", failedConnections) } } diff --git a/webapi/public/css/vspd.css b/webapi/public/css/vspd.css index a1267bf..f5e65d3 100644 --- a/webapi/public/css/vspd.css +++ b/webapi/public/css/vspd.css @@ -103,7 +103,8 @@ footer .code { .block__content th { font-weight: normal; padding-right: 15px; - text-align: right; + color: #495057; + background-color: #e9ecef; } .block__content table td { @@ -114,4 +115,23 @@ footer .code { .block__content table th { vertical-align: top; white-space: nowrap; +} + +td.status-good{ + background-color: #C4ECCA; +} +td.status-bad{ + background-color: #FEB8A5; +} + +.ticket-table th { + text-align: right; +} +.ticket-table td { + text-align: left; +} + +.status-table th, +.status-table td { + text-align: center; } \ No newline at end of file diff --git a/webapi/templates/admin.html b/webapi/templates/admin.html index 8bf789f..54bf710 100644 --- a/webapi/templates/admin.html +++ b/webapi/templates/admin.html @@ -22,13 +22,69 @@
+
+
+
+

Voting Wallet Status

+ + + + + + + + + + + {{ range $host, $status := .WalletStatus }} + + + + {{ if $status.Connected }} + + {{ if $status.BestBlockError }} + + {{ else }} + + {{ end }} + + {{ if $status.InfoError }} + + {{ else }} + + + + + + + + + + {{ end }} + + {{else}} + + {{end}} + + {{end}} +
URLBest Block HeightDaemon ConnectedUnlockedVotingVote Version
{{ $host }}Error{{ $status.BestBlockHeight }}Error{{ $status.DaemonConnected }}{{ $status.Unlocked }}{{ $status.Voting }}{{ $status.VoteVersion }}Cannot connect to wallet
+ +
+
+ +
+
+ +

Ticket Search

-
@@ -38,7 +94,7 @@ {{ with .SearchResult }} {{ if .Found }} {{ with .Ticket }} - +
@@ -104,7 +160,6 @@ - {{ template "footer" . }} diff --git a/webapi/webapi.go b/webapi/webapi.go index 734dfbb..583217f 100644 --- a/webapi/webapi.go +++ b/webapi/webapi.go @@ -205,7 +205,7 @@ func router(debugMode bool, cookieSecret []byte, dcrd rpc.DcrdConnect, wallets r login.POST("", adminLogin) admin := router.Group("/admin").Use( - withSession(cookieStore), requireAdmin(), + withWalletClients(wallets), withSession(cookieStore), requireAdmin(), ) admin.GET("", adminPage) admin.POST("/ticket", ticketSearch)
Hash {{ .Hash }}