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