From 191531da87b0e2d26f08376a79834b2db35f5ad7 Mon Sep 17 00:00:00 2001 From: George Tankersley Date: Wed, 22 May 2019 13:25:21 -0400 Subject: [PATCH] implement scaffolding --- api/token-redemption.pb.go | 63 ++++++------ cmd/swagserver/main.go | 195 +++++++++++++++++++++++++++++++++++++ go.mod | 10 ++ go.sum | 67 +++++++++++++ swag/server.go | 21 ++++ zrpc/zrpc.go | 37 +++++++ 6 files changed, 362 insertions(+), 31 deletions(-) create mode 100644 cmd/swagserver/main.go create mode 100644 go.sum create mode 100644 swag/server.go create mode 100644 zrpc/zrpc.go diff --git a/api/token-redemption.pb.go b/api/token-redemption.pb.go index b8ee1bb..74f032d 100644 --- a/api/token-redemption.pb.go +++ b/api/token-redemption.pb.go @@ -3,12 +3,13 @@ package api +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" + import ( - context "context" - fmt "fmt" - proto "github.com/golang/protobuf/proto" + context "golang.org/x/net/context" grpc "google.golang.org/grpc" - math "math" ) // Reference imports to suppress errors if they are not otherwise used. @@ -20,7 +21,7 @@ var _ = math.Inf // is compatible with the proto package it is being compiled against. // A compilation error at this line likely means your copy of the // proto package needs to be updated. -const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package type Request struct { Token string `protobuf:"bytes,1,opt,name=token,proto3" json:"token,omitempty"` @@ -34,17 +35,16 @@ func (m *Request) Reset() { *m = Request{} } func (m *Request) String() string { return proto.CompactTextString(m) } func (*Request) ProtoMessage() {} func (*Request) Descriptor() ([]byte, []int) { - return fileDescriptor_7cacfaf902f20ee9, []int{0} + return fileDescriptor_token_redemption_727604cb7b5677c7, []int{0} } - func (m *Request) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Request.Unmarshal(m, b) } func (m *Request) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_Request.Marshal(b, m, deterministic) } -func (m *Request) XXX_Merge(src proto.Message) { - xxx_messageInfo_Request.Merge(m, src) +func (dst *Request) XXX_Merge(src proto.Message) { + xxx_messageInfo_Request.Merge(dst, src) } func (m *Request) XXX_Size() int { return xxx_messageInfo_Request.Size(m) @@ -81,17 +81,16 @@ func (m *Response) Reset() { *m = Response{} } func (m *Response) String() string { return proto.CompactTextString(m) } func (*Response) ProtoMessage() {} func (*Response) Descriptor() ([]byte, []int) { - return fileDescriptor_7cacfaf902f20ee9, []int{1} + return fileDescriptor_token_redemption_727604cb7b5677c7, []int{1} } - func (m *Response) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Response.Unmarshal(m, b) } func (m *Response) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_Response.Marshal(b, m, deterministic) } -func (m *Response) XXX_Merge(src proto.Message) { - xxx_messageInfo_Response.Merge(m, src) +func (dst *Response) XXX_Merge(src proto.Message) { + xxx_messageInfo_Response.Merge(dst, src) } func (m *Response) XXX_Size() int { return xxx_messageInfo_Response.Size(m) @@ -121,24 +120,6 @@ func init() { proto.RegisterType((*Response)(nil), "swagapi.Response") } -func init() { proto.RegisterFile("token-redemption.proto", fileDescriptor_7cacfaf902f20ee9) } - -var fileDescriptor_7cacfaf902f20ee9 = []byte{ - // 186 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0x2b, 0xc9, 0xcf, 0x4e, - 0xcd, 0xd3, 0x2d, 0x4a, 0x4d, 0x49, 0xcd, 0x2d, 0x28, 0xc9, 0xcc, 0xcf, 0xd3, 0x2b, 0x28, 0xca, - 0x2f, 0xc9, 0x17, 0x62, 0x2f, 0x2e, 0x4f, 0x4c, 0x4f, 0x2c, 0xc8, 0x54, 0xb2, 0xe4, 0x62, 0x0f, - 0x4a, 0x2d, 0x2c, 0x4d, 0x2d, 0x2e, 0x11, 0x12, 0xe1, 0x62, 0x05, 0xab, 0x96, 0x60, 0x54, 0x60, - 0xd4, 0xe0, 0x0c, 0x82, 0x70, 0x84, 0x24, 0xb8, 0xd8, 0x13, 0x53, 0x52, 0x8a, 0x52, 0x8b, 0x8b, - 0x25, 0x98, 0xc0, 0xe2, 0x30, 0xae, 0x92, 0x19, 0x17, 0x47, 0x50, 0x6a, 0x71, 0x41, 0x7e, 0x5e, - 0x71, 0x2a, 0x48, 0x55, 0x71, 0x69, 0x72, 0x32, 0x48, 0x15, 0x48, 0x37, 0x47, 0x10, 0x8c, 0x2b, - 0x24, 0xc0, 0xc5, 0x9c, 0x5b, 0x9c, 0x0e, 0xd5, 0x0b, 0x62, 0x1a, 0x59, 0x71, 0xb1, 0x07, 0x97, - 0x27, 0xa6, 0x3b, 0x06, 0x78, 0x0a, 0xe9, 0x73, 0xb1, 0x05, 0xa5, 0xa6, 0xa4, 0xa6, 0xe6, 0x0a, - 0x09, 0xe8, 0x41, 0x5d, 0xa4, 0x07, 0x75, 0x8e, 0x94, 0x20, 0x92, 0x08, 0xc4, 0x16, 0x25, 0x06, - 0x27, 0xd6, 0x28, 0xe6, 0xc4, 0x82, 0xcc, 0x24, 0x36, 0xb0, 0x2f, 0x8c, 0x01, 0x01, 0x00, 0x00, - 0xff, 0xff, 0xf8, 0x3c, 0x52, 0x97, 0xdf, 0x00, 0x00, 0x00, -} - // Reference imports to suppress errors if they are not otherwise used. var _ context.Context var _ grpc.ClientConn @@ -210,3 +191,23 @@ var _SwagAPI_serviceDesc = grpc.ServiceDesc{ Streams: []grpc.StreamDesc{}, Metadata: "token-redemption.proto", } + +func init() { + proto.RegisterFile("token-redemption.proto", fileDescriptor_token_redemption_727604cb7b5677c7) +} + +var fileDescriptor_token_redemption_727604cb7b5677c7 = []byte{ + // 186 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0x2b, 0xc9, 0xcf, 0x4e, + 0xcd, 0xd3, 0x2d, 0x4a, 0x4d, 0x49, 0xcd, 0x2d, 0x28, 0xc9, 0xcc, 0xcf, 0xd3, 0x2b, 0x28, 0xca, + 0x2f, 0xc9, 0x17, 0x62, 0x2f, 0x2e, 0x4f, 0x4c, 0x4f, 0x2c, 0xc8, 0x54, 0xb2, 0xe4, 0x62, 0x0f, + 0x4a, 0x2d, 0x2c, 0x4d, 0x2d, 0x2e, 0x11, 0x12, 0xe1, 0x62, 0x05, 0xab, 0x96, 0x60, 0x54, 0x60, + 0xd4, 0xe0, 0x0c, 0x82, 0x70, 0x84, 0x24, 0xb8, 0xd8, 0x13, 0x53, 0x52, 0x8a, 0x52, 0x8b, 0x8b, + 0x25, 0x98, 0xc0, 0xe2, 0x30, 0xae, 0x92, 0x19, 0x17, 0x47, 0x50, 0x6a, 0x71, 0x41, 0x7e, 0x5e, + 0x71, 0x2a, 0x48, 0x55, 0x71, 0x69, 0x72, 0x32, 0x48, 0x15, 0x48, 0x37, 0x47, 0x10, 0x8c, 0x2b, + 0x24, 0xc0, 0xc5, 0x9c, 0x5b, 0x9c, 0x0e, 0xd5, 0x0b, 0x62, 0x1a, 0x59, 0x71, 0xb1, 0x07, 0x97, + 0x27, 0xa6, 0x3b, 0x06, 0x78, 0x0a, 0xe9, 0x73, 0xb1, 0x05, 0xa5, 0xa6, 0xa4, 0xa6, 0xe6, 0x0a, + 0x09, 0xe8, 0x41, 0x5d, 0xa4, 0x07, 0x75, 0x8e, 0x94, 0x20, 0x92, 0x08, 0xc4, 0x16, 0x25, 0x06, + 0x27, 0xd6, 0x28, 0xe6, 0xc4, 0x82, 0xcc, 0x24, 0x36, 0xb0, 0x2f, 0x8c, 0x01, 0x01, 0x00, 0x00, + 0xff, 0xff, 0xf8, 0x3c, 0x52, 0x97, 0xdf, 0x00, 0x00, 0x00, +} diff --git a/cmd/swagserver/main.go b/cmd/swagserver/main.go new file mode 100644 index 0000000..38dd6e2 --- /dev/null +++ b/cmd/swagserver/main.go @@ -0,0 +1,195 @@ +package main + +import ( + "context" + "flag" + "net" + "os" + "os/signal" + "syscall" + "time" + + "github.com/sirupsen/logrus" + + "github.com/zcash-hackworks/zcon1-swag-api/api" + "github.com/zcash-hackworks/zcon1-swag-api/swag" + "github.com/zcash-hackworks/zcon1-swag-api/zrpc" + + "google.golang.org/grpc" + "google.golang.org/grpc/credentials" + "google.golang.org/grpc/peer" + "google.golang.org/grpc/reflection" +) + +var log *logrus.Entry +var logger = logrus.New() + +func init() { + logger.SetFormatter(&logrus.TextFormatter{ + //DisableColors: true, + FullTimestamp: true, + DisableLevelTruncation: true, + }) + + log = logger.WithFields(logrus.Fields{ + "app": "zcon1-swag-api", + }) +} + +func LoggingInterceptor() grpc.ServerOption { + return grpc.UnaryInterceptor(logInterceptor) +} + +func logInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) { + reqLog := loggerFromContext(ctx) + start := time.Now() + + resp, err := handler(ctx, req) + + entry := reqLog.WithFields(logrus.Fields{ + "method": info.FullMethod, + "duration": time.Since(start), + "error": err, + }) + + if err != nil { + entry.Error("call failed") + } else { + entry.Info("method called") + } + + return resp, err +} + +func loggerFromContext(ctx context.Context) *logrus.Entry { + // TODO: anonymize the addresses. cryptopan? + if peerInfo, ok := peer.FromContext(ctx); ok { + return log.WithFields(logrus.Fields{"peer_addr": peerInfo.Addr}) + } + return log.WithFields(logrus.Fields{"peer_addr": "unknown"}) +} + +type Options struct { + bindAddr string `json:"bind_address,omitempty"` + dbPath string `json:"db_path"` + tlsCertPath string `json:"tls_cert_path,omitempty"` + tlsKeyPath string `json:"tls_cert_key,omitempty"` + logLevel uint64 `json:"log_level,omitempty"` + logPath string `json:"log_file,omitempty"` + zcashConfPath string `json:"zcash_conf,omitempty"` +} + +func main() { + opts := &Options{} + flag.StringVar(&opts.bindAddr, "bind-addr", "127.0.0.1:9067", "the address to listen on") + flag.StringVar(&opts.dbPath, "db-path", "", "the path to a sqlite database file") + flag.StringVar(&opts.tlsCertPath, "tls-cert", "", "the path to a TLS certificate (optional)") + flag.StringVar(&opts.tlsKeyPath, "tls-key", "", "the path to a TLS key file (optional)") + flag.Uint64Var(&opts.logLevel, "log-level", uint64(logrus.InfoLevel), "log level (logrus 1-7)") + flag.StringVar(&opts.logPath, "log-file", "", "log file to write to") + flag.StringVar(&opts.zcashConfPath, "conf-file", "", "conf file to pull RPC creds from") + // TODO prod metrics + // TODO support config from file and env vars + flag.Parse() + + if opts.dbPath == "" || opts.zcashConfPath == "" { + flag.Usage() + os.Exit(1) + } + + if opts.logPath != "" { + // instead write parsable logs for logstash/splunk/etc + output, err := os.OpenFile(opts.logPath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) + if err != nil { + log.WithFields(logrus.Fields{ + "error": err, + "path": opts.logPath, + }).Fatal("couldn't open log file") + } + defer output.Close() + logger.SetOutput(output) + logger.SetFormatter(&logrus.JSONFormatter{}) + } + + logger.SetLevel(logrus.Level(opts.logLevel)) + + // gRPC initialization + var server *grpc.Server + + if opts.tlsCertPath != "" && opts.tlsKeyPath != "" { + transportCreds, err := credentials.NewServerTLSFromFile(opts.tlsCertPath, opts.tlsKeyPath) + if err != nil { + log.WithFields(logrus.Fields{ + "cert_file": opts.tlsCertPath, + "key_path": opts.tlsKeyPath, + "error": err, + }).Fatal("couldn't load TLS credentials") + } + server = grpc.NewServer(grpc.Creds(transportCreds), LoggingInterceptor()) + } else { + server = grpc.NewServer(LoggingInterceptor()) + } + + // Enable reflection for debugging + if opts.logLevel >= uint64(logrus.WarnLevel) { + reflection.Register(server) + } + + // Initialize Zcash RPC client. + rpcClient, err := zrpc.NewZRPCFromConf(opts.zcashConfPath) + if err != nil { + log.WithFields(logrus.Fields{ + "error": err, + }).Warn("zcash.conf failed, will try empty credentials for rpc") + + rpcClient, err = zrpc.NewZRPCFromCreds("127.0.0.1:8232", "", "") + + if err != nil { + log.WithFields(logrus.Fields{ + "error": err, + }).Warn("couldn't start rpc conn. won't be able to send transactions") + } + } + + // Initialize swag server + service, err := swag.NewServer(opts.dbPath, rpcClient) + if err != nil { + log.WithFields(logrus.Fields{ + "db_path": opts.dbPath, + "error": err, + }).Fatal("couldn't create SQL backend") + } + defer service.(*swag.Server).GracefulStop() + + // Register service + api.RegisterSwagAPIServer(server, service) + + // Start listening + listener, err := net.Listen("tcp", opts.bindAddr) + if err != nil { + log.WithFields(logrus.Fields{ + "bind_addr": opts.bindAddr, + "error": err, + }).Fatal("couldn't create listener") + } + + // Signal handler for graceful stops + signals := make(chan os.Signal, 1) + signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM) + go func() { + s := <-signals + log.WithFields(logrus.Fields{ + "signal": s.String(), + }).Info("caught signal, stopping gRPC server") + server.GracefulStop() + }() + + log.Infof("Starting gRPC server on %s", opts.bindAddr) + + err = server.Serve(listener) + if err != nil { + log.WithFields(logrus.Fields{ + "error": err, + }).Fatal("gRPC server exited") + } +} diff --git a/go.mod b/go.mod index dadc27e..9d4e50e 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,13 @@ module github.com/zcash-hackworks/zcon1-swag-api go 1.12 + +require ( + github.com/btcsuite/btcd v0.0.0-20190427004231-96897255fd17 + github.com/golang/protobuf v1.2.0 + github.com/pkg/errors v0.8.1 + github.com/sirupsen/logrus v1.4.1 + golang.org/x/net v0.0.0-20190311183353-d8887717615a + google.golang.org/grpc v1.20.1 + gopkg.in/ini.v1 v1.42.0 +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..9ef6d4e --- /dev/null +++ b/go.sum @@ -0,0 +1,67 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= +github.com/btcsuite/btcd v0.0.0-20190427004231-96897255fd17 h1:m0N5Vg5nP3zEz8TREZpwX3gt4Biw3/8fbIf4A3hO96g= +github.com/btcsuite/btcd v0.0.0-20190427004231-96897255fd17/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI= +github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f h1:bAs4lUbRJpnnkd9VhRV3jjAVU7DJVjMaK+IsvSeZvFo= +github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= +github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d h1:yJzD/yFppdVCf6ApMkVy8cUxV0XrxdP9rVf6D87/Mng= +github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= +github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd h1:R/opQEbFEy9JGkIguV40SvRY1uliPX8ifOvi6ICsFCw= +github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= +github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= +github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= +github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792 h1:R8vQdOQdZ9Y3SkEwmHoWBmX1DNXhXZqlTpq6s4tyJGc= +github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= +github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= +github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/sirupsen/logrus v1.4.1 h1:GL2rEmy6nsikmW0r8opw9JIRScdMF5hA8cOYLH7In1k= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8 h1:Nw54tB0rB7hY/N0NQvRW8DG4Yk3Q6T9cu9RcFQDu1tc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/grpc v1.20.1 h1:Hz2g2wirWK7H0qIIhGIqRGTuMwTE8HEKFnDZZ7lm9NU= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/ini.v1 v1.42.0 h1:7N3gPTt50s8GuLortA00n8AqRTk75qOP98+mTPpgzRk= +gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/swag/server.go b/swag/server.go new file mode 100644 index 0000000..a1aa8e7 --- /dev/null +++ b/swag/server.go @@ -0,0 +1,21 @@ +package swag + +import ( + "context" + + "github.com/btcsuite/btcd/rpcclient" + "github.com/zcash-hackworks/zcon1-swag-api/api" +) + +type Server struct { +} + +func NewServer(dbPath string, zc *rpcclient.Client) (api.SwagAPIServer, error) { + return nil, nil +} + +func (s *Server) Redeem(ctx context.Context, req *api.Request) (*api.Response, error) { + return nil, nil +} + +func (s *Server) GracefulStop() {} diff --git a/zrpc/zrpc.go b/zrpc/zrpc.go new file mode 100644 index 0000000..563bc6d --- /dev/null +++ b/zrpc/zrpc.go @@ -0,0 +1,37 @@ +package zrpc + +import ( + "net" + + "github.com/btcsuite/btcd/rpcclient" + "github.com/pkg/errors" + "gopkg.in/ini.v1" +) + +func NewZRPCFromConf(confPath string) (*rpcclient.Client, error) { + cfg, err := ini.Load(confPath) + if err != nil { + return nil, errors.Wrap(err, "failed to read config file") + } + + rpcaddr := cfg.Section("").Key("rpcbind").String() + rpcport := cfg.Section("").Key("rpcport").String() + username := cfg.Section("").Key("rpcuser").String() + password := cfg.Section("").Key("rpcpassword").String() + + return NewZRPCFromCreds(net.JoinHostPort(rpcaddr, rpcport), username, password) +} + +func NewZRPCFromCreds(addr, username, password string) (*rpcclient.Client, error) { + // Connect to local zcash RPC server using HTTP POST mode. + connCfg := &rpcclient.ConnConfig{ + Host: addr, + User: username, + Pass: password, + HTTPPostMode: true, // Zcash only supports HTTP POST mode + DisableTLS: true, // Zcash does not provide TLS by default + } + // Notice the notification parameter is nil since notifications are + // not supported in HTTP POST mode. + return rpcclient.New(connCfg, nil) +}