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