github.com/unionj-cloud/go-doudou@v1.3.8-0.20221011095552-0088008e5b31/cmd/internal/svc/codegen/svcimpl.go (about)

     1  package codegen
     2  
     3  import (
     4  	"bufio"
     5  	"bytes"
     6  	"github.com/iancoleman/strcase"
     7  	"github.com/sirupsen/logrus"
     8  	"github.com/unionj-cloud/go-doudou/cmd/internal/astutils"
     9  	v3 "github.com/unionj-cloud/go-doudou/cmd/internal/protobuf/v3"
    10  	"github.com/unionj-cloud/go-doudou/toolkit/copier"
    11  	"github.com/unionj-cloud/go-doudou/version"
    12  	"go/ast"
    13  	"go/parser"
    14  	"go/token"
    15  	"io/ioutil"
    16  	"os"
    17  	"path/filepath"
    18  	"strings"
    19  	"text/template"
    20  )
    21  
    22  var svcimportTmpl = `
    23  	"context"
    24  	"{{.ConfigPackage}}"
    25  	"{{.VoPackage}}"
    26  	"github.com/jmoiron/sqlx"
    27  	"github.com/brianvoe/gofakeit/v6"
    28  `
    29  
    30  var appendPart = `{{- range $m := .Meta.Methods }}
    31  	func (receiver *{{$.Meta.Name}}Impl) {{$m.Name}}({{- range $i, $p := $m.Params}}
    32      {{- if $i}},{{end}}
    33      {{- $p.Name}} {{$p.Type}}
    34      {{- end }}) ({{- range $i, $r := $m.Results}}
    35                       {{- if $i}},{{end}}
    36                       {{- $r.Name}} {{$r.Type}}
    37                       {{- end }}) {
    38      	var _result struct{
    39  			{{- range $r := $m.Results }}
    40  			{{- if ne $r.Type "error" }}
    41  			{{ $r.Name | toCamel }} {{ $r.Type }}
    42  			{{- end }}
    43  			{{- end }}
    44  		}
    45  		_ = gofakeit.Struct(&_result)
    46  		return {{range $i, $r := $m.Results }}{{- if $i}},{{end}}{{ if eq $r.Type "error" }}nil{{else}}_result.{{ $r.Name | toCamel }}{{end}}{{- end }}
    47      }
    48  {{- end }}`
    49  
    50  var svcimplTmpl = `/**
    51  * Generated by go-doudou {{.Version}}.
    52  * You can edit it as your need.
    53  */
    54  package {{.SvcPackage}}
    55  
    56  import ()
    57  
    58  var _ {{.Meta.Name}} = (*{{.Meta.Name}}Impl)(nil)
    59  
    60  type {{.Meta.Name}}Impl struct {
    61  	conf *config.Config
    62  }
    63  
    64  ` + appendPart + `
    65  
    66  func New{{.Meta.Name}}(conf *config.Config) *{{.Meta.Name}}Impl {
    67  	return &{{.Meta.Name}}Impl{
    68  		conf: conf,
    69  	}
    70  }
    71  `
    72  
    73  var svcimportTmplGrpc = `
    74  	"context"
    75  	"{{.ConfigPackage}}"
    76  	"{{.VoPackage}}"
    77  	pb "{{.PbPackage}}"
    78  `
    79  
    80  var appendPartGrpc = `{{- range $m := .GrpcSvc.Rpcs }}
    81      {{- if eq $m.StreamType 0 }}
    82  	func (receiver *{{$.Meta.Name}}Impl) {{$m.Name}}(ctx context.Context, request *pb.{{$m.Request}}) (*pb.{{$m.Response}}, error) {
    83      	//TODO implement me
    84  		panic("implement me")
    85      }
    86      {{- end }}
    87      {{- if eq $m.StreamType 1 }}
    88  	func (receiver *{{$.Meta.Name}}Impl) {{$m.Name}}(server pb.{{$.GrpcSvc.Name}}_{{$m.Name}}Server) error {
    89  		//TODO implement me
    90  		panic("implement me")
    91  	}
    92      {{- end }}
    93      {{- if eq $m.StreamType 2 }}
    94  	func (receiver *{{$.Meta.Name}}Impl) {{$m.Name}}(server pb.{{$.GrpcSvc.Name}}_{{$m.Name}}Server) error {
    95  		//TODO implement me
    96  		panic("implement me")
    97  	}
    98      {{- end }}
    99      {{- if eq $m.StreamType 3 }}
   100  	func (receiver *{{$.Meta.Name}}Impl) {{$m.Name}}(request *pb.{{$m.Request}}, server pb.{{$.GrpcSvc.Name}}_{{$m.Name}}Server) error {
   101  		//TODO implement me
   102  		panic("implement me")
   103  	}
   104      {{- end }}
   105  {{- end }}`
   106  
   107  /**
   108  type Service struct {
   109  	Name      string
   110  	Package   string
   111  	GoPackage string
   112  	Syntax    string
   113  	// go-doudou version
   114  	Version  string
   115  	ProtoVer string
   116  	Rpcs     []Rpc
   117  	Messages []Message
   118  	Enums    []Enum
   119  	Comments []string
   120  	Imports  []string
   121  }
   122  */
   123  var svcimplTmplGrpc = `/**
   124  * Generated by go-doudou {{.Version}}.
   125  * You can edit it as your need.
   126  */
   127  package {{.SvcPackage}}
   128  
   129  import ()
   130  
   131  var _ pb.{{.GrpcSvc.Name}}Server = (*{{.Meta.Name}}Impl)(nil)
   132  
   133  type {{.Meta.Name}}Impl struct {
   134      pb.Unimplemented{{.GrpcSvc.Name}}Server
   135  	conf *config.Config
   136  }
   137  
   138  ` + appendPartGrpc + `
   139  
   140  func New{{.Meta.Name}}(conf *config.Config) *{{.Meta.Name}}Impl {
   141  	return &{{.Meta.Name}}Impl{
   142  		conf: conf,
   143  	}
   144  }
   145  `
   146  
   147  // GenSvcImpl generates service implementation
   148  func GenSvcImpl(dir string, ic astutils.InterfaceCollector) {
   149  	var (
   150  		err         error
   151  		modfile     string
   152  		modName     string
   153  		svcimplfile string
   154  		firstLine   string
   155  		f           *os.File
   156  		tpl         *template.Template
   157  		buf         bytes.Buffer
   158  		meta        astutils.InterfaceMeta
   159  		tmpl        string
   160  		importBuf   bytes.Buffer
   161  	)
   162  	svcimplfile = filepath.Join(dir, "svcimpl.go")
   163  	err = copier.DeepCopy(ic.Interfaces[0], &meta)
   164  	if err != nil {
   165  		panic(err)
   166  	}
   167  	modfile = filepath.Join(dir, "go.mod")
   168  	if f, err = os.Open(modfile); err != nil {
   169  		panic(err)
   170  	}
   171  	reader := bufio.NewReader(f)
   172  	firstLine, _ = reader.ReadString('\n')
   173  	modName = strings.TrimSpace(strings.TrimPrefix(firstLine, "module"))
   174  	if _, err = os.Stat(svcimplfile); os.IsNotExist(err) {
   175  		if f, err = os.Create(svcimplfile); err != nil {
   176  			panic(err)
   177  		}
   178  		defer f.Close()
   179  		tmpl = svcimplTmpl
   180  	} else {
   181  		logrus.Warningln("New content will be append to file svcimpl.go")
   182  		if f, err = os.OpenFile(svcimplfile, os.O_APPEND, os.ModePerm); err != nil {
   183  			panic(err)
   184  		}
   185  		defer f.Close()
   186  		tmpl = appendPart
   187  
   188  		fset := token.NewFileSet()
   189  		root, err := parser.ParseFile(fset, svcimplfile, nil, parser.ParseComments)
   190  		if err != nil {
   191  			panic(err)
   192  		}
   193  		sc := astutils.NewStructCollector(astutils.ExprString)
   194  		ast.Walk(sc, root)
   195  		if implementations, exists := sc.Methods[meta.Name+"Impl"]; exists {
   196  			var notimplemented []astutils.MethodMeta
   197  			for _, item := range meta.Methods {
   198  				for _, implemented := range implementations {
   199  					if item.Name == implemented.Name {
   200  						goto L
   201  					}
   202  				}
   203  				notimplemented = append(notimplemented, item)
   204  
   205  			L:
   206  			}
   207  
   208  			meta.Methods = notimplemented
   209  		}
   210  	}
   211  
   212  	funcMap := make(map[string]interface{})
   213  	funcMap["toCamel"] = strcase.ToCamel
   214  	if tpl, err = template.New("svcimpl.go.tmpl").Funcs(funcMap).Parse(tmpl); err != nil {
   215  		panic(err)
   216  	}
   217  	if err = tpl.Execute(&buf, struct {
   218  		ConfigPackage string
   219  		VoPackage     string
   220  		SvcPackage    string
   221  		Meta          astutils.InterfaceMeta
   222  		Version       string
   223  	}{
   224  		VoPackage:     modName + "/vo",
   225  		ConfigPackage: modName + "/config",
   226  		SvcPackage:    ic.Package.Name,
   227  		Meta:          meta,
   228  		Version:       version.Release,
   229  	}); err != nil {
   230  		panic(err)
   231  	}
   232  
   233  	original, err := ioutil.ReadAll(f)
   234  	if err != nil {
   235  		panic(err)
   236  	}
   237  
   238  	original = append(original, buf.Bytes()...)
   239  	if tpl, err = template.New("simportimpl.go.tmpl").Parse(svcimportTmpl); err != nil {
   240  		panic(err)
   241  	}
   242  	if err = tpl.Execute(&importBuf, struct {
   243  		ConfigPackage string
   244  		VoPackage     string
   245  	}{
   246  		VoPackage:     modName + "/vo",
   247  		ConfigPackage: modName + "/config",
   248  	}); err != nil {
   249  		panic(err)
   250  	}
   251  	original = astutils.AppendImportStatements(original, importBuf.Bytes())
   252  	original = astutils.RestRelatedModify(original, meta.Name)
   253  	//fmt.Println(string(original))
   254  	astutils.FixImport(original, svcimplfile)
   255  }
   256  
   257  // GenSvcImplGrpc generates service implementation for grpc
   258  func GenSvcImplGrpc(dir string, ic astutils.InterfaceCollector, grpcSvc v3.Service) {
   259  	var (
   260  		err         error
   261  		modfile     string
   262  		modName     string
   263  		svcimplfile string
   264  		firstLine   string
   265  		f           *os.File
   266  		tpl         *template.Template
   267  		buf         bytes.Buffer
   268  		meta        astutils.InterfaceMeta
   269  		tmpl        string
   270  		importBuf   bytes.Buffer
   271  	)
   272  	svcimplfile = filepath.Join(dir, "svcimpl.go")
   273  	err = copier.DeepCopy(ic.Interfaces[0], &meta)
   274  	if err != nil {
   275  		panic(err)
   276  	}
   277  	modfile = filepath.Join(dir, "go.mod")
   278  	if f, err = os.Open(modfile); err != nil {
   279  		panic(err)
   280  	}
   281  	reader := bufio.NewReader(f)
   282  	firstLine, _ = reader.ReadString('\n')
   283  	modName = strings.TrimSpace(strings.TrimPrefix(firstLine, "module"))
   284  	if _, err = os.Stat(svcimplfile); os.IsNotExist(err) {
   285  		if f, err = os.Create(svcimplfile); err != nil {
   286  			panic(err)
   287  		}
   288  		defer f.Close()
   289  		tmpl = svcimplTmplGrpc
   290  	} else {
   291  		logrus.Warningln("New content will be append to file svcimpl.go")
   292  		if f, err = os.OpenFile(svcimplfile, os.O_APPEND, os.ModePerm); err != nil {
   293  			panic(err)
   294  		}
   295  		defer f.Close()
   296  		tmpl = appendPartGrpc
   297  
   298  		fset := token.NewFileSet()
   299  		root, err := parser.ParseFile(fset, svcimplfile, nil, parser.ParseComments)
   300  		if err != nil {
   301  			panic(err)
   302  		}
   303  		sc := astutils.NewStructCollector(astutils.ExprString)
   304  		ast.Walk(sc, root)
   305  		if implementations, exists := sc.Methods[meta.Name+"Impl"]; exists {
   306  			var notimplemented []v3.Rpc
   307  			for _, item := range grpcSvc.Rpcs {
   308  				for _, implemented := range implementations {
   309  					if item.Name == implemented.Name {
   310  						goto L
   311  					}
   312  				}
   313  				notimplemented = append(notimplemented, item)
   314  
   315  			L:
   316  			}
   317  
   318  			grpcSvc.Rpcs = notimplemented
   319  		}
   320  	}
   321  
   322  	funcMap := make(map[string]interface{})
   323  	funcMap["toCamel"] = strcase.ToCamel
   324  	if tpl, err = template.New("svcimpl.go.tmpl").Funcs(funcMap).Parse(tmpl); err != nil {
   325  		panic(err)
   326  	}
   327  	if err = tpl.Execute(&buf, struct {
   328  		ConfigPackage string
   329  		VoPackage     string
   330  		PbPackage     string
   331  		SvcPackage    string
   332  		Meta          astutils.InterfaceMeta
   333  		GrpcSvc       v3.Service
   334  		Version       string
   335  	}{
   336  		VoPackage:     modName + "/vo",
   337  		ConfigPackage: modName + "/config",
   338  		PbPackage:     modName + "/transport/grpc",
   339  		SvcPackage:    ic.Package.Name,
   340  		Meta:          meta,
   341  		GrpcSvc:       grpcSvc,
   342  		Version:       version.Release,
   343  	}); err != nil {
   344  		panic(err)
   345  	}
   346  
   347  	original, err := ioutil.ReadAll(f)
   348  	if err != nil {
   349  		panic(err)
   350  	}
   351  
   352  	original = append(original, buf.Bytes()...)
   353  	if tpl, err = template.New("simportimpl.go.tmpl").Parse(svcimportTmplGrpc); err != nil {
   354  		panic(err)
   355  	}
   356  	if err = tpl.Execute(&importBuf, struct {
   357  		ConfigPackage string
   358  		VoPackage     string
   359  		PbPackage     string
   360  	}{
   361  		VoPackage:     modName + "/vo",
   362  		ConfigPackage: modName + "/config",
   363  		PbPackage:     modName + "/transport/grpc",
   364  	}); err != nil {
   365  		panic(err)
   366  	}
   367  	original = astutils.AppendImportStatements(original, importBuf.Bytes())
   368  	original = astutils.GrpcRelatedModify(original, meta.Name, grpcSvc.Name)
   369  	//fmt.Println(string(original))
   370  	astutils.FixImport(original, svcimplfile)
   371  }