github.com/xraypb/Xray-core@v1.8.1/app/commander/commander.go (about) 1 package commander 2 3 //go:generate go run github.com/xraypb/Xray-core/common/errors/errorgen 4 5 import ( 6 "context" 7 "net" 8 "sync" 9 10 "github.com/xraypb/Xray-core/common" 11 "github.com/xraypb/Xray-core/common/signal/done" 12 core "github.com/xraypb/Xray-core/core" 13 "github.com/xraypb/Xray-core/features/outbound" 14 "google.golang.org/grpc" 15 ) 16 17 // Commander is a Xray feature that provides gRPC methods to external clients. 18 type Commander struct { 19 sync.Mutex 20 server *grpc.Server 21 services []Service 22 ohm outbound.Manager 23 tag string 24 } 25 26 // NewCommander creates a new Commander based on the given config. 27 func NewCommander(ctx context.Context, config *Config) (*Commander, error) { 28 c := &Commander{ 29 tag: config.Tag, 30 } 31 32 common.Must(core.RequireFeatures(ctx, func(om outbound.Manager) { 33 c.ohm = om 34 })) 35 36 for _, rawConfig := range config.Service { 37 config, err := rawConfig.GetInstance() 38 if err != nil { 39 return nil, err 40 } 41 rawService, err := common.CreateObject(ctx, config) 42 if err != nil { 43 return nil, err 44 } 45 service, ok := rawService.(Service) 46 if !ok { 47 return nil, newError("not a Service.") 48 } 49 c.services = append(c.services, service) 50 } 51 52 return c, nil 53 } 54 55 // Type implements common.HasType. 56 func (c *Commander) Type() interface{} { 57 return (*Commander)(nil) 58 } 59 60 // Start implements common.Runnable. 61 func (c *Commander) Start() error { 62 c.Lock() 63 c.server = grpc.NewServer() 64 for _, service := range c.services { 65 service.Register(c.server) 66 } 67 c.Unlock() 68 69 listener := &OutboundListener{ 70 buffer: make(chan net.Conn, 4), 71 done: done.New(), 72 } 73 74 go func() { 75 if err := c.server.Serve(listener); err != nil { 76 newError("failed to start grpc server").Base(err).AtError().WriteToLog() 77 } 78 }() 79 80 if err := c.ohm.RemoveHandler(context.Background(), c.tag); err != nil { 81 newError("failed to remove existing handler").WriteToLog() 82 } 83 84 return c.ohm.AddHandler(context.Background(), &Outbound{ 85 tag: c.tag, 86 listener: listener, 87 }) 88 } 89 90 // Close implements common.Closable. 91 func (c *Commander) Close() error { 92 c.Lock() 93 defer c.Unlock() 94 95 if c.server != nil { 96 c.server.Stop() 97 c.server = nil 98 } 99 100 return nil 101 } 102 103 func init() { 104 common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, cfg interface{}) (interface{}, error) { 105 return NewCommander(ctx, cfg.(*Config)) 106 })) 107 }