Skip to content

Commit

Permalink
[FAB-7984] Add InvokeHandler to ChannelClient
Browse files Browse the repository at this point in the history
Allow callers to invoke custom handlers via
InvokeHandler. This required ChannelClient
to be moved into a sub-package of apitxn to
avoid circular import errors.

Change-Id: Ifd5d627332323c7da0dd4e084225e1fcd8deb7ee
Signed-off-by: Bob Stasyszyn <bob.stasyszyn@securekey.com>
  • Loading branch information
bstasyszyn committed Jan 31, 2018
1 parent 4fc40fa commit cf9810f
Show file tree
Hide file tree
Showing 20 changed files with 268 additions and 157 deletions.
18 changes: 11 additions & 7 deletions api/apitxn/txn.go → api/apitxn/chclient/chclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ Copyright SecureKey Technologies Inc. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/

package apitxn
package chclient

import (
"time"

"github.com/hyperledger/fabric-sdk-go/api/apitxn"
"github.com/hyperledger/fabric-sdk-go/pkg/errors/retry"
pb "github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/protos/peer"
)
Expand All @@ -24,14 +25,14 @@ type Request struct {
//Response contains response parameters for query and execute transaction
type Response struct {
Payload []byte
TransactionID TransactionID
TransactionID apitxn.TransactionID
TxValidationCode pb.TxValidationCode
Responses []*TransactionProposalResponse
Responses []*apitxn.TransactionProposalResponse
}

// Opts allows the user to specify more advanced options
type Opts struct {
ProposalProcessors []ProposalProcessor // targets
ProposalProcessors []apitxn.ProposalProcessor // targets
Timeout time.Duration
Retry retry.Opts
}
Expand All @@ -42,7 +43,7 @@ type Option func(opts *Opts) error
// TxProposalResponseFilter allows the user to inspect/modify response before commit
type TxProposalResponseFilter interface {
// process transaction proposal response (there will be no commit if an error is returned)
ProcessTxProposalResponse(txProposalResponse []*TransactionProposalResponse) ([]*TransactionProposalResponse, error)
ProcessTxProposalResponse(txProposalResponse []*apitxn.TransactionProposalResponse) ([]*apitxn.TransactionProposalResponse, error)
}

// Registration is a handle that is returned from a successful Register Chaincode Event.
Expand Down Expand Up @@ -70,12 +71,15 @@ type CCEvent struct {
*/
type ChannelClient interface {

// Query chaincode with request and optional options provided
// Query chaincode with request and optional options provided
Query(request Request, opts ...Option) (Response, error)

// Execute execute transaction with request and optional options provided
// Execute execute transaction with request and optional options provided
Execute(request Request, opts ...Option) (Response, error)

// InvokeHandler invokes the given handler with the given request and optional options provided
InvokeHandler(handler Handler, request Request, options ...Option) (Response, error)

// RegisterChaincodeEvent registers chain code event
// @param {chan bool} channel which receives event details when the event is complete
// @returns {object} object handle that should be used to unregister
Expand Down
5 changes: 3 additions & 2 deletions api/apitxn/opts.go → api/apitxn/chclient/opts.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ Copyright SecureKey Technologies Inc. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/

package apitxn
package chclient

import (
"time"

"github.com/hyperledger/fabric-sdk-go/api/apitxn"
"github.com/hyperledger/fabric-sdk-go/pkg/errors/retry"
)

Expand All @@ -21,7 +22,7 @@ func WithTimeout(timeout time.Duration) Option {
}

//WithProposalProcessor encapsulates ProposalProcessors to Option
func WithProposalProcessor(proposalProcessors ...ProposalProcessor) Option {
func WithProposalProcessor(proposalProcessors ...apitxn.ProposalProcessor) Option {
return func(opts *Opts) error {
opts.ProposalProcessors = proposalProcessors
return nil
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,10 @@ Copyright SecureKey Technologies Inc. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/

package txnhandler
package chclient

import (
"github.com/hyperledger/fabric-sdk-go/api/apifabclient"
"github.com/hyperledger/fabric-sdk-go/api/apitxn"
"github.com/hyperledger/fabric-sdk-go/pkg/errors/retry"
)

Expand All @@ -27,9 +26,9 @@ type ClientContext struct {

//RequestContext contains request, opts, response parameters for handler execution
type RequestContext struct {
Request apitxn.Request
Opts apitxn.Opts
Response apitxn.Response
Request Request
Opts Opts
Response Response
Error error
RetryHandler retry.Handler
}
42 changes: 20 additions & 22 deletions pkg/fabric-txn/chclient/chclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,8 @@ import (

"github.com/hyperledger/fabric-sdk-go/api/apiconfig"
fab "github.com/hyperledger/fabric-sdk-go/api/apifabclient"
"github.com/hyperledger/fabric-sdk-go/api/apitxn"

"github.com/hyperledger/fabric-sdk-go/api/apitxn/txnhandler"
"github.com/hyperledger/fabric-sdk-go/api/apitxn/chclient"
"github.com/hyperledger/fabric-sdk-go/pkg/errors"
"github.com/hyperledger/fabric-sdk-go/pkg/errors/retry"
"github.com/hyperledger/fabric-sdk-go/pkg/errors/status"
Expand Down Expand Up @@ -59,28 +58,27 @@ func New(c Context) (*ChannelClient, error) {
}

// Query chaincode using request and optional options provided
func (cc *ChannelClient) Query(request apitxn.Request, options ...apitxn.Option) (apitxn.Response, error) {
func (cc *ChannelClient) Query(request chclient.Request, options ...chclient.Option) (chclient.Response, error) {
return cc.InvokeHandler(txnHandlerImpl.NewQueryHandler(), request, cc.addDefaultTimeout(apiconfig.Query, options...)...)
}

// Execute prepares and executes transaction using request and optional options provided
func (cc *ChannelClient) Execute(request apitxn.Request, options ...apitxn.Option) (apitxn.Response, error) {
func (cc *ChannelClient) Execute(request chclient.Request, options ...chclient.Option) (chclient.Response, error) {
return cc.InvokeHandler(txnHandlerImpl.NewExecuteHandler(), request, cc.addDefaultTimeout(apiconfig.Execute, options...)...)
}

//InvokeHandler invokes handler using request and options provided
func (cc *ChannelClient) InvokeHandler(handler txnhandler.Handler, request apitxn.Request, options ...apitxn.Option) (apitxn.Response, error) {
//TODO: this function going to be exposed through ChannelClient interface
func (cc *ChannelClient) InvokeHandler(handler chclient.Handler, request chclient.Request, options ...chclient.Option) (chclient.Response, error) {
//Read execute tx options
txnOpts, err := cc.prepareOptsFromOptions(options...)
if err != nil {
return apitxn.Response{}, err
return chclient.Response{}, err
}

//Prepare context objects for handler
requestContext, clientContext, err := cc.prepareHandlerContexts(request, txnOpts)
if err != nil {
return apitxn.Response{}, err
return chclient.Response{}, err
}

complete := make(chan bool)
Expand All @@ -98,29 +96,29 @@ func (cc *ChannelClient) InvokeHandler(handler txnhandler.Handler, request apitx
case <-complete:
return requestContext.Response, requestContext.Error
case <-time.After(txnOpts.Timeout):
return apitxn.Response{}, status.New(status.ClientStatus, status.Timeout.ToInt32(),
return chclient.Response{}, status.New(status.ClientStatus, status.Timeout.ToInt32(),
"Operation timed out", nil)
}
}

//prepareHandlerContexts prepares context objects for handlers
func (cc *ChannelClient) prepareHandlerContexts(request apitxn.Request, options apitxn.Opts) (*txnhandler.RequestContext, *txnhandler.ClientContext, error) {
func (cc *ChannelClient) prepareHandlerContexts(request chclient.Request, options chclient.Opts) (*chclient.RequestContext, *chclient.ClientContext, error) {

if request.ChaincodeID == "" || request.Fcn == "" {
return nil, nil, errors.New("ChaincodeID and Fcn are required")
}

clientContext := &txnhandler.ClientContext{
clientContext := &chclient.ClientContext{
Channel: cc.channel,
Selection: cc.selection,
Discovery: cc.discovery,
EventHub: cc.eventHub,
}

requestContext := &txnhandler.RequestContext{
requestContext := &chclient.RequestContext{
Request: request,
Opts: options,
Response: apitxn.Response{},
Response: chclient.Response{},
RetryHandler: retry.New(options.Retry),
}

Expand All @@ -132,9 +130,9 @@ func (cc *ChannelClient) prepareHandlerContexts(request apitxn.Request, options

}

//prepareOptsFromOptions Reads apitxn.Opts from apitxn.Option array
func (cc *ChannelClient) prepareOptsFromOptions(options ...apitxn.Option) (apitxn.Opts, error) {
txnOpts := apitxn.Opts{}
//prepareOptsFromOptions Reads apitxn.Opts from chclient.Option array
func (cc *ChannelClient) prepareOptsFromOptions(options ...chclient.Option) (chclient.Opts, error) {
txnOpts := chclient.Opts{}
for _, option := range options {
err := option(&txnOpts)
if err != nil {
Expand All @@ -145,14 +143,14 @@ func (cc *ChannelClient) prepareOptsFromOptions(options ...apitxn.Option) (apitx
}

//addDefaultTimeout adds given default timeout if it is missing in options
func (cc *ChannelClient) addDefaultTimeout(timeOutType apiconfig.TimeoutType, options ...apitxn.Option) []apitxn.Option {
txnOpts := apitxn.Opts{}
func (cc *ChannelClient) addDefaultTimeout(timeOutType apiconfig.TimeoutType, options ...chclient.Option) []chclient.Option {
txnOpts := chclient.Opts{}
for _, option := range options {
option(&txnOpts)
}

if txnOpts.Timeout == 0 {
return append(options, apitxn.WithTimeout(cc.context.Config().TimeoutOrDefault(timeOutType)))
return append(options, chclient.WithTimeout(cc.context.Config().TimeoutOrDefault(timeOutType)))
}
return options
}
Expand All @@ -169,18 +167,18 @@ func (cc *ChannelClient) Close() error {
// RegisterChaincodeEvent registers chain code event
// @param {chan bool} channel which receives event details when the event is complete
// @returns {object} object handle that should be used to unregister
func (cc *ChannelClient) RegisterChaincodeEvent(notify chan<- *apitxn.CCEvent, chainCodeID string, eventID string) apitxn.Registration {
func (cc *ChannelClient) RegisterChaincodeEvent(notify chan<- *chclient.CCEvent, chainCodeID string, eventID string) chclient.Registration {

// Register callback for CE
rce := cc.eventHub.RegisterChaincodeEvent(chainCodeID, eventID, func(ce *fab.ChaincodeEvent) {
notify <- &apitxn.CCEvent{ChaincodeID: ce.ChaincodeID, EventName: ce.EventName, TxID: ce.TxID, Payload: ce.Payload}
notify <- &chclient.CCEvent{ChaincodeID: ce.ChaincodeID, EventName: ce.EventName, TxID: ce.TxID, Payload: ce.Payload}
})

return rce
}

// UnregisterChaincodeEvent removes chain code event registration
func (cc *ChannelClient) UnregisterChaincodeEvent(registration apitxn.Registration) error {
func (cc *ChannelClient) UnregisterChaincodeEvent(registration chclient.Registration) error {

switch regType := registration.(type) {

Expand Down
Loading

0 comments on commit cf9810f

Please sign in to comment.