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 }