Enable pool closure (#80)
* Enable pool closure. * Move homepage to its own file * Docs and rename status>info
This commit is contained in:
parent
e65a7fdbf3
commit
6a100811f4
@ -29,6 +29,7 @@ var (
|
|||||||
defaultWalletHost = "127.0.0.1"
|
defaultWalletHost = "127.0.0.1"
|
||||||
defaultWebServerDebug = false
|
defaultWebServerDebug = false
|
||||||
defaultBackupInterval = time.Minute * 3
|
defaultBackupInterval = time.Minute * 3
|
||||||
|
defaultVspClosed = false
|
||||||
)
|
)
|
||||||
|
|
||||||
// config defines the configuration options for the VSP.
|
// config defines the configuration options for the VSP.
|
||||||
@ -51,6 +52,7 @@ type config struct {
|
|||||||
WebServerDebug bool `long:"webserverdebug" ini-name:"webserverdebug" description:"Enable web server debug mode (verbose logging to terminal and live-reloading templates)."`
|
WebServerDebug bool `long:"webserverdebug" ini-name:"webserverdebug" description:"Enable web server debug mode (verbose logging to terminal and live-reloading templates)."`
|
||||||
SupportEmail string `long:"supportemail" ini-name:"supportemail" description:"Email address for users in need of support."`
|
SupportEmail string `long:"supportemail" ini-name:"supportemail" description:"Email address for users in need of support."`
|
||||||
BackupInterval time.Duration `long:"backupinterval" ini-name:"backupinterval" description:"Time period between automatic database backups. Valid time units are {s,m,h}. Minimum 30 seconds."`
|
BackupInterval time.Duration `long:"backupinterval" ini-name:"backupinterval" description:"Time period between automatic database backups. Valid time units are {s,m,h}. Minimum 30 seconds."`
|
||||||
|
VspClosed bool `long:"vspclosed" ini-name:"vspclosed" description:"Closed prevents the VSP from accepting new tickets."`
|
||||||
|
|
||||||
dbPath string
|
dbPath string
|
||||||
netParams *netParams
|
netParams *netParams
|
||||||
@ -156,6 +158,7 @@ func loadConfig() (*config, error) {
|
|||||||
WalletHost: defaultWalletHost,
|
WalletHost: defaultWalletHost,
|
||||||
WebServerDebug: defaultWebServerDebug,
|
WebServerDebug: defaultWebServerDebug,
|
||||||
BackupInterval: defaultBackupInterval,
|
BackupInterval: defaultBackupInterval,
|
||||||
|
VspClosed: defaultVspClosed,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pre-parse the command line options to see if an alternative config
|
// Pre-parse the command line options to see if an alternative config
|
||||||
|
|||||||
25
docs/api.md
25
docs/api.md
@ -15,13 +15,15 @@
|
|||||||
|
|
||||||
## Expected usage
|
## Expected usage
|
||||||
|
|
||||||
### Get VSP public key
|
### Get VSP info
|
||||||
|
|
||||||
Clients should first retrieve the VSP's public key so they can check the
|
Clients should retrieve the VSP's public key so they can check the signature on
|
||||||
signature on later API responses. A VSP should never change their public key so
|
future API responses. A VSP should never change their public key so it can be
|
||||||
it can be requested once and cached indefinitely.
|
requested once and cached indefinitely. `vspclosed` indicates that the VSP is
|
||||||
|
not currently accepting new tickets. Calling `/feeaddress` when a VSP is closed
|
||||||
|
will result in an error.
|
||||||
|
|
||||||
- `GET /api/pubkey`
|
- `GET /api/vspinfo`
|
||||||
|
|
||||||
No request body.
|
No request body.
|
||||||
|
|
||||||
@ -29,8 +31,11 @@ it can be requested once and cached indefinitely.
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"timestamp":1590509065,
|
"timestamp":1590599436,
|
||||||
"pubkey":"bLNwVVcda3LqRLv+m0J5sjd60+twjO/fuhcx8RUErDQ="
|
"pubkey":"SjAmrAqH7LScCUwM1qo5O6Cu7aKhrM1ORszgZwD7HmU=",
|
||||||
|
"feepercentage":0.05,
|
||||||
|
"vspclosed":false,
|
||||||
|
"network":"testnet3"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -101,11 +106,7 @@ has 6 confirmations.
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Information requests
|
### Ticket Status
|
||||||
|
|
||||||
Clients can check the status of the server at any time.
|
|
||||||
|
|
||||||
// TODO
|
|
||||||
|
|
||||||
Clients can check the status of a ticket at any time after calling
|
Clients can check the status of a ticket at any time after calling
|
||||||
`/feeaddress`.
|
`/feeaddress`.
|
||||||
|
|||||||
6
main.go
6
main.go
@ -44,6 +44,11 @@ func run(ctx context.Context) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if cfg.VspClosed {
|
||||||
|
log.Warnf("Config --vspclosed is set. This will prevent vspd from " +
|
||||||
|
"accepting new tickets.")
|
||||||
|
}
|
||||||
|
|
||||||
// Waitgroup for services to signal when they have shutdown cleanly.
|
// Waitgroup for services to signal when they have shutdown cleanly.
|
||||||
var shutdownWg sync.WaitGroup
|
var shutdownWg sync.WaitGroup
|
||||||
defer log.Info("Shutdown complete")
|
defer log.Info("Shutdown complete")
|
||||||
@ -117,6 +122,7 @@ func run(ctx context.Context) error {
|
|||||||
NetParams: cfg.netParams.Params,
|
NetParams: cfg.netParams.Params,
|
||||||
FeeAddressExpiration: defaultFeeAddressExpiration,
|
FeeAddressExpiration: defaultFeeAddressExpiration,
|
||||||
SupportEmail: cfg.SupportEmail,
|
SupportEmail: cfg.SupportEmail,
|
||||||
|
VspClosed: cfg.VspClosed,
|
||||||
}
|
}
|
||||||
err = webapi.Start(ctx, shutdownRequestChannel, &shutdownWg, cfg.Listen, db,
|
err = webapi.Start(ctx, shutdownRequestChannel, &shutdownWg, cfg.Listen, db,
|
||||||
dcrdConnect, walletConnect, cfg.WebServerDebug, cfg.FeeXPub, apiCfg)
|
dcrdConnect, walletConnect, cfg.WebServerDebug, cfg.FeeXPub, apiCfg)
|
||||||
|
|||||||
@ -69,6 +69,11 @@ func feeAddress(c *gin.Context) {
|
|||||||
commitmentAddress := c.MustGet("CommitmentAddress").(string)
|
commitmentAddress := c.MustGet("CommitmentAddress").(string)
|
||||||
dcrdClient := c.MustGet("DcrdClient").(*rpc.DcrdRPC)
|
dcrdClient := c.MustGet("DcrdClient").(*rpc.DcrdRPC)
|
||||||
|
|
||||||
|
if cfg.VspClosed {
|
||||||
|
sendErrorResponse("pool is not accepting new tickets", http.StatusBadRequest, c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
var feeAddressRequest FeeAddressRequest
|
var feeAddressRequest FeeAddressRequest
|
||||||
if err := binding.JSON.BindBody(rawRequest, &feeAddressRequest); err != nil {
|
if err := binding.JSON.BindBody(rawRequest, &feeAddressRequest); err != nil {
|
||||||
log.Warnf("Bad feeaddress request from %s: %v", c.ClientIP(), err)
|
log.Warnf("Bad feeaddress request from %s: %v", c.ClientIP(), err)
|
||||||
|
|||||||
44
webapi/homepage.go
Normal file
44
webapi/homepage.go
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
package webapi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/jholdstock/vspd/database"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
type vspStats struct {
|
||||||
|
PubKey []byte
|
||||||
|
TotalTickets int
|
||||||
|
FeePaidTickets int
|
||||||
|
VSPFee float64
|
||||||
|
Network string
|
||||||
|
UpdateTime string
|
||||||
|
SupportEmail string
|
||||||
|
VspClosed bool
|
||||||
|
}
|
||||||
|
|
||||||
|
var stats *vspStats
|
||||||
|
|
||||||
|
func updateVSPStats(db *database.VspDatabase, cfg Config) (*vspStats, error) {
|
||||||
|
total, feePaid, err := db.CountTickets()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &vspStats{
|
||||||
|
PubKey: signPubKey,
|
||||||
|
TotalTickets: total,
|
||||||
|
FeePaidTickets: feePaid,
|
||||||
|
VSPFee: cfg.VSPFee,
|
||||||
|
Network: cfg.NetParams.Name,
|
||||||
|
UpdateTime: time.Now().Format("Mon Jan _2 15:04:05 2006"),
|
||||||
|
SupportEmail: cfg.SupportEmail,
|
||||||
|
VspClosed: cfg.VspClosed,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func homepage(c *gin.Context) {
|
||||||
|
c.HTML(http.StatusOK, "homepage.html", stats)
|
||||||
|
}
|
||||||
@ -1,23 +0,0 @@
|
|||||||
package webapi
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
)
|
|
||||||
|
|
||||||
// pubKey is the handler for "GET /pubkey".
|
|
||||||
func pubKey(c *gin.Context) {
|
|
||||||
sendJSONResponse(pubKeyResponse{
|
|
||||||
Timestamp: time.Now().Unix(),
|
|
||||||
PubKey: signPubKey,
|
|
||||||
}, c)
|
|
||||||
}
|
|
||||||
|
|
||||||
// fee is the handler for "GET /fee".
|
|
||||||
func fee(c *gin.Context) {
|
|
||||||
sendJSONResponse(feeResponse{
|
|
||||||
Timestamp: time.Now().Unix(),
|
|
||||||
FeePercentage: cfg.VSPFee,
|
|
||||||
}, c)
|
|
||||||
}
|
|
||||||
@ -48,6 +48,7 @@
|
|||||||
<tr><td>Network:</td><td>{{ .Network }}</td></tr>
|
<tr><td>Network:</td><td>{{ .Network }}</td></tr>
|
||||||
<tr><td>Support:</td><td>{{ .SupportEmail }}</td></tr>
|
<tr><td>Support:</td><td>{{ .SupportEmail }}</td></tr>
|
||||||
<tr><td>Pubkey:</td><td>{{ printf "%x" .PubKey }}</td></tr>
|
<tr><td>Pubkey:</td><td>{{ printf "%x" .PubKey }}</td></tr>
|
||||||
|
<tr><td>VSP closed:</td><td>{{ .VspClosed }}</td></tr>
|
||||||
</table>
|
</table>
|
||||||
<p>Last updated: {{.UpdateTime}}</p>
|
<p>Last updated: {{.UpdateTime}}</p>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@ -1,13 +1,11 @@
|
|||||||
package webapi
|
package webapi
|
||||||
|
|
||||||
type pubKeyResponse struct {
|
type vspInfoResponse struct {
|
||||||
Timestamp int64 `json:"timestamp" binding:"required"`
|
|
||||||
PubKey []byte `json:"pubkey" binding:"required"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type feeResponse struct {
|
|
||||||
Timestamp int64 `json:"timestamp" binding:"required"`
|
Timestamp int64 `json:"timestamp" binding:"required"`
|
||||||
|
PubKey []byte `json:"pubkey" binding:"required"`
|
||||||
FeePercentage float64 `json:"feepercentage" binding:"required"`
|
FeePercentage float64 `json:"feepercentage" binding:"required"`
|
||||||
|
VspClosed bool `json:"vspclosed" binding:"required"`
|
||||||
|
Network string `json:"network" binding:"required"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type FeeAddressRequest struct {
|
type FeeAddressRequest struct {
|
||||||
|
|||||||
18
webapi/vspstatus.go
Normal file
18
webapi/vspstatus.go
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
package webapi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
// vspInfo is the handler for "GET /vspinfo".
|
||||||
|
func vspInfo(c *gin.Context) {
|
||||||
|
sendJSONResponse(vspInfoResponse{
|
||||||
|
Timestamp: time.Now().Unix(),
|
||||||
|
PubKey: signPubKey,
|
||||||
|
FeePercentage: cfg.VSPFee,
|
||||||
|
Network: cfg.NetParams.Name,
|
||||||
|
VspClosed: cfg.VspClosed,
|
||||||
|
}, c)
|
||||||
|
}
|
||||||
@ -24,6 +24,7 @@ type Config struct {
|
|||||||
FeeAccountName string
|
FeeAccountName string
|
||||||
FeeAddressExpiration time.Duration
|
FeeAddressExpiration time.Duration
|
||||||
SupportEmail string
|
SupportEmail string
|
||||||
|
VspClosed bool
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -34,18 +35,6 @@ const (
|
|||||||
relayFee = 0.0001
|
relayFee = 0.0001
|
||||||
)
|
)
|
||||||
|
|
||||||
type vspStats struct {
|
|
||||||
PubKey []byte
|
|
||||||
TotalTickets int
|
|
||||||
FeePaidTickets int
|
|
||||||
VSPFee float64
|
|
||||||
Network string
|
|
||||||
UpdateTime string
|
|
||||||
SupportEmail string
|
|
||||||
}
|
|
||||||
|
|
||||||
var stats *vspStats
|
|
||||||
|
|
||||||
var cfg Config
|
var cfg Config
|
||||||
var db *database.VspDatabase
|
var db *database.VspDatabase
|
||||||
var dcrdConnect rpc.Connect
|
var dcrdConnect rpc.Connect
|
||||||
@ -185,8 +174,7 @@ func router(debugMode bool) *gin.Engine {
|
|||||||
|
|
||||||
// These routes have no extra middleware. They can be accessed by anybody.
|
// These routes have no extra middleware. They can be accessed by anybody.
|
||||||
router.GET("/", homepage)
|
router.GET("/", homepage)
|
||||||
router.GET("/api/fee", fee)
|
router.GET("/api/vspinfo", vspInfo)
|
||||||
router.GET("/api/pubkey", pubKey)
|
|
||||||
|
|
||||||
// These API routes access dcrd and they need authentication.
|
// These API routes access dcrd and they need authentication.
|
||||||
feeOnly := router.Group("/api").Use(
|
feeOnly := router.Group("/api").Use(
|
||||||
@ -206,26 +194,6 @@ func router(debugMode bool) *gin.Engine {
|
|||||||
return router
|
return router
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateVSPStats(db *database.VspDatabase, cfg Config) (*vspStats, error) {
|
|
||||||
total, feePaid, err := db.CountTickets()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &vspStats{
|
|
||||||
PubKey: signPubKey,
|
|
||||||
TotalTickets: total,
|
|
||||||
FeePaidTickets: feePaid,
|
|
||||||
VSPFee: cfg.VSPFee,
|
|
||||||
Network: cfg.NetParams.Name,
|
|
||||||
UpdateTime: time.Now().Format("Mon Jan _2 15:04:05 2006"),
|
|
||||||
SupportEmail: cfg.SupportEmail,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func homepage(c *gin.Context) {
|
|
||||||
c.HTML(http.StatusOK, "homepage.html", stats)
|
|
||||||
}
|
|
||||||
|
|
||||||
func sendJSONResponse(resp interface{}, c *gin.Context) {
|
func sendJSONResponse(resp interface{}, c *gin.Context) {
|
||||||
dec, err := json.Marshal(resp)
|
dec, err := json.Marshal(resp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user