diff --git a/README.md b/README.md index 95617fd..b46c96c 100644 --- a/README.md +++ b/README.md @@ -6,4 +6,15 @@ coco 快速项目开发脚手架 - 新建项目 - 代码生成 -- 自更新 \ No newline at end of file +- 工具自更新 + +## 安装 + +```shell +go install gitter.top/coco/bootstrap/coco/...@latest +go install gitter.top/coco/protoc-gen-coco@latest +go install github.com/golang/protobuf/protoc-gen-go@latest +go install github.com/bufbuild/buf/cmd/...@latest +go install github.com/google/wire/cmd/wire@latest +go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest +``` diff --git a/coco/main.go b/coco/main.go new file mode 100644 index 0000000..ee23a63 --- /dev/null +++ b/coco/main.go @@ -0,0 +1,39 @@ +package main + +import ( + "github.com/sirupsen/logrus" + "github.com/spf13/cobra" + + "gitter.top/coco/bootstrap" +) + +var ( + rootCmd = &cobra.Command{ + Use: "coco", + Short: "golang project toolkit", + } +) + +func init() { + logrus.SetFormatter(&logrus.TextFormatter{ + ForceColors: true, + EnvironmentOverrideColors: true, + DisableTimestamp: true, + DisableSorting: true, + DisableLevelTruncation: false, + PadLevelText: false, + QuoteEmptyFields: false, + }) + rootCmd.AddCommand(bootstrap.Update()) + rootCmd.AddCommand(bootstrap.CreateProject()) + rootCmd.AddCommand(bootstrap.AddAPICommand()) + rootCmd.AddCommand(bootstrap.AddServiceCommand()) + rootCmd.AddCommand(bootstrap.GenerateProtoFile()) + rootCmd.AddCommand(bootstrap.InjectProtoFile()) +} + +func main() { + if err := rootCmd.Execute(); err != nil { + logrus.Fatalln(err) + } +} diff --git a/coco_config.go b/coco_config.go index 85e7418..da3d5e1 100644 --- a/coco_config.go +++ b/coco_config.go @@ -1,4 +1,4 @@ -package main +package bootstrap type Config struct { Version string `yaml:"version"` diff --git a/coco_generate.go b/coco_generate.go new file mode 100644 index 0000000..587c2f3 --- /dev/null +++ b/coco_generate.go @@ -0,0 +1,57 @@ +package bootstrap + +import ( + "os" + "os/exec" + + "github.com/sirupsen/logrus" + "github.com/spf13/cobra" +) + +func GenerateProtoFile() *cobra.Command { + var protoFile string + var onlyGout, onlyCocout bool + cmd := &cobra.Command{ + Use: "gen", + Short: "generate proto file", + PreRun: func(_ *cobra.Command, _ []string) { + stat, err := os.Stat(protoFile) + if err != nil { + logrus.Errorf("read proto file %s failed: %v", protoFile, err) + return + } + if stat.IsDir() { + logrus.Errorf("proto file can not be directory") + return + } + }, + Run: func(_ *cobra.Command, _ []string) { + var args = []string{protoFile} + var goOut = "--go_out=.." + var cocoOut = "--coco_out=.." + if onlyGout { + args = append(args, goOut) + } + if onlyCocout { + args = append(args, cocoOut) + } + if !onlyCocout && !onlyGout { + args = append(args, cocoOut, goOut) + } + var command = exec.Command("protoc", args...) + output, err := command.CombinedOutput() + logrus.Infof("exec command: %s", command.String()) + if err != nil { + logrus.Errorf("exec command failed: %v: %v\noutput: %v", command.String(), err, string(output)) + return + } + logrus.Infof("generate %s success", protoFile) + }, + } + + cmd.Flags().StringVar(&protoFile, "path", "", "proto file path") + cmd.Flags().BoolVar(&onlyGout, "onlyGo", false, "only generate by protoc-gen-go") + cmd.Flags().BoolVar(&onlyCocout, "onlyCoco", false, "only generate by protoc-gen-coco") + + return cmd +} diff --git a/coco_inject.go b/coco_inject.go new file mode 100644 index 0000000..39f3c6a --- /dev/null +++ b/coco_inject.go @@ -0,0 +1,59 @@ +package bootstrap + +import ( + "os" + + "github.com/sirupsen/logrus" + "github.com/spf13/cobra" + "gitter.top/common/gobuf" +) + +func InjectProtoFile() *cobra.Command { + var protoFile string + var tags []string + var tagStyle string + cmd := &cobra.Command{ + Use: "inject", + Short: "inject pb.go file", + PreRun: func(_ *cobra.Command, _ []string) { + stat, err := os.Stat(protoFile) + if err != nil { + logrus.Errorf("read pb.go file %s failed: %v", protoFile, err) + return + } + if stat.IsDir() { + logrus.Errorf("proto file can not be directory") + return + } + }, + Run: func(_ *cobra.Command, _ []string) { + var getStyle = func(style string) gobuf.TagValueStyle { + if style == "underline" { + return gobuf.Underline + } + if style == "lowercase" { + return gobuf.LowerCase + } + return gobuf.UpperCase + } + var inject = gobuf.NewInjectTag(protoFile) + for _, tag := range tags { + inject.WithTags(gobuf.InjectTagProps{ + TagName: tag, + Style: getStyle(tagStyle), + }) + } + if err := inject.Inject(); err != nil { + logrus.Errorf("inject %s file failed: %v", protoFile, err) + return + } + logrus.Infof("inject %s success", protoFile) + }, + } + + cmd.Flags().StringVar(&protoFile, "path", "", "pb.go file path") + cmd.Flags().StringVar(&tagStyle, "style", "underline", "tag value style, value underline|lowercase|uppercase") + cmd.Flags().StringSliceVar(&tags, "tags", []string{"bson"}, "inject tag field name") + + return cmd +} diff --git a/coco_update.go b/coco_update.go index 74d16e0..98a6200 100644 --- a/coco_update.go +++ b/coco_update.go @@ -1,26 +1,27 @@ -package main +package bootstrap import ( "fmt" + "github.com/sirupsen/logrus" "github.com/spf13/cobra" - gitea_api "gitter.top/coco/components/gitea-api" + giteaApi "gitter.top/coco/components/gitea-api" "gitter.top/coco/components/runtime" "gitter.top/coco/components/yaml" ) -func cocoUpdate() *cobra.Command { +func Update() *cobra.Command { var config Config var configPath string return &cobra.Command{ Use: "update", - Short: "coco tool update", + Short: "coco update", PreRun: func(cmd *cobra.Command, args []string) { configPath = runtime.ReplaceEachSlash(fmt.Sprintf("%s/.coco.yaml", runtime.GetHomeDir())) _ = yaml.Read(configPath, &config) }, Run: func(cmd *cobra.Command, args []string) { - client, err := gitea_api.NewClient("https://gitter.top") + client, err := giteaApi.NewClient("https://gitter.top") if err != nil { logrus.Errorf("new gitea api failed: %v", err) return @@ -36,12 +37,10 @@ func cocoUpdate() *cobra.Command { } // exec update - repo := fmt.Sprintf("gitter.top/coco/bootstrap@%s", commitID) - if output, err := runtime.Exec("go", "build", "-o", "coco", repo); err != nil { - logrus.Errorf("update coco failed: %v", err) + repo := fmt.Sprintf("gitter.top/coco/bootstrap/coco/...@%s", commitID) + if _, err := runtime.Exec("go", "install", repo); err != nil { + logrus.Errorf("update bootstrap failed: %v", err) return - } else { - logrus.Infof("%s", output) } config.Version = commitID @@ -49,6 +48,8 @@ func cocoUpdate() *cobra.Command { logrus.Errorf("write config failed: %v", err) return } + + logrus.Infof("update success!") }, } } diff --git a/create_api.go b/create_api.go new file mode 100644 index 0000000..55fee05 --- /dev/null +++ b/create_api.go @@ -0,0 +1,77 @@ +package bootstrap + +import ( + "os" + + "github.com/sirupsen/logrus" + "github.com/spf13/cobra" + "gitter.top/common/gobuf" +) + +func AddAPICommand() *cobra.Command { + pbPath, _ := os.Getwd() + var routerGroup = "" + var routerName = "" + cmd := &cobra.Command{ + Use: "addapi", + Short: "add api for service", + Run: func(cmd *cobra.Command, args []string) { + if routerName == "" { + logrus.Errorf("router name --name empty") + return + } + routerName = FirstUpper(routerName) + buf, err := gobuf.NewParser(pbPath) + if err != nil { + logrus.Errorf("read proto file failed: %v", err) + return + } + if buf.ExistRPC(routerGroup, routerName) { + logrus.Warnf("router name exist") + return + } + err = buf.AddRPC(routerGroup, routerName) + if err != nil { + logrus.Warnf("add router failed: %v", err) + return + } + }, + } + cmd.Flags().StringVar(&pbPath, "path", pbPath, "proto file path") + cmd.Flags().StringVar(&routerName, "name", routerName, "api name") + cmd.Flags().StringVar(&routerGroup, "service", routerGroup, "service name") + return cmd +} + +func AddServiceCommand() *cobra.Command { + var pbPath = "" + var svcName = "" + cmd := &cobra.Command{ + Use: "addgroup", + Short: "add router group", + Run: func(cmd *cobra.Command, args []string) { + if svcName == "" { + logrus.Errorf("router group name -- name empty") + return + } + + buf, err := gobuf.NewParser(pbPath) + if err != nil { + logrus.Errorf("read proto file failed: %v", err) + return + } + if buf.ExistService(svcName) { + logrus.Errorf("router group name exist") + return + } + if err := buf.AddService(svcName); err != nil { + logrus.Errorf("add router group failed: %+v", err) + return + } + }, + } + cmd.Flags().StringVar(&pbPath, "path", pbPath, "proto file path") + cmd.Flags().StringVar(&svcName, "name", svcName, "router group name, such as UserModule") + + return cmd +} diff --git a/create_project.go b/create_project.go new file mode 100644 index 0000000..bf9846d --- /dev/null +++ b/create_project.go @@ -0,0 +1,45 @@ +package bootstrap + +import ( + "fmt" + "os" + "path" + + "github.com/spf13/cobra" + + "gitter.top/coco/bootstrap/template" +) + +func CreateProject() *cobra.Command { + var name, output string + cmd := &cobra.Command{ + Use: "new", + Short: "create new project", + PreRun: func(cmd *cobra.Command, args []string) { + if name != "" { + return + } + if len(args) == 1 { + name = args[0] + return + } + name = "DemoProject" + }, + Run: func(cmd *cobra.Command, args []string) { + b := &template.Builder{ + Path: output, + Name: name, + } + b.Path = path.Join(output, b.Name) + if err := b.Build(); err != nil { + _, _ = fmt.Fprint(os.Stderr, err) + os.Exit(1) + } + }, + } + + cmd.Flags().StringVar(&name, "name", "", "project name") + cmd.Flags().StringVar(&output, "path", ".", "project path") + + return cmd +} diff --git a/go.mod b/go.mod index bfbc943..d4070c6 100644 --- a/go.mod +++ b/go.mod @@ -1,18 +1,22 @@ -module gitter.top/xuthus5/coco +module gitter.top/coco/bootstrap -go 1.18 +go 1.20 require ( - github.com/sirupsen/logrus v1.9.0 - github.com/spf13/cobra v1.6.1 - gitter.top/coco/components v0.0.0-20230101151943-8e94d6d01339 + github.com/sirupsen/logrus v1.9.3 + github.com/spf13/cobra v1.8.0 + gitter.top/coco/components v0.0.0-20230414170908-eb14d021db12 + gitter.top/common/gobuf v0.0.0-20230929042601-dda09f2e32de ) require ( code.gitea.io/sdk/gitea v0.15.1 // indirect + github.com/emicklei/proto v1.13.0 // indirect github.com/hashicorp/go-version v1.2.1 // indirect - github.com/inconshreveable/mousetrap v1.0.1 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect - golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect + gitter.top/sync/proto-contrib v0.15.0 // indirect + golang.org/x/sys v0.16.0 // indirect + google.golang.org/protobuf v1.32.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/main.go b/main.go deleted file mode 100644 index 297bd25..0000000 --- a/main.go +++ /dev/null @@ -1,23 +0,0 @@ -package main - -import ( - "github.com/sirupsen/logrus" - "github.com/spf13/cobra" -) - -var ( - rootCmd = &cobra.Command{ - Use: "coco", - Short: "golang project generator", - } -) - -func init() { - rootCmd.AddCommand(cocoUpdate()) -} - -func main() { - if err := rootCmd.Execute(); err != nil { - logrus.Fatalln(err) - } -} diff --git a/template/creator.go b/template/creator.go new file mode 100644 index 0000000..5391fdc --- /dev/null +++ b/template/creator.go @@ -0,0 +1,89 @@ +package template + +import ( + "bytes" + "fmt" + "os" + "strings" + "text/template" +) + +var ( + scaffold = map[string]string{ + "/.gitignore": templateGitignore, + "/Makefile": templateMakefile, + "/Dockerfile": templateDockerfile, + "/docker-compose.yaml": templateDockerCompose, + "/buf.yaml": templateBuf, + "/buf.gen.yaml": templateBufGen, + "/buf.work.yaml": templateBufWork, + "/go.mod": templateModule, + "/config_dev.yaml": templateDevYaml, + "/config_prod.yaml": templateProdYaml, + "/proto/v1/file_module.proto": templateApiservicesProto, + "/proto/v1/file_model.proto": templateProto, + "/proto/v1/buf.yaml": templateBuf, + "/cmd/serve.go": templateCmdNewServe, + "/cmd/exec.go": templateCmdExec, + "/common/time.go": templateCommon, + "/config/config.go": templateConfig, + "/register/register.go": templateRouter, + "/internal/repositories/.gitkeep": "", + "/services/.gitkeep": "", + "/gen/.gitkeep": "", + } +) + +type Builder struct { + Name string + Path string + SSH string +} + +func (b *Builder) Build() error { + if err := os.MkdirAll(b.Path, 0755); err != nil { + return err + } + if err := b.write(b.Path+"/"+b.Name+".go", templateMain); err != nil { + return err + } + for sr, v := range scaffold { + i := strings.LastIndex(sr, "/") + if i > 0 { + dir := sr[:i] + if err := os.MkdirAll(b.Path+dir, 0755); err != nil { + return err + } + } + if err := b.write(b.Path+sr, v); err != nil { + return err + } + } + return nil +} + +func (b *Builder) write(name, tpl string) (err error) { + defer func() { + if err := recover(); err != nil { + fmt.Println("Failed") + } + }() + fmt.Printf("create %s \n", name) + data, err := b.parse(tpl) + if err != nil { + return + } + return os.WriteFile(name, data, 0644) +} + +func (b *Builder) parse(s string) ([]byte, error) { + t, err := template.New("").Parse(s) + if err != nil { + return nil, err + } + var buf bytes.Buffer + if err := t.Execute(&buf, b); err != nil { + return nil, err + } + return buf.Bytes(), nil +} diff --git a/template/template_apiservices.go b/template/template_apiservices.go new file mode 100644 index 0000000..c1a3fac --- /dev/null +++ b/template/template_apiservices.go @@ -0,0 +1,70 @@ +package template + +const templateApiservicesProto = `syntax = "proto3"; + +package proto.v1; + +option go_package = "project/gen;genv1"; + + +// @route_group: true +// @base_url: /v1/file +// @gen_to: ./services/controller/v1/file_controller.go +// @rpc_to: ./services/rpc/v1/file_impl.go +service FileService { + // @desc: 列表 + // @author: Young Xu + // @method: GET + // @api: /list + rpc List (FileServiceListRequest) returns (FileServiceListResponse); + // @desc: 上传 + // @author: Young Xu + // @method: POST + // @api: /upload + rpc Upload (FileServiceUploadRequest) returns (FileServiceUploadResponse); + // @desc: 删除 + // @author: Young Xu + // @method: DELETE + // @api: /delete + rpc Delete (FileServiceDeleteRequest) returns (FileServiceDeleteResponse); + // @desc: 下载 + // @author: Young Xu + // @method: GET + // @api: /download + rpc Download (FileServiceDownloadRequest) returns (FileServiceDownloadResponse); +} + + +message FileServiceListRequest { + string dirname = 1; // 目录 +} + +message FileServiceListResponse { + message Item { + int64 file_id = 1; // 文件ID + string filename = 2; // 文件名 + string file_size = 3; // 文件大小 + string created_at = 4; // 上传时间 + string dirname = 5; // 文件路径 + bool is_directory = 6; // 是否是目录 + } + repeated Item items = 1; // 列表 +} + +message FileServiceUploadRequest {} + +message FileServiceUploadResponse {} + +message FileServiceDeleteRequest { + int64 file_id = 1; // 文件名 +} + +message FileServiceDeleteResponse {} + +message FileServiceDownloadRequest { + // @v: required + string file_id = 1; // 文件ID +} + +message FileServiceDownloadResponse {} +` diff --git a/template/template_command.go b/template/template_command.go new file mode 100644 index 0000000..299be41 --- /dev/null +++ b/template/template_command.go @@ -0,0 +1,83 @@ +package template + +const templateCmdExec = `package cmd + +import ( + "github.com/sirupsen/logrus" + "github.com/spf13/cobra" + "gitter.top/common/lormatter" + + "{{.Name}}/config" +) + +var ( + rootCmd = &cobra.Command{} + cfgFile string +) + +func Execute() { + // 预加载配置文件 + loadConfig() + if err := rootCmd.Execute(); err != nil { + logrus.Fatalf("exec command failed: %v", err) + } +} + +func init() { + var formatter = lormatter.Formatter{ + ShowTime: true, + ShowFile: true, + } + formatter.Register() + rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "config_dev.yaml", "config file") + rootCmd.AddCommand(apiServerCommand) // API服务 + rootCmd.AddCommand(grpcServerCommand) // GRPC服务 +} + +func loadConfig() { + // 初始化配置文件 + config.New(cfgFile) + conf := config.Get() + if err := conf.Load(); err != nil { + panic(err) + } +} +` + +const templateCmdNewServe = `package cmd + +import ( + "github.com/sirupsen/logrus" + "github.com/spf13/cobra" + + "{{.Name}}/register" +) + +var ( + apiServerCommand = &cobra.Command{ + Use: "api", + Short: "start api server", + Long: "start api server", + Run: func(cmd *cobra.Command, args []string) { + router := register.NewRegister() + if err := router.NewRouter(); err != nil { + logrus.Errorf("register router failed: %v", err) + } + }, + } +) + +var ( + grpcServerCommand = &cobra.Command{ + Use: "grpc", + Short: "start grpc server", + Long: "start grpc server", + Run: func(cmd *cobra.Command, args []string) { + router := register.NewRegister() + if err := router.NewGrpc(); err != nil { + logrus.Errorf("register grpc failed: %v", err) + } + }, + } +) +` diff --git a/template/template_common.go b/template/template_common.go new file mode 100644 index 0000000..06803a2 --- /dev/null +++ b/template/template_common.go @@ -0,0 +1,10 @@ +package template + +const templateCommon = `package common + +import "time" + +func Unix2Datetime(t int64) string { + return time.Unix(t, 0).Format(time.DateTime) +} +` diff --git a/template/template_config.go b/template/template_config.go new file mode 100644 index 0000000..18d5727 --- /dev/null +++ b/template/template_config.go @@ -0,0 +1,62 @@ +package template + +const templateConfig = `package config + +import ( + "os" + + "github.com/sirupsen/logrus" + "gopkg.in/yaml.v3" +) + +type ServerConfig struct { + ServerName string ` + "`" + `yaml:"server-name"` + "`" + ` + ServerListen string ` + "`" + `yaml:"server-listen"` + "`" + ` + GrpcListen string ` + "`" + `yaml:"grpc-listen"` + "`" + ` + Environment string ` + "`" + `yaml:"environment"` + "`" + ` +} + +type ServerConf struct { + ConfigFile string + ServerConfig ` + "`" + `yaml:",inline"` + "`" + ` +} + +var conf *ServerConf + +func New(fileName string) { + conf = new(ServerConf) + conf.ConfigFile = fileName + if err := conf.Load(); err != nil { + logrus.Fatalf("read config file failed: %v", err) + } +} + +func Get() *ServerConf { + if conf == nil { + panic("config file not initialized") + } + return conf +} + +func (receiver *ServerConf) Load() error { + data, err := os.ReadFile(receiver.ConfigFile) + if err != nil && !os.IsNotExist(err) { + return err + } + if err := yaml.Unmarshal(data, receiver); err != nil { + return err + } + return nil +} + +func (receiver *ServerConf) Rewrite() error { + data, err := yaml.Marshal(receiver) + if err != nil { + return err + } + if err := os.WriteFile(receiver.ConfigFile, data, os.ModePerm); err != nil { + return err + } + return nil +} +` diff --git a/template/template_main.go b/template/template_main.go new file mode 100644 index 0000000..846db13 --- /dev/null +++ b/template/template_main.go @@ -0,0 +1,10 @@ +package template + +const templateMain = `package main + +import "{{.Name}}/cmd" + +func main() { + cmd.Execute() +} +` diff --git a/template/template_model.go b/template/template_model.go new file mode 100644 index 0000000..ea9ae9c --- /dev/null +++ b/template/template_model.go @@ -0,0 +1,19 @@ +package template + +const templateProto = `syntax = "proto3"; + +package proto.v1; + +option go_package = "project/gen;genv1"; + + +// @table_name: t_file +message ModelFileRecord { + int64 id = 1; + string filename = 2; + string file_size = 3; + string dirname = 4; + int64 created_at = 5; + bool is_directory = 6; +} +` diff --git a/template/template_module.go b/template/template_module.go new file mode 100644 index 0000000..78ea34f --- /dev/null +++ b/template/template_module.go @@ -0,0 +1,18 @@ +package template + +const templateModule = `module {{.Name}} + +go 1.20 + +require ( + github.com/gin-gonic/gin v1.9.1 + github.com/google/wire v0.5.0 + github.com/sirupsen/logrus v1.9.3 + github.com/spf13/cobra v1.8.0 + gitter.top/coco/coco v0.0.1 + gitter.top/common/lormatter v0.0.0-20230910075849-28d49dccd03a + google.golang.org/grpc v1.60.1 + google.golang.org/protobuf v1.32.0 + gopkg.in/yaml.v3 v3.0.1 +) +` diff --git a/template/template_plugins_config.go b/template/template_plugins_config.go new file mode 100644 index 0000000..d8ca31e --- /dev/null +++ b/template/template_plugins_config.go @@ -0,0 +1,99 @@ +package template + +const templateGitignore = `.idea +{{.Name}} +{{.Name}}.exe +{{.Name}}.exe~ +` + +const templateMakefile = `.PHONY : clean all ui api gen wire +gen: +ifeq ($(wildcard "webui/node_modules"),) + buf generate +else + buf generate --exclude-path webui/node_modules +endif + +wire: + cd gen/wire && wire + +ui: + cd webui && npm install && npm run build + +api: + go mod tidy && go build . + ./{{.Name}} api + +all: gen wire ui api +` + +const templateDockerfile = `FROM images.local/golang:latest + +WORKDIR /app + +RUN go install gitter.top/coco/protoc-gen-coco@latest &&\ + go install github.com/golang/protobuf/protoc-gen-go@latest &&\ + go install github.com/bufbuild/buf/cmd/...@latest + +COPY . /app +RUN npm install ts-proto +RUN buf generate --exclude-path node_modules +RUN cd webui && npm install && npm run build &&\ + cd .. && go mod tidy && go build . + +EXPOSE 38080 +ENTRYPOINT [ "./filesaver", "api" ] +` + +const templateDockerCompose = `version: "3" + +services: + server: + image: xuthus5/{{.Name}}:latest + container_name: {{.Name}} + restart: always + volumes: + - /data/containers/{{.Name}}:/app/data + ports: + - "30001:38080" +` + +const templateBuf = `version: v1 +breaking: + use: + - FILE +lint: + use: + - DEFAULT + except: + - MINIMAL +` + +const templateBufGen = `version: v1 +plugins: + - plugin: buf.build/protocolbuffers/go + out: gen + opt: paths=source_relative + - plugin: coco + out: gen + opt: + - paths=source_relative + - prefix=proto + - project_name={{.Name}} + - plugin: buf.build/community/stephenh-ts-proto + out: ./webui/src/gen + opt: + - paths=source_relative + - snakeToCamel=json + - esModuleInterop=true + - plugin: buf.build/grpc/go:v1.3.0 + out: gen + opt: + - paths=source_relative + - require_unimplemented_servers=false +` + +const templateBufWork = `version: v1 +directories: + - proto +` diff --git a/template/template_router.go b/template/template_router.go new file mode 100644 index 0000000..ae64acb --- /dev/null +++ b/template/template_router.go @@ -0,0 +1,62 @@ +package template + +const templateRouter = `package register + +import ( + "net" + + "github.com/gin-gonic/gin" + "github.com/sirupsen/logrus" + "gitter.top/coco/coco" + "google.golang.org/grpc" + "google.golang.org/grpc/reflection" + + "{{.Name}}/config" + "{{.Name}}/gen/wire" +) + +type Register struct{ + *config.ServerConf +} + +func NewRegister() *Register { + return &Register{config.Get()} +} + +// NewRouter 注册路由 +func (receiver *Register) NewRouter() error { + // 从这里开始实例化路由注册器 + var register = coco.NewRegister() + register.DefaultRouter(coco.WithListenAddress(receiver.ServerListen), + coco.WithGinMode(gin.ReleaseMode), coco.WithCors(), coco.WithRecovery()) + // register.RegisterStruct(wire.InitFileService()) + _ = register.PreRun(func() error { + engine := register.RawEngine() + engine.Static("/assets", "./webui/dist/assets") + engine.NoRoute(func(ctx *gin.Context) { + ctx.File("./webui/dist/index.html") + }) + return nil + }) + logrus.Infof("start api server: http://%s", receiver.ServerListen) + register.Run() + return nil +} + +// NewGrpc 注册grpc服务端 +func (receiver *Register) NewGrpc() error { + lis, err := net.Listen("tcp", receiver.GrpcListen) + if err != nil { + logrus.Fatalf("failed to listen grpc: %v", err) + } + s := grpc.NewServer() + //genv1.RegisterFileServiceServer(s, &rpcv1.FileService{}) + // Register reflection service on gRPC server. + reflection.Register(s) + logrus.Infof("grpc server: %s", receiver.GrpcListen) + if err := s.Serve(lis); err != nil { + logrus.Fatalf("failed to serve grpc: %v", err) + } + return nil +} +` diff --git a/template/template_yaml.go b/template/template_yaml.go new file mode 100644 index 0000000..455f6b2 --- /dev/null +++ b/template/template_yaml.go @@ -0,0 +1,13 @@ +package template + +const templateDevYaml = `server-name: {{.Name}} +server-listen: 0.0.0.0:38080 +grpc-listen: 0.0.0.0:38090 +environment: dev +` + +const templateProdYaml = `server-name: {{.Name}} +server-listen: 0.0.0.0:38080 +grpc-listen: 0.0.0.0:38090 +environment: prod +` diff --git a/util.go b/util.go new file mode 100644 index 0000000..a547ac7 --- /dev/null +++ b/util.go @@ -0,0 +1,11 @@ +package bootstrap + +import "strings" + +// FirstUpper 字符串首字母大写 +func FirstUpper(s string) string { + if s == "" { + return "" + } + return strings.ToUpper(s[:1]) + s[1:] +}