refine goctl rpc generator

master
kevin 4 years ago
parent db16115037
commit 72132ce399

Binary file not shown.

Before

Width:  |  Height:  |  Size: 118 KiB

After

Width:  |  Height:  |  Size: 140 KiB

@ -102,7 +102,7 @@
* 测试API Gateway服务
```shell
curl -i "http://localhost:8888/shorten?url=a"
curl -i "http://localhost:8888/shorten?url=http://www.xiaoheiban.cn"
```
返回如下:
@ -116,6 +116,8 @@
{"shortUrl":""}
```
可以看到我们API Gateway其实啥也没干就返回了个空值接下来我们会在rpc服务里实现业务逻辑
* 可以修改`internal/svc/servicecontext.go`来传递服务依赖(如果需要)
* 实现逻辑可以修改`internal/logic`下的对应文件
@ -125,11 +127,65 @@
## 4. 编写shorten rpc服务未完
* 编写`shorten.proto`文件
可以通过命令生成proto文件模板
```shell
goctl rpc template -o shorten.proto
```
修改后文件内容如下:
```protobuf
syntax = "proto3";
package shorten;
message shortenReq {
string url = 1;
}
message shortenResp {
string key = 1;
}
service shortener {
rpc shorten(shortenReq) returns(shortenResp);
}
```
* 用`goctl`生成rpc代码
## 5. 编写expand rpc服务未完
* 编写`expand.proto`文件
可以通过命令生成proto文件模板
```shell
goctl rpc template -o expand.proto
```
修改后文件内容如下:
```protobuf
syntax = "proto3";
package expand;
message expandReq {
string key = 1;
}
message expandResp {
string url = 1;
}
service expander {
rpc expand(expandReq) returns(expandResp);
}
```
* 用`goctl`生成rpc代码
## 6. 修改API Gateway代码调用shorten/expand rpc服务未完
@ -150,6 +206,16 @@
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
```
* 创建DB和table
```sql
create database gozero;
```
```sql
source shorturl.sql;
```
* 在`rpc/model`目录下执行如下命令生成CRUD+cache代码`-c`表示使用`redis cache`
```shell
@ -198,3 +264,9 @@
## 10. Benchmark未完
## 11. 总结(未完)
可以看到go-zero不只是一个框架更是一个建立在框架+工具基础上的,简化和规范了整个微服务构建的技术体系。
我们一直强调**工具大于约定和文档**。
另外,我们在保持简单的同时也尽可能把微服务治理的复杂度封装到了框架内部,极大的降低了开发人员的心智负担,使得业务开发得以快速推进。

@ -4,8 +4,6 @@ import (
"fmt"
"os"
"github.com/urfave/cli"
"github.com/tal-tech/go-zero/core/logx"
"github.com/tal-tech/go-zero/tools/goctl/api/apigen"
"github.com/tal-tech/go-zero/tools/goctl/api/dartgen"
@ -21,6 +19,7 @@ import (
"github.com/tal-tech/go-zero/tools/goctl/feature"
model "github.com/tal-tech/go-zero/tools/goctl/model/sql/command"
rpc "github.com/tal-tech/go-zero/tools/goctl/rpc/command"
"github.com/urfave/cli"
)
var (
@ -196,7 +195,7 @@ var (
Subcommands: []cli.Command{
{
Name: "template",
Usage: `generate proto template"`,
Usage: `generate proto template`,
Flags: []cli.Flag{
cli.StringFlag{
Name: "out, o",
@ -211,7 +210,7 @@ var (
},
{
Name: "proto",
Usage: `generate rpc from proto"`,
Usage: `generate rpc from proto`,
Flags: []cli.Flag{
cli.StringFlag{
Name: "src, s",
@ -227,7 +226,7 @@ var (
},
cli.StringFlag{
Name: "shared",
Usage: `the dir of the shared file,default path is "${pwd}/shared. [option]"`,
Usage: `the dir of the shared file,default path is "${pwd}/shared. [option]`,
},
cli.BoolFlag{
Name: "idea",

@ -17,7 +17,7 @@ $ goctl rpc template -o=user.proto
```golang
syntax = "proto3";
package remoteuser;
package remote;
message Request {
// 用户名
@ -146,7 +146,7 @@ OPTIONS:
* proto不支持外部依赖包引入message不支持inline
* 目前main文件、shared文件、handler文件会被强制覆盖而和开发人员手动需要编写的则不会覆盖生成这一类在代码头部均有
```shell script
// Code generated by goctl. DO NOT EDIT.
// Code generated by goctl. DO NOT EDIT!
// Source: xxx.proto
```
的标识,请注意不要将也写业务性代码写在里面。

@ -4,7 +4,7 @@ import (
"github.com/urfave/cli"
"github.com/tal-tech/go-zero/tools/goctl/rpc/ctx"
"github.com/tal-tech/go-zero/tools/goctl/rpc/goen"
"github.com/tal-tech/go-zero/tools/goctl/rpc/gen"
)
func Rpc(c *cli.Context) error {

@ -16,9 +16,7 @@ import (
"github.com/tal-tech/go-zero/tools/goctl/util/console"
)
var (
errProtobufNotFound = errors.New("github.com/golang/protobuf is not found,please ensure you has already [go get github.com/golang/protobuf]")
)
var errProtobufNotFound = errors.New("github.com/golang/protobuf is not found,please ensure you has already [go get github.com/golang/protobuf]")
const (
constGo = "go"
@ -51,7 +49,7 @@ type (
)
func prepare(log console.Console) (*Project, error) {
log.Info("check go env ...")
log.Info("checking go env...")
_, err := exec.LookPath(constGo)
if err != nil {
return nil, err
@ -109,11 +107,6 @@ func prepare(log console.Console) (*Project, error) {
if err != nil {
return nil, err
}
protobufModule, err = matchProtoBuf(data)
if err != nil {
return nil, err
}
} else {
if goModCache == "" {
goModCache = src
@ -180,21 +173,6 @@ func prepare(log console.Console) (*Project, error) {
}, nil
}
// github.com/golang/protobuf@{version}
func matchProtoBuf(data []byte) (string, error) {
text := string(data)
re := regexp.MustCompile(`(?m)(github.com/golang/protobuf)\s+(v[0-9.]+)`)
matches := re.FindAllStringSubmatch(text, -1)
if len(matches) == 0 {
return "", errProtobufNotFound
}
groups := matches[0]
if len(groups) < 3 {
return "", errProtobufNotFound
}
return fmt.Sprintf("%s@%s", groups[1], groups[2]), nil
}
func matchModule(data []byte) (string, error) {
text := string(data)
re := regexp.MustCompile(`(?m)^\s*module\s+[a-z0-9/\-.]+$`)
@ -204,5 +182,6 @@ func matchModule(data []byte) (string, error) {
index := strings.Index(target, "module")
return strings.TrimSpace(target[index+6:]), nil
}
return "", nil
}

@ -34,7 +34,7 @@ func NewDefaultRpcGenerator(ctx *ctx.RpcContext) *defaultRpcGenerator {
}
func (g *defaultRpcGenerator) Generate() (err error) {
g.Ctx.Info("code generating...")
g.Ctx.Info("generating code...")
defer func() {
if err == nil {
g.Ctx.Success("Done.")

@ -8,15 +8,13 @@ import (
"github.com/tal-tech/go-zero/tools/goctl/util"
)
var configTemplate = `package config
const configTemplate = `package config
import "github.com/tal-tech/go-zero/rpcx"
type (
Config struct {
type Config struct {
rpcx.RpcServerConf
}
)
`
func (g *defaultRpcGenerator) genConfig() error {

@ -0,0 +1,30 @@
package gogen
import (
"fmt"
"path/filepath"
"github.com/tal-tech/go-zero/tools/goctl/util"
)
const etcTemplate = `Name: {{.serviceName}}.rpc
Log:
Mode: console
ListenOn: 127.0.0.1:8080
Etcd:
Hosts:
- 127.0.0.1:6379
Key: {{.serviceName}}.rpc
`
func (g *defaultRpcGenerator) genEtc() error {
etdDir := g.dirM[dirEtc]
fileName := filepath.Join(etdDir, fmt.Sprintf("%v.yaml", g.Ctx.ServiceName.Lower()))
if util.FileExists(fileName) {
return nil
}
return util.With("etc").Parse(etcTemplate).SaveTo(map[string]interface{}{
"serviceName": g.Ctx.ServiceName.Lower(),
}, fileName, false)
}

@ -8,18 +8,14 @@ import (
"github.com/tal-tech/go-zero/tools/goctl/util"
)
var (
const (
remoteTemplate = `{{.head}}
package handler
import (
{{.imports}}
)
import {{.imports}}
type (
{{.types}}
)
type {{.types}}
{{.newFuncs}}
`
@ -33,6 +29,8 @@ import (
{{.imports}}
)
type {{.server}}Server struct{}
{{if .hasComment}}{{.comment}}{{end}}
func (s *{{.server}}Server) {{.method}} (ctx context.Context, in *{{.package}}.{{.request}}) (*{{.package}}.{{.response}}, error) {
l := logic.New{{.logicName}}(ctx,s.svcCtx)

@ -10,29 +10,26 @@ import (
"github.com/tal-tech/go-zero/tools/goctl/util"
)
var (
const (
logicTemplate = `package logic
import (
"context"
{{.imports}}
"github.com/tal-tech/go-zero/core/logx"
)
type (
{{.logicName}} struct {
type {{.logicName}} struct {
ctx context.Context
logx.Logger
// todo: add your logic here and delete this line
}
)
func New{{.logicName}}(ctx context.Context,svcCtx *svc.ServiceContext) *{{.logicName}} {
return &{{.logicName}}{
ctx: ctx,
Logger: logx.WithContext(ctx),
// todo: add your logic here and delete this line
}
}
{{.functions}}
@ -40,6 +37,7 @@ func New{{.logicName}}(ctx context.Context,svcCtx *svc.ServiceContext) *{{.logic
logicFunctionTemplate = `{{if .hasComment}}{{.comment}}{{end}}
func (l *{{.logicName}}) {{.method}} (in *{{.package}}.{{.request}}) (*{{.package}}.{{.response}}, error) {
var resp {{.package}}.{{.response}}
// todo: add your logic here and delete this line
return &resp,nil

@ -9,7 +9,7 @@ import (
"github.com/tal-tech/go-zero/tools/goctl/util"
)
var mainTemplate = `{{.head}}
const mainTemplate = `{{.head}}
package main
@ -18,15 +18,14 @@ import (
"fmt"
"log"
"google.golang.org/grpc"
{{.imports}}
"github.com/tal-tech/go-zero/core/conf"
"github.com/tal-tech/go-zero/rpcx"
{{.imports}}
"google.golang.org/grpc"
)
var configFile = flag.String("f", "etc/{{.serviceName}}.json", "the config file")
var configFile = flag.String("f", "etc/{{.serviceName}}.yaml", "the config file")
func main() {
flag.Parse()
@ -42,10 +41,10 @@ func main() {
if err != nil {
log.Fatal(err)
}
fmt.Printf("Starting rpc server at %s...\n", c.ListenOn)
s.Start()
}
`
func (g *defaultRpcGenerator) genMain() error {

@ -8,7 +8,6 @@ import (
"strings"
"github.com/dsymonds/gotoc/parser"
"github.com/tal-tech/go-zero/core/lang"
"github.com/tal-tech/go-zero/tools/goctl/rpc/execx"
astParser "github.com/tal-tech/go-zero/tools/goctl/rpc/parser"
@ -80,6 +79,9 @@ protoc -I=%s --go_out=plugins=grpc:%s %s`, filepath.Join(g.Ctx.GoPath, "bin"), s
return err
}
if len(stdout) > 0 {
g.Ctx.Info(stdout)
}
return nil
}

@ -12,10 +12,10 @@ import (
"github.com/tal-tech/go-zero/tools/goctl/util"
)
var (
const (
sharedTemplateText = `{{.head}}
//go:generate mockgen -destination ./mock{{.name}}model.go -package {{.filePackage}} -source $GOFILE
//go:generate mockgen -destination ./{{.name}}model_mock.go -package {{.filePackage}} -source $GOFILE
package {{.filePackage}}
@ -23,6 +23,7 @@ import (
"context"
{{.package}}
"github.com/tal-tech/go-zero/core/jsonx"
"github.com/tal-tech/go-zero/rpcx"
)
@ -31,13 +32,13 @@ type (
{{.serviceName}}Model interface {
{{.interface}}
}
default{{.serviceName}}Model struct {
cli rpcx.Client
}
)
func NewDefault{{.serviceName}}Model(cli rpcx.Client) {{.serviceName}}Model {
func New{{.serviceName}}Model(cli rpcx.Client) {{.serviceName}}Model {
return &default{{.serviceName}}Model{
cli: cli,
}
@ -49,51 +50,52 @@ func NewDefault{{.serviceName}}Model(cli rpcx.Client) {{.serviceName}}Model {
package {{.filePackage}}
import (
"errors"
)
import "errors"
var (
errJsonConvert = errors.New("json convert error")
)
var errJsonConvert = errors.New("json convert error")
{{.types}}
`
sharedInterfaceFunctionTemplate = `{{if .hasComment}}{{.comment}}
{{end}}{{.method}}(ctx context.Context,in *{{.pbRequest}}) {{if .hasResponse}}(*{{.pbResponse}},{{end}} error{{if .hasResponse}}){{end}}`
sharedFunctionTemplate = `
{{if .hasComment}}{{.comment}}{{end}}
func (m *default{{.rpcServiceName}}Model) {{.method}}(ctx context.Context,in *{{.pbRequest}}) {{if .hasResponse}}(*{{.pbResponse}},{{end}} error{{if .hasResponse}}){{end}} {
conn:= m.cli.Conn()
client := {{.package}}.New{{.rpcServiceName}}Client(conn)
client := {{.package}}.New{{.rpcServiceName}}Client(m.cli.Conn())
var request {{.package}}.{{.pbRequest}}
bts, err := jsonx.Marshal(in)
if err != nil {
return {{if .hasResponse}}nil, {{end}}errJsonConvert
}
err = jsonx.Unmarshal(bts, &request)
if err != nil {
return {{if .hasResponse}}nil, {{end}}errJsonConvert
}
{{if .hasResponse}}resp, err := {{else}}_, err = {{end}}client.{{.method}}(ctx, &request)
{{if .hasResponse}}if err != nil{
return nil, err
}
var ret {{.pbResponse}}
bts, err = jsonx.Marshal(resp)
if err != nil{
return nil, errJsonConvert
}
err = jsonx.Unmarshal(bts, &ret)
if err != nil{
return nil, errJsonConvert
}
return &ret, nil{{else}}if err != nil {
return err
}
return nil{{end}}
}`
}
`
)
func (g *defaultRpcGenerator) genShared() error {
@ -127,7 +129,7 @@ func (g *defaultRpcGenerator) genShared() error {
if err != nil {
return err
}
mockFile := filepath.Join(g.Ctx.SharedDir, fmt.Sprintf("mock%smodel.go", service.Name.Lower()))
mockFile := filepath.Join(g.Ctx.SharedDir, fmt.Sprintf("%smodel_mock.go", service.Name.Lower()))
os.Remove(mockFile)
err = util.With("shared").GoFmt(true).Parse(sharedTemplateText).SaveTo(map[string]interface{}{
"name": service.Name.Lower(),

@ -7,16 +7,13 @@ import (
"github.com/tal-tech/go-zero/tools/goctl/util"
)
var svcTemplate = `package svc
const svcTemplate = `package svc
import {{.imports}}
type (
ServiceContext struct {
type ServiceContext struct {
c config.Config
// todo: add your logic here and delete this line
}
)
func NewServiceContext(c config.Config) *ServiceContext {
return &ServiceContext{

@ -5,9 +5,9 @@ import (
"github.com/tal-tech/go-zero/tools/goctl/util/console"
)
var rpcTemplateText = `syntax = "proto3";
const rpcTemplateText = `syntax = "proto3";
package remoteuser;
package remote;
message Request {
string username = 1;
@ -21,14 +21,13 @@ message Response {
service User {
rpc Login(Request) returns(Response);
}`
}
`
type (
rpcTemplate struct {
type rpcTemplate struct {
out string
console.Console
}
)
func NewRpcTemplate(out string, idea bool) *rpcTemplate {
return &rpcTemplate{

@ -1,34 +0,0 @@
package gogen
import (
"fmt"
"path/filepath"
"github.com/tal-tech/go-zero/tools/goctl/util"
)
var etcTemplate = `{
"Name": "{{.serviceName}}.rpc",
"Log": {
"Mode": "console"
},
"ListenOn": "127.0.0.1:8080",
"Etcd": {
"Hosts": ["127.0.0.1:6379"],
"Key": "{{.serviceName}}.rpc"
}
}
`
func (g *defaultRpcGenerator) genEtc() error {
etdDir := g.dirM[dirEtc]
fileName := filepath.Join(etdDir, fmt.Sprintf("%v.json", g.Ctx.ServiceName.Lower()))
if util.FileExists(fileName) {
return nil
}
return util.With("etc").
Parse(etcTemplate).
SaveTo(map[string]interface{}{
"serviceName": g.Ctx.ServiceName.Lower(),
}, fileName, false)
}

@ -435,7 +435,7 @@ func (a *PbAst) GenTypesCode() (string, error) {
types = append(types, structCode)
}
buffer, err := util.With("type").Parse(typeTemplate).Execute(map[string]interface{}{
"types": strings.Join(types, "\n"),
"types": strings.Join(types, "\n\n"),
})
if err != nil {
return "", err

@ -1,6 +1,6 @@
package util
var headTemplate = `// Code generated by goctl. DO NOT EDIT.
var headTemplate = `// Code generated by goctl. DO NOT EDIT!
// Source: {{.source}}`
func GetHead(source string) string {

Loading…
Cancel
Save