[NOD-286] Implement API-Server base structure (#379)

* [NOD-286] Implement API-Server base structure

* [NOD-286] Add rpc user and password as command line arguments

* [NOD-286] Make log directory a CLI argument

* [NOD-286] Add db login details as CLI arguments
This commit is contained in:
Ori Newman 2019-08-27 16:19:01 +03:00 committed by Svarog
parent c73113a12e
commit ed9165f533
6 changed files with 217 additions and 1 deletions

63
apiserver/client.go Normal file
View File

@ -0,0 +1,63 @@
package main
import (
"fmt"
"github.com/daglabs/btcd/btcjson"
"github.com/daglabs/btcd/util/daghash"
"github.com/daglabs/btcd/rpcclient"
"github.com/daglabs/btcd/util"
"github.com/daglabs/btcd/wire"
)
type apiServerClient struct {
*rpcclient.Client
onBlockAdded chan *blockAddedMsg
onChainChanged chan *chainChangedMsg
}
type blockAddedMsg struct {
chainHeight uint64
header *wire.BlockHeader
}
type chainChangedMsg struct {
removedChainBlockHashes []*daghash.Hash
addedChainBlocks []*btcjson.ChainBlock
}
func newAPIServerClient(connCfg *rpcclient.ConnConfig) (*apiServerClient, error) {
client := &apiServerClient{
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 []*btcjson.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
}

58
apiserver/config.go Normal file
View File

@ -0,0 +1,58 @@
package main
import (
"errors"
"github.com/daglabs/btcd/util"
"github.com/jessevdk/go-flags"
"path/filepath"
)
const (
defaultLogFilename = "apiserver.log"
defaultErrLogFilename = "apiserver_err.log"
)
var (
// Default configuration options
defaultLogDir = util.AppDataDir("apiserver", false)
defaultDBHost = "localhost:3306"
)
type config struct {
LogDir string `long:"logdir" description:"Directory to log output."`
RPCUser string `short:"u" long:"rpcuser" description:"RPC username" required:"true"`
RPCPassword string `short:"P" long:"rpcpass" default-mask:"-" description:"RPC password" required:"true"`
RPCServer string `short:"s" long:"rpcserver" description:"RPC server to connect to" required:"true"`
RPCCert string `short:"c" long:"rpccert" description:"RPC server certificate chain for validation"`
DisableTLS bool `long:"notls" description:"Disable TLS"`
DBHost string `long:"dbhost" description:"Database host"`
DBUser string `long:"dbuser" description:"Database user" required:"true"`
DBPassword string `long:"dbpass" description:"Database password" required:"true"`
}
func parseConfig() (*config, error) {
cfg := &config{
LogDir: defaultLogDir,
DBHost: defaultDBHost,
}
parser := flags.NewParser(cfg, flags.PrintErrors|flags.HelpFlag)
_, err := parser.Parse()
if err != nil {
return nil, err
}
if cfg.RPCCert == "" && !cfg.DisableTLS {
return nil, errors.New("--notls has to be disabled if --cert is used")
}
if cfg.RPCCert != "" && cfg.DisableTLS {
return nil, errors.New("--cert should be omitted if --notls is used")
}
logFile := filepath.Join(cfg.LogDir, defaultLogFilename)
errLogFile := filepath.Join(cfg.LogDir, defaultErrLogFilename)
initLog(logFile, errLogFile)
return cfg, nil
}

39
apiserver/connect.go Normal file
View File

@ -0,0 +1,39 @@
package main
import (
"fmt"
"github.com/daglabs/btcd/rpcclient"
"io/ioutil"
)
func connectToServer(cfg *config) (*apiServerClient, error) {
var cert []byte
if !cfg.DisableTLS {
var err error
cert, err = ioutil.ReadFile(cfg.RPCCert)
if err != nil {
return nil, 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,
}
if !cfg.DisableTLS {
connCfg.Certificates = cert
}
client, err := newAPIServerClient(connCfg)
if err != nil {
return nil, fmt.Errorf("Error connecting to address %s: %s", cfg.RPCServer, err)
}
log.Infof("Connected to server %s", cfg.RPCServer)
return client, nil
}

27
apiserver/log.go Normal file
View File

@ -0,0 +1,27 @@
package main
import (
"fmt"
"github.com/daglabs/btcd/logs"
"github.com/daglabs/btcd/util/panics"
"os"
)
var (
backendLog = logs.NewBackend()
log = backendLog.Logger("APIS")
spawn = panics.GoroutineWrapperFunc(log, backendLog)
)
func initLog(logFile, errLogFile string) {
err := backendLog.AddLogFile(logFile, logs.LevelTrace)
if err != nil {
fmt.Fprintf(os.Stderr, "Error adding log file %s as log rotator for level %s: %s", logFile, logs.LevelTrace, err)
os.Exit(1)
}
err = backendLog.AddLogFile(errLogFile, logs.LevelWarn)
if err != nil {
fmt.Fprintf(os.Stderr, "Error adding log file %s as log rotator for level %s: %s", errLogFile, logs.LevelWarn, err)
os.Exit(1)
}
}

30
apiserver/main.go Normal file
View File

@ -0,0 +1,30 @@
package main
import (
"fmt"
"github.com/daglabs/btcd/signal"
"github.com/daglabs/btcd/util/panics"
)
func main() {
defer panics.HandlePanic(log, backendLog)
cfg, err := parseConfig()
if err != nil {
panic(fmt.Errorf("Error parsing command-line arguments: %s", err))
}
client, err := connectToServer(cfg)
if err != nil {
panic(fmt.Errorf("Error connecting to servers: %s", err))
}
defer disconnect(client)
interrupt := signal.InterruptListener()
<-interrupt
}
func disconnect(client *apiServerClient) {
log.Infof("Disconnecting client")
client.Disconnect()
}

View File

@ -7,7 +7,6 @@ import (
)
func connectToServer(cfg *config) (*txgenClient, error) {
var cert []byte
if !cfg.DisableTLS {
var err error