From ea06d7212cc8fe58c135994a53f1119658511ab1 Mon Sep 17 00:00:00 2001 From: Rogee Date: Thu, 23 Jan 2025 19:03:17 +0800 Subject: [PATCH] fix: issues --- templates/project/pkg/atom/atom.go.tpl | 159 ++++++++++++++++++ .../project/pkg/atom/config/config.go.tpl | 41 +++++ .../pkg/atom/container/container.go.tpl | 77 +++++++++ .../pkg/atom/contracts/cron_job.go.tpl | 15 ++ .../project/pkg/atom/contracts/events.go.tpl | 14 ++ .../project/pkg/atom/contracts/http.go.tpl | 10 ++ .../project/pkg/atom/contracts/misc.go.tpl | 3 + templates/project/pkg/atom/opt/options.go.tpl | 62 +++++++ 8 files changed, 381 insertions(+) create mode 100644 templates/project/pkg/atom/atom.go.tpl create mode 100644 templates/project/pkg/atom/config/config.go.tpl create mode 100644 templates/project/pkg/atom/container/container.go.tpl create mode 100644 templates/project/pkg/atom/contracts/cron_job.go.tpl create mode 100644 templates/project/pkg/atom/contracts/events.go.tpl create mode 100644 templates/project/pkg/atom/contracts/http.go.tpl create mode 100644 templates/project/pkg/atom/contracts/misc.go.tpl create mode 100644 templates/project/pkg/atom/opt/options.go.tpl diff --git a/templates/project/pkg/atom/atom.go.tpl b/templates/project/pkg/atom/atom.go.tpl new file mode 100644 index 0000000..4388d11 --- /dev/null +++ b/templates/project/pkg/atom/atom.go.tpl @@ -0,0 +1,159 @@ +package atom + +import ( + "github.com/pkg/errors" + "github.com/spf13/cobra" + "go.uber.org/dig" + "{{.ModuleName}}/pkg/atom/config" + "{{.ModuleName}}/pkg/atom/container" +) + +var ( + GroupInitialName = "initials" + GroupRoutesName = "routes" + GroupGrpcServerServiceName = "grpc_server_services" + GroupCommandName = "command_services" + GroupQueueName = "queue_handler" + GroupCronJobName = "cron_jobs" + + GroupInitial = dig.Group(GroupInitialName) + GroupRoutes = dig.Group(GroupRoutesName) + GroupGrpcServer = dig.Group(GroupGrpcServerServiceName) + GroupCommand = dig.Group(GroupCommandName) + GroupQueue = dig.Group(GroupQueueName) + GroupCronJob = dig.Group(GroupCronJobName) +) + +func Serve(opts ...Option) error { + rootCmd := &cobra.Command{Use: "app"} + for _, opt := range opts { + opt(rootCmd) + } + + rootCmd.SilenceErrors = true + rootCmd.SilenceUsage = true + rootCmd.SetFlagErrorFunc(func(cmd *cobra.Command, err error) error { + cmd.Println(err) + cmd.Println(cmd.UsageString()) + return err + }) + + rootCmd.PersistentFlags().StringP("config", "c", "config.toml", "config file") + + return rootCmd.Execute() +} + +func LoadProviders(configFile string, providers container.Providers) error { + configure, err := config.Load(configFile) + if err != nil { + return errors.Wrapf(err, "load config file: %s", configFile) + } + + if err := providers.Provide(configure); err != nil { + return err + } + return nil +} + +type Option func(*cobra.Command) + +var ( + AppName string + AppVersion string +) + +func Providers(providers container.Providers) Option { + return func(cmd *cobra.Command) { + cmd.PreRunE = func(cmd *cobra.Command, args []string) error { + return LoadProviders(cmd.Flag("config").Value.String(), providers) + } + } +} + +func Command(opt ...Option) Option { + return func(parentCmd *cobra.Command) { + cmd := &cobra.Command{} + for _, o := range opt { + o(cmd) + } + parentCmd.AddCommand(cmd) + } +} + +func Arguments(f func(cmd *cobra.Command)) Option { + return f +} + +func Version(ver string) Option { + return func(cmd *cobra.Command) { + cmd.Version = ver + AppVersion = ver + } +} + +func Name(name string) Option { + return func(cmd *cobra.Command) { + cmd.Use = name + AppName = name + } +} + +func Short(short string) Option { + return func(cmd *cobra.Command) { + cmd.Short = short + } +} + +func Long(long string) Option { + return func(cmd *cobra.Command) { + cmd.Long = long + } +} + +func Example(example string) Option { + return func(cmd *cobra.Command) { + cmd.Example = example + } +} + +func Run(run func(cmd *cobra.Command, args []string)) Option { + return func(cmd *cobra.Command) { + cmd.Run = run + } +} + +func RunE(run func(cmd *cobra.Command, args []string) error) Option { + return func(cmd *cobra.Command) { + cmd.RunE = run + } +} + +func PostRun(run func(cmd *cobra.Command, args []string)) Option { + return func(cmd *cobra.Command) { + cmd.PostRun = run + } +} + +func PostRunE(run func(cmd *cobra.Command, args []string) error) Option { + return func(cmd *cobra.Command) { + cmd.PostRunE = run + } +} + +func PreRun(run func(cmd *cobra.Command, args []string)) Option { + return func(cmd *cobra.Command) { + cmd.PreRun = run + } +} + +func PreRunE(run func(cmd *cobra.Command, args []string) error) Option { + return func(cmd *cobra.Command) { + cmd.PreRunE = run + } +} + +func Config(file string) Option { + return func(cmd *cobra.Command) { + _ = cmd.PersistentFlags().Set("config", file) + } +} diff --git a/templates/project/pkg/atom/config/config.go.tpl b/templates/project/pkg/atom/config/config.go.tpl new file mode 100644 index 0000000..8fa28f0 --- /dev/null +++ b/templates/project/pkg/atom/config/config.go.tpl @@ -0,0 +1,41 @@ +package config + +import ( + "log" + "path/filepath" + + "github.com/pkg/errors" + "github.com/spf13/viper" + "{{.ModuleName}}/pkg/atom/container" +) + +func Load(file string) (*viper.Viper, error) { + v := viper.NewWithOptions(viper.KeyDelimiter("_")) + v.AutomaticEnv() + + ext := filepath.Ext(file) + if ext == "" { + v.SetConfigType("toml") + v.SetConfigFile(file) + } else { + v.SetConfigType(ext[1:]) + v.SetConfigFile(file) + } + + v.AddConfigPath(".") + + err := v.ReadInConfig() + log.Println("config file:", v.ConfigFileUsed()) + if err != nil { + return nil, errors.Wrap(err, "config file read error") + } + + err = container.Container.Provide(func() (*viper.Viper, error) { + return v, nil + }) + if err != nil { + return nil, err + } + + return v, nil +} diff --git a/templates/project/pkg/atom/container/container.go.tpl b/templates/project/pkg/atom/container/container.go.tpl new file mode 100644 index 0000000..2e9f05d --- /dev/null +++ b/templates/project/pkg/atom/container/container.go.tpl @@ -0,0 +1,77 @@ +package container + +import ( + "context" + "log" + "os" + "os/signal" + "syscall" + + "github.com/spf13/viper" + "go.uber.org/dig" + "{{.ModuleName}}/pkg/atom/opt" +) + +var ( + Container *dig.Container = dig.New() + Cancel context.CancelFunc + closeable []func() +) + +func init() { + closeable = make([]func(), 0) + if err := Container.Provide(func() context.Context { + signals := []os.Signal{syscall.SIGTERM, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGKILL} + ctx, cancel := signal.NotifyContext(context.Background(), signals...) + go func() { + <-ctx.Done() + Close() + cancel() + }() + Cancel = cancel + return ctx + }); err != nil { + log.Fatal(err) + } +} + +func AddCloseAble(c func()) { + closeable = append(closeable, c) +} + +func Close() { + for _, c := range closeable { + c() + } +} + +type ProviderContainer struct { + Provider func(...opt.Option) error + Options []opt.Option +} + +type Providers []ProviderContainer + +func (p Providers) With(pcs ...func(...opt.Option) error) Providers { + for _, pc := range pcs { + p = append(p, ProviderContainer{Provider: pc}) + } + return p +} + +func (p Providers) WithProviders(pcs ...Providers) Providers { + for _, pc := range pcs { + p = append(p, pc...) + } + return p +} + +func (p Providers) Provide(config *viper.Viper) error { + for _, provider := range p { + provider.Options = append(provider.Options, opt.Config(config)) + if err := provider.Provider(provider.Options...); err != nil { + return err + } + } + return nil +} diff --git a/templates/project/pkg/atom/contracts/cron_job.go.tpl b/templates/project/pkg/atom/contracts/cron_job.go.tpl new file mode 100644 index 0000000..3b40b9f --- /dev/null +++ b/templates/project/pkg/atom/contracts/cron_job.go.tpl @@ -0,0 +1,15 @@ +package contracts + +import ( + "time" + + "github.com/riverqueue/river" +) + +type CronJob interface { + Description() string + Periodic() time.Duration + JobArgs() []river.JobArgs + InsertOpts() *river.InsertOpts + RunOnStart() bool +} diff --git a/templates/project/pkg/atom/contracts/events.go.tpl b/templates/project/pkg/atom/contracts/events.go.tpl new file mode 100644 index 0000000..60776b4 --- /dev/null +++ b/templates/project/pkg/atom/contracts/events.go.tpl @@ -0,0 +1,14 @@ +package contracts + +import "github.com/ThreeDotsLabs/watermill/message" + +type EventHandler interface { + Topic() string + PublishToTopic() string + Handler(msg *message.Message) ([]*message.Message, error) +} + +type EventPublisher interface { + Topic() string + Marshal() ([]byte, error) +} diff --git a/templates/project/pkg/atom/contracts/http.go.tpl b/templates/project/pkg/atom/contracts/http.go.tpl new file mode 100644 index 0000000..43502ad --- /dev/null +++ b/templates/project/pkg/atom/contracts/http.go.tpl @@ -0,0 +1,10 @@ +package contracts + +import ( + "github.com/gofiber/fiber/v3" +) + +type HttpRoute interface { + Register(fiber.Router) + Name() string +} diff --git a/templates/project/pkg/atom/contracts/misc.go.tpl b/templates/project/pkg/atom/contracts/misc.go.tpl new file mode 100644 index 0000000..c1b1fcc --- /dev/null +++ b/templates/project/pkg/atom/contracts/misc.go.tpl @@ -0,0 +1,3 @@ +package contracts + +type Initial interface{} diff --git a/templates/project/pkg/atom/opt/options.go.tpl b/templates/project/pkg/atom/opt/options.go.tpl new file mode 100644 index 0000000..bff20e1 --- /dev/null +++ b/templates/project/pkg/atom/opt/options.go.tpl @@ -0,0 +1,62 @@ +package opt + +import ( + "github.com/spf13/viper" + "go.uber.org/dig" +) + +type Options struct { + Config *viper.Viper + Prefix string + Name string + Group string +} + +type Option func(o *Options) + +func New(opts ...Option) *Options { + o := &Options{} + for _, opt := range opts { + opt(o) + } + return o +} + +func (o *Options) UnmarshalConfig(config interface{}) error { + return o.Config.UnmarshalKey(o.Prefix, &config) +} + +func (o *Options) DiOptions() []dig.ProvideOption { + options := []dig.ProvideOption{} + if o.Name != "" { + options = append(options, dig.Name(o.Name)) + } + if o.Group != "" { + options = append(options, dig.Group(o.Group)) + } + return options +} + +func Config(config *viper.Viper) Option { + return func(o *Options) { + o.Config = config + } +} + +func Name(name string) Option { + return func(o *Options) { + o.Name = name + } +} + +func Group(group string) Option { + return func(o *Options) { + o.Group = group + } +} + +func Prefix(prefix string) Option { + return func(o *Options) { + o.Prefix = prefix + } +}