* Delay fee broadcast and adding tickets to wallets. - Adds a `background` package which implements a dcrd notification handler. On each blockconnected notification, tickets with 6+ confirmations are marked confirmed, relevant fee transactions are broadcast, and any fees with 6+ confirmations have their tickets added to voting wallets. - VSP fee is now an absolute value measured in DCR rather than a percentage. This simplifies the code and is more appropriate for an MVP. We can re-add percentage based fees later. - Database code for tickets is now simplified to just "Insert/Update", rather than having functions for updating particular fields. - Pay fee response no longer includes the fee tx hash, because we dont necessarily broadcast the fee tx straight away. * Const for required confs
90 lines
2.2 KiB
Go
90 lines
2.2 KiB
Go
package rpc
|
|
|
|
import (
|
|
"context"
|
|
"crypto/tls"
|
|
"crypto/x509"
|
|
"sync"
|
|
|
|
"github.com/jrick/wsrpc/v2"
|
|
)
|
|
|
|
// Caller provides a client interface to perform JSON-RPC remote procedure calls.
|
|
type Caller interface {
|
|
// Call performs the remote procedure call defined by method and
|
|
// waits for a response or a broken client connection.
|
|
// Args provides positional parameters for the call.
|
|
// Res must be a pointer to a struct, slice, or map type to unmarshal
|
|
// a result (if any), or nil if no result is needed.
|
|
Call(ctx context.Context, method string, res interface{}, args ...interface{}) error
|
|
}
|
|
|
|
// Connect dials and returns a connected RPC client.
|
|
type Connect func() (Caller, error)
|
|
|
|
// Setup accepts RPC connection details, creates an RPC client, and returns a
|
|
// function which can be called to access the client. The returned function will
|
|
// try to handle any client disconnects by attempting to reconnect, but will
|
|
// return an error if a new connection cannot be established.
|
|
func Setup(ctx context.Context, shutdownWg *sync.WaitGroup, user, pass, addr string, cert []byte, n wsrpc.Notifier) Connect {
|
|
|
|
// Create TLS options.
|
|
pool := x509.NewCertPool()
|
|
pool.AppendCertsFromPEM(cert)
|
|
tc := &tls.Config{RootCAs: pool}
|
|
tlsOpt := wsrpc.WithTLSConfig(tc)
|
|
|
|
// Create authentication options.
|
|
authOpt := wsrpc.WithBasicAuth(user, pass)
|
|
|
|
fullAddr := "wss://" + addr + "/ws"
|
|
|
|
var mu sync.Mutex
|
|
var c *wsrpc.Client
|
|
|
|
// Add the graceful shutdown to the waitgroup.
|
|
shutdownWg.Add(1)
|
|
go func() {
|
|
// Wait until shutdown is signaled before shutting down.
|
|
<-ctx.Done()
|
|
|
|
if c != nil {
|
|
select {
|
|
case <-c.Done():
|
|
log.Debugf("RPC already closed (%s)", addr)
|
|
|
|
default:
|
|
if err := c.Close(); err != nil {
|
|
log.Errorf("Failed to close RPC (%s): %v", addr, err)
|
|
} else {
|
|
log.Debugf("RPC closed (%s)", addr)
|
|
}
|
|
}
|
|
}
|
|
shutdownWg.Done()
|
|
}()
|
|
|
|
return func() (Caller, error) {
|
|
defer mu.Unlock()
|
|
mu.Lock()
|
|
|
|
if c != nil {
|
|
select {
|
|
case <-c.Done():
|
|
log.Debugf("RPC client errored (%v); reconnecting...", c.Err())
|
|
c = nil
|
|
default:
|
|
return c, nil
|
|
}
|
|
}
|
|
|
|
var err error
|
|
c, err = wsrpc.Dial(ctx, fullAddr, tlsOpt, authOpt, wsrpc.WithNotifier(n))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return c, nil
|
|
}
|
|
}
|