Svarog d4083cbdbe [NOD-309] post transaction (#403)
* [NOD-319] Add query params to api server route handler

* Temp commit

* [NOD-322] Make database.DB a function

* [NOD-322] Move context to be the first parameter in all functions

* [NOD-322] Set db to nil on database.Close()

* [NOD-322] Tidy go.mod/go.sum

* [NOD-323] Move rpc-client to separate package

* [NOD-309] Add controller for POST /transaction

* [NOD-309] Added route for POST /transaction

* [NOD-309] in POST /transaction: Forward reject errors to client

* [NOD-309] Added custom client messages to errors in POST /transaction

* [NOD-309] Use utils.NewInternalServerHandlerError where appropriate
2019-09-18 16:09:48 +03:00

124 lines
3.0 KiB
Go

package jsonrpc
import (
"errors"
"fmt"
"io/ioutil"
"time"
"github.com/daglabs/btcd/apiserver/config"
"github.com/daglabs/btcd/util/daghash"
"github.com/daglabs/btcd/rpcclient"
"github.com/daglabs/btcd/util"
"github.com/daglabs/btcd/wire"
)
// Client represents a connection to the JSON-RPC API of a full node
type Client struct {
*rpcclient.Client
onBlockAdded chan *blockAddedMsg
onChainChanged chan *chainChangedMsg
}
var client *Client
// GetClient returns an instance of the JSON-RPC client, in case we have an active connection
func GetClient() (*Client, error) {
if client == nil {
return nil, errors.New("JSON-RPC is not connected")
}
return client, nil
}
type blockAddedMsg struct {
chainHeight uint64
header *wire.BlockHeader
}
type chainChangedMsg struct {
removedChainBlockHashes []*daghash.Hash
addedChainBlocks []*rpcclient.ChainBlock
}
// Close closes the connection to the JSON-RPC API server
func Close() {
if client == nil {
return
}
client.Disconnect()
client = nil
}
// Connect initiates a connection to the JSON-RPC API Server
func Connect(cfg *config.Config) error {
var cert []byte
if !cfg.DisableTLS {
var err error
cert, err = ioutil.ReadFile(cfg.RPCCert)
if err != nil {
return fmt.Errorf("Error reading certificates file: %s", err)
}
}
connCfg := &rpcclient.ConnConfig{
Host: cfg.RPCServer,
Endpoint: "ws",
User: cfg.RPCUser,
Pass: cfg.RPCPassword,
DisableTLS: cfg.DisableTLS,
RequestTimeout: time.Second * 5,
}
if !cfg.DisableTLS {
connCfg.Certificates = cert
}
var err error
client, err = newClient(connCfg)
if err != nil {
return fmt.Errorf("Error connecting to address %s: %s", cfg.RPCServer, err)
}
return nil
}
func newClient(connCfg *rpcclient.ConnConfig) (*Client, error) {
client = &Client{
onBlockAdded: make(chan *blockAddedMsg),
onChainChanged: make(chan *chainChangedMsg),
}
notificationHandlers := &rpcclient.NotificationHandlers{
OnFilteredBlockAdded: func(height uint64, header *wire.BlockHeader,
txs []*util.Tx) {
client.onBlockAdded <- &blockAddedMsg{
chainHeight: height,
header: header,
}
},
OnChainChanged: func(removedChainBlockHashes []*daghash.Hash,
addedChainBlocks []*rpcclient.ChainBlock) {
client.onChainChanged <- &chainChangedMsg{
removedChainBlockHashes: removedChainBlockHashes,
addedChainBlocks: addedChainBlocks,
}
},
}
var err error
client.Client, err = rpcclient.New(connCfg, notificationHandlers)
if err != nil {
return nil, fmt.Errorf("Error connecting to address %s: %s", connCfg.Host, err)
}
if err = client.NotifyBlocks(); err != nil {
return nil, fmt.Errorf("Error while registering client %s for block notifications: %s", client.Host(), err)
}
if err = client.NotifyChainChanges(); err != nil {
return nil, fmt.Errorf("Error while registering client %s for chain changes notifications: %s", client.Host(), err)
}
return client, nil
}