mirror of https://github.com/XTLS/Xray-core
				
				
				
			BurstObservatory: add option to set http method for burst check (#4835)
* feat: add options to set method for burst check. * chore: gen proto. * chore: change protoc-gen-go to latest. * revert --------- Co-authored-by: 风扇滑翔翼 <Fangliding.fshxy@outlook.com>pull/4860/head
							parent
							
								
									fbae89d017
								
							
						
					
					
						commit
						27742da2c6
					
				| 
						 | 
				
			
			@ -90,6 +90,8 @@ type HealthPingConfig struct {
 | 
			
		|||
	SamplingCount int32 `protobuf:"varint,4,opt,name=samplingCount,proto3" json:"samplingCount,omitempty"`
 | 
			
		||||
	// ping timeout, int64 values of time.Duration
 | 
			
		||||
	Timeout int64 `protobuf:"varint,5,opt,name=timeout,proto3" json:"timeout,omitempty"`
 | 
			
		||||
	// http method to make request
 | 
			
		||||
	HttpMethod string `protobuf:"bytes,6,opt,name=httpMethod,proto3" json:"httpMethod,omitempty"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (x *HealthPingConfig) Reset() {
 | 
			
		||||
| 
						 | 
				
			
			@ -157,6 +159,13 @@ func (x *HealthPingConfig) GetTimeout() int64 {
 | 
			
		|||
	return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (x *HealthPingConfig) GetHttpMethod() string {
 | 
			
		||||
	if x != nil {
 | 
			
		||||
		return x.HttpMethod
 | 
			
		||||
	}
 | 
			
		||||
	return ""
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var File_app_observatory_burst_config_proto protoreflect.FileDescriptor
 | 
			
		||||
 | 
			
		||||
var file_app_observatory_burst_config_proto_rawDesc = []byte{
 | 
			
		||||
| 
						 | 
				
			
			@ -173,7 +182,7 @@ var file_app_observatory_burst_config_proto_rawDesc = []byte{
 | 
			
		|||
	0x2e, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72, 0x79, 0x2e, 0x62, 0x75, 0x72,
 | 
			
		||||
	0x73, 0x74, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x50, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e,
 | 
			
		||||
	0x66, 0x69, 0x67, 0x52, 0x0a, 0x70, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22,
 | 
			
		||||
	0xb4, 0x01, 0x0a, 0x10, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x50, 0x69, 0x6e, 0x67, 0x43, 0x6f,
 | 
			
		||||
	0xd4, 0x01, 0x0a, 0x10, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x50, 0x69, 0x6e, 0x67, 0x43, 0x6f,
 | 
			
		||||
	0x6e, 0x66, 0x69, 0x67, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74,
 | 
			
		||||
	0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x74, 0x69,
 | 
			
		||||
	0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x22, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63,
 | 
			
		||||
| 
						 | 
				
			
			@ -184,7 +193,9 @@ var file_app_observatory_burst_config_proto_rawDesc = []byte{
 | 
			
		|||
	0x6e, 0x67, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x73,
 | 
			
		||||
	0x61, 0x6d, 0x70, 0x6c, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x18, 0x0a, 0x07,
 | 
			
		||||
	0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x74,
 | 
			
		||||
	0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x42, 0x70, 0x0a, 0x1e, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72,
 | 
			
		||||
	0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x68, 0x74, 0x74, 0x70, 0x4d, 0x65,
 | 
			
		||||
	0x74, 0x68, 0x6f, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x68, 0x74, 0x74, 0x70,
 | 
			
		||||
	0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x42, 0x70, 0x0a, 0x1e, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72,
 | 
			
		||||
	0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f,
 | 
			
		||||
	0x72, 0x79, 0x2e, 0x62, 0x75, 0x72, 0x73, 0x74, 0x50, 0x01, 0x5a, 0x2f, 0x67, 0x69, 0x74, 0x68,
 | 
			
		||||
	0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -26,4 +26,7 @@ message HealthPingConfig {
 | 
			
		|||
  int32 samplingCount = 4;
 | 
			
		||||
  // ping timeout, int64 values of time.Duration
 | 
			
		||||
  int64 timeout = 5;
 | 
			
		||||
  // http method to make request
 | 
			
		||||
  string httpMethod = 6;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,6 +19,7 @@ type HealthPingSettings struct {
 | 
			
		|||
	Interval      time.Duration `json:"interval"`
 | 
			
		||||
	SamplingCount int           `json:"sampling"`
 | 
			
		||||
	Timeout       time.Duration `json:"timeout"`
 | 
			
		||||
	HttpMethod    string        `json:"httpMethod"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// HealthPing is the health checker for balancers
 | 
			
		||||
| 
						 | 
				
			
			@ -37,12 +38,21 @@ type HealthPing struct {
 | 
			
		|||
func NewHealthPing(ctx context.Context, dispatcher routing.Dispatcher, config *HealthPingConfig) *HealthPing {
 | 
			
		||||
	settings := &HealthPingSettings{}
 | 
			
		||||
	if config != nil {
 | 
			
		||||
 | 
			
		||||
		var httpMethod string
 | 
			
		||||
		if config.HttpMethod == "" {
 | 
			
		||||
			httpMethod = "HEAD"
 | 
			
		||||
		} else {
 | 
			
		||||
			httpMethod = strings.TrimSpace(config.HttpMethod)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		settings = &HealthPingSettings{
 | 
			
		||||
			Connectivity:  strings.TrimSpace(config.Connectivity),
 | 
			
		||||
			Destination:   strings.TrimSpace(config.Destination),
 | 
			
		||||
			Interval:      time.Duration(config.Interval),
 | 
			
		||||
			SamplingCount: int(config.SamplingCount),
 | 
			
		||||
			Timeout:       time.Duration(config.Timeout),
 | 
			
		||||
			HttpMethod:    httpMethod,
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if settings.Destination == "" {
 | 
			
		||||
| 
						 | 
				
			
			@ -164,7 +174,7 @@ func (h *HealthPing) doCheck(tags []string, duration time.Duration, rounds int)
 | 
			
		|||
			}
 | 
			
		||||
			time.AfterFunc(delay, func() {
 | 
			
		||||
				errors.LogDebug(h.ctx, "checking ", handler)
 | 
			
		||||
				delay, err := client.MeasureDelay()
 | 
			
		||||
				delay, err := client.MeasureDelay(h.Settings.HttpMethod)
 | 
			
		||||
				if err == nil {
 | 
			
		||||
					ch <- &rtt{
 | 
			
		||||
						handler: handler,
 | 
			
		||||
| 
						 | 
				
			
			@ -251,7 +261,7 @@ func (h *HealthPing) checkConnectivity() bool {
 | 
			
		|||
		h.Settings.Connectivity,
 | 
			
		||||
		h.Settings.Timeout,
 | 
			
		||||
	)
 | 
			
		||||
	if _, err := tester.MeasureDelay(); err != nil {
 | 
			
		||||
	if _, err := tester.MeasureDelay(h.Settings.HttpMethod); err != nil {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	return true
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,6 +2,7 @@ package burst
 | 
			
		|||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"io"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -51,20 +52,28 @@ func newHTTPClient(ctxv context.Context, dispatcher routing.Dispatcher, handler
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
// MeasureDelay returns the delay time of the request to dest
 | 
			
		||||
func (s *pingClient) MeasureDelay() (time.Duration, error) {
 | 
			
		||||
func (s *pingClient) MeasureDelay(httpMethod string) (time.Duration, error) {
 | 
			
		||||
	if s.httpClient == nil {
 | 
			
		||||
		panic("pingClient not initialized")
 | 
			
		||||
	}
 | 
			
		||||
	req, err := http.NewRequest(http.MethodHead, s.destination, nil)
 | 
			
		||||
 | 
			
		||||
	req, err := http.NewRequest(httpMethod, s.destination, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return rttFailed, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	start := time.Now()
 | 
			
		||||
	resp, err := s.httpClient.Do(req)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return rttFailed, err
 | 
			
		||||
	}
 | 
			
		||||
	// don't wait for body
 | 
			
		||||
	if httpMethod == http.MethodGet {
 | 
			
		||||
		_, err = io.Copy(io.Discard, resp.Body)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return rttFailed, err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	resp.Body.Close()
 | 
			
		||||
 | 
			
		||||
	return time.Since(start), nil
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,6 +2,7 @@ package conf
 | 
			
		|||
 | 
			
		||||
import (
 | 
			
		||||
	"google.golang.org/protobuf/proto"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"github.com/xtls/xray-core/app/observatory/burst"
 | 
			
		||||
	"github.com/xtls/xray-core/app/router"
 | 
			
		||||
| 
						 | 
				
			
			@ -51,15 +52,23 @@ type healthCheckSettings struct {
 | 
			
		|||
	Interval      duration.Duration `json:"interval"`
 | 
			
		||||
	SamplingCount int               `json:"sampling"`
 | 
			
		||||
	Timeout       duration.Duration `json:"timeout"`
 | 
			
		||||
	HttpMethod    string            `json:"httpMethod"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (h healthCheckSettings) Build() (proto.Message, error) {
 | 
			
		||||
	var httpMethod string
 | 
			
		||||
	if h.HttpMethod == "" {
 | 
			
		||||
		httpMethod = "HEAD"
 | 
			
		||||
	} else {
 | 
			
		||||
		httpMethod = strings.TrimSpace(h.HttpMethod)
 | 
			
		||||
	}
 | 
			
		||||
	return &burst.HealthPingConfig{
 | 
			
		||||
		Destination:   h.Destination,
 | 
			
		||||
		Connectivity:  h.Connectivity,
 | 
			
		||||
		Interval:      int64(h.Interval),
 | 
			
		||||
		Timeout:       int64(h.Timeout),
 | 
			
		||||
		SamplingCount: int32(h.SamplingCount),
 | 
			
		||||
		HttpMethod:    httpMethod,
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue