github.com/vmware/transport-go@v1.3.4/service/fabric_core.go (about)

     1  // Copyright 2019-2021 VMware, Inc.
     2  // SPDX-License-Identifier: BSD-2-Clause
     3  
     4  package service
     5  
     6  import (
     7  	"fmt"
     8  	"github.com/google/uuid"
     9  	"github.com/vmware/transport-go/bus"
    10  	"github.com/vmware/transport-go/model"
    11  )
    12  
    13  // FabricServiceCore is the interface providing base functionality to fabric services.
    14  type FabricServiceCore interface {
    15  	// Bus Returns the EventBus instance.
    16  	Bus() bus.EventBus
    17  
    18  	// SendResponse Uses the "responsePayload" and "request" params to build and send model.Response object
    19  	// on the service channel.
    20  	SendResponse(request *model.Request, responsePayload interface{})
    21  
    22  	// SendResponseWithHeaders is the same as SendResponse, but include headers. Useful for HTTP REST interfaces - these headers will be
    23  	// set as HTTP response headers. Great for custom mime-types, binary stuff and more.
    24  	SendResponseWithHeaders(request *model.Request, responsePayload interface{}, headers map[string]string)
    25  
    26  	// SendErrorResponse builds an error model.Response object and sends it on the service channel as response to the "request" param.
    27  	SendErrorResponse(request *model.Request, responseErrorCode int, responseErrorMessage string)
    28  
    29  	// SendErrorResponseWithPayload is the same as SendErrorResponse, but adds a payload
    30  	SendErrorResponseWithPayload(request *model.Request, responseErrorCode int, responseErrorMessage string, payload interface{})
    31  
    32  	// SendErrorResponseWithHeaders is the same as SendErrorResponse, but adds headers as well.
    33  	SendErrorResponseWithHeaders(request *model.Request, responseErrorCode int, responseErrorMessage string, headers map[string]string)
    34  
    35  	// SendErrorResponseWithHeadersAndPayload is the same as SendErrorResponseWithPayload, but adds headers as well.
    36  	SendErrorResponseWithHeadersAndPayload(request *model.Request, responseErrorCode int, responseErrorMessage string, payload interface{}, headers map[string]string)
    37  
    38  	// HandleUnknownRequest handles unknown/unsupported/un-implemented requests,
    39  	HandleUnknownRequest(request *model.Request)
    40  
    41  	// RestServiceRequest will make a new RestService call.
    42  	RestServiceRequest(restRequest *RestServiceRequest,
    43  		successHandler model.ResponseHandlerFunction, errorHandler model.ResponseHandlerFunction)
    44  
    45  	// SetHeaders Set global headers for a given fabric service (each service has its own set of global headers).
    46  	// The headers will be applied to all requests made by this instance's RestServiceRequest method.
    47  	// Global header values can be overridden per request via the RestServiceRequest.Headers property.
    48  	SetHeaders(headers map[string]string)
    49  
    50  	// GenerateJSONHeaders Automatically ready to go map with json headers.
    51  	GenerateJSONHeaders() map[string]string
    52  
    53  	// SetDefaultJSONHeaders Automatically sets default accept and return content types as 'application/json'
    54  	SetDefaultJSONHeaders()
    55  }
    56  
    57  type fabricCore struct {
    58  	channelName string
    59  	bus         bus.EventBus
    60  	headers     map[string]string
    61  }
    62  
    63  func (core *fabricCore) Bus() bus.EventBus {
    64  	return core.bus
    65  }
    66  
    67  func (core *fabricCore) SendResponse(request *model.Request, responsePayload interface{}) {
    68  
    69  	headers := core.mergeHeadersWithDefaults(nil)
    70  
    71  	response := &model.Response{
    72  		Id:                request.Id,
    73  		Destination:       core.channelName,
    74  		Payload:           responsePayload,
    75  		Headers:           headers,
    76  		BrokerDestination: request.BrokerDestination,
    77  	}
    78  	core.bus.SendResponseMessage(core.channelName, response, request.Id)
    79  }
    80  
    81  func (core *fabricCore) SendResponseWithHeaders(request *model.Request, responsePayload interface{}, headers map[string]string) {
    82  
    83  	headers = core.mergeHeadersWithDefaults(headers)
    84  
    85  	response := &model.Response{
    86  		Id:                request.Id,
    87  		Destination:       core.channelName,
    88  		Payload:           responsePayload,
    89  		BrokerDestination: request.BrokerDestination,
    90  		Headers:           headers,
    91  	}
    92  	core.bus.SendResponseMessage(core.channelName, response, request.Id)
    93  }
    94  
    95  func (core *fabricCore) SendErrorResponse(
    96  	request *model.Request, responseErrorCode int, responseErrorMessage string) {
    97  	core.SendErrorResponseWithPayload(request, responseErrorCode, responseErrorMessage, nil)
    98  }
    99  
   100  func (core *fabricCore) SendErrorResponseWithPayload(
   101  	request *model.Request,
   102  	responseErrorCode int, responseErrorMessage string, payload interface{}) {
   103  
   104  	headers := core.mergeHeadersWithDefaults(nil)
   105  
   106  	response := &model.Response{
   107  		Id:                request.Id,
   108  		Destination:       core.channelName,
   109  		Payload:           payload,
   110  		Headers:           headers,
   111  		Error:             true,
   112  		ErrorCode:         responseErrorCode,
   113  		ErrorMessage:      responseErrorMessage,
   114  		BrokerDestination: request.BrokerDestination,
   115  	}
   116  	core.bus.SendResponseMessage(core.channelName, response, request.Id)
   117  }
   118  
   119  func (core *fabricCore) SendErrorResponseWithHeaders(
   120  	request *model.Request,
   121  	responseErrorCode int, responseErrorMessage string, headers map[string]string) {
   122  
   123  	headers = core.mergeHeadersWithDefaults(headers)
   124  
   125  	response := &model.Response{
   126  		Id:                request.Id,
   127  		Destination:       core.channelName,
   128  		Headers:           headers,
   129  		Error:             true,
   130  		ErrorCode:         responseErrorCode,
   131  		ErrorMessage:      responseErrorMessage,
   132  		BrokerDestination: request.BrokerDestination,
   133  	}
   134  	core.bus.SendResponseMessage(core.channelName, response, request.Id)
   135  }
   136  
   137  func (core *fabricCore) SendErrorResponseWithHeadersAndPayload(
   138  	request *model.Request,
   139  	responseErrorCode int, responseErrorMessage string, payload interface{}, headers map[string]string) {
   140  
   141  	headers = core.mergeHeadersWithDefaults(headers)
   142  
   143  	response := &model.Response{
   144  		Id:                request.Id,
   145  		Destination:       core.channelName,
   146  		Payload:           payload,
   147  		Headers:           headers,
   148  		Error:             true,
   149  		ErrorCode:         responseErrorCode,
   150  		ErrorMessage:      responseErrorMessage,
   151  		BrokerDestination: request.BrokerDestination,
   152  	}
   153  	core.bus.SendResponseMessage(core.channelName, response, request.Id)
   154  }
   155  
   156  func (core *fabricCore) HandleUnknownRequest(request *model.Request) {
   157  	errorMsg := fmt.Sprintf("unsupported request for \"%s\": %s", core.channelName, request.Request)
   158  	core.SendErrorResponse(request, 403, errorMsg)
   159  }
   160  
   161  func (core *fabricCore) SetHeaders(headers map[string]string) {
   162  	core.headers = headers
   163  }
   164  
   165  func (core *fabricCore) GenerateJSONHeaders() map[string]string {
   166  	return map[string]string{"Content-Type": "application/json"}
   167  }
   168  
   169  func (core *fabricCore) SetDefaultJSONHeaders() {
   170  	core.SetHeaders(core.GenerateJSONHeaders())
   171  }
   172  
   173  func (core *fabricCore) mergeHeadersWithDefaults(headers map[string]string) map[string]string {
   174  
   175  	// merge global service headers with the headers from user supplied headers.
   176  	// note that headers specified in user requirements will override the global headers.
   177  	mergedHeaders := make(map[string]string)
   178  	for k, v := range core.headers {
   179  		mergedHeaders[k] = v
   180  	}
   181  	if headers != nil {
   182  		for k, v := range headers {
   183  			mergedHeaders[k] = v
   184  		}
   185  	}
   186  	return mergedHeaders
   187  }
   188  
   189  func (core *fabricCore) RestServiceRequest(restRequest *RestServiceRequest,
   190  	successHandler model.ResponseHandlerFunction, errorHandler model.ResponseHandlerFunction) {
   191  
   192  	// merge global service headers with the headers from the httpRequest
   193  	// note that headers specified in restRequest override the global headers.
   194  	mergedHeaders := make(map[string]string)
   195  	for k, v := range core.headers {
   196  		mergedHeaders[k] = v
   197  	}
   198  	for k, v := range restRequest.Headers {
   199  		mergedHeaders[k] = v
   200  	}
   201  	restRequest.Headers = mergedHeaders
   202  
   203  	id := uuid.New()
   204  	request := &model.Request{
   205  		Id:      &id,
   206  		Payload: restRequest,
   207  	}
   208  	mh, _ := core.bus.ListenOnceForDestination(restServiceChannel, request.Id)
   209  	mh.Handle(func(message *model.Message) {
   210  		response := message.Payload.(*model.Response)
   211  		if response.Error {
   212  			errorHandler(response)
   213  		} else {
   214  			successHandler(response)
   215  		}
   216  	}, func(e error) {
   217  		errorHandler(&model.Response{
   218  			Error:        true,
   219  			ErrorMessage: e.Error(),
   220  			ErrorCode:    500,
   221  		})
   222  	})
   223  	core.bus.SendRequestMessage(restServiceChannel, request, request.Id)
   224  }