From 3ab76a656f0ca0c72ad80164b2945ae60e47baf0 Mon Sep 17 00:00:00 2001 From: Kleonikos Kyriakis Date: Thu, 18 Apr 2024 11:38:16 +0300 Subject: [PATCH] Move error handling into message headers (part 1) --- internal/messaging/noop_response_handler.go | 3 +- internal/messaging/processor.go | 5 +- internal/messaging/response_handler.go | 69 ++++++++++++++------- internal/tvm/client.go | 2 +- 4 files changed, 50 insertions(+), 29 deletions(-) diff --git a/internal/messaging/noop_response_handler.go b/internal/messaging/noop_response_handler.go index 5c4627df..481bbe50 100644 --- a/internal/messaging/noop_response_handler.go +++ b/internal/messaging/noop_response_handler.go @@ -14,6 +14,5 @@ var _ ResponseHandler = (*NoopResponseHandler)(nil) type NoopResponseHandler struct { } -func (n NoopResponseHandler) HandleResponse(context.Context, MessageType, *RequestContent, *ResponseContent) error { - return nil +func (n NoopResponseHandler) HandleResponse(context.Context, MessageType, *RequestContent, *ResponseContent) { } diff --git a/internal/messaging/processor.go b/internal/messaging/processor.go index 701a1711..88f824a9 100644 --- a/internal/messaging/processor.go +++ b/internal/messaging/processor.go @@ -185,10 +185,7 @@ func (p *processor) Respond(msg Message) error { p.logger.Infof("error extracting metadata for request: %s", md.RequestID) } - err = p.responseHandler.HandleResponse(ctx, msgType, &msg.Content.RequestContent, &response) - if err != nil { - return err //TODO handle error and return a response message - } + p.responseHandler.HandleResponse(ctx, msgType, &msg.Content.RequestContent, &response) responseMsg := Message{ Type: msgType, Content: MessageContent{ diff --git a/internal/messaging/response_handler.go b/internal/messaging/response_handler.go index fabec99f..4fcd8084 100644 --- a/internal/messaging/response_handler.go +++ b/internal/messaging/response_handler.go @@ -6,6 +6,7 @@ package messaging import ( + typesv1alpha "buf.build/gen/go/chain4travel/camino-messenger-protocol/protocolbuffers/go/cmp/types/v1alpha" "context" "errors" "fmt" @@ -22,61 +23,85 @@ import ( var _ ResponseHandler = (*TvmResponseHandler)(nil) type ResponseHandler interface { - HandleResponse(ctx context.Context, msgType MessageType, request *RequestContent, response *ResponseContent) error + HandleResponse(ctx context.Context, msgType MessageType, request *RequestContent, response *ResponseContent) } type TvmResponseHandler struct { tvmClient *tvm.Client logger *zap.SugaredLogger } -func (h *TvmResponseHandler) HandleResponse(ctx context.Context, msgType MessageType, request *RequestContent, response *ResponseContent) error { +func (h *TvmResponseHandler) HandleResponse(ctx context.Context, msgType MessageType, request *RequestContent, response *ResponseContent) { switch msgType { - case MintRequest: + case MintRequest: // distributor will post-process a mint request to buy the returned NFT + if response.MintResponse.Header == nil { + response.MintResponse.Header = &typesv1alpha.ResponseHeader{} + } if response.MintTransactionId == "" { - return fmt.Errorf("missing mint transaction id") + addErrorToResponseHeader(response, "missing mint transaction id") + return } mintID, err := ids.FromString(response.MintTransactionId) if err != nil { - return fmt.Errorf("error parsing mint transaction id: %w", err) + addErrorToResponseHeader(response, fmt.Sprintf("error parsing mint transaction id: %v", err)) + return } + success, txID, err := h.tvmClient.SendTxAndWait(ctx, transferNFTAction(h.tvmClient.Address(), mintID)) - if errors.Is(err, context.DeadlineExceeded) { - return fmt.Errorf("%w: %v", tvm.ErrAwaitTxConfirmationTimeout, h.tvmClient.Timeout) - } if err != nil { - return fmt.Errorf("error buying NFT: %v", err) + errMessage := fmt.Sprintf("error buying NFT: %v", err) + if errors.Is(err, context.DeadlineExceeded) { + errMessage = fmt.Sprintf("%v: %v", tvm.ErrAwaitTxConfirmationTimeout, h.tvmClient.Timeout) + } + addErrorToResponseHeader(response, errMessage) + return } if !success { - return fmt.Errorf("buying NFT failed") + addErrorToResponseHeader(response, "buying NFT failed") + return } - h.logger.Infof("Bought NFT with ID: %s\n", txID) + + h.logger.Infof("Bought NFT (txID=%s) with ID: %s\n", txID, mintID) response.BuyTransactionId = txID.String() - return nil - case MintResponse: + case MintResponse: // provider will act upon receiving a mint response by minting an NFT owner := h.tvmClient.Address() + if response.MintResponse.Header == nil { + response.MintResponse.Header = &typesv1alpha.ResponseHeader{} + } buyer, err := codec.ParseAddressBech32(consts.HRP, request.MintRequest.BuyerAddress) if err != nil { - return fmt.Errorf("error parsing buyer address: %w", err) + addErrorToResponseHeader(response, fmt.Sprintf("error parsing buyer address: %v", err)) + return } price, err := strconv.Atoi(response.MintResponse.Price.Value) if err != nil { - return fmt.Errorf("error parsing price value: %w", err) + addErrorToResponseHeader(response, fmt.Sprintf("error parsing price value: %v", err)) + return } success, txID, err := h.tvmClient.SendTxAndWait(ctx, createNFTAction(owner, buyer, uint64(response.MintResponse.BuyableUntil.Seconds), uint64(price), response.MintResponse.MintId)) - if errors.Is(err, context.DeadlineExceeded) { - return fmt.Errorf("%w: %v", tvm.ErrAwaitTxConfirmationTimeout, h.tvmClient.Timeout) - } if err != nil { - return fmt.Errorf("error minting NFT: %v", err) + errMessage := fmt.Sprintf("error minting NFT: %v", err) + if errors.Is(err, context.DeadlineExceeded) { + errMessage = fmt.Sprintf("%v: %v", tvm.ErrAwaitTxConfirmationTimeout, h.tvmClient.Timeout) + } + addErrorToResponseHeader(response, errMessage) + return } if !success { - return fmt.Errorf("minting NFT tx failed") + addErrorToResponseHeader(response, "minting NFT tx failed") + return } h.logger.Infof("NFT minted with txID: %s\n", txID) + response.MintResponse.Header.Status = typesv1alpha.StatusType_STATUS_TYPE_SUCCESS response.MintTransactionId = txID.String() - return nil } - return nil +} + +func addErrorToResponseHeader(response *ResponseContent, errMessage string) { + response.MintResponse.Header.Status = typesv1alpha.StatusType_STATUS_TYPE_FAILURE + response.MintResponse.Header.Alerts = append(response.MintResponse.Header.Alerts, &typesv1alpha.Alert{ + Message: errMessage, + Type: typesv1alpha.AlertType_ALERT_TYPE_ERROR, + }) } func NewResponseHandler(tvmClient *tvm.Client, logger *zap.SugaredLogger) *TvmResponseHandler { diff --git a/internal/tvm/client.go b/internal/tvm/client.go index 87b36cf3..b422bf66 100644 --- a/internal/tvm/client.go +++ b/internal/tvm/client.go @@ -24,7 +24,7 @@ import ( ) var ( - ErrAwaitTxConfirmationTimeout = errors.New("awaiting transaction confirmation exceeded Timeout of") + ErrAwaitTxConfirmationTimeout = errors.New("awaiting transaction confirmation exceeded timeout of") ) type Client struct {