httpclientmdl.go 4.06 KiB
Newer Older
Sandeep S. Shewalkar's avatar
Sandeep S. Shewalkar committed
package httpclientmdl

import (
	"bytes"
	"io/ioutil"
Sandeep S. Shewalkar's avatar
Sandeep S. Shewalkar committed
	"net/http"
	"sync"
Sandeep S. Shewalkar's avatar
Sandeep S. Shewalkar committed
	"time"

	"corelab.mkcl.org/MKCLOS/coredevelopmentplatform/corepkgv2/constantmdl"
	"corelab.mkcl.org/MKCLOS/coredevelopmentplatform/corepkgv2/errormdl"
var httpClient *http.Client
var once sync.Once

Sandeep S. Shewalkar's avatar
Sandeep S. Shewalkar committed
// GetHTTPClient This method will return the httpClient object with preconfigured settings
func GetHTTPClient() *http.Client {
	once.Do(func() {
		transport := &http.Transport{
			MaxIdleConns:        constantmdl.MAXIDLECONNS,
			MaxIdleConnsPerHost: constantmdl.MAXIDLECONNSPERHOST,
			IdleConnTimeout:     constantmdl.IDLECONNTIMEOUT,
		}
		httpClient = &http.Client{
			Transport: transport,
		}
	})
Sandeep S. Shewalkar's avatar
Sandeep S. Shewalkar committed
	return httpClient
}

type HTTPTransport struct {
	MaxIdleConns        int
	MaxIdleConnsPerHost int
	IdleConnTimeout     time.Duration
}

// GetHTTPClientWithConfig This method will return the httpClient object with preconfigured settings
Sandeep S. Shewalkar's avatar
Sandeep S. Shewalkar committed
func GetHTTPClientWithConfig(httpTransport HTTPTransport) *http.Client {

	if httpTransport.MaxIdleConns == 0 {
		httpTransport.MaxIdleConns = constantmdl.MAXIDLECONNS
	}
	if httpTransport.MaxIdleConnsPerHost == 0 {
		httpTransport.MaxIdleConnsPerHost = constantmdl.MAXIDLECONNSPERHOST
	}
	if httpTransport.IdleConnTimeout == 0 {
		httpTransport.IdleConnTimeout = constantmdl.IDLECONNTIMEOUT
	}
	transport := &http.Transport{
		MaxIdleConns:        httpTransport.MaxIdleConns,
		MaxIdleConnsPerHost: httpTransport.MaxIdleConnsPerHost,
		IdleConnTimeout:     httpTransport.IdleConnTimeout,
	}
	httpClient := &http.Client{
		Transport: transport,
	}
	return httpClient
}

// DoHTTPWithRetry for retry support to http request
func DoHTTPWithRetry(attempts int, sleeptime time.Duration, request *http.Request) (*http.Response, error) {
	// Get the HTTPClient
	client := GetHTTPClient()
	if request.Body != nil {
		// Read the content
		bodyBytes, errReadAll := ioutil.ReadAll(request.Body)
		if errormdl.CheckBool(errReadAll != nil) {
			return nil, errormdl.Wrap("Error in ReadAll function in DoHTTPWithRetry")
		}
		//fmt.Println("request.Body after readong its content-----", request.Body)
		// Restore the io.ReadCloser to its original state
		request.Body = ioutil.NopCloser(bytes.NewBuffer(bodyBytes))
		resp, err := client.Do(request)
		if errormdl.CheckBool(resp != nil && err == nil && resp.StatusCode < constantmdl.HTTP400ERROR) {
			defer resp.Body.Close()
			return resp, nil
		}
		//fmt.Println("request.Body after do request-----", request.Body)
		return TryAttemptsWithRequestBody(client, request, resp, err, attempts, sleeptime, bodyBytes)
	}
	resp, err := client.Do(request)
	if errormdl.CheckBool(resp != nil && err == nil && resp.StatusCode < constantmdl.HTTP400ERROR) {
		defer resp.Body.Close()
		return resp, nil
	}
	return TryAttempts(client, request, resp, err, attempts, sleeptime)

}

// TryAttemptsWithRequestBody it retries http post request with a request body when failed or gives error
func TryAttemptsWithRequestBody(client *http.Client, request *http.Request, resp *http.Response, err error, attempts int, sleeptime time.Duration, bodyBytes []byte) (*http.Response, error) {
	newURL := request.URL.String()
	for i := attempts; i > 0; i-- {
		time.Sleep(sleeptime)
		newRequest, newReqErr := http.NewRequest(request.Method, newURL, bytes.NewBuffer(bodyBytes))
		if newReqErr == nil {
			resp, err = client.Do(newRequest)
			//fmt.Println("attempts remained", i)
			if resp == nil {
				continue
			}
			defer resp.Body.Close()
			if resp.StatusCode < constantmdl.HTTP400ERROR && err == nil {
				return resp, nil
			}
		}
	}
	return resp, errormdl.CheckErr(err)
}

// TryAttempts it retries http get/post request without request body
func TryAttempts(client *http.Client, request *http.Request, resp *http.Response, err error, attempts int, sleeptime time.Duration) (*http.Response, error) {
	for i := attempts; i > 0; i-- {
		time.Sleep(sleeptime)
		resp, err = client.Do(request)
		//fmt.Println("attempts remained", i)
		if resp == nil {
			continue
		}
		defer resp.Body.Close()
		if resp.StatusCode < constantmdl.HTTP400ERROR && err == nil {
			return resp, nil
		}
	}
	return resp, errormdl.CheckErr(err)
}