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 }