github.com/ronaksoft/rony@v0.16.26-0.20230807065236-1743dbfe6959/edgec/http_conn.go (about)

     1  package edgec
     2  
     3  import (
     4  	"net/http"
     5  	"time"
     6  
     7  	"github.com/ronaksoft/rony"
     8  	"github.com/ronaksoft/rony/log"
     9  	"github.com/ronaksoft/rony/pools"
    10  	"github.com/valyala/fasthttp"
    11  	"go.uber.org/zap"
    12  	"google.golang.org/protobuf/proto"
    13  )
    14  
    15  /*
    16     Creation Time: 2021 - Jan - 05
    17     Created by:  (ehsan)
    18     Maintainers:
    19        1.  Ehsan N. Moosa (E2)
    20     Auditor: Ehsan N. Moosa (E2)
    21     Copyright Ronak Software Group 2020
    22  */
    23  
    24  type httpConn struct {
    25  	h          *Http
    26  	replicaSet uint64
    27  	id         string
    28  	hostPorts  []string
    29  	secure     bool
    30  }
    31  
    32  func (c *httpConn) send(req, res *rony.MessageEnvelope, timeout time.Duration) (replicaSet uint64, err error) {
    33  	replicaSet = c.replicaSet
    34  
    35  	mo := proto.MarshalOptions{UseCachedSize: true}
    36  	buf := pools.Buffer.GetCap(mo.Size(req))
    37  	defer pools.Buffer.Put(buf)
    38  
    39  	b, err := mo.MarshalAppend(*buf.Bytes(), req)
    40  	if err != nil {
    41  		return
    42  	}
    43  
    44  	httpReq := fasthttp.AcquireRequest()
    45  	defer fasthttp.ReleaseRequest(httpReq)
    46  
    47  	httpReq.Header.SetMethod(http.MethodPost)
    48  	if c.secure {
    49  		httpReq.URI().SetScheme("https")
    50  	}
    51  	httpReq.SetHost(c.hostPorts[0])
    52  	httpReq.SetBody(b)
    53  	if hf := c.h.cfg.HeaderFunc; hf != nil {
    54  		for k, v := range hf() {
    55  			httpReq.Header.Set(k, v)
    56  		}
    57  	}
    58  
    59  	httpRes := fasthttp.AcquireResponse()
    60  	defer fasthttp.ReleaseResponse(httpRes)
    61  
    62  SendLoop:
    63  	err = c.h.c.DoTimeout(httpReq, httpRes, timeout)
    64  	switch err {
    65  	case fasthttp.ErrNoFreeConns:
    66  		goto SendLoop
    67  	}
    68  	if err != nil {
    69  		return
    70  	}
    71  	err = res.Unmarshal(httpRes.Body())
    72  	if err != nil {
    73  		return
    74  	}
    75  	switch res.GetConstructor() {
    76  	case rony.C_Redirect:
    77  		x := &rony.Redirect{}
    78  		err = proto.Unmarshal(res.Message, x)
    79  		if err != nil {
    80  			return
    81  		}
    82  		replicaSet, err = c.redirect(x)
    83  
    84  		return
    85  	}
    86  
    87  	return
    88  }
    89  
    90  func (c *httpConn) redirect(x *rony.Redirect) (replicaSet uint64, err error) {
    91  	if ce := c.h.logger.Check(log.InfoLevel, "Redirect"); ce != nil {
    92  		ce.Write(
    93  			zap.Any("Edges", x.Edges),
    94  			zap.Any("Wait", x.WaitInSec),
    95  		)
    96  	}
    97  
    98  	replicaSet = x.Edges[0].ReplicaSet
    99  	for _, n := range x.Edges {
   100  		c.h.addConn(n.ServerID, n.ReplicaSet, c.h.newConn(n.ServerID, n.ReplicaSet, n.HostPorts...))
   101  	}
   102  
   103  	switch x.Reason {
   104  	case rony.RedirectReason_ReplicaSetSession:
   105  		c.h.sessionReplica = replicaSet
   106  		err = ErrReplicaSetSession
   107  	case rony.RedirectReason_ReplicaSetRequest:
   108  		replicaSet = x.Edges[0].ReplicaSet
   109  		err = ErrReplicaSetRequest
   110  	default:
   111  		err = ErrUnknownResponse
   112  	}
   113  
   114  	return
   115  }