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  }