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 @@
| URL | +Best Block Height | +Daemon Connected | +Unlocked | +Voting | +Vote Version | +|||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| {{ $host }} | + + {{ if $status.Connected }} + + {{ if $status.BestBlockError }} +Error | + {{ else }} +{{ $status.BestBlockHeight }} | + {{ end }} + + {{ if $status.InfoError }} +Error | + {{ else }} +{{ $status.DaemonConnected }} | + + +{{ $status.Unlocked }} | + + +{{ $status.Voting }} | + +{{ $status.VoteVersion }} | + {{ end }} + + {{else}} +Cannot connect to wallet | + {{end}} +||||||