Add voting wallet status to admin page
This commit is contained in:
parent
da410b5060
commit
1c351d02ec
@ -155,3 +155,12 @@ func (c *WalletRPC) AddTicketForVoting(votingWIF, blockHash, txHex string) error
|
|||||||
func (c *WalletRPC) SetVoteChoice(agenda, choice, ticketHash string) error {
|
func (c *WalletRPC) SetVoteChoice(agenda, choice, ticketHash string) error {
|
||||||
return c.Call(c.ctx, "setvotechoice", nil, agenda, choice, ticketHash)
|
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
|
||||||
|
}
|
||||||
|
|||||||
@ -3,14 +3,64 @@ package webapi
|
|||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/decred/vspd/rpc"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/gorilla/sessions"
|
"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".
|
// adminPage is the handler for "GET /admin".
|
||||||
func adminPage(c *gin.Context) {
|
func adminPage(c *gin.Context) {
|
||||||
c.HTML(http.StatusOK, "admin.html", gin.H{
|
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,
|
"Found": found,
|
||||||
"Ticket": ticket,
|
"Ticket": ticket,
|
||||||
},
|
},
|
||||||
"VspStats": getVSPStats(),
|
"VspStats": getVSPStats(),
|
||||||
|
"WalletStatus": walletStatus(c),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -105,6 +105,7 @@ func withWalletClients(wallets rpc.WalletConnect) gin.HandlerFunc {
|
|||||||
len(failedConnections), len(clients))
|
len(failedConnections), len(clients))
|
||||||
}
|
}
|
||||||
c.Set("WalletClients", clients)
|
c.Set("WalletClients", clients)
|
||||||
|
c.Set("FailedWalletClients", failedConnections)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -103,7 +103,8 @@ footer .code {
|
|||||||
.block__content th {
|
.block__content th {
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
padding-right: 15px;
|
padding-right: 15px;
|
||||||
text-align: right;
|
color: #495057;
|
||||||
|
background-color: #e9ecef;
|
||||||
}
|
}
|
||||||
|
|
||||||
.block__content table td {
|
.block__content table td {
|
||||||
@ -115,3 +116,22 @@ footer .code {
|
|||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
white-space: nowrap;
|
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;
|
||||||
|
}
|
||||||
@ -22,14 +22,70 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
|
<div class="row">
|
||||||
|
|
||||||
|
<div class="col-12 p-3">
|
||||||
|
<div class="block__content">
|
||||||
|
<h1>Voting Wallet Status</h1>
|
||||||
|
|
||||||
|
<table class="table status-table mb-0" width="100%">
|
||||||
|
<tr>
|
||||||
|
<th>URL</th>
|
||||||
|
<th>Best Block Height</th>
|
||||||
|
<th>Daemon Connected</th>
|
||||||
|
<th>Unlocked</th>
|
||||||
|
<th>Voting</th>
|
||||||
|
<th>Vote Version</th>
|
||||||
|
</tr>
|
||||||
|
{{ range $host, $status := .WalletStatus }}
|
||||||
|
<tr>
|
||||||
|
<td>{{ $host }}</td>
|
||||||
|
|
||||||
|
{{ if $status.Connected }}
|
||||||
|
|
||||||
|
{{ if $status.BestBlockError }}
|
||||||
|
<td class="status-bad">Error</td>
|
||||||
|
{{ else }}
|
||||||
|
<td>{{ $status.BestBlockHeight }}</td>
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
{{ if $status.InfoError }}
|
||||||
|
<td class="status-bad" colspan="4">Error</td>
|
||||||
|
{{ else }}
|
||||||
|
<td class="{{ if $status.DaemonConnected }}status-good{{else}}status-bad{{end}}"
|
||||||
|
>{{ $status.DaemonConnected }}</td>
|
||||||
|
|
||||||
|
|
||||||
|
<td class="{{ if $status.Unlocked }}status-good{{else}}status-bad{{end}}"
|
||||||
|
>{{ $status.Unlocked }}</td>
|
||||||
|
|
||||||
|
|
||||||
|
<td class="{{ if $status.Voting }}status-good{{else}}status-bad{{end}}"
|
||||||
|
>{{ $status.Voting }}</td>
|
||||||
|
|
||||||
|
<td>{{ $status.VoteVersion }}</td>
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
{{else}}
|
||||||
|
<td class="status-bad" colspan="4">Cannot connect to wallet</td>
|
||||||
|
{{end}}
|
||||||
|
</tr>
|
||||||
|
{{end}}
|
||||||
|
</table>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
|
||||||
<div class="col-12 p-3">
|
<div class="col-12 p-3">
|
||||||
<div class="block__content">
|
<div class="block__content">
|
||||||
<h1>Ticket Search</h1>
|
<h1>Ticket Search</h1>
|
||||||
|
|
||||||
|
|
||||||
<form class="my-2" action="/admin/ticket" method="post">
|
<form class="my-2" action="/admin/ticket" method="post">
|
||||||
<input type="text" name="hash" size="64" minlength="64" maxlength="64" required placeholder="Ticket hash" autocomplete="off">
|
<input type="text" name="hash" size="64" minlength="64" maxlength="64" required placeholder="Ticket hash" autocomplete="off">
|
||||||
<button class="ml-3 btn btn-primary" type="submit">Search</button>
|
<button class="ml-3 btn btn-primary" type="submit">Search</button>
|
||||||
@ -38,7 +94,7 @@
|
|||||||
{{ with .SearchResult }}
|
{{ with .SearchResult }}
|
||||||
{{ if .Found }}
|
{{ if .Found }}
|
||||||
{{ with .Ticket }}
|
{{ with .Ticket }}
|
||||||
<table class="table mt-4 mb-0">
|
<table class="table ticket-table mt-4 mb-0">
|
||||||
<tr>
|
<tr>
|
||||||
<th>Hash</th>
|
<th>Hash</th>
|
||||||
<td>{{ .Hash }}</td>
|
<td>{{ .Hash }}</td>
|
||||||
@ -104,7 +160,6 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{ template "footer" . }}
|
{{ template "footer" . }}
|
||||||
|
|||||||
@ -205,7 +205,7 @@ func router(debugMode bool, cookieSecret []byte, dcrd rpc.DcrdConnect, wallets r
|
|||||||
login.POST("", adminLogin)
|
login.POST("", adminLogin)
|
||||||
|
|
||||||
admin := router.Group("/admin").Use(
|
admin := router.Group("/admin").Use(
|
||||||
withSession(cookieStore), requireAdmin(),
|
withWalletClients(wallets), withSession(cookieStore), requireAdmin(),
|
||||||
)
|
)
|
||||||
admin.GET("", adminPage)
|
admin.GET("", adminPage)
|
||||||
admin.POST("/ticket", ticketSearch)
|
admin.POST("/ticket", ticketSearch)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user