github.com/xmplusdev/xray-core@v1.8.10/app/router/command/command.go (about)

     1  package command
     2  
     3  //go:generate go run github.com/xmplusdev/xray-core/common/errors/errorgen
     4  
     5  import (
     6  	"context"
     7  	"time"
     8  
     9  	"github.com/xmplusdev/xray-core/common"
    10  	"github.com/xmplusdev/xray-core/core"
    11  	"github.com/xmplusdev/xray-core/features/routing"
    12  	"github.com/xmplusdev/xray-core/features/stats"
    13  	"google.golang.org/grpc"
    14  )
    15  
    16  // routingServer is an implementation of RoutingService.
    17  type routingServer struct {
    18  	router       routing.Router
    19  	routingStats stats.Channel
    20  }
    21  
    22  func (s *routingServer) GetBalancerInfo(ctx context.Context, request *GetBalancerInfoRequest) (*GetBalancerInfoResponse, error) {
    23  	var ret GetBalancerInfoResponse
    24  	ret.Balancer = &BalancerMsg{}
    25  	if bo, ok := s.router.(routing.BalancerOverrider); ok {
    26  		{
    27  			res, err := bo.GetOverrideTarget(request.GetTag())
    28  			if err != nil {
    29  				return nil, err
    30  			}
    31  			ret.Balancer.Override = &OverrideInfo{
    32  				Target: res,
    33  			}
    34  		}
    35  	}
    36  
    37  	if pt, ok := s.router.(routing.BalancerPrincipleTarget); ok {
    38  		{
    39  			res, err := pt.GetPrincipleTarget(request.GetTag())
    40  			if err != nil {
    41  				newError("unable to obtain principle target").Base(err).AtInfo().WriteToLog()
    42  			} else {
    43  				ret.Balancer.PrincipleTarget = &PrincipleTargetInfo{Tag: res}
    44  			}
    45  		}
    46  	}
    47  	return &ret, nil
    48  }
    49  
    50  func (s *routingServer) OverrideBalancerTarget(ctx context.Context, request *OverrideBalancerTargetRequest) (*OverrideBalancerTargetResponse, error) {
    51  	if bo, ok := s.router.(routing.BalancerOverrider); ok {
    52  		return &OverrideBalancerTargetResponse{}, bo.SetOverrideTarget(request.BalancerTag, request.Target)
    53  	}
    54  	return nil, newError("unsupported router implementation")
    55  }
    56  
    57  func (s *routingServer) AddRule(ctx context.Context, request *AddRuleRequest) (*AddRuleResponse, error) {
    58  	if bo, ok := s.router.(routing.Router); ok {
    59  		return &AddRuleResponse{}, bo.AddRule(request.Config, request.ShouldAppend)
    60  	}
    61  	return nil, newError("unsupported router implementation")
    62  
    63  }
    64  func (s *routingServer) RemoveRule(ctx context.Context, request *RemoveRuleRequest) (*RemoveRuleResponse, error) {
    65  	if bo, ok := s.router.(routing.Router); ok {
    66  		return &RemoveRuleResponse{}, bo.RemoveRule(request.RuleTag)
    67  	}
    68  	return nil, newError("unsupported router implementation")
    69  }
    70  
    71  // NewRoutingServer creates a statistics service with statistics manager.
    72  func NewRoutingServer(router routing.Router, routingStats stats.Channel) RoutingServiceServer {
    73  	return &routingServer{
    74  		router:       router,
    75  		routingStats: routingStats,
    76  	}
    77  }
    78  
    79  func (s *routingServer) TestRoute(ctx context.Context, request *TestRouteRequest) (*RoutingContext, error) {
    80  	if request.RoutingContext == nil {
    81  		return nil, newError("Invalid routing request.")
    82  	}
    83  	route, err := s.router.PickRoute(AsRoutingContext(request.RoutingContext))
    84  	if err != nil {
    85  		return nil, err
    86  	}
    87  	if request.PublishResult && s.routingStats != nil {
    88  		ctx, _ := context.WithTimeout(context.Background(), 4*time.Second)
    89  		s.routingStats.Publish(ctx, route)
    90  	}
    91  	return AsProtobufMessage(request.FieldSelectors)(route), nil
    92  }
    93  
    94  func (s *routingServer) SubscribeRoutingStats(request *SubscribeRoutingStatsRequest, stream RoutingService_SubscribeRoutingStatsServer) error {
    95  	if s.routingStats == nil {
    96  		return newError("Routing statistics not enabled.")
    97  	}
    98  	genMessage := AsProtobufMessage(request.FieldSelectors)
    99  	subscriber, err := stats.SubscribeRunnableChannel(s.routingStats)
   100  	if err != nil {
   101  		return err
   102  	}
   103  	defer stats.UnsubscribeClosableChannel(s.routingStats, subscriber)
   104  	for {
   105  		select {
   106  		case value, ok := <-subscriber:
   107  			if !ok {
   108  				return newError("Upstream closed the subscriber channel.")
   109  			}
   110  			route, ok := value.(routing.Route)
   111  			if !ok {
   112  				return newError("Upstream sent malformed statistics.")
   113  			}
   114  			err := stream.Send(genMessage(route))
   115  			if err != nil {
   116  				return err
   117  			}
   118  		case <-stream.Context().Done():
   119  			return stream.Context().Err()
   120  		}
   121  	}
   122  }
   123  
   124  func (s *routingServer) mustEmbedUnimplementedRoutingServiceServer() {}
   125  
   126  type service struct {
   127  	v *core.Instance
   128  }
   129  
   130  func (s *service) Register(server *grpc.Server) {
   131  	common.Must(s.v.RequireFeatures(func(router routing.Router, stats stats.Manager) {
   132  		rs := NewRoutingServer(router, nil)
   133  		RegisterRoutingServiceServer(server, rs)
   134  
   135  		// For compatibility purposes
   136  		vCoreDesc := RoutingService_ServiceDesc
   137  		vCoreDesc.ServiceName = "v2ray.core.app.router.command.RoutingService"
   138  		server.RegisterService(&vCoreDesc, rs)
   139  	}))
   140  }
   141  
   142  func init() {
   143  	common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, cfg interface{}) (interface{}, error) {
   144  		s := core.MustFromContext(ctx)
   145  		return &service{v: s}, nil
   146  	}))
   147  }