github.com/xtls/xray-core@v1.8.12-0.20240518155711-3168d27b0bdb/app/observatory/burst/burstobserver.go (about) 1 package burst 2 3 import ( 4 "context" 5 6 "github.com/xtls/xray-core/core" 7 "github.com/xtls/xray-core/app/observatory" 8 "github.com/xtls/xray-core/common" 9 "github.com/xtls/xray-core/common/signal/done" 10 "github.com/xtls/xray-core/features/extension" 11 "github.com/xtls/xray-core/features/outbound" 12 "google.golang.org/protobuf/proto" 13 "sync" 14 ) 15 16 type Observer struct { 17 config *Config 18 ctx context.Context 19 20 statusLock sync.Mutex 21 hp *HealthPing 22 23 finished *done.Instance 24 25 ohm outbound.Manager 26 } 27 28 func (o *Observer) GetObservation(ctx context.Context) (proto.Message, error) { 29 return &observatory.ObservationResult{Status: o.createResult()}, nil 30 } 31 32 func (o *Observer) createResult() []*observatory.OutboundStatus { 33 var result []*observatory.OutboundStatus 34 o.hp.access.Lock() 35 defer o.hp.access.Unlock() 36 for name, value := range o.hp.Results { 37 status := observatory.OutboundStatus{ 38 Alive: value.getStatistics().All != value.getStatistics().Fail, 39 Delay: value.getStatistics().Average.Milliseconds(), 40 LastErrorReason: "", 41 OutboundTag: name, 42 LastSeenTime: 0, 43 LastTryTime: 0, 44 HealthPing: &observatory.HealthPingMeasurementResult{ 45 All: int64(value.getStatistics().All), 46 Fail: int64(value.getStatistics().Fail), 47 Deviation: int64(value.getStatistics().Deviation), 48 Average: int64(value.getStatistics().Average), 49 Max: int64(value.getStatistics().Max), 50 Min: int64(value.getStatistics().Min), 51 }, 52 } 53 result = append(result, &status) 54 } 55 return result 56 } 57 58 func (o *Observer) Type() interface{} { 59 return extension.ObservatoryType() 60 } 61 62 func (o *Observer) Start() error { 63 if o.config != nil && len(o.config.SubjectSelector) != 0 { 64 o.finished = done.New() 65 o.hp.StartScheduler(func() ([]string, error) { 66 hs, ok := o.ohm.(outbound.HandlerSelector) 67 if !ok { 68 69 return nil, newError("outbound.Manager is not a HandlerSelector") 70 } 71 72 outbounds := hs.Select(o.config.SubjectSelector) 73 return outbounds, nil 74 }) 75 } 76 return nil 77 } 78 79 func (o *Observer) Close() error { 80 if o.finished != nil { 81 o.hp.StopScheduler() 82 return o.finished.Close() 83 } 84 return nil 85 } 86 87 func New(ctx context.Context, config *Config) (*Observer, error) { 88 var outboundManager outbound.Manager 89 err := core.RequireFeatures(ctx, func(om outbound.Manager) { 90 outboundManager = om 91 }) 92 if err != nil { 93 return nil, newError("Cannot get depended features").Base(err) 94 } 95 hp := NewHealthPing(ctx, config.PingConfig) 96 return &Observer{ 97 config: config, 98 ctx: ctx, 99 ohm: outboundManager, 100 hp: hp, 101 }, nil 102 } 103 104 func init() { 105 common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) { 106 return New(ctx, config.(*Config)) 107 })) 108 }