github.com/volts-dev/volts@v0.0.0-20240120094013-5e9c65924106/transport/http_client.go (about)

     1  package transport
     2  
     3  import (
     4  	"bufio"
     5  	"bytes"
     6  	"errors"
     7  	"io"
     8  	"io/ioutil"
     9  	"net"
    10  	"net/http"
    11  	"net/url"
    12  	"sync"
    13  	"time"
    14  
    15  	"github.com/volts-dev/volts/internal/buf"
    16  )
    17  
    18  type (
    19  	httpTransportClient struct {
    20  		transport *HttpTransport
    21  		addr      string
    22  		conn      net.Conn
    23  		config    DialConfig
    24  		once      sync.Once
    25  
    26  		sync.RWMutex
    27  
    28  		// request must be stored for response processing
    29  		r    chan *http.Request
    30  		bl   []*http.Request
    31  		buff *bufio.Reader
    32  
    33  		// local/remote ip
    34  		local  string
    35  		remote string
    36  	}
    37  )
    38  
    39  func (t *httpTransportClient) Transport() ITransport {
    40  	return t.transport
    41  }
    42  
    43  func (t *httpTransportClient) Conn() net.Conn {
    44  	return t.conn
    45  }
    46  
    47  func (h *httpTransportClient) Local() string {
    48  	return h.local
    49  }
    50  
    51  func (h *httpTransportClient) Remote() string {
    52  	return h.remote
    53  }
    54  
    55  func (h *httpTransportClient) Send(m *Message) error {
    56  	header := make(http.Header)
    57  
    58  	for k, v := range m.Header {
    59  		header.Set(k, v)
    60  	}
    61  
    62  	b := buf.New(bytes.NewBuffer(m.Body))
    63  	defer b.Close()
    64  
    65  	req := &http.Request{
    66  		Method: "POST",
    67  		URL: &url.URL{
    68  			Scheme: "http",
    69  			Host:   h.addr,
    70  		},
    71  		Header:        header,
    72  		Body:          b,
    73  		ContentLength: int64(b.Len()),
    74  		Host:          h.addr,
    75  	}
    76  
    77  	h.Lock()
    78  	h.bl = append(h.bl, req)
    79  	select {
    80  	case h.r <- h.bl[0]:
    81  		h.bl = h.bl[1:]
    82  	default:
    83  	}
    84  	h.Unlock()
    85  
    86  	// set timeout if its greater than 0
    87  	if h.transport.config.WriteTimeout > time.Duration(0) {
    88  		h.conn.SetDeadline(time.Now().Add(h.transport.config.WriteTimeout))
    89  	}
    90  
    91  	return req.Write(h.conn)
    92  }
    93  
    94  func (h *httpTransportClient) Recv(m *Message) error {
    95  	if m == nil {
    96  		return errors.New("message passed in is nil")
    97  	}
    98  
    99  	var r *http.Request
   100  	if !h.config.Stream {
   101  		rc, ok := <-h.r
   102  		if !ok {
   103  			return io.EOF
   104  		}
   105  		r = rc
   106  	}
   107  
   108  	// set timeout if its greater than 0
   109  	if h.transport.config.ReadTimeout > time.Duration(0) {
   110  		h.conn.SetDeadline(time.Now().Add(h.transport.config.ReadTimeout))
   111  	}
   112  
   113  	rsp, err := http.ReadResponse(h.buff, r)
   114  	if err != nil {
   115  		return err
   116  	}
   117  	defer rsp.Body.Close()
   118  
   119  	b, err := ioutil.ReadAll(rsp.Body)
   120  	if err != nil {
   121  		return err
   122  	}
   123  
   124  	if rsp.StatusCode != 200 {
   125  		return errors.New(rsp.Status + ": " + string(b))
   126  	}
   127  
   128  	m.Body = b
   129  
   130  	if m.Header == nil {
   131  		m.Header = make(map[string]string, len(rsp.Header))
   132  	}
   133  
   134  	for k, v := range rsp.Header {
   135  		if len(v) > 0 {
   136  			m.Header[k] = v[0]
   137  		} else {
   138  			m.Header[k] = ""
   139  		}
   140  	}
   141  
   142  	return nil
   143  }
   144  
   145  func (h *httpTransportClient) Close() error {
   146  	h.once.Do(func() {
   147  		h.Lock()
   148  		h.buff.Reset(nil)
   149  		h.Unlock()
   150  		close(h.r)
   151  	})
   152  	return h.conn.Close()
   153  }