diff --git a/templates/project/providers/cmux/config.go.tpl b/templates/project/providers/cmux/config.go.tpl new file mode 100644 index 0000000..31f51e3 --- /dev/null +++ b/templates/project/providers/cmux/config.go.tpl @@ -0,0 +1,59 @@ +package cmux + +import ( + "fmt" + + "qq/providers/grpc" + "qq/providers/http" + + "git.ipao.vip/rogeecn/atom/container" + "git.ipao.vip/rogeecn/atom/utils/opt" + "github.com/soheilhy/cmux" + "golang.org/x/sync/errgroup" +) + +const DefaultPrefix = "Cmux" + +func DefaultProvider() container.ProviderContainer { + return container.ProviderContainer{ + Provider: Provide, + Options: []opt.Option{ + opt.Prefix(DefaultPrefix), + }, + } +} + +type Config struct { + Host *string + Port uint +} + +func (h *Config) Address() string { + if h.Host == nil { + return fmt.Sprintf(":%d", h.Port) + } + return fmt.Sprintf("%s:%d", *h.Host, h.Port) +} + +type CMux struct { + Http http.Service + Grpc *grpc.Grpc + Mux cmux.CMux +} + +func (c *CMux) Serve() error { + grpcL := c.Mux.Match(cmux.HTTP2HeaderField("content-type", "application/grpc")) + // httpL := c.Mux.Match(cmux.HTTP1Fast()) + httpL := c.Mux.Match(cmux.Any()) + + var eg errgroup.Group + eg.Go(func() error { + return c.Grpc.ServeWithListener(grpcL) + }) + + eg.Go(func() error { + return c.Http.Listener(httpL) + }) + + return c.Mux.Serve() +} diff --git a/templates/project/providers/cmux/provider.go.tpl b/templates/project/providers/cmux/provider.go.tpl new file mode 100644 index 0000000..69764b5 --- /dev/null +++ b/templates/project/providers/cmux/provider.go.tpl @@ -0,0 +1,32 @@ +package cmux + +import ( + "net" + + "qq/providers/grpc" + "qq/providers/http" + + "git.ipao.vip/rogeecn/atom/container" + "git.ipao.vip/rogeecn/atom/utils/opt" + "github.com/soheilhy/cmux" +) + +func Provide(opts ...opt.Option) error { + o := opt.New(opts...) + var config Config + if err := o.UnmarshalConfig(&config); err != nil { + return err + } + return container.Container.Provide(func(http http.Service, grpc *grpc.Grpc) (*CMux, error) { + l, err := net.Listen("tcp", config.Address()) + if err != nil { + return nil, err + } + + return &CMux{ + Http: http, + Grpc: grpc, + Mux: cmux.New(l), + }, nil + }, o.DiOptions()...) +} diff --git a/templates/project/providers/grpc/config.go.tpl b/templates/project/providers/grpc/config.go.tpl index fbd1be4..fcb7764 100644 --- a/templates/project/providers/grpc/config.go.tpl +++ b/templates/project/providers/grpc/config.go.tpl @@ -46,3 +46,7 @@ func (g *Grpc) Serve() error { return g.Server.Serve(l) } + +func (g *Grpc) ServeWithListener(ln net.Listener) error { + return g.Server.Serve(ln) +} diff --git a/templates/project/providers/http/engine.go.tpl b/templates/project/providers/http/engine.go.tpl index 19a4996..15594a0 100644 --- a/templates/project/providers/http/engine.go.tpl +++ b/templates/project/providers/http/engine.go.tpl @@ -3,6 +3,7 @@ package http import ( "errors" "fmt" + "net" "runtime/debug" "time" @@ -29,7 +30,7 @@ type Service struct { Engine *fiber.App } -func (svc *Service) Serve() error { +func (svc *Service) listenerConfig() fiber.ListenConfig { listenConfig := fiber.ListenConfig{ EnablePrintRoutes: true, OnShutdownSuccess: func() { @@ -44,7 +45,7 @@ func (svc *Service) Serve() error { if svc.conf.Tls != nil { if svc.conf.Tls.Cert == "" || svc.conf.Tls.Key == "" { - return errors.New("tls cert or key is empty") + panic(errors.New("tls cert and key must be set")) } listenConfig.CertFile = svc.conf.Tls.Cert listenConfig.CertKeyFile = svc.conf.Tls.Key @@ -52,8 +53,15 @@ func (svc *Service) Serve() error { container.AddCloseAble(func() { svc.Engine.Shutdown() }) + return listenConfig +} - return svc.Engine.Listen(svc.conf.Address(), listenConfig) +func (svc *Service) Listener(ln net.Listener) error { + return svc.Engine.Listener(ln, svc.listenerConfig()) +} + +func (svc *Service) Serve() error { + return svc.Engine.Listen(svc.conf.Address(), svc.listenerConfig()) } func Provide(opts ...opt.Option) error {