diff --git a/Makefile b/Makefile index f74673f..e170d89 100644 --- a/Makefile +++ b/Makefile @@ -32,7 +32,7 @@ endef $(eval $(call makemock, pkg/ethsigner, Wallet, ethsignermocks)) $(eval $(call makemock, internal/rpcserver, Server, rpcservermocks)) -$(eval $(call makemock, internal/rpcbackend, Backend, rpcbackendmocks)) +$(eval $(call makemock, pkg/rpcbackend, Backend, rpcbackendmocks)) firefly-signer: ${GOFILES} $(VGO) build -o ./firefly-signer -ldflags "-X main.buildDate=`date -u +\"%Y-%m-%dT%H:%M:%SZ\"` -X main.buildVersion=$(BUILD_VERSION)" -tags=prod -tags=prod -v ./ffsigner diff --git a/internal/rpcserver/rpchandler.go b/internal/rpcserver/rpchandler.go index 4a2709a..764c7e6 100644 --- a/internal/rpcserver/rpchandler.go +++ b/internal/rpcserver/rpchandler.go @@ -27,8 +27,8 @@ import ( "github.com/hyperledger/firefly-common/pkg/fftypes" "github.com/hyperledger/firefly-common/pkg/i18n" "github.com/hyperledger/firefly-common/pkg/log" - "github.com/hyperledger/firefly-signer/internal/rpcbackend" "github.com/hyperledger/firefly-signer/internal/signermsgs" + "github.com/hyperledger/firefly-signer/pkg/rpcbackend" ) func (s *rpcServer) rpcHandler(w http.ResponseWriter, r *http.Request) { diff --git a/internal/rpcserver/rpchandler_test.go b/internal/rpcserver/rpchandler_test.go index 20543c9..facdcc4 100644 --- a/internal/rpcserver/rpchandler_test.go +++ b/internal/rpcserver/rpchandler_test.go @@ -27,11 +27,11 @@ import ( "testing/iotest" "github.com/hyperledger/firefly-common/pkg/fftypes" - "github.com/hyperledger/firefly-signer/internal/rpcbackend" "github.com/hyperledger/firefly-signer/mocks/ethsignermocks" "github.com/hyperledger/firefly-signer/mocks/rpcbackendmocks" "github.com/hyperledger/firefly-signer/pkg/ethsigner" "github.com/hyperledger/firefly-signer/pkg/ethtypes" + "github.com/hyperledger/firefly-signer/pkg/rpcbackend" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" ) diff --git a/internal/rpcserver/rpcprocessor.go b/internal/rpcserver/rpcprocessor.go index 2d22c97..857511d 100644 --- a/internal/rpcserver/rpcprocessor.go +++ b/internal/rpcserver/rpcprocessor.go @@ -23,10 +23,10 @@ import ( "github.com/hyperledger/firefly-common/pkg/fftypes" "github.com/hyperledger/firefly-common/pkg/i18n" - "github.com/hyperledger/firefly-signer/internal/rpcbackend" "github.com/hyperledger/firefly-signer/internal/signermsgs" "github.com/hyperledger/firefly-signer/pkg/ethsigner" "github.com/hyperledger/firefly-signer/pkg/ethtypes" + "github.com/hyperledger/firefly-signer/pkg/rpcbackend" ) func (s *rpcServer) processRPC(ctx context.Context, rpcReq *rpcbackend.RPCRequest) (*rpcbackend.RPCResponse, error) { diff --git a/internal/rpcserver/rpcprocessor_test.go b/internal/rpcserver/rpcprocessor_test.go index 5a28f43..5897a7f 100644 --- a/internal/rpcserver/rpcprocessor_test.go +++ b/internal/rpcserver/rpcprocessor_test.go @@ -21,10 +21,10 @@ import ( "testing" "github.com/hyperledger/firefly-common/pkg/fftypes" - "github.com/hyperledger/firefly-signer/internal/rpcbackend" "github.com/hyperledger/firefly-signer/mocks/ethsignermocks" "github.com/hyperledger/firefly-signer/mocks/rpcbackendmocks" "github.com/hyperledger/firefly-signer/pkg/ethtypes" + "github.com/hyperledger/firefly-signer/pkg/rpcbackend" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" ) diff --git a/internal/rpcserver/server.go b/internal/rpcserver/server.go index 0dcaf69..077c048 100644 --- a/internal/rpcserver/server.go +++ b/internal/rpcserver/server.go @@ -22,13 +22,14 @@ import ( "github.com/gorilla/mux" "github.com/hyperledger/firefly-common/pkg/config" + "github.com/hyperledger/firefly-common/pkg/ffresty" "github.com/hyperledger/firefly-common/pkg/httpserver" "github.com/hyperledger/firefly-common/pkg/i18n" - "github.com/hyperledger/firefly-signer/internal/rpcbackend" "github.com/hyperledger/firefly-signer/internal/signerconfig" "github.com/hyperledger/firefly-signer/internal/signermsgs" "github.com/hyperledger/firefly-signer/pkg/ethsigner" "github.com/hyperledger/firefly-signer/pkg/ethtypes" + "github.com/hyperledger/firefly-signer/pkg/rpcbackend" ) type Server interface { @@ -40,7 +41,7 @@ type Server interface { func NewServer(ctx context.Context, wallet ethsigner.Wallet) (ss Server, err error) { s := &rpcServer{ - backend: rpcbackend.NewRPCBackend(ctx), + backend: rpcbackend.NewRPCClient(ffresty.New(ctx, signerconfig.BackendConfig)), apiServerDone: make(chan error), wallet: wallet, chainID: config.GetInt64(signerconfig.BackendChainID), diff --git a/internal/signermsgs/en_error_messges.go b/internal/signermsgs/en_error_messges.go index 07ab7d6..456e86b 100644 --- a/internal/signermsgs/en_error_messges.go +++ b/internal/signermsgs/en_error_messges.go @@ -29,7 +29,7 @@ var ffe = func(key, translation string, statusHint ...int) i18n.ErrorMessageKey var ( MsgInvalidOutputType = ffe("FF22010", "Invalid output type: %s") MsgInvalidParam = ffe("FF22011", "Invalid parameter at position %d for method %s: %s") - MsgRPCRequestFailed = ffe("FF22012", "Backend RPC request failed") + MsgRPCRequestFailed = ffe("FF22012", "Backend RPC request failed: %s") MsgReadDirFile = ffe("FF22013", "Directory listing failed") MsgWalletNotAvailable = ffe("FF22014", "Wallet for address '%s' not available") MsgWalletFailed = ffe("FF22015", "Wallet for address '%s' could not be initialized") diff --git a/mocks/rpcbackendmocks/backend.go b/mocks/rpcbackendmocks/backend.go index 60668f9..26d0a96 100644 --- a/mocks/rpcbackendmocks/backend.go +++ b/mocks/rpcbackendmocks/backend.go @@ -5,7 +5,7 @@ package rpcbackendmocks import ( context "context" - rpcbackend "github.com/hyperledger/firefly-signer/internal/rpcbackend" + rpcbackend "github.com/hyperledger/firefly-signer/pkg/rpcbackend" mock "github.com/stretchr/testify/mock" ) diff --git a/internal/rpcbackend/backend.go b/pkg/rpcbackend/backend.go similarity index 71% rename from internal/rpcbackend/backend.go rename to pkg/rpcbackend/backend.go index 16b6c82..31b6054 100644 --- a/internal/rpcbackend/backend.go +++ b/pkg/rpcbackend/backend.go @@ -23,12 +23,11 @@ import ( "sync/atomic" "github.com/go-resty/resty/v2" - "github.com/hyperledger/firefly-common/pkg/ffresty" "github.com/hyperledger/firefly-common/pkg/fftypes" "github.com/hyperledger/firefly-common/pkg/i18n" "github.com/hyperledger/firefly-common/pkg/log" - "github.com/hyperledger/firefly-signer/internal/signerconfig" "github.com/hyperledger/firefly-signer/internal/signermsgs" + "github.com/sirupsen/logrus" ) type RPCCode int64 @@ -45,14 +44,14 @@ type Backend interface { SyncRequest(ctx context.Context, rpcReq *RPCRequest) (rpcRes *RPCResponse, err error) } -// NewRPCBackend Constructor -func NewRPCBackend(ctx context.Context) Backend { - return &rpcBackend{ - client: ffresty.New(ctx, signerconfig.BackendConfig), +// NewRPCClient Constructor +func NewRPCClient(client *resty.Client) Backend { + return &RPCClient{ + client: client, } } -type rpcBackend struct { +type RPCClient struct { client *resty.Client requestCounter int64 } @@ -65,9 +64,9 @@ type RPCRequest struct { } type RPCError struct { - Code int64 `json:"code"` - Message string `json:"message"` - Data []*fftypes.JSONAny `json:"data,omitempty"` + Code int64 `json:"code"` + Message string `json:"message"` + Data fftypes.JSONAny `json:"data,omitempty"` } type RPCResponse struct { @@ -84,12 +83,12 @@ func (r *RPCResponse) Message() string { return "" } -func (rb *rpcBackend) allocateRequestID(req *RPCRequest) { - reqID := atomic.AddInt64(&rb.requestCounter, 1) +func (rc *RPCClient) allocateRequestID(req *RPCRequest) { + reqID := atomic.AddInt64(&rc.requestCounter, 1) req.ID = fftypes.JSONAnyPtr(fmt.Sprintf(`"%.9d"`, reqID)) } -func (rb *rpcBackend) CallRPC(ctx context.Context, result interface{}, method string, params ...interface{}) error { +func (rc *RPCClient) CallRPC(ctx context.Context, result interface{}, method string, params ...interface{}) error { req := &RPCRequest{ JSONRpc: "2.0", Method: method, @@ -102,7 +101,7 @@ func (rb *rpcBackend) CallRPC(ctx context.Context, result interface{}, method st } req.Params[i] = fftypes.JSONAnyPtrBytes(b) } - res, err := rb.SyncRequest(ctx, req) + res, err := rc.SyncRequest(ctx, req) if err != nil { return err } @@ -114,32 +113,42 @@ func (rb *rpcBackend) CallRPC(ctx context.Context, result interface{}, method st // // In all return paths *including error paths* the RPCResponse is populated // so the caller has an RPC structure to send back to the front-end caller. -func (rb *rpcBackend) SyncRequest(ctx context.Context, rpcReq *RPCRequest) (rpcRes *RPCResponse, err error) { +func (rc *RPCClient) SyncRequest(ctx context.Context, rpcReq *RPCRequest) (rpcRes *RPCResponse, err error) { // We always set the back-end request ID - as we need to support requests coming in from // multiple concurrent clients on our front-end that might use clashing IDs. var beReq = *rpcReq beReq.JSONRpc = "2.0" - rb.allocateRequestID(&beReq) + rc.allocateRequestID(&beReq) rpcRes = new(RPCResponse) - log.L(ctx).Infof("RPC:%s:%s --> %s", beReq.ID, rpcReq.ID, rpcReq.Method) - res, err := rb.client.R(). + log.L(ctx).Debugf("RPC:%s:%s --> %s", rpcReq.ID, rpcReq.ID, rpcReq.Method) + if logrus.IsLevelEnabled(logrus.TraceLevel) { + jsonInput, _ := json.Marshal(rpcReq) + log.L(ctx).Tracef("RPC:%s:%s INPUT: %s", rpcReq.ID, rpcReq.ID, jsonInput) + } + res, err := rc.client.R(). SetContext(ctx). - SetBody(&beReq). - SetResult(rpcRes). + SetBody(beReq). + SetResult(&rpcRes). SetError(rpcRes). Post("") + // Restore the original ID rpcRes.ID = rpcReq.ID if err != nil { err := i18n.NewError(ctx, signermsgs.MsgRPCRequestFailed) - log.L(ctx).Errorf("RPC:%s:%s <-- ERROR: %s", beReq.ID, rpcReq.ID, err) + log.L(ctx).Errorf("RPC[%d] <-- ERROR: %s", rpcReq.ID, err) rpcRes = RPCErrorResponse(err, rpcReq.ID, RPCCodeInternalError) return rpcRes, err } - if res.IsError() { - log.L(ctx).Errorf("RPC:%s:%s <-- [%d]: %s", beReq.ID, rpcReq.ID, res.StatusCode(), rpcRes.Message()) + if logrus.IsLevelEnabled(logrus.TraceLevel) { + jsonOutput, _ := json.Marshal(rpcRes) + log.L(ctx).Tracef("RPC:%s:%s OUTPUT: %s", rpcReq.ID, rpcReq.ID, jsonOutput) + } + // JSON/RPC allows errors to be returned with a 200 status code, as well as other status codes + if res.IsError() || rpcRes.Error != nil && rpcRes.Error.Code != 0 { + log.L(ctx).Errorf("RPC[%d] <-- [%d]: %s", rpcReq.ID, res.StatusCode(), rpcRes.Message()) err := fmt.Errorf(rpcRes.Message()) return rpcRes, err } diff --git a/internal/rpcbackend/backend_test.go b/pkg/rpcbackend/backend_test.go similarity index 98% rename from internal/rpcbackend/backend_test.go rename to pkg/rpcbackend/backend_test.go index adb5293..3a10e71 100644 --- a/internal/rpcbackend/backend_test.go +++ b/pkg/rpcbackend/backend_test.go @@ -34,7 +34,7 @@ import ( type testRPCHander func(rpcReq *RPCRequest) (int, *RPCResponse) -func newTestServer(t *testing.T, rpcHandler testRPCHander) (context.Context, *rpcBackend, func()) { +func newTestServer(t *testing.T, rpcHandler testRPCHander) (context.Context, *RPCClient, func()) { ctx, cancelCtx := context.WithCancel(context.Background()) server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { @@ -60,7 +60,7 @@ func newTestServer(t *testing.T, rpcHandler testRPCHander) (context.Context, *rp prefix := signerconfig.BackendConfig prefix.Set(ffresty.HTTPConfigURL, fmt.Sprintf("http://%s", server.Listener.Addr())) - rb := NewRPCBackend(ctx).(*rpcBackend) + rb := NewRPCClient(ffresty.New(ctx, signerconfig.BackendConfig)).(*RPCClient) return ctx, rb, func() { cancelCtx()