1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
|
package bridge
import (
"bytes"
"fmt"
"github.com/pkg/errors"
"github.com/viant/toolbox"
"io/ioutil"
"path"
"strings"
)
//RecordedHttpTrip represents a recorded http trip
type RecordedHttpTrip struct {
Request *HttpRequest
Response *HttpResponse
}
//ReadRecordedHttpTripsWithPrefix scans provided directory for request, response pairs
func ReadRecordedHttpTripsWithTemplate(directory string, requestTemplate, respTemplate string) ([]*RecordedHttpTrip, error) {
if !strings.Contains(requestTemplate, "%") {
return nil, errors.New("invalid request template: it could contains counter '%' expressions")
}
if !strings.Contains(respTemplate, "%") {
return nil, errors.New("invalid response template: it could contains counter '%' expressions")
}
var result = make([]*RecordedHttpTrip, 0)
var requestTemplatePath = path.Join(directory, requestTemplate)
var responseTemplatePath = path.Join(directory, respTemplate)
requests, err := readAll(requestTemplatePath, func() interface{} {
return &HttpRequest{}
})
if err != nil {
return nil, err
}
responses, err := readAll(responseTemplatePath, func() interface{} {
return &HttpResponse{}
})
if err != nil {
return nil, err
}
if len(requests) != len(responses) {
return nil, fmt.Errorf("request and Response count does not match req:%v, resp:%v ", len(requests), len(responses))
}
for i := 0; i < len(requests); i++ {
var ok bool
var trip = &RecordedHttpTrip{}
trip.Request, ok = requests[i].(*HttpRequest)
if !ok {
return nil, fmt.Errorf("expected HttpRequest but had %T", requests[i])
}
if i < len(responses) {
trip.Response, ok = responses[i].(*HttpResponse)
if !ok {
return nil, fmt.Errorf("expected HttpRequest but had %T", responses[i])
}
}
result = append(result, trip)
}
return result, nil
}
//ReadRecordedHttpTrips scans provided directory for bridge.HttpRequest-%v.json and bridge.HttpResponse-%v.json template pairs
func ReadRecordedHttpTrips(directory string) ([]*RecordedHttpTrip, error) {
return ReadRecordedHttpTripsWithTemplate(directory, "bridge.HttpRequest-%v.json", "bridge.HttpResponse-%v.json")
}
func readAll(pathTemplate string, provider func() interface{}) ([]interface{}, error) {
var result = make([]interface{}, 0)
for i := 0; ; i++ {
filename := fmt.Sprintf(pathTemplate, i)
if !toolbox.FileExists(filename) {
break
}
data, err := ioutil.ReadFile(filename)
if err != nil {
return nil, err
}
aStruct := provider()
err = toolbox.NewJSONDecoderFactory().Create(bytes.NewReader(data)).Decode(aStruct)
if err != nil {
return nil, err
}
result = append(result, aStruct)
}
return result, nil
}
//StartRecordingBridge start recording bridge proxy
func StartRecordingBridge(port string, outputDirectory string, routes ...*HttpBridgeProxyRoute) (*HttpBridge, error) {
if len(routes) == 0 {
routes = append(routes, &HttpBridgeProxyRoute{
Pattern: "/",
})
}
config := &HttpBridgeConfig{
Endpoint: &HttpBridgeEndpointConfig{
Port: port,
},
Proxy: &HttpBridgeProxyConfig{
BufferPoolSize: 2,
BufferSize: 8 * 1024,
},
Routes: routes,
}
for _, route := range routes {
route.Listener = HttpFileRecorder(outputDirectory, false)
}
httpBridge, err := NewHttpBridge(config, NewProxyRecordingHandler)
if err != nil {
return nil, err
}
go httpBridge.ListenAndServe()
return httpBridge, nil
}
|