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