├── .gitignore ├── Gopkg.lock ├── Gopkg.toml ├── LICENSE ├── Makefile ├── README.md ├── cmd └── microgen │ └── main.go ├── examples ├── addsvc │ ├── Makefile │ ├── README.md │ ├── addsvc │ │ └── api.go │ ├── cmd │ │ └── service │ │ │ └── main.go │ ├── service │ │ ├── caching.microgen.go │ │ ├── error_logging.microgen.go │ │ ├── logging.microgen.go │ │ ├── middleware.microgen.go │ │ └── recovering.microgen.go │ └── transport │ │ ├── client.microgen.go │ │ ├── endpoints.microgen.go │ │ ├── exchanges.microgen.go │ │ ├── grpc │ │ ├── client.microgen.go │ │ ├── protobuf_endpoint_converters.microgen.go │ │ ├── protobuf_type_converters.microgen.go │ │ └── server.microgen.go │ │ ├── http │ │ ├── client.microgen.go │ │ ├── converters.microgen.go │ │ └── server.microgen.go │ │ └── server.microgen.go ├── generated │ ├── cmd │ │ └── string_service │ │ │ └── main.go │ ├── comment.go │ ├── service.proto │ ├── service │ │ ├── caching.microgen.go │ │ ├── error_logging.microgen.go │ │ ├── logging.microgen.go │ │ ├── middleware.microgen.go │ │ └── recovering.microgen.go │ ├── svc.go │ └── transport │ │ ├── client.microgen.go │ │ ├── endpoints.microgen.go │ │ ├── exchanges.microgen.go │ │ ├── grpc │ │ ├── client.microgen.go │ │ ├── protobuf_endpoint_converters.microgen.go │ │ ├── protobuf_type_converters.microgen.go │ │ └── server.microgen.go │ │ ├── http │ │ ├── client.microgen.go │ │ ├── converters.microgen.go │ │ └── server.microgen.go │ │ └── server.microgen.go ├── protobuf │ ├── gen.go │ ├── pb │ │ └── service.proto │ └── service.pb.go ├── svc │ ├── entity │ │ └── comment.go │ └── svc.go └── usersvc │ ├── Makefile │ ├── README.md │ ├── pb │ └── api.proto │ └── pkg │ ├── cmd │ └── user_service │ │ └── main.go │ ├── service │ ├── caching.microgen.go │ ├── error_logging.microgen.go │ ├── logging.microgen.go │ ├── middleware.microgen.go │ └── recovering.microgen.go │ ├── transport │ ├── client.microgen.go │ ├── endpoints.microgen.go │ ├── exchanges.microgen.go │ ├── grpc │ │ ├── client.microgen.go │ │ ├── protobuf_endpoint_converters.microgen.go │ │ ├── protobuf_type_converters.microgen.go │ │ └── server.microgen.go │ ├── http │ │ ├── client.microgen.go │ │ ├── converters.microgen.go │ │ └── server.microgen.go │ └── server.microgen.go │ └── usersvc │ ├── api.go │ └── user.go ├── generator ├── decide.go ├── generator.go ├── generator_test.go ├── strings │ ├── string.go │ ├── string_test.go │ └── strings.go ├── template │ ├── buffer_adapter.go │ ├── cmd_main.go │ ├── common.go │ ├── context.go │ ├── prepare_utils.go │ ├── service.go │ ├── service.proto.go │ ├── service_caching.go │ ├── service_error_logging.go │ ├── service_logging.go │ ├── service_middleware.go │ ├── service_recovering.go │ ├── template.go │ ├── transport_client.go │ ├── transport_converter_jsonrpc_exchange_converters.go │ ├── transport_endpoints.go │ ├── transport_exchanges.go │ ├── transport_grpc_client.go │ ├── transport_grpc_protobuf_endpoint_converters.go │ ├── transport_grpc_protobuf_type_converters.go │ ├── transport_grpc_server.go │ ├── transport_http_client.go │ ├── transport_http_converters.go │ ├── transport_http_server.go │ └── transport_server.go ├── test_assets │ ├── endpoints.go.txt │ ├── exchanges.go.txt │ ├── grpc_client.go.txt │ ├── grpc_converters.go.txt │ ├── grpc_server.go.txt │ ├── grpc_type.go.txt │ ├── logging.go.txt │ ├── middleware.go.txt │ └── service.go.txt ├── validate.go └── write_strategy │ ├── common.go │ ├── file.go │ ├── nop.go │ └── writer.go ├── logger └── logger.go └── test ├── microgen_test.go └── util_test.go /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | 3 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 4 | *.o 5 | *.a 6 | *.so 7 | 8 | # Folders 9 | _obj 10 | _test 11 | 12 | # Architecture specific extensions/prefixes 13 | *.[568vq] 14 | [568vq].out 15 | 16 | *.cgo1.go 17 | *.cgo2.c 18 | _cgo_defun.c 19 | _cgo_gotypes.go 20 | _cgo_export.* 21 | 22 | _testmain.go 23 | 24 | *.exe 25 | *.test 26 | *.prof 27 | 28 | vendor/ 29 | 30 | generator/test_out/* -------------------------------------------------------------------------------- /Gopkg.toml: -------------------------------------------------------------------------------- 1 | 2 | # Gopkg.toml example 3 | # 4 | # Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md 5 | # for detailed Gopkg.toml documentation. 6 | # 7 | # required = ["github.com/user/thing/cmd/thing"] 8 | # ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"] 9 | # 10 | # [[constraint]] 11 | # name = "github.com/user/project" 12 | # version = "1.0.0" 13 | # 14 | # [[constraint]] 15 | # name = "github.com/user/project2" 16 | # branch = "dev" 17 | # source = "github.com/myfork/project2" 18 | # 19 | # [[override]] 20 | # name = "github.com/x/y" 21 | # version = "2.4.0" 22 | 23 | [[constraint]] 24 | name = "github.com/go-kit/kit" 25 | version = "0.7.0" 26 | 27 | [[constraint]] 28 | name = "github.com/dave/jennifer" 29 | version = "=0.19.0" 30 | 31 | [[constraint]] 32 | name = "github.com/vetcher/go-astra" 33 | version = "^1.1.2" 34 | 35 | [[constraint]] 36 | name = "github.com/stretchr/testify" 37 | revision = "2aa2c176b9dab406a6970f6a55f513e8a8c8b18f" 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Vitaly Bolychev 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | install: ; go install ./cmd/microgen 2 | 3 | examples_update: 4 | cd ./examples ;\ 5 | echo addsvc ;\ 6 | cd ./addsvc ;\ 7 | rm -rf ./cmd ./service ./transport ;\ 8 | make gen ;\ 9 | cd .. ;\ 10 | echo usersvc ;\ 11 | cd ./usersvc ;\ 12 | rm -rf ./cmd ./service ./transport ;\ 13 | make gen ;\ 14 | cd .. ;\ 15 | cd .. ;\ 16 | -------------------------------------------------------------------------------- /cmd/microgen/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "flag" 6 | "fmt" 7 | "os" 8 | "path/filepath" 9 | "strings" 10 | 11 | "github.com/devimteam/microgen/generator" 12 | mstrings "github.com/devimteam/microgen/generator/strings" 13 | "github.com/devimteam/microgen/generator/template" 14 | lg "github.com/devimteam/microgen/logger" 15 | "github.com/vetcher/go-astra" 16 | "github.com/vetcher/go-astra/types" 17 | ) 18 | 19 | const ( 20 | Version = generator.Version 21 | ) 22 | 23 | var ( 24 | flagFileName = flag.String("file", "service.go", "Path to input file with interface.") 25 | flagOutputDir = flag.String("out", ".", "Output directory.") 26 | flagHelp = flag.Bool("help", false, "Show help.") 27 | flagVerbose = flag.Int("v", 1, "Sets microgen verbose level.") 28 | flagDebug = flag.Bool("debug", false, "Print all microgen messages. Equivalent to -v=100.") 29 | flagGenProtofile = flag.String(".proto", "", "Package field in protobuf file. If not empty, service.proto file will be generated.") 30 | flagGenMain = flag.Bool(generator.MainTag, false, "Generate main.go file.") 31 | ) 32 | 33 | func init() { 34 | flag.Parse() 35 | } 36 | 37 | func main() { 38 | lg.Logger.Level = *flagVerbose 39 | if *flagDebug { 40 | lg.Logger.Level = 100 41 | } 42 | lg.Logger.Logln(1, "@microgen", Version) 43 | if *flagHelp || *flagFileName == "" { 44 | flag.Usage() 45 | os.Exit(0) 46 | } 47 | 48 | lg.Logger.Logln(4, "Source file:", *flagFileName) 49 | info, err := astra.ParseFile(*flagFileName) 50 | if err != nil { 51 | lg.Logger.Logln(0, "fatal:", err) 52 | os.Exit(1) 53 | } 54 | 55 | i := findInterface(info) 56 | if i == nil { 57 | lg.Logger.Logln(0, "fatal: could not find interface with @microgen tag") 58 | lg.Logger.Logln(4, "All founded interfaces:") 59 | lg.Logger.Logln(4, listInterfaces(info.Interfaces)) 60 | os.Exit(1) 61 | } 62 | 63 | if err := generator.ValidateInterface(i); err != nil { 64 | lg.Logger.Logln(0, "validation:", err) 65 | os.Exit(1) 66 | } 67 | 68 | ctx, err := prepareContext(*flagFileName, i) 69 | if err != nil { 70 | lg.Logger.Logln(0, "fatal:", err) 71 | os.Exit(1) 72 | } 73 | 74 | absOutputDir, err := filepath.Abs(*flagOutputDir) 75 | if err != nil { 76 | lg.Logger.Logln(0, "fatal:", err) 77 | os.Exit(1) 78 | } 79 | units, err := generator.ListTemplatesForGen(ctx, i, absOutputDir, *flagFileName, *flagGenProtofile, *flagGenMain) 80 | if err != nil { 81 | lg.Logger.Logln(0, "fatal:", err) 82 | os.Exit(1) 83 | } 84 | for _, unit := range units { 85 | err := unit.Generate(ctx) 86 | if err != nil && err != generator.EmptyStrategyError { 87 | lg.Logger.Logln(0, "fatal:", unit.Path(), err) 88 | os.Exit(1) 89 | } 90 | } 91 | lg.Logger.Logln(1, "all files successfully generated") 92 | } 93 | 94 | func listInterfaces(ii []types.Interface) string { 95 | var s string 96 | for _, i := range ii { 97 | s = s + fmt.Sprintf("\t%s(%d methods, %d embedded interfaces)\n", i.Name, len(i.Methods), len(i.Interfaces)) 98 | } 99 | return s 100 | } 101 | 102 | func prepareContext(filename string, iface *types.Interface) (context.Context, error) { 103 | ctx := context.Background() 104 | p, err := astra.ResolvePackagePath(filename) 105 | if err != nil { 106 | return nil, err 107 | } 108 | ctx = template.WithSourcePackageImport(ctx, p) 109 | 110 | set := template.TagsSet{} 111 | genTags := mstrings.FetchTags(iface.Docs, generator.TagMark+generator.MicrogenMainTag) 112 | for _, tag := range genTags { 113 | set.Add(tag) 114 | } 115 | ctx = template.WithTags(ctx, set) 116 | return ctx, nil 117 | } 118 | 119 | func findInterface(file *types.File) *types.Interface { 120 | for i := range file.Interfaces { 121 | if docsContainMicrogenTag(file.Interfaces[i].Docs) { 122 | return &file.Interfaces[i] 123 | } 124 | } 125 | return nil 126 | } 127 | 128 | func docsContainMicrogenTag(strs []string) bool { 129 | for _, str := range strs { 130 | if strings.HasPrefix(str, generator.TagMark+generator.MicrogenMainTag) { 131 | return true 132 | } 133 | } 134 | return false 135 | } 136 | -------------------------------------------------------------------------------- /examples/addsvc/Makefile: -------------------------------------------------------------------------------- 1 | gen: ; microgen -file=./addsvc/api.go -out=. -main -------------------------------------------------------------------------------- /examples/addsvc/README.md: -------------------------------------------------------------------------------- 1 | # addsvc 2 | Example addsvc is use [gokit addsvc example](https://github.com/go-kit/kit/tree/master/examples/addsvc) to illustrate what can be generated via `microgen`. 3 | 4 | Everything begins from `./addsvc/api.go` file. -------------------------------------------------------------------------------- /examples/addsvc/addsvc/api.go: -------------------------------------------------------------------------------- 1 | package addsvc 2 | 3 | import "context" 4 | 5 | // Service describes a service that adds things together. 6 | // Service realization should be in addsvc/service package. 7 | // 8 | // @microgen middleware, logging, grpc, http, recovering, error-logging, tracing, caching, metrics 9 | // @protobuf github.com/devimteam/microgen/examples/protobuf 10 | type Service interface { 11 | Sum(ctx context.Context, a, b int) (result int, err error) 12 | Concat(ctx context.Context, a, b string) (result string, err error) 13 | } 14 | -------------------------------------------------------------------------------- /examples/addsvc/cmd/service/main.go: -------------------------------------------------------------------------------- 1 | // Microgen appends missed functions. 2 | package main 3 | 4 | import ( 5 | "context" 6 | "errors" 7 | "fmt" 8 | addsvc "github.com/devimteam/microgen/examples/addsvc/addsvc" 9 | service "github.com/devimteam/microgen/examples/addsvc/service" 10 | transport "github.com/devimteam/microgen/examples/addsvc/transport" 11 | grpc "github.com/devimteam/microgen/examples/addsvc/transport/grpc" 12 | http "github.com/devimteam/microgen/examples/addsvc/transport/http" 13 | protobuf "github.com/devimteam/microgen/examples/protobuf" 14 | log "github.com/go-kit/kit/log" 15 | opentracinggo "github.com/opentracing/opentracing-go" 16 | errgroup "golang.org/x/sync/errgroup" 17 | grpc1 "google.golang.org/grpc" 18 | "io" 19 | "net" 20 | http1 "net/http" 21 | "os" 22 | "os/signal" 23 | "syscall" 24 | ) 25 | 26 | func main() { 27 | logger := log.With(InitLogger(os.Stdout), "level", "info") 28 | errorLogger := log.With(InitLogger(os.Stderr), "level", "error") 29 | logger.Log("message", "Hello, I am alive") 30 | defer logger.Log("message", "goodbye, good luck") 31 | 32 | g, ctx := errgroup.WithContext(context.Background()) 33 | g.Go(func() error { 34 | return InterruptHandler(ctx) 35 | }) 36 | 37 | var svc addsvc.Service // TODO: = service.NewService () // Create new service. 38 | svc = service.LoggingMiddleware(logger)(svc) // Setup service logging. 39 | svc = service.ErrorLoggingMiddleware(logger)(svc) // Setup error logging. 40 | svc = service.RecoveringMiddleware(errorLogger)(svc) // Setup service recovering. 41 | 42 | endpoints := transport.Endpoints(svc) 43 | endpoints = transport.TraceServerEndpoints(endpoints, opentracinggo.NoopTracer{}) // TODO: Add tracer 44 | 45 | grpcAddr := ":8081" // TODO: use normal address 46 | // Start grpc server. 47 | g.Go(func() error { 48 | return ServeGRPC(ctx, &endpoints, grpcAddr, log.With(logger, "transport", "GRPC")) 49 | }) 50 | 51 | httpAddr := ":8080" // TODO: use normal address 52 | // Start http server. 53 | g.Go(func() error { 54 | return ServeHTTP(ctx, &endpoints, httpAddr, log.With(logger, "transport", "HTTP")) 55 | }) 56 | 57 | if err := g.Wait(); err != nil { 58 | logger.Log("error", err) 59 | } 60 | } 61 | 62 | // InitLogger initialize go-kit JSON logger with timestamp and caller. 63 | func InitLogger(writer io.Writer) log.Logger { 64 | logger := log.NewJSONLogger(writer) 65 | logger = log.With(logger, "@timestamp", log.DefaultTimestampUTC) 66 | logger = log.With(logger, "caller", log.DefaultCaller) 67 | return logger 68 | } 69 | 70 | // InterruptHandler handles first SIGINT and SIGTERM and returns it as error. 71 | func InterruptHandler(ctx context.Context) error { 72 | interruptHandler := make(chan os.Signal, 1) 73 | signal.Notify(interruptHandler, syscall.SIGINT, syscall.SIGTERM) 74 | select { 75 | case sig := <-interruptHandler: 76 | return fmt.Errorf("signal received: %v", sig.String()) 77 | case <-ctx.Done(): 78 | return errors.New("signal listener: context canceled") 79 | } 80 | } 81 | 82 | // ServeGRPC starts new GRPC server on address and sends first error to channel. 83 | func ServeGRPC(ctx context.Context, endpoints *transport.EndpointsSet, addr string, logger log.Logger) error { 84 | listener, err := net.Listen("tcp", addr) 85 | if err != nil { 86 | return err 87 | } 88 | // Here you can add middlewares for grpc server. 89 | server := grpc.NewGRPCServer(endpoints, 90 | logger, 91 | opentracinggo.NoopTracer{}, // TODO: Add tracer 92 | ) 93 | grpcServer := grpc1.NewServer() 94 | protobuf.RegisterServiceServer(grpcServer, server) 95 | logger.Log("listen on", addr) 96 | ch := make(chan error) 97 | go func() { 98 | ch <- grpcServer.Serve(listener) 99 | }() 100 | select { 101 | case err := <-ch: 102 | return fmt.Errorf("grpc server: serve: %v", err) 103 | case <-ctx.Done(): 104 | grpcServer.GracefulStop() 105 | return errors.New("grpc server: context canceled") 106 | } 107 | } 108 | 109 | // ServeHTTP starts new HTTP server on address and sends first error to channel. 110 | func ServeHTTP(ctx context.Context, endpoints *transport.EndpointsSet, addr string, logger log.Logger) error { 111 | handler := http.NewHTTPHandler(endpoints, 112 | logger, 113 | opentracinggo.NoopTracer{}, // TODO: Add tracer 114 | ) 115 | httpServer := &http1.Server{ 116 | Addr: addr, 117 | Handler: handler, 118 | } 119 | logger.Log("listen on", addr) 120 | ch := make(chan error) 121 | go func() { 122 | ch <- httpServer.ListenAndServe() 123 | }() 124 | select { 125 | case err := <-ch: 126 | if err == http1.ErrServerClosed { 127 | return nil 128 | } 129 | return fmt.Errorf("http server: serve: %v", err) 130 | case <-ctx.Done(): 131 | return httpServer.Shutdown(context.Background()) 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /examples/addsvc/service/caching.microgen.go: -------------------------------------------------------------------------------- 1 | // Code generated by microgen 0.9.0. DO NOT EDIT. 2 | 3 | package service 4 | 5 | import ( 6 | "context" 7 | service "github.com/devimteam/microgen/examples/addsvc/addsvc" 8 | log "github.com/go-kit/kit/log" 9 | ) 10 | 11 | // Cache interface uses for middleware as key-value storage for requests. 12 | type Cache interface { 13 | Set(key, value interface{}) (err error) 14 | Get(key interface{}) (value interface{}, err error) 15 | } 16 | 17 | func CachingMiddleware(cache Cache) Middleware { 18 | return func(next service.Service) service.Service { 19 | return &cachingMiddleware{ 20 | cache: cache, 21 | next: next, 22 | } 23 | } 24 | } 25 | 26 | type cachingMiddleware struct { 27 | cache Cache 28 | logger log.Logger 29 | next service.Service 30 | } 31 | 32 | func (M cachingMiddleware) Sum(ctx context.Context, a int, b int) (res0 int, res1 error) { 33 | return M.next.Sum(ctx, a, b) 34 | } 35 | 36 | func (M cachingMiddleware) Concat(ctx context.Context, a string, b string) (res0 string, res1 error) { 37 | return M.next.Concat(ctx, a, b) 38 | } 39 | 40 | type sumResponseCacheEntity struct { 41 | Result int 42 | } 43 | type concatResponseCacheEntity struct { 44 | Result string 45 | } 46 | -------------------------------------------------------------------------------- /examples/addsvc/service/error_logging.microgen.go: -------------------------------------------------------------------------------- 1 | // Code generated by microgen 0.9.0. DO NOT EDIT. 2 | 3 | package service 4 | 5 | import ( 6 | "context" 7 | service "github.com/devimteam/microgen/examples/addsvc/addsvc" 8 | log "github.com/go-kit/kit/log" 9 | ) 10 | 11 | // ErrorLoggingMiddleware writes to logger any error, if it is not nil. 12 | func ErrorLoggingMiddleware(logger log.Logger) Middleware { 13 | return func(next service.Service) service.Service { 14 | return &errorLoggingMiddleware{ 15 | logger: logger, 16 | next: next, 17 | } 18 | } 19 | } 20 | 21 | type errorLoggingMiddleware struct { 22 | logger log.Logger 23 | next service.Service 24 | } 25 | 26 | func (M errorLoggingMiddleware) Sum(ctx context.Context, a int, b int) (result int, err error) { 27 | defer func() { 28 | if err != nil { 29 | M.logger.Log("method", "Sum", "message", err) 30 | } 31 | }() 32 | return M.next.Sum(ctx, a, b) 33 | } 34 | 35 | func (M errorLoggingMiddleware) Concat(ctx context.Context, a string, b string) (result string, err error) { 36 | defer func() { 37 | if err != nil { 38 | M.logger.Log("method", "Concat", "message", err) 39 | } 40 | }() 41 | return M.next.Concat(ctx, a, b) 42 | } 43 | -------------------------------------------------------------------------------- /examples/addsvc/service/logging.microgen.go: -------------------------------------------------------------------------------- 1 | // Code generated by microgen 0.9.0. DO NOT EDIT. 2 | 3 | package service 4 | 5 | import ( 6 | "context" 7 | service "github.com/devimteam/microgen/examples/addsvc/addsvc" 8 | log "github.com/go-kit/kit/log" 9 | "time" 10 | ) 11 | 12 | // LoggingMiddleware writes params, results and working time of method call to provided logger after its execution. 13 | func LoggingMiddleware(logger log.Logger) Middleware { 14 | return func(next service.Service) service.Service { 15 | return &loggingMiddleware{ 16 | logger: logger, 17 | next: next, 18 | } 19 | } 20 | } 21 | 22 | type loggingMiddleware struct { 23 | logger log.Logger 24 | next service.Service 25 | } 26 | 27 | func (M loggingMiddleware) Sum(arg0 context.Context, arg1 int, arg2 int) (res0 int, res1 error) { 28 | defer func(begin time.Time) { 29 | M.logger.Log( 30 | "method", "Sum", 31 | "request", logSumRequest{ 32 | A: arg1, 33 | B: arg2, 34 | }, 35 | "response", logSumResponse{Result: res0}, 36 | "err", res1, 37 | "took", time.Since(begin)) 38 | }(time.Now()) 39 | return M.next.Sum(arg0, arg1, arg2) 40 | } 41 | 42 | func (M loggingMiddleware) Concat(arg0 context.Context, arg1 string, arg2 string) (res0 string, res1 error) { 43 | defer func(begin time.Time) { 44 | M.logger.Log( 45 | "method", "Concat", 46 | "request", logConcatRequest{ 47 | A: arg1, 48 | B: arg2, 49 | }, 50 | "response", logConcatResponse{Result: res0}, 51 | "err", res1, 52 | "took", time.Since(begin)) 53 | }(time.Now()) 54 | return M.next.Concat(arg0, arg1, arg2) 55 | } 56 | 57 | type ( 58 | logSumRequest struct { 59 | A int 60 | B int 61 | } 62 | logSumResponse struct { 63 | Result int 64 | } 65 | logConcatRequest struct { 66 | A string 67 | B string 68 | } 69 | logConcatResponse struct { 70 | Result string 71 | } 72 | ) 73 | -------------------------------------------------------------------------------- /examples/addsvc/service/middleware.microgen.go: -------------------------------------------------------------------------------- 1 | // Code generated by microgen 0.9.0. DO NOT EDIT. 2 | 3 | package service 4 | 5 | import service "github.com/devimteam/microgen/examples/addsvc/addsvc" 6 | 7 | // Service middleware (closure). 8 | type Middleware func(service.Service) service.Service 9 | -------------------------------------------------------------------------------- /examples/addsvc/service/recovering.microgen.go: -------------------------------------------------------------------------------- 1 | // Code generated by microgen 0.9.0. DO NOT EDIT. 2 | 3 | package service 4 | 5 | import ( 6 | "context" 7 | "fmt" 8 | service "github.com/devimteam/microgen/examples/addsvc/addsvc" 9 | log "github.com/go-kit/kit/log" 10 | ) 11 | 12 | // RecoveringMiddleware recovers panics from method calls, writes to provided logger and returns the error of panic as method error. 13 | func RecoveringMiddleware(logger log.Logger) Middleware { 14 | return func(next service.Service) service.Service { 15 | return &recoveringMiddleware{ 16 | logger: logger, 17 | next: next, 18 | } 19 | } 20 | } 21 | 22 | type recoveringMiddleware struct { 23 | logger log.Logger 24 | next service.Service 25 | } 26 | 27 | func (M recoveringMiddleware) Sum(ctx context.Context, a int, b int) (result int, err error) { 28 | defer func() { 29 | if r := recover(); r != nil { 30 | M.logger.Log("method", "Sum", "message", r) 31 | err = fmt.Errorf("%v", r) 32 | } 33 | }() 34 | return M.next.Sum(ctx, a, b) 35 | } 36 | 37 | func (M recoveringMiddleware) Concat(ctx context.Context, a string, b string) (result string, err error) { 38 | defer func() { 39 | if r := recover(); r != nil { 40 | M.logger.Log("method", "Concat", "message", r) 41 | err = fmt.Errorf("%v", r) 42 | } 43 | }() 44 | return M.next.Concat(ctx, a, b) 45 | } 46 | -------------------------------------------------------------------------------- /examples/addsvc/transport/client.microgen.go: -------------------------------------------------------------------------------- 1 | // Code generated by microgen 0.9.0. DO NOT EDIT. 2 | 3 | package transport 4 | 5 | import ( 6 | "context" 7 | "errors" 8 | opentracing "github.com/go-kit/kit/tracing/opentracing" 9 | opentracinggo "github.com/opentracing/opentracing-go" 10 | codes "google.golang.org/grpc/codes" 11 | status "google.golang.org/grpc/status" 12 | ) 13 | 14 | // TraceClientEndpoints is used for tracing endpoints on client side. 15 | func TraceClientEndpoints(endpoints EndpointsSet, tracer opentracinggo.Tracer) EndpointsSet { 16 | return EndpointsSet{ 17 | ConcatEndpoint: opentracing.TraceClient(tracer, "Concat")(endpoints.ConcatEndpoint), 18 | SumEndpoint: opentracing.TraceClient(tracer, "Sum")(endpoints.SumEndpoint), 19 | } 20 | } 21 | 22 | func (set EndpointsSet) Sum(arg0 context.Context, arg1 int, arg2 int) (res0 int, res1 error) { 23 | request := SumRequest{ 24 | A: arg1, 25 | B: arg2, 26 | } 27 | response, res1 := set.SumEndpoint(arg0, &request) 28 | if res1 != nil { 29 | if e, ok := status.FromError(res1); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { 30 | res1 = errors.New(e.Message()) 31 | } 32 | return 33 | } 34 | return response.(*SumResponse).Result, res1 35 | } 36 | 37 | func (set EndpointsSet) Concat(arg0 context.Context, arg1 string, arg2 string) (res0 string, res1 error) { 38 | request := ConcatRequest{ 39 | A: arg1, 40 | B: arg2, 41 | } 42 | response, res1 := set.ConcatEndpoint(arg0, &request) 43 | if res1 != nil { 44 | if e, ok := status.FromError(res1); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { 45 | res1 = errors.New(e.Message()) 46 | } 47 | return 48 | } 49 | return response.(*ConcatResponse).Result, res1 50 | } 51 | -------------------------------------------------------------------------------- /examples/addsvc/transport/endpoints.microgen.go: -------------------------------------------------------------------------------- 1 | // Code generated by microgen 0.9.0. DO NOT EDIT. 2 | 3 | package transport 4 | 5 | import ( 6 | "context" 7 | "fmt" 8 | endpoint "github.com/go-kit/kit/endpoint" 9 | metrics "github.com/go-kit/kit/metrics" 10 | opentracing "github.com/go-kit/kit/tracing/opentracing" 11 | opentracinggo "github.com/opentracing/opentracing-go" 12 | "time" 13 | ) 14 | 15 | // EndpointsSet implements Service API and used for transport purposes. 16 | type EndpointsSet struct { 17 | SumEndpoint endpoint.Endpoint 18 | ConcatEndpoint endpoint.Endpoint 19 | } 20 | 21 | func InstrumentingEndpoints(endpoints EndpointsSet, tracer opentracinggo.Tracer) EndpointsSet { 22 | return EndpointsSet{ 23 | ConcatEndpoint: opentracing.TraceServer(tracer, "Concat")(endpoints.ConcatEndpoint), 24 | SumEndpoint: opentracing.TraceServer(tracer, "Sum")(endpoints.SumEndpoint), 25 | } 26 | } 27 | 28 | func LatencyMiddleware(dur metrics.Histogram, methodName string) endpoint.Middleware { 29 | return func(next endpoint.Endpoint) endpoint.Endpoint { 30 | dur := dur.With("method", methodName) 31 | return func(ctx context.Context, request interface{}) (response interface{}, err error) { 32 | defer func(begin time.Time) { 33 | dur.With("success", fmt.Sprint(err == nil)).Observe(time.Since(begin).Seconds()) 34 | }(time.Now()) 35 | return next(ctx, request) 36 | } 37 | } 38 | } 39 | 40 | func RequestFrequencyMiddleware(freq metrics.Gauge, methodName string) endpoint.Middleware { 41 | return func(next endpoint.Endpoint) endpoint.Endpoint { 42 | freq := freq.With("method", methodName) 43 | return func(ctx context.Context, request interface{}) (interface{}, error) { 44 | freq.Add(1) 45 | response, err := next(ctx, request) 46 | freq.Add(-1) 47 | return response, err 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /examples/addsvc/transport/exchanges.microgen.go: -------------------------------------------------------------------------------- 1 | // Code generated by microgen 0.9.0. DO NOT EDIT. 2 | 3 | package transport 4 | 5 | type ( 6 | SumRequest struct { 7 | A int `json:"a"` 8 | B int `json:"b"` 9 | } 10 | SumResponse struct { 11 | Result int `json:"result"` 12 | } 13 | 14 | ConcatRequest struct { 15 | A string `json:"a"` 16 | B string `json:"b"` 17 | } 18 | ConcatResponse struct { 19 | Result string `json:"result"` 20 | } 21 | ) 22 | -------------------------------------------------------------------------------- /examples/addsvc/transport/grpc/client.microgen.go: -------------------------------------------------------------------------------- 1 | // Code generated by microgen 0.9.0. DO NOT EDIT. 2 | 3 | package transportgrpc 4 | 5 | import ( 6 | transport "github.com/devimteam/microgen/examples/addsvc/transport" 7 | pb "github.com/devimteam/microgen/examples/protobuf" 8 | log "github.com/go-kit/kit/log" 9 | opentracing "github.com/go-kit/kit/tracing/opentracing" 10 | grpckit "github.com/go-kit/kit/transport/grpc" 11 | opentracinggo "github.com/opentracing/opentracing-go" 12 | grpc "google.golang.org/grpc" 13 | ) 14 | 15 | func NewGRPCClient(conn *grpc.ClientConn, addr string, opts ...grpckit.ClientOption) transport.EndpointsSet { 16 | return transport.EndpointsSet{ 17 | ConcatEndpoint: grpckit.NewClient( 18 | conn, addr, "Concat", 19 | _Encode_Concat_Request, 20 | _Decode_Concat_Response, 21 | pb.ConcatResponse{}, 22 | opts..., 23 | ).Endpoint(), 24 | SumEndpoint: grpckit.NewClient( 25 | conn, addr, "Sum", 26 | _Encode_Sum_Request, 27 | _Decode_Sum_Response, 28 | pb.SumResponse{}, 29 | opts..., 30 | ).Endpoint(), 31 | } 32 | } 33 | 34 | func TracingGRPCClientOptions(tracer opentracinggo.Tracer, logger log.Logger) func([]grpckit.ClientOption) []grpckit.ClientOption { 35 | return func(opts []grpckit.ClientOption) []grpckit.ClientOption { 36 | return append(opts, grpckit.ClientBefore( 37 | opentracing.ContextToGRPC(tracer, logger), 38 | )) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /examples/addsvc/transport/grpc/protobuf_endpoint_converters.microgen.go: -------------------------------------------------------------------------------- 1 | // Code generated by microgen 0.9.0. DO NOT EDIT. 2 | 3 | // Please, do not change functions names! 4 | package transportgrpc 5 | 6 | import ( 7 | "context" 8 | "errors" 9 | transport "github.com/devimteam/microgen/examples/addsvc/transport" 10 | pb "github.com/devimteam/microgen/examples/protobuf" 11 | ) 12 | 13 | func _Encode_Sum_Request(ctx context.Context, request interface{}) (interface{}, error) { 14 | if request == nil { 15 | return nil, errors.New("nil SumRequest") 16 | } 17 | req := request.(*transport.SumRequest) 18 | return &pb.SumRequest{ 19 | A: int64(req.A), 20 | B: int64(req.B), 21 | }, nil 22 | } 23 | 24 | func _Encode_Concat_Request(ctx context.Context, request interface{}) (interface{}, error) { 25 | if request == nil { 26 | return nil, errors.New("nil ConcatRequest") 27 | } 28 | req := request.(*transport.ConcatRequest) 29 | return &pb.ConcatRequest{ 30 | A: req.A, 31 | B: req.B, 32 | }, nil 33 | } 34 | 35 | func _Encode_Sum_Response(ctx context.Context, response interface{}) (interface{}, error) { 36 | if response == nil { 37 | return nil, errors.New("nil SumResponse") 38 | } 39 | resp := response.(*transport.SumResponse) 40 | return &pb.SumResponse{Result: int64(resp.Result)}, nil 41 | } 42 | 43 | func _Encode_Concat_Response(ctx context.Context, response interface{}) (interface{}, error) { 44 | if response == nil { 45 | return nil, errors.New("nil ConcatResponse") 46 | } 47 | resp := response.(*transport.ConcatResponse) 48 | return &pb.ConcatResponse{Result: resp.Result}, nil 49 | } 50 | 51 | func _Decode_Sum_Request(ctx context.Context, request interface{}) (interface{}, error) { 52 | if request == nil { 53 | return nil, errors.New("nil SumRequest") 54 | } 55 | req := request.(*pb.SumRequest) 56 | return &transport.SumRequest{ 57 | A: int(req.A), 58 | B: int(req.B), 59 | }, nil 60 | } 61 | 62 | func _Decode_Concat_Request(ctx context.Context, request interface{}) (interface{}, error) { 63 | if request == nil { 64 | return nil, errors.New("nil ConcatRequest") 65 | } 66 | req := request.(*pb.ConcatRequest) 67 | return &transport.ConcatRequest{ 68 | A: string(req.A), 69 | B: string(req.B), 70 | }, nil 71 | } 72 | 73 | func _Decode_Sum_Response(ctx context.Context, response interface{}) (interface{}, error) { 74 | if response == nil { 75 | return nil, errors.New("nil SumResponse") 76 | } 77 | resp := response.(*pb.SumResponse) 78 | return &transport.SumResponse{Result: int(resp.Result)}, nil 79 | } 80 | 81 | func _Decode_Concat_Response(ctx context.Context, response interface{}) (interface{}, error) { 82 | if response == nil { 83 | return nil, errors.New("nil ConcatResponse") 84 | } 85 | resp := response.(*pb.ConcatResponse) 86 | return &transport.ConcatResponse{Result: string(resp.Result)}, nil 87 | } 88 | -------------------------------------------------------------------------------- /examples/addsvc/transport/grpc/protobuf_type_converters.microgen.go: -------------------------------------------------------------------------------- 1 | // Code generated by microgen 0.9.0. DO NOT EDIT. 2 | 3 | // It is better for you if you do not change functions names! 4 | // This file will never be overwritten. 5 | package transportgrpc 6 | -------------------------------------------------------------------------------- /examples/addsvc/transport/grpc/server.microgen.go: -------------------------------------------------------------------------------- 1 | // Code generated by microgen 0.9.0. DO NOT EDIT. 2 | 3 | // DO NOT EDIT. 4 | package transportgrpc 5 | 6 | import ( 7 | transport "github.com/devimteam/microgen/examples/addsvc/transport" 8 | pb "github.com/devimteam/microgen/examples/protobuf" 9 | log "github.com/go-kit/kit/log" 10 | opentracing "github.com/go-kit/kit/tracing/opentracing" 11 | grpc "github.com/go-kit/kit/transport/grpc" 12 | opentracinggo "github.com/opentracing/opentracing-go" 13 | context "golang.org/x/net/context" 14 | ) 15 | 16 | type serviceServer struct { 17 | sum grpc.Handler 18 | concat grpc.Handler 19 | } 20 | 21 | func NewGRPCServer(endpoints *transport.EndpointsSet, logger log.Logger, tracer opentracinggo.Tracer, opts ...grpc.ServerOption) pb.ServiceServer { 22 | return &serviceServer{ 23 | concat: grpc.NewServer( 24 | endpoints.ConcatEndpoint, 25 | _Decode_Concat_Request, 26 | _Encode_Concat_Response, 27 | append(opts, grpc.ServerBefore( 28 | opentracing.GRPCToContext(tracer, "Concat", logger)))..., 29 | ), 30 | sum: grpc.NewServer( 31 | endpoints.SumEndpoint, 32 | _Decode_Sum_Request, 33 | _Encode_Sum_Response, 34 | append(opts, grpc.ServerBefore( 35 | opentracing.GRPCToContext(tracer, "Sum", logger)))..., 36 | ), 37 | } 38 | } 39 | 40 | func (S *serviceServer) Sum(ctx context.Context, req *pb.SumRequest) (*pb.SumResponse, error) { 41 | _, resp, err := S.sum.ServeGRPC(ctx, req) 42 | if err != nil { 43 | return nil, err 44 | } 45 | return resp.(*pb.SumResponse), nil 46 | } 47 | 48 | func (S *serviceServer) Concat(ctx context.Context, req *pb.ConcatRequest) (*pb.ConcatResponse, error) { 49 | _, resp, err := S.concat.ServeGRPC(ctx, req) 50 | if err != nil { 51 | return nil, err 52 | } 53 | return resp.(*pb.ConcatResponse), nil 54 | } 55 | -------------------------------------------------------------------------------- /examples/addsvc/transport/http/client.microgen.go: -------------------------------------------------------------------------------- 1 | // Code generated by microgen 0.9.0. DO NOT EDIT. 2 | 3 | package transporthttp 4 | 5 | import ( 6 | transport "github.com/devimteam/microgen/examples/addsvc/transport" 7 | log "github.com/go-kit/kit/log" 8 | opentracing "github.com/go-kit/kit/tracing/opentracing" 9 | httpkit "github.com/go-kit/kit/transport/http" 10 | opentracinggo "github.com/opentracing/opentracing-go" 11 | "net/url" 12 | ) 13 | 14 | func NewHTTPClient(u *url.URL, opts ...httpkit.ClientOption) transport.EndpointsSet { 15 | return transport.EndpointsSet{ 16 | ConcatEndpoint: httpkit.NewClient( 17 | "POST", u, 18 | _Encode_Concat_Request, 19 | _Decode_Concat_Response, 20 | opts..., 21 | ).Endpoint(), 22 | SumEndpoint: httpkit.NewClient( 23 | "POST", u, 24 | _Encode_Sum_Request, 25 | _Decode_Sum_Response, 26 | opts..., 27 | ).Endpoint(), 28 | } 29 | } 30 | 31 | func TracingHTTPClientOptions(tracer opentracinggo.Tracer, logger log.Logger) func([]httpkit.ClientOption) []httpkit.ClientOption { 32 | return func(opts []httpkit.ClientOption) []httpkit.ClientOption { 33 | return append(opts, httpkit.ClientBefore( 34 | opentracing.ContextToHTTP(tracer, logger), 35 | )) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /examples/addsvc/transport/http/converters.microgen.go: -------------------------------------------------------------------------------- 1 | // Code generated by microgen 0.9.0. DO NOT EDIT. 2 | 3 | // Please, do not change functions names! 4 | package transporthttp 5 | 6 | import ( 7 | "bytes" 8 | "context" 9 | "encoding/json" 10 | transport "github.com/devimteam/microgen/examples/addsvc/transport" 11 | "io/ioutil" 12 | "net/http" 13 | "path" 14 | ) 15 | 16 | func CommonHTTPRequestEncoder(_ context.Context, r *http.Request, request interface{}) error { 17 | var buf bytes.Buffer 18 | if err := json.NewEncoder(&buf).Encode(request); err != nil { 19 | return err 20 | } 21 | r.Body = ioutil.NopCloser(&buf) 22 | return nil 23 | } 24 | 25 | func CommonHTTPResponseEncoder(_ context.Context, w http.ResponseWriter, response interface{}) error { 26 | w.Header().Set("Content-Type", "application/json; charset=utf-8") 27 | return json.NewEncoder(w).Encode(response) 28 | } 29 | 30 | func _Decode_Sum_Request(_ context.Context, r *http.Request) (interface{}, error) { 31 | var req transport.SumRequest 32 | err := json.NewDecoder(r.Body).Decode(&req) 33 | return &req, err 34 | } 35 | 36 | func _Decode_Concat_Request(_ context.Context, r *http.Request) (interface{}, error) { 37 | var req transport.ConcatRequest 38 | err := json.NewDecoder(r.Body).Decode(&req) 39 | return &req, err 40 | } 41 | 42 | func _Decode_Sum_Response(_ context.Context, r *http.Response) (interface{}, error) { 43 | var resp transport.SumResponse 44 | err := json.NewDecoder(r.Body).Decode(&resp) 45 | return &resp, err 46 | } 47 | 48 | func _Decode_Concat_Response(_ context.Context, r *http.Response) (interface{}, error) { 49 | var resp transport.ConcatResponse 50 | err := json.NewDecoder(r.Body).Decode(&resp) 51 | return &resp, err 52 | } 53 | 54 | func _Encode_Sum_Request(ctx context.Context, r *http.Request, request interface{}) error { 55 | r.URL.Path = path.Join(r.URL.Path, "sum") 56 | return CommonHTTPRequestEncoder(ctx, r, request) 57 | } 58 | 59 | func _Encode_Concat_Request(ctx context.Context, r *http.Request, request interface{}) error { 60 | r.URL.Path = path.Join(r.URL.Path, "concat") 61 | return CommonHTTPRequestEncoder(ctx, r, request) 62 | } 63 | 64 | func _Encode_Sum_Response(ctx context.Context, w http.ResponseWriter, response interface{}) error { 65 | return CommonHTTPResponseEncoder(ctx, w, response) 66 | } 67 | 68 | func _Encode_Concat_Response(ctx context.Context, w http.ResponseWriter, response interface{}) error { 69 | return CommonHTTPResponseEncoder(ctx, w, response) 70 | } 71 | -------------------------------------------------------------------------------- /examples/addsvc/transport/http/server.microgen.go: -------------------------------------------------------------------------------- 1 | // Code generated by microgen 0.9.0. DO NOT EDIT. 2 | 3 | package transporthttp 4 | 5 | import ( 6 | transport "github.com/devimteam/microgen/examples/addsvc/transport" 7 | log "github.com/go-kit/kit/log" 8 | opentracing "github.com/go-kit/kit/tracing/opentracing" 9 | http "github.com/go-kit/kit/transport/http" 10 | mux "github.com/gorilla/mux" 11 | opentracinggo "github.com/opentracing/opentracing-go" 12 | http1 "net/http" 13 | ) 14 | 15 | func NewHTTPHandler(endpoints *transport.EndpointsSet, logger log.Logger, tracer opentracinggo.Tracer, opts ...http.ServerOption) http1.Handler { 16 | mux := mux.NewRouter() 17 | mux.Methods("POST").Path("/sum").Handler( 18 | http.NewServer( 19 | endpoints.SumEndpoint, 20 | _Decode_Sum_Request, 21 | _Encode_Sum_Response, 22 | append(opts, http.ServerBefore( 23 | opentracing.HTTPToContext(tracer, "Sum", logger)))...)) 24 | mux.Methods("POST").Path("/concat").Handler( 25 | http.NewServer( 26 | endpoints.ConcatEndpoint, 27 | _Decode_Concat_Request, 28 | _Encode_Concat_Response, 29 | append(opts, http.ServerBefore( 30 | opentracing.HTTPToContext(tracer, "Concat", logger)))...)) 31 | return mux 32 | } 33 | -------------------------------------------------------------------------------- /examples/addsvc/transport/server.microgen.go: -------------------------------------------------------------------------------- 1 | // Code generated by microgen 0.9.0. DO NOT EDIT. 2 | 3 | package transport 4 | 5 | import ( 6 | "context" 7 | addsvc "github.com/devimteam/microgen/examples/addsvc/addsvc" 8 | endpoint "github.com/go-kit/kit/endpoint" 9 | opentracing "github.com/go-kit/kit/tracing/opentracing" 10 | opentracinggo "github.com/opentracing/opentracing-go" 11 | ) 12 | 13 | func Endpoints(svc addsvc.Service) EndpointsSet { 14 | return EndpointsSet{ 15 | ConcatEndpoint: ConcatEndpoint(svc), 16 | SumEndpoint: SumEndpoint(svc), 17 | } 18 | } 19 | 20 | // TraceServerEndpoints is used for tracing endpoints on server side. 21 | func TraceServerEndpoints(endpoints EndpointsSet, tracer opentracinggo.Tracer) EndpointsSet { 22 | return EndpointsSet{ 23 | ConcatEndpoint: opentracing.TraceServer(tracer, "Concat")(endpoints.ConcatEndpoint), 24 | SumEndpoint: opentracing.TraceServer(tracer, "Sum")(endpoints.SumEndpoint), 25 | } 26 | } 27 | 28 | func SumEndpoint(svc addsvc.Service) endpoint.Endpoint { 29 | return func(arg0 context.Context, request interface{}) (interface{}, error) { 30 | req := request.(*SumRequest) 31 | res0, res1 := svc.Sum(arg0, req.A, req.B) 32 | return &SumResponse{Result: res0}, res1 33 | } 34 | } 35 | 36 | func ConcatEndpoint(svc addsvc.Service) endpoint.Endpoint { 37 | return func(arg0 context.Context, request interface{}) (interface{}, error) { 38 | req := request.(*ConcatRequest) 39 | res0, res1 := svc.Concat(arg0, req.A, req.B) 40 | return &ConcatResponse{Result: res0}, res1 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /examples/generated/cmd/string_service/main.go: -------------------------------------------------------------------------------- 1 | // Microgen appends missed functions. 2 | package main 3 | 4 | import ( 5 | "context" 6 | "errors" 7 | "fmt" 8 | generated "github.com/devimteam/microgen/examples/generated" 9 | service "github.com/devimteam/microgen/examples/generated/service" 10 | transport "github.com/devimteam/microgen/examples/generated/transport" 11 | grpc "github.com/devimteam/microgen/examples/generated/transport/grpc" 12 | http "github.com/devimteam/microgen/examples/generated/transport/http" 13 | protobuf "github.com/devimteam/microgen/examples/protobuf" 14 | log "github.com/go-kit/kit/log" 15 | opentracinggo "github.com/opentracing/opentracing-go" 16 | errgroup "golang.org/x/sync/errgroup" 17 | grpc1 "google.golang.org/grpc" 18 | "io" 19 | "net" 20 | http1 "net/http" 21 | "os" 22 | "os/signal" 23 | "syscall" 24 | ) 25 | 26 | func main() { 27 | logger := log.With(InitLogger(os.Stdout), "level", "info") 28 | errorLogger := log.With(InitLogger(os.Stderr), "level", "error") 29 | logger.Log("message", "Hello, I am alive") 30 | defer logger.Log("message", "goodbye, good luck") 31 | 32 | g, ctx := errgroup.WithContext(context.Background()) 33 | g.Go(func() error { 34 | return InterruptHandler(ctx) 35 | }) 36 | 37 | var svc generated.StringService // TODO: = service.NewStringService () // Create new service. 38 | svc = service.LoggingMiddleware(logger)(svc) // Setup service logging. 39 | svc = service.ErrorLoggingMiddleware(logger)(svc) // Setup error logging. 40 | svc = service.RecoveringMiddleware(errorLogger)(svc) // Setup service recovering. 41 | 42 | endpoints := transport.Endpoints(svc) 43 | endpoints = transport.TraceServerEndpoints(endpoints, opentracinggo.NoopTracer{}) // TODO: Add tracer 44 | 45 | grpcAddr := ":8081" // TODO: use normal address 46 | // Start grpc server. 47 | g.Go(func() error { 48 | return ServeGRPC(ctx, &endpoints, grpcAddr, log.With(logger, "transport", "GRPC")) 49 | }) 50 | 51 | httpAddr := ":8080" // TODO: use normal address 52 | // Start http server. 53 | g.Go(func() error { 54 | return ServeHTTP(ctx, &endpoints, httpAddr, log.With(logger, "transport", "HTTP")) 55 | }) 56 | 57 | if err := g.Wait(); err != nil { 58 | logger.Log("error", err) 59 | } 60 | } 61 | 62 | // InitLogger initialize go-kit JSON logger with timestamp and caller. 63 | func InitLogger(writer io.Writer) log.Logger { 64 | logger := log.NewJSONLogger(writer) 65 | logger = log.With(logger, "@timestamp", log.DefaultTimestampUTC) 66 | logger = log.With(logger, "caller", log.DefaultCaller) 67 | return logger 68 | } 69 | 70 | // InterruptHandler handles first SIGINT and SIGTERM and returns it as error. 71 | func InterruptHandler(ctx context.Context) error { 72 | interruptHandler := make(chan os.Signal, 1) 73 | signal.Notify(interruptHandler, syscall.SIGINT, syscall.SIGTERM) 74 | select { 75 | case sig := <-interruptHandler: 76 | return fmt.Errorf("signal received: %v", sig.String()) 77 | case <-ctx.Done(): 78 | return errors.New("signal listener: context canceled") 79 | } 80 | } 81 | 82 | // ServeGRPC starts new GRPC server on address and sends first error to channel. 83 | func ServeGRPC(ctx context.Context, endpoints *transport.EndpointsSet, addr string, logger log.Logger) error { 84 | listener, err := net.Listen("tcp", addr) 85 | if err != nil { 86 | return err 87 | } 88 | // Here you can add middlewares for grpc server. 89 | server := grpc.NewGRPCServer(endpoints, 90 | logger, 91 | opentracinggo.NoopTracer{}, // TODO: Add tracer 92 | ) 93 | grpcServer := grpc1.NewServer() 94 | protobuf.RegisterStringServiceServer(grpcServer, server) 95 | logger.Log("listen on", addr) 96 | ch := make(chan error) 97 | go func() { 98 | ch <- grpcServer.Serve(listener) 99 | }() 100 | select { 101 | case err := <-ch: 102 | return fmt.Errorf("grpc server: serve: %v", err) 103 | case <-ctx.Done(): 104 | grpcServer.GracefulStop() 105 | return errors.New("grpc server: context canceled") 106 | } 107 | } 108 | 109 | // ServeHTTP starts new HTTP server on address and sends first error to channel. 110 | func ServeHTTP(ctx context.Context, endpoints *transport.EndpointsSet, addr string, logger log.Logger) error { 111 | handler := http.NewHTTPHandler(endpoints, 112 | logger, 113 | opentracinggo.NoopTracer{}, // TODO: Add tracer 114 | ) 115 | httpServer := &http1.Server{ 116 | Addr: addr, 117 | Handler: handler, 118 | } 119 | logger.Log("listen on", addr) 120 | ch := make(chan error) 121 | go func() { 122 | ch <- httpServer.ListenAndServe() 123 | }() 124 | select { 125 | case err := <-ch: 126 | if err == http1.ErrServerClosed { 127 | return nil 128 | } 129 | return fmt.Errorf("http server: serve: %v", err) 130 | case <-ctx.Done(): 131 | return httpServer.Shutdown(context.Background()) 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /examples/generated/comment.go: -------------------------------------------------------------------------------- 1 | package stringsvc 2 | 3 | import "time" 4 | 5 | // Example structure 6 | type Comment struct { 7 | Text string 8 | Relates *Comment 9 | PostedAt time.Time 10 | } 11 | -------------------------------------------------------------------------------- /examples/generated/service.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | option go_package = "github.com/devimteam/microgen/examples/protobuf;pb"; 4 | 5 | package service.string; 6 | 7 | import "google/protobuf/empty.proto"; 8 | 9 | service StringService { 10 | rpc Uppercase (UppercaseRequest) returns (UppercaseResponse); 11 | rpc Count (CountRequest) returns (CountResponse); 12 | rpc TestCase (TestCaseRequest) returns (TestCaseResponse); 13 | rpc DummyMethod (google.protobuf.Empty) returns (google.protobuf.Empty); 14 | } 15 | 16 | message UppercaseRequest { 17 | map strings_map = 1; 18 | } 19 | 20 | message UppercaseResponse { 21 | string ans = 1; 22 | } 23 | 24 | message CountRequest { 25 | string text = 1; 26 | string symbol = 2; 27 | } 28 | 29 | message CountResponse { 30 | int64 count = 1; 31 | repeated int64 positions = 2; 32 | } 33 | 34 | message TestCaseRequest { 35 | repeated Comment comments = 1; 36 | } 37 | 38 | message TestCaseResponse { 39 | map tree = 1; 40 | } 41 | -------------------------------------------------------------------------------- /examples/generated/service/caching.microgen.go: -------------------------------------------------------------------------------- 1 | // Code generated by microgen 0.9.0. DO NOT EDIT. 2 | 3 | package service 4 | 5 | import ( 6 | "context" 7 | service "github.com/devimteam/microgen/examples/generated" 8 | log "github.com/go-kit/kit/log" 9 | ) 10 | 11 | // Cache interface uses for middleware as key-value storage for requests. 12 | type Cache interface { 13 | Set(key, value interface{}) (err error) 14 | Get(key interface{}) (value interface{}, err error) 15 | } 16 | 17 | func CachingMiddleware(cache Cache) Middleware { 18 | return func(next service.StringService) service.StringService { 19 | return &cachingMiddleware{ 20 | cache: cache, 21 | next: next, 22 | } 23 | } 24 | } 25 | 26 | type cachingMiddleware struct { 27 | cache Cache 28 | logger log.Logger 29 | next service.StringService 30 | } 31 | 32 | func (M cachingMiddleware) Uppercase(ctx context.Context, stringsMap map[string]string) (res0 string, res1 error) { 33 | return M.next.Uppercase(ctx, stringsMap) 34 | } 35 | 36 | func (M cachingMiddleware) Count(ctx context.Context, text string, symbol string) (res0 int, res1 []int, res2 error) { 37 | value, e := M.cache.Get(text) 38 | if e == nil { 39 | return value.(*countResponseCacheEntity).Count, value.(*countResponseCacheEntity).Positions, res2 40 | } 41 | defer func() { 42 | M.cache.Set(text, &countResponseCacheEntity{ 43 | Count: res0, 44 | Positions: res1, 45 | }) 46 | }() 47 | return M.next.Count(ctx, text, symbol) 48 | } 49 | 50 | func (M cachingMiddleware) TestCase(ctx context.Context, comments []*service.Comment) (res0 map[string]int, res1 error) { 51 | return M.next.TestCase(ctx, comments) 52 | } 53 | 54 | func (M cachingMiddleware) DummyMethod(ctx context.Context) (res0 error) { 55 | return M.next.DummyMethod(ctx) 56 | } 57 | 58 | func (M cachingMiddleware) IgnoredMethod() { 59 | M.next.IgnoredMethod() 60 | } 61 | 62 | func (M cachingMiddleware) IgnoredErrorMethod() (res0 error) { 63 | return M.next.IgnoredErrorMethod() 64 | } 65 | 66 | type uppercaseResponseCacheEntity struct { 67 | Ans string 68 | } 69 | type countResponseCacheEntity struct { 70 | Count int 71 | Positions []int 72 | } 73 | type testCaseResponseCacheEntity struct { 74 | Tree map[string]int 75 | } 76 | type dummyMethodResponseCacheEntity struct{} 77 | -------------------------------------------------------------------------------- /examples/generated/service/error_logging.microgen.go: -------------------------------------------------------------------------------- 1 | // Code generated by microgen 0.9.0. DO NOT EDIT. 2 | 3 | package service 4 | 5 | import ( 6 | "context" 7 | service "github.com/devimteam/microgen/examples/generated" 8 | log "github.com/go-kit/kit/log" 9 | ) 10 | 11 | // ErrorLoggingMiddleware writes to logger any error, if it is not nil. 12 | func ErrorLoggingMiddleware(logger log.Logger) Middleware { 13 | return func(next service.StringService) service.StringService { 14 | return &errorLoggingMiddleware{ 15 | logger: logger, 16 | next: next, 17 | } 18 | } 19 | } 20 | 21 | type errorLoggingMiddleware struct { 22 | logger log.Logger 23 | next service.StringService 24 | } 25 | 26 | func (M errorLoggingMiddleware) Uppercase(ctx context.Context, stringsMap map[string]string) (ans string, err error) { 27 | defer func() { 28 | if err != nil { 29 | M.logger.Log("method", "Uppercase", "message", err) 30 | } 31 | }() 32 | return M.next.Uppercase(ctx, stringsMap) 33 | } 34 | 35 | func (M errorLoggingMiddleware) Count(ctx context.Context, text string, symbol string) (count int, positions []int, err error) { 36 | defer func() { 37 | if err != nil { 38 | M.logger.Log("method", "Count", "message", err) 39 | } 40 | }() 41 | return M.next.Count(ctx, text, symbol) 42 | } 43 | 44 | func (M errorLoggingMiddleware) TestCase(ctx context.Context, comments []*service.Comment) (tree map[string]int, err error) { 45 | defer func() { 46 | if err != nil { 47 | M.logger.Log("method", "TestCase", "message", err) 48 | } 49 | }() 50 | return M.next.TestCase(ctx, comments) 51 | } 52 | 53 | func (M errorLoggingMiddleware) DummyMethod(ctx context.Context) (err error) { 54 | defer func() { 55 | if err != nil { 56 | M.logger.Log("method", "DummyMethod", "message", err) 57 | } 58 | }() 59 | return M.next.DummyMethod(ctx) 60 | } 61 | 62 | func (M errorLoggingMiddleware) IgnoredMethod() { 63 | M.next.IgnoredMethod() 64 | } 65 | 66 | func (M errorLoggingMiddleware) IgnoredErrorMethod() error { 67 | return M.next.IgnoredErrorMethod() 68 | } 69 | -------------------------------------------------------------------------------- /examples/generated/service/logging.microgen.go: -------------------------------------------------------------------------------- 1 | // Code generated by microgen 0.9.0. DO NOT EDIT. 2 | 3 | package service 4 | 5 | import ( 6 | "context" 7 | service "github.com/devimteam/microgen/examples/generated" 8 | log "github.com/go-kit/kit/log" 9 | "time" 10 | ) 11 | 12 | // LoggingMiddleware writes params, results and working time of method call to provided logger after its execution. 13 | func LoggingMiddleware(logger log.Logger) Middleware { 14 | return func(next service.StringService) service.StringService { 15 | return &loggingMiddleware{ 16 | logger: logger, 17 | next: next, 18 | } 19 | } 20 | } 21 | 22 | type loggingMiddleware struct { 23 | logger log.Logger 24 | next service.StringService 25 | } 26 | 27 | func (M loggingMiddleware) Uppercase(arg0 context.Context, arg1 map[string]string) (res0 string, res1 error) { 28 | defer func(begin time.Time) { 29 | M.logger.Log( 30 | "method", "Uppercase", 31 | "request", logUppercaseRequest{StringsMap: arg1}, 32 | "took", time.Since(begin)) 33 | }(time.Now()) 34 | return M.next.Uppercase(arg0, arg1) 35 | } 36 | 37 | func (M loggingMiddleware) Count(arg0 context.Context, arg1 string, arg2 string) (res0 int, res1 []int, res2 error) { 38 | defer func(begin time.Time) { 39 | M.logger.Log( 40 | "method", "Count", 41 | "request", logCountRequest{ 42 | Symbol: arg2, 43 | Text: arg1, 44 | }, 45 | "response", logCountResponse{ 46 | Count: res0, 47 | Positions: res1, 48 | }, 49 | "err", res2, 50 | "took", time.Since(begin)) 51 | }(time.Now()) 52 | return M.next.Count(arg0, arg1, arg2) 53 | } 54 | 55 | func (M loggingMiddleware) TestCase(arg0 context.Context, arg1 []*service.Comment) (res0 map[string]int, res1 error) { 56 | defer func(begin time.Time) { 57 | M.logger.Log( 58 | "method", "TestCase", 59 | "request", logTestCaseRequest{ 60 | Comments: arg1, 61 | LenComments: len(arg1), 62 | }, 63 | "response", logTestCaseResponse{Tree: res0}, 64 | "err", res1, 65 | "took", time.Since(begin)) 66 | }(time.Now()) 67 | return M.next.TestCase(arg0, arg1) 68 | } 69 | 70 | func (M loggingMiddleware) DummyMethod(arg0 context.Context) (res0 error) { 71 | defer func(begin time.Time) { 72 | M.logger.Log( 73 | "method", "DummyMethod", 74 | "err", res0, 75 | "took", time.Since(begin)) 76 | }(time.Now()) 77 | return M.next.DummyMethod(arg0) 78 | } 79 | 80 | func (M loggingMiddleware) IgnoredMethod() { 81 | M.next.IgnoredMethod() 82 | } 83 | 84 | func (M loggingMiddleware) IgnoredErrorMethod() (res0 error) { 85 | return M.next.IgnoredErrorMethod() 86 | } 87 | 88 | type ( 89 | logUppercaseRequest struct { 90 | StringsMap map[string]string 91 | } 92 | logCountRequest struct { 93 | Text string 94 | Symbol string 95 | } 96 | logCountResponse struct { 97 | Count int 98 | Positions []int 99 | } 100 | logTestCaseRequest struct { 101 | Comments []*service.Comment 102 | LenComments int `json:"len(Comments)"` 103 | } 104 | logTestCaseResponse struct { 105 | Tree map[string]int 106 | } 107 | ) 108 | -------------------------------------------------------------------------------- /examples/generated/service/middleware.microgen.go: -------------------------------------------------------------------------------- 1 | // Code generated by microgen 0.9.0. DO NOT EDIT. 2 | 3 | package service 4 | 5 | import service "github.com/devimteam/microgen/examples/generated" 6 | 7 | // Service middleware (closure). 8 | type Middleware func(service.StringService) service.StringService 9 | -------------------------------------------------------------------------------- /examples/generated/service/recovering.microgen.go: -------------------------------------------------------------------------------- 1 | // Code generated by microgen 0.9.0. DO NOT EDIT. 2 | 3 | package service 4 | 5 | import ( 6 | "context" 7 | "fmt" 8 | service "github.com/devimteam/microgen/examples/generated" 9 | log "github.com/go-kit/kit/log" 10 | ) 11 | 12 | // RecoveringMiddleware recovers panics from method calls, writes to provided logger and returns the error of panic as method error. 13 | func RecoveringMiddleware(logger log.Logger) Middleware { 14 | return func(next service.StringService) service.StringService { 15 | return &recoveringMiddleware{ 16 | logger: logger, 17 | next: next, 18 | } 19 | } 20 | } 21 | 22 | type recoveringMiddleware struct { 23 | logger log.Logger 24 | next service.StringService 25 | } 26 | 27 | func (M recoveringMiddleware) Uppercase(ctx context.Context, stringsMap map[string]string) (ans string, err error) { 28 | defer func() { 29 | if r := recover(); r != nil { 30 | M.logger.Log("method", "Uppercase", "message", r) 31 | err = fmt.Errorf("%v", r) 32 | } 33 | }() 34 | return M.next.Uppercase(ctx, stringsMap) 35 | } 36 | 37 | func (M recoveringMiddleware) Count(ctx context.Context, text string, symbol string) (count int, positions []int, err error) { 38 | defer func() { 39 | if r := recover(); r != nil { 40 | M.logger.Log("method", "Count", "message", r) 41 | err = fmt.Errorf("%v", r) 42 | } 43 | }() 44 | return M.next.Count(ctx, text, symbol) 45 | } 46 | 47 | func (M recoveringMiddleware) TestCase(ctx context.Context, comments []*service.Comment) (tree map[string]int, err error) { 48 | defer func() { 49 | if r := recover(); r != nil { 50 | M.logger.Log("method", "TestCase", "message", r) 51 | err = fmt.Errorf("%v", r) 52 | } 53 | }() 54 | return M.next.TestCase(ctx, comments) 55 | } 56 | 57 | func (M recoveringMiddleware) DummyMethod(ctx context.Context) (err error) { 58 | defer func() { 59 | if r := recover(); r != nil { 60 | M.logger.Log("method", "DummyMethod", "message", r) 61 | err = fmt.Errorf("%v", r) 62 | } 63 | }() 64 | return M.next.DummyMethod(ctx) 65 | } 66 | 67 | func (M recoveringMiddleware) IgnoredMethod() { 68 | M.next.IgnoredMethod() 69 | } 70 | 71 | func (M recoveringMiddleware) IgnoredErrorMethod() error { 72 | return M.next.IgnoredErrorMethod() 73 | } 74 | -------------------------------------------------------------------------------- /examples/generated/svc.go: -------------------------------------------------------------------------------- 1 | package stringsvc 2 | 3 | import ( 4 | "context" 5 | ) 6 | 7 | // @microgen middleware, logging, grpc, http, recovering, error-logging, tracing, caching, metrics, service-discovery 8 | // @grpc-addr service.string.StringService 9 | // @protobuf github.com/devimteam/microgen/examples/protobuf 10 | type StringService interface { 11 | // @logs-ignore ans, err 12 | // @cache 13 | Uppercase(ctx context.Context, stringsMap map[string]string) (ans string, err error) 14 | // @http-method geT 15 | // @cache-key text 16 | // @json-rpc-prefix v1. 17 | Count(ctx context.Context, text string, symbol string) (count int, positions []int, err error) 18 | // @logs-len comments 19 | TestCase(ctx context.Context, comments []*Comment) (tree map[string]int, err error) 20 | 21 | DummyMethod(ctx context.Context) (err error) 22 | 23 | // @microgen - 24 | IgnoredMethod() 25 | // @microgen - 26 | IgnoredErrorMethod() error 27 | } 28 | -------------------------------------------------------------------------------- /examples/generated/transport/client.microgen.go: -------------------------------------------------------------------------------- 1 | // Code generated by microgen 0.9.0. DO NOT EDIT. 2 | 3 | package transport 4 | 5 | import ( 6 | "context" 7 | "errors" 8 | generated "github.com/devimteam/microgen/examples/generated" 9 | opentracing "github.com/go-kit/kit/tracing/opentracing" 10 | opentracinggo "github.com/opentracing/opentracing-go" 11 | codes "google.golang.org/grpc/codes" 12 | status "google.golang.org/grpc/status" 13 | ) 14 | 15 | // TraceClientEndpoints is used for tracing endpoints on client side. 16 | func TraceClientEndpoints(endpoints EndpointsSet, tracer opentracinggo.Tracer) EndpointsSet { 17 | return EndpointsSet{ 18 | CountEndpoint: opentracing.TraceClient(tracer, "Count")(endpoints.CountEndpoint), 19 | DummyMethodEndpoint: opentracing.TraceClient(tracer, "DummyMethod")(endpoints.DummyMethodEndpoint), 20 | TestCaseEndpoint: opentracing.TraceClient(tracer, "TestCase")(endpoints.TestCaseEndpoint), 21 | UppercaseEndpoint: opentracing.TraceClient(tracer, "Uppercase")(endpoints.UppercaseEndpoint), 22 | } 23 | } 24 | 25 | func (set EndpointsSet) Uppercase(arg0 context.Context, arg1 map[string]string) (res0 string, res1 error) { 26 | request := UppercaseRequest{StringsMap: arg1} 27 | response, res1 := set.UppercaseEndpoint(arg0, &request) 28 | if res1 != nil { 29 | if e, ok := status.FromError(res1); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { 30 | res1 = errors.New(e.Message()) 31 | } 32 | return 33 | } 34 | return response.(*UppercaseResponse).Ans, res1 35 | } 36 | 37 | func (set EndpointsSet) Count(arg0 context.Context, arg1 string, arg2 string) (res0 int, res1 []int, res2 error) { 38 | request := CountRequest{ 39 | Symbol: arg2, 40 | Text: arg1, 41 | } 42 | response, res2 := set.CountEndpoint(arg0, &request) 43 | if res2 != nil { 44 | if e, ok := status.FromError(res2); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { 45 | res2 = errors.New(e.Message()) 46 | } 47 | return 48 | } 49 | return response.(*CountResponse).Count, response.(*CountResponse).Positions, res2 50 | } 51 | 52 | func (set EndpointsSet) TestCase(arg0 context.Context, arg1 []*generated.Comment) (res0 map[string]int, res1 error) { 53 | request := TestCaseRequest{Comments: arg1} 54 | response, res1 := set.TestCaseEndpoint(arg0, &request) 55 | if res1 != nil { 56 | if e, ok := status.FromError(res1); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { 57 | res1 = errors.New(e.Message()) 58 | } 59 | return 60 | } 61 | return response.(*TestCaseResponse).Tree, res1 62 | } 63 | 64 | func (set EndpointsSet) DummyMethod(arg0 context.Context) (res0 error) { 65 | request := DummyMethodRequest{} 66 | _, res0 = set.DummyMethodEndpoint(arg0, &request) 67 | if res0 != nil { 68 | if e, ok := status.FromError(res0); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { 69 | res0 = errors.New(e.Message()) 70 | } 71 | return 72 | } 73 | return res0 74 | } 75 | 76 | func (set EndpointsSet) IgnoredMethod() { 77 | return 78 | } 79 | 80 | func (set EndpointsSet) IgnoredErrorMethod() (res0 error) { 81 | return 82 | } 83 | -------------------------------------------------------------------------------- /examples/generated/transport/endpoints.microgen.go: -------------------------------------------------------------------------------- 1 | // Code generated by microgen 0.9.0. DO NOT EDIT. 2 | 3 | package transport 4 | 5 | import ( 6 | "context" 7 | "fmt" 8 | endpoint "github.com/go-kit/kit/endpoint" 9 | metrics "github.com/go-kit/kit/metrics" 10 | opentracing "github.com/go-kit/kit/tracing/opentracing" 11 | opentracinggo "github.com/opentracing/opentracing-go" 12 | "time" 13 | ) 14 | 15 | // EndpointsSet implements StringService API and used for transport purposes. 16 | type EndpointsSet struct { 17 | UppercaseEndpoint endpoint.Endpoint 18 | CountEndpoint endpoint.Endpoint 19 | TestCaseEndpoint endpoint.Endpoint 20 | DummyMethodEndpoint endpoint.Endpoint 21 | } 22 | 23 | func InstrumentingEndpoints(endpoints EndpointsSet, tracer opentracinggo.Tracer) EndpointsSet { 24 | return EndpointsSet{ 25 | CountEndpoint: opentracing.TraceServer(tracer, "Count")(endpoints.CountEndpoint), 26 | DummyMethodEndpoint: opentracing.TraceServer(tracer, "DummyMethod")(endpoints.DummyMethodEndpoint), 27 | TestCaseEndpoint: opentracing.TraceServer(tracer, "TestCase")(endpoints.TestCaseEndpoint), 28 | UppercaseEndpoint: opentracing.TraceServer(tracer, "Uppercase")(endpoints.UppercaseEndpoint), 29 | } 30 | } 31 | 32 | func LatencyMiddleware(dur metrics.Histogram, methodName string) endpoint.Middleware { 33 | return func(next endpoint.Endpoint) endpoint.Endpoint { 34 | dur := dur.With("method", methodName) 35 | return func(ctx context.Context, request interface{}) (response interface{}, err error) { 36 | defer func(begin time.Time) { 37 | dur.With("success", fmt.Sprint(err == nil)).Observe(time.Since(begin).Seconds()) 38 | }(time.Now()) 39 | return next(ctx, request) 40 | } 41 | } 42 | } 43 | 44 | func RequestFrequencyMiddleware(freq metrics.Gauge, methodName string) endpoint.Middleware { 45 | return func(next endpoint.Endpoint) endpoint.Endpoint { 46 | freq := freq.With("method", methodName) 47 | return func(ctx context.Context, request interface{}) (interface{}, error) { 48 | freq.Add(1) 49 | response, err := next(ctx, request) 50 | freq.Add(-1) 51 | return response, err 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /examples/generated/transport/exchanges.microgen.go: -------------------------------------------------------------------------------- 1 | // Code generated by microgen 0.9.0. DO NOT EDIT. 2 | 3 | package transport 4 | 5 | import generated "github.com/devimteam/microgen/examples/generated" 6 | 7 | type ( 8 | UppercaseRequest struct { 9 | StringsMap map[string]string `json:"strings_map"` 10 | } 11 | UppercaseResponse struct { 12 | Ans string `json:"ans"` 13 | } 14 | 15 | CountRequest struct { 16 | Text string `json:"text"` 17 | Symbol string `json:"symbol"` 18 | } 19 | CountResponse struct { 20 | Count int `json:"count"` 21 | Positions []int `json:"positions"` 22 | } 23 | 24 | TestCaseRequest struct { 25 | Comments []*generated.Comment `json:"comments"` 26 | } 27 | TestCaseResponse struct { 28 | Tree map[string]int `json:"tree"` 29 | } 30 | 31 | // Formal exchange type, please do not delete. 32 | DummyMethodRequest struct{} 33 | // Formal exchange type, please do not delete. 34 | DummyMethodResponse struct{} 35 | ) 36 | -------------------------------------------------------------------------------- /examples/generated/transport/grpc/client.microgen.go: -------------------------------------------------------------------------------- 1 | // Code generated by microgen 0.9.0. DO NOT EDIT. 2 | 3 | package transportgrpc 4 | 5 | import ( 6 | transport "github.com/devimteam/microgen/examples/generated/transport" 7 | pb "github.com/devimteam/microgen/examples/protobuf" 8 | log "github.com/go-kit/kit/log" 9 | opentracing "github.com/go-kit/kit/tracing/opentracing" 10 | grpckit "github.com/go-kit/kit/transport/grpc" 11 | empty "github.com/golang/protobuf/ptypes/empty" 12 | opentracinggo "github.com/opentracing/opentracing-go" 13 | grpc "google.golang.org/grpc" 14 | ) 15 | 16 | func NewGRPCClient(conn *grpc.ClientConn, addr string, opts ...grpckit.ClientOption) transport.EndpointsSet { 17 | if addr == "" { 18 | addr = "service.string.StringService" 19 | } 20 | return transport.EndpointsSet{ 21 | CountEndpoint: grpckit.NewClient( 22 | conn, addr, "Count", 23 | _Encode_Count_Request, 24 | _Decode_Count_Response, 25 | pb.CountResponse{}, 26 | opts..., 27 | ).Endpoint(), 28 | DummyMethodEndpoint: grpckit.NewClient( 29 | conn, addr, "DummyMethod", 30 | _Encode_DummyMethod_Request, 31 | _Decode_DummyMethod_Response, 32 | empty.Empty{}, 33 | opts..., 34 | ).Endpoint(), 35 | TestCaseEndpoint: grpckit.NewClient( 36 | conn, addr, "TestCase", 37 | _Encode_TestCase_Request, 38 | _Decode_TestCase_Response, 39 | pb.TestCaseResponse{}, 40 | opts..., 41 | ).Endpoint(), 42 | UppercaseEndpoint: grpckit.NewClient( 43 | conn, addr, "Uppercase", 44 | _Encode_Uppercase_Request, 45 | _Decode_Uppercase_Response, 46 | pb.UppercaseResponse{}, 47 | opts..., 48 | ).Endpoint(), 49 | } 50 | } 51 | 52 | func TracingGRPCClientOptions(tracer opentracinggo.Tracer, logger log.Logger) func([]grpckit.ClientOption) []grpckit.ClientOption { 53 | return func(opts []grpckit.ClientOption) []grpckit.ClientOption { 54 | return append(opts, grpckit.ClientBefore( 55 | opentracing.ContextToGRPC(tracer, logger), 56 | )) 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /examples/generated/transport/grpc/protobuf_endpoint_converters.microgen.go: -------------------------------------------------------------------------------- 1 | // Code generated by microgen 0.9.0. DO NOT EDIT. 2 | 3 | // Please, do not change functions names! 4 | package transportgrpc 5 | 6 | import ( 7 | "context" 8 | "errors" 9 | transport "github.com/devimteam/microgen/examples/generated/transport" 10 | pb "github.com/devimteam/microgen/examples/protobuf" 11 | empty "github.com/golang/protobuf/ptypes/empty" 12 | ) 13 | 14 | func _Encode_Uppercase_Request(ctx context.Context, request interface{}) (interface{}, error) { 15 | if request == nil { 16 | return nil, errors.New("nil UppercaseRequest") 17 | } 18 | req := request.(*transport.UppercaseRequest) 19 | reqStringsMap, err := MapStringStringToProto(req.StringsMap) 20 | if err != nil { 21 | return nil, err 22 | } 23 | return &pb.UppercaseRequest{StringsMap: reqStringsMap}, nil 24 | } 25 | 26 | func _Encode_Count_Request(ctx context.Context, request interface{}) (interface{}, error) { 27 | if request == nil { 28 | return nil, errors.New("nil CountRequest") 29 | } 30 | req := request.(*transport.CountRequest) 31 | return &pb.CountRequest{ 32 | Symbol: req.Symbol, 33 | Text: req.Text, 34 | }, nil 35 | } 36 | 37 | func _Encode_TestCase_Request(ctx context.Context, request interface{}) (interface{}, error) { 38 | if request == nil { 39 | return nil, errors.New("nil TestCaseRequest") 40 | } 41 | req := request.(*transport.TestCaseRequest) 42 | reqComments, err := ListPtrCommentToProto(req.Comments) 43 | if err != nil { 44 | return nil, err 45 | } 46 | return &pb.TestCaseRequest{Comments: reqComments}, nil 47 | } 48 | 49 | func _Encode_DummyMethod_Request(ctx context.Context, request interface{}) (interface{}, error) { 50 | return &empty.Empty{}, nil 51 | } 52 | 53 | func _Encode_Uppercase_Response(ctx context.Context, response interface{}) (interface{}, error) { 54 | if response == nil { 55 | return nil, errors.New("nil UppercaseResponse") 56 | } 57 | resp := response.(*transport.UppercaseResponse) 58 | return &pb.UppercaseResponse{Ans: resp.Ans}, nil 59 | } 60 | 61 | func _Encode_Count_Response(ctx context.Context, response interface{}) (interface{}, error) { 62 | if response == nil { 63 | return nil, errors.New("nil CountResponse") 64 | } 65 | resp := response.(*transport.CountResponse) 66 | respPositions, err := ListIntToProto(resp.Positions) 67 | if err != nil { 68 | return nil, err 69 | } 70 | return &pb.CountResponse{ 71 | Count: int64(resp.Count), 72 | Positions: respPositions, 73 | }, nil 74 | } 75 | 76 | func _Encode_TestCase_Response(ctx context.Context, response interface{}) (interface{}, error) { 77 | if response == nil { 78 | return nil, errors.New("nil TestCaseResponse") 79 | } 80 | resp := response.(*transport.TestCaseResponse) 81 | respTree, err := MapStringIntToProto(resp.Tree) 82 | if err != nil { 83 | return nil, err 84 | } 85 | return &pb.TestCaseResponse{Tree: respTree}, nil 86 | } 87 | 88 | func _Encode_DummyMethod_Response(ctx context.Context, response interface{}) (interface{}, error) { 89 | return &empty.Empty{}, nil 90 | } 91 | 92 | func _Decode_Uppercase_Request(ctx context.Context, request interface{}) (interface{}, error) { 93 | if request == nil { 94 | return nil, errors.New("nil UppercaseRequest") 95 | } 96 | req := request.(*pb.UppercaseRequest) 97 | reqStringsMap, err := ProtoToMapStringString(req.StringsMap) 98 | if err != nil { 99 | return nil, err 100 | } 101 | return &transport.UppercaseRequest{StringsMap: reqStringsMap}, nil 102 | } 103 | 104 | func _Decode_Count_Request(ctx context.Context, request interface{}) (interface{}, error) { 105 | if request == nil { 106 | return nil, errors.New("nil CountRequest") 107 | } 108 | req := request.(*pb.CountRequest) 109 | return &transport.CountRequest{ 110 | Symbol: string(req.Symbol), 111 | Text: string(req.Text), 112 | }, nil 113 | } 114 | 115 | func _Decode_TestCase_Request(ctx context.Context, request interface{}) (interface{}, error) { 116 | if request == nil { 117 | return nil, errors.New("nil TestCaseRequest") 118 | } 119 | req := request.(*pb.TestCaseRequest) 120 | reqComments, err := ProtoToListPtrComment(req.Comments) 121 | if err != nil { 122 | return nil, err 123 | } 124 | return &transport.TestCaseRequest{Comments: reqComments}, nil 125 | } 126 | 127 | func _Decode_DummyMethod_Request(ctx context.Context, request interface{}) (interface{}, error) { 128 | return &empty.Empty{}, nil 129 | } 130 | 131 | func _Decode_Uppercase_Response(ctx context.Context, response interface{}) (interface{}, error) { 132 | if response == nil { 133 | return nil, errors.New("nil UppercaseResponse") 134 | } 135 | resp := response.(*pb.UppercaseResponse) 136 | return &transport.UppercaseResponse{Ans: string(resp.Ans)}, nil 137 | } 138 | 139 | func _Decode_Count_Response(ctx context.Context, response interface{}) (interface{}, error) { 140 | if response == nil { 141 | return nil, errors.New("nil CountResponse") 142 | } 143 | resp := response.(*pb.CountResponse) 144 | respPositions, err := ProtoToListInt(resp.Positions) 145 | if err != nil { 146 | return nil, err 147 | } 148 | return &transport.CountResponse{ 149 | Count: int(resp.Count), 150 | Positions: respPositions, 151 | }, nil 152 | } 153 | 154 | func _Decode_TestCase_Response(ctx context.Context, response interface{}) (interface{}, error) { 155 | if response == nil { 156 | return nil, errors.New("nil TestCaseResponse") 157 | } 158 | resp := response.(*pb.TestCaseResponse) 159 | respTree, err := ProtoToMapStringInt(resp.Tree) 160 | if err != nil { 161 | return nil, err 162 | } 163 | return &transport.TestCaseResponse{Tree: respTree}, nil 164 | } 165 | 166 | func _Decode_DummyMethod_Response(ctx context.Context, response interface{}) (interface{}, error) { 167 | return &empty.Empty{}, nil 168 | } 169 | -------------------------------------------------------------------------------- /examples/generated/transport/grpc/protobuf_type_converters.microgen.go: -------------------------------------------------------------------------------- 1 | // Code generated by microgen 0.9.0. DO NOT EDIT. 2 | 3 | // It is better for you if you do not change functions names! 4 | // This file will never be overwritten. 5 | package transportgrpc 6 | 7 | import ( 8 | service "github.com/devimteam/microgen/examples/generated" 9 | pb "github.com/devimteam/microgen/examples/protobuf" 10 | ) 11 | 12 | func MapStringStringToProto(stringsMap map[string]string) (map[string]string, error) { 13 | panic("function not provided") // TODO: provide converter 14 | } 15 | 16 | func ProtoToMapStringString(protoStringsMap map[string]string) (map[string]string, error) { 17 | panic("function not provided") // TODO: provide converter 18 | } 19 | 20 | func ListIntToProto(positions []int) ([]int64, error) { 21 | panic("function not provided") // TODO: provide converter 22 | } 23 | 24 | func ProtoToListInt(protoPositions []int64) ([]int, error) { 25 | panic("function not provided") // TODO: provide converter 26 | } 27 | 28 | func ListPtrCommentToProto(comments []*service.Comment) ([]*pb.Comment, error) { 29 | panic("function not provided") // TODO: provide converter 30 | } 31 | 32 | func ProtoToListPtrComment(protoComments []*pb.Comment) ([]*service.Comment, error) { 33 | panic("function not provided") // TODO: provide converter 34 | } 35 | 36 | func MapStringIntToProto(tree map[string]int) (map[string]int64, error) { 37 | panic("function not provided") // TODO: provide converter 38 | } 39 | 40 | func ProtoToMapStringInt(protoTree map[string]int64) (map[string]int, error) { 41 | panic("function not provided") // TODO: provide converter 42 | } 43 | -------------------------------------------------------------------------------- /examples/generated/transport/grpc/server.microgen.go: -------------------------------------------------------------------------------- 1 | // Code generated by microgen 0.9.0. DO NOT EDIT. 2 | 3 | // DO NOT EDIT. 4 | package transportgrpc 5 | 6 | import ( 7 | transport "github.com/devimteam/microgen/examples/generated/transport" 8 | pb "github.com/devimteam/microgen/examples/protobuf" 9 | log "github.com/go-kit/kit/log" 10 | opentracing "github.com/go-kit/kit/tracing/opentracing" 11 | grpc "github.com/go-kit/kit/transport/grpc" 12 | empty "github.com/golang/protobuf/ptypes/empty" 13 | opentracinggo "github.com/opentracing/opentracing-go" 14 | context "golang.org/x/net/context" 15 | ) 16 | 17 | type stringServiceServer struct { 18 | uppercase grpc.Handler 19 | count grpc.Handler 20 | testCase grpc.Handler 21 | dummyMethod grpc.Handler 22 | } 23 | 24 | func NewGRPCServer(endpoints *transport.EndpointsSet, logger log.Logger, tracer opentracinggo.Tracer, opts ...grpc.ServerOption) pb.StringServiceServer { 25 | return &stringServiceServer{ 26 | count: grpc.NewServer( 27 | endpoints.CountEndpoint, 28 | _Decode_Count_Request, 29 | _Encode_Count_Response, 30 | append(opts, grpc.ServerBefore( 31 | opentracing.GRPCToContext(tracer, "Count", logger)))..., 32 | ), 33 | dummyMethod: grpc.NewServer( 34 | endpoints.DummyMethodEndpoint, 35 | _Decode_DummyMethod_Request, 36 | _Encode_DummyMethod_Response, 37 | append(opts, grpc.ServerBefore( 38 | opentracing.GRPCToContext(tracer, "DummyMethod", logger)))..., 39 | ), 40 | testCase: grpc.NewServer( 41 | endpoints.TestCaseEndpoint, 42 | _Decode_TestCase_Request, 43 | _Encode_TestCase_Response, 44 | append(opts, grpc.ServerBefore( 45 | opentracing.GRPCToContext(tracer, "TestCase", logger)))..., 46 | ), 47 | uppercase: grpc.NewServer( 48 | endpoints.UppercaseEndpoint, 49 | _Decode_Uppercase_Request, 50 | _Encode_Uppercase_Response, 51 | append(opts, grpc.ServerBefore( 52 | opentracing.GRPCToContext(tracer, "Uppercase", logger)))..., 53 | ), 54 | } 55 | } 56 | 57 | func (S *stringServiceServer) Uppercase(ctx context.Context, req *pb.UppercaseRequest) (*pb.UppercaseResponse, error) { 58 | _, resp, err := S.uppercase.ServeGRPC(ctx, req) 59 | if err != nil { 60 | return nil, err 61 | } 62 | return resp.(*pb.UppercaseResponse), nil 63 | } 64 | 65 | func (S *stringServiceServer) Count(ctx context.Context, req *pb.CountRequest) (*pb.CountResponse, error) { 66 | _, resp, err := S.count.ServeGRPC(ctx, req) 67 | if err != nil { 68 | return nil, err 69 | } 70 | return resp.(*pb.CountResponse), nil 71 | } 72 | 73 | func (S *stringServiceServer) TestCase(ctx context.Context, req *pb.TestCaseRequest) (*pb.TestCaseResponse, error) { 74 | _, resp, err := S.testCase.ServeGRPC(ctx, req) 75 | if err != nil { 76 | return nil, err 77 | } 78 | return resp.(*pb.TestCaseResponse), nil 79 | } 80 | 81 | func (S *stringServiceServer) DummyMethod(ctx context.Context, req *empty.Empty) (*empty.Empty, error) { 82 | _, resp, err := S.dummyMethod.ServeGRPC(ctx, req) 83 | if err != nil { 84 | return nil, err 85 | } 86 | return resp.(*empty.Empty), nil 87 | } 88 | -------------------------------------------------------------------------------- /examples/generated/transport/http/client.microgen.go: -------------------------------------------------------------------------------- 1 | // Code generated by microgen 0.9.0. DO NOT EDIT. 2 | 3 | package transporthttp 4 | 5 | import ( 6 | transport "github.com/devimteam/microgen/examples/generated/transport" 7 | endpoint "github.com/go-kit/kit/endpoint" 8 | log "github.com/go-kit/kit/log" 9 | sd "github.com/go-kit/kit/sd" 10 | lb "github.com/go-kit/kit/sd/lb" 11 | opentracing "github.com/go-kit/kit/tracing/opentracing" 12 | httpkit "github.com/go-kit/kit/transport/http" 13 | opentracinggo "github.com/opentracing/opentracing-go" 14 | "io" 15 | "net/url" 16 | ) 17 | 18 | func NewHTTPClient(u *url.URL, opts ...httpkit.ClientOption) transport.EndpointsSet { 19 | return transport.EndpointsSet{ 20 | CountEndpoint: httpkit.NewClient( 21 | "GET", u, 22 | _Encode_Count_Request, 23 | _Decode_Count_Response, 24 | opts..., 25 | ).Endpoint(), 26 | DummyMethodEndpoint: httpkit.NewClient( 27 | "POST", u, 28 | _Encode_DummyMethod_Request, 29 | _Decode_DummyMethod_Response, 30 | opts..., 31 | ).Endpoint(), 32 | TestCaseEndpoint: httpkit.NewClient( 33 | "POST", u, 34 | _Encode_TestCase_Request, 35 | _Decode_TestCase_Response, 36 | opts..., 37 | ).Endpoint(), 38 | UppercaseEndpoint: httpkit.NewClient( 39 | "POST", u, 40 | _Encode_Uppercase_Request, 41 | _Decode_Uppercase_Response, 42 | opts..., 43 | ).Endpoint(), 44 | } 45 | } 46 | 47 | func TracingHTTPClientOptions(tracer opentracinggo.Tracer, logger log.Logger) func([]httpkit.ClientOption) []httpkit.ClientOption { 48 | return func(opts []httpkit.ClientOption) []httpkit.ClientOption { 49 | return append(opts, httpkit.ClientBefore( 50 | opentracing.ContextToHTTP(tracer, logger), 51 | )) 52 | } 53 | } 54 | 55 | // NewHTTPClientSD is a http client for StringService and uses service discovery inside. 56 | var NewHTTPClientSD = sdClientFactory(httpClientFactoryMaker) 57 | 58 | // sdClientFactory is a factory to create constructors for HTTPClientSD 59 | func sdClientFactory( 60 | maker func(opts ...httpkit.ClientOption) func(string) (transport.EndpointsSet, error), 61 | ) func(sd.Instancer, log.Logger, ...httpkit.ClientOption) transport.EndpointsSet { 62 | return func(instancer sd.Instancer, logger log.Logger, opts ...httpkit.ClientOption) transport.EndpointsSet { 63 | var endpoints transport.EndpointsSet 64 | { 65 | endpointer := sd.NewEndpointer(instancer, uppercaseSDFactory(maker(opts...)), logger) 66 | endpoints.UppercaseEndpoint, _ = lb.NewRoundRobin(endpointer).Endpoint() 67 | } 68 | { 69 | endpointer := sd.NewEndpointer(instancer, countSDFactory(maker(opts...)), logger) 70 | endpoints.CountEndpoint, _ = lb.NewRoundRobin(endpointer).Endpoint() 71 | } 72 | { 73 | endpointer := sd.NewEndpointer(instancer, testCaseSDFactory(maker(opts...)), logger) 74 | endpoints.TestCaseEndpoint, _ = lb.NewRoundRobin(endpointer).Endpoint() 75 | } 76 | { 77 | endpointer := sd.NewEndpointer(instancer, dummyMethodSDFactory(maker(opts...)), logger) 78 | endpoints.DummyMethodEndpoint, _ = lb.NewRoundRobin(endpointer).Endpoint() 79 | } 80 | return endpoints 81 | } 82 | } 83 | 84 | // httpClientFactoryMaker returns function, that describes what to do with `instance string` to create new instance of client. 85 | // Commonly, for http protocol it would be some sort of url, e.g. `host:port`. 86 | func httpClientFactoryMaker(opts ...httpkit.ClientOption) func(string) (transport.EndpointsSet, error) { 87 | return func(instance string) (transport.EndpointsSet, error) { 88 | u, err := url.Parse(instance) 89 | if err != nil { 90 | return transport.EndpointsSet{}, err 91 | } 92 | return NewHTTPClient(u, opts...), nil 93 | } 94 | } 95 | func uppercaseSDFactory(clientMaker func(string) (transport.EndpointsSet, error)) sd.Factory { 96 | return func(instance string) (endpoint.Endpoint, io.Closer, error) { 97 | c, err := clientMaker(instance) 98 | return c.UppercaseEndpoint, nil, err 99 | } 100 | } 101 | func countSDFactory(clientMaker func(string) (transport.EndpointsSet, error)) sd.Factory { 102 | return func(instance string) (endpoint.Endpoint, io.Closer, error) { 103 | c, err := clientMaker(instance) 104 | return c.CountEndpoint, nil, err 105 | } 106 | } 107 | func testCaseSDFactory(clientMaker func(string) (transport.EndpointsSet, error)) sd.Factory { 108 | return func(instance string) (endpoint.Endpoint, io.Closer, error) { 109 | c, err := clientMaker(instance) 110 | return c.TestCaseEndpoint, nil, err 111 | } 112 | } 113 | func dummyMethodSDFactory(clientMaker func(string) (transport.EndpointsSet, error)) sd.Factory { 114 | return func(instance string) (endpoint.Endpoint, io.Closer, error) { 115 | c, err := clientMaker(instance) 116 | return c.DummyMethodEndpoint, nil, err 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /examples/generated/transport/http/converters.microgen.go: -------------------------------------------------------------------------------- 1 | // Code generated by microgen 0.9.0. DO NOT EDIT. 2 | 3 | // Please, do not change functions names! 4 | package transporthttp 5 | 6 | import ( 7 | "bytes" 8 | "context" 9 | "encoding/json" 10 | "errors" 11 | transport "github.com/devimteam/microgen/examples/generated/transport" 12 | mux "github.com/gorilla/mux" 13 | "io/ioutil" 14 | "net/http" 15 | "path" 16 | ) 17 | 18 | func CommonHTTPRequestEncoder(_ context.Context, r *http.Request, request interface{}) error { 19 | var buf bytes.Buffer 20 | if err := json.NewEncoder(&buf).Encode(request); err != nil { 21 | return err 22 | } 23 | r.Body = ioutil.NopCloser(&buf) 24 | return nil 25 | } 26 | 27 | func CommonHTTPResponseEncoder(_ context.Context, w http.ResponseWriter, response interface{}) error { 28 | w.Header().Set("Content-Type", "application/json; charset=utf-8") 29 | return json.NewEncoder(w).Encode(response) 30 | } 31 | 32 | func _Decode_Uppercase_Request(_ context.Context, r *http.Request) (interface{}, error) { 33 | var req transport.UppercaseRequest 34 | err := json.NewDecoder(r.Body).Decode(&req) 35 | return &req, err 36 | } 37 | 38 | func _Decode_Count_Request(_ context.Context, r *http.Request) (interface{}, error) { 39 | var ( 40 | _param string 41 | ) 42 | var ok bool 43 | _vars := mux.Vars(r) 44 | _param, ok = _vars["text"] 45 | if !ok { 46 | return nil, errors.New("param text not found") 47 | } 48 | text := _param 49 | _param, ok = _vars["symbol"] 50 | if !ok { 51 | return nil, errors.New("param symbol not found") 52 | } 53 | symbol := _param 54 | return &transport.CountRequest{ 55 | Symbol: string(symbol), 56 | Text: string(text), 57 | }, nil 58 | } 59 | 60 | func _Decode_TestCase_Request(_ context.Context, r *http.Request) (interface{}, error) { 61 | var req transport.TestCaseRequest 62 | err := json.NewDecoder(r.Body).Decode(&req) 63 | return &req, err 64 | } 65 | 66 | func _Decode_DummyMethod_Request(_ context.Context, r *http.Request) (interface{}, error) { 67 | var req transport.DummyMethodRequest 68 | err := json.NewDecoder(r.Body).Decode(&req) 69 | return &req, err 70 | } 71 | 72 | func _Decode_Uppercase_Response(_ context.Context, r *http.Response) (interface{}, error) { 73 | var resp transport.UppercaseResponse 74 | err := json.NewDecoder(r.Body).Decode(&resp) 75 | return &resp, err 76 | } 77 | 78 | func _Decode_Count_Response(_ context.Context, r *http.Response) (interface{}, error) { 79 | var resp transport.CountResponse 80 | err := json.NewDecoder(r.Body).Decode(&resp) 81 | return &resp, err 82 | } 83 | 84 | func _Decode_TestCase_Response(_ context.Context, r *http.Response) (interface{}, error) { 85 | var resp transport.TestCaseResponse 86 | err := json.NewDecoder(r.Body).Decode(&resp) 87 | return &resp, err 88 | } 89 | 90 | func _Decode_DummyMethod_Response(_ context.Context, r *http.Response) (interface{}, error) { 91 | var resp transport.DummyMethodResponse 92 | err := json.NewDecoder(r.Body).Decode(&resp) 93 | return &resp, err 94 | } 95 | 96 | func _Encode_Uppercase_Request(ctx context.Context, r *http.Request, request interface{}) error { 97 | r.URL.Path = path.Join(r.URL.Path, "uppercase") 98 | return CommonHTTPRequestEncoder(ctx, r, request) 99 | } 100 | 101 | func _Encode_Count_Request(ctx context.Context, r *http.Request, request interface{}) error { 102 | req := request.(*transport.CountRequest) 103 | r.URL.Path = path.Join(r.URL.Path, "count", 104 | req.Text, 105 | req.Symbol, 106 | ) 107 | return nil 108 | } 109 | 110 | func _Encode_TestCase_Request(ctx context.Context, r *http.Request, request interface{}) error { 111 | r.URL.Path = path.Join(r.URL.Path, "test-case") 112 | return CommonHTTPRequestEncoder(ctx, r, request) 113 | } 114 | 115 | func _Encode_DummyMethod_Request(ctx context.Context, r *http.Request, request interface{}) error { 116 | r.URL.Path = path.Join(r.URL.Path, "dummy-method") 117 | return CommonHTTPRequestEncoder(ctx, r, request) 118 | } 119 | 120 | func _Encode_Uppercase_Response(ctx context.Context, w http.ResponseWriter, response interface{}) error { 121 | return CommonHTTPResponseEncoder(ctx, w, response) 122 | } 123 | 124 | func _Encode_Count_Response(ctx context.Context, w http.ResponseWriter, response interface{}) error { 125 | return CommonHTTPResponseEncoder(ctx, w, response) 126 | } 127 | 128 | func _Encode_TestCase_Response(ctx context.Context, w http.ResponseWriter, response interface{}) error { 129 | return CommonHTTPResponseEncoder(ctx, w, response) 130 | } 131 | 132 | func _Encode_DummyMethod_Response(ctx context.Context, w http.ResponseWriter, response interface{}) error { 133 | return CommonHTTPResponseEncoder(ctx, w, response) 134 | } 135 | -------------------------------------------------------------------------------- /examples/generated/transport/http/server.microgen.go: -------------------------------------------------------------------------------- 1 | // Code generated by microgen 0.9.0. DO NOT EDIT. 2 | 3 | package transporthttp 4 | 5 | import ( 6 | transport "github.com/devimteam/microgen/examples/generated/transport" 7 | log "github.com/go-kit/kit/log" 8 | opentracing "github.com/go-kit/kit/tracing/opentracing" 9 | http "github.com/go-kit/kit/transport/http" 10 | mux "github.com/gorilla/mux" 11 | opentracinggo "github.com/opentracing/opentracing-go" 12 | http1 "net/http" 13 | ) 14 | 15 | func NewHTTPHandler(endpoints *transport.EndpointsSet, logger log.Logger, tracer opentracinggo.Tracer, opts ...http.ServerOption) http1.Handler { 16 | mux := mux.NewRouter() 17 | mux.Methods("POST").Path("/uppercase").Handler( 18 | http.NewServer( 19 | endpoints.UppercaseEndpoint, 20 | _Decode_Uppercase_Request, 21 | _Encode_Uppercase_Response, 22 | append(opts, http.ServerBefore( 23 | opentracing.HTTPToContext(tracer, "Uppercase", logger)))...)) 24 | mux.Methods("GET").Path("/count/{text}/{symbol}").Handler( 25 | http.NewServer( 26 | endpoints.CountEndpoint, 27 | _Decode_Count_Request, 28 | _Encode_Count_Response, 29 | append(opts, http.ServerBefore( 30 | opentracing.HTTPToContext(tracer, "Count", logger)))...)) 31 | mux.Methods("POST").Path("/test-case").Handler( 32 | http.NewServer( 33 | endpoints.TestCaseEndpoint, 34 | _Decode_TestCase_Request, 35 | _Encode_TestCase_Response, 36 | append(opts, http.ServerBefore( 37 | opentracing.HTTPToContext(tracer, "TestCase", logger)))...)) 38 | mux.Methods("POST").Path("/dummy-method").Handler( 39 | http.NewServer( 40 | endpoints.DummyMethodEndpoint, 41 | _Decode_DummyMethod_Request, 42 | _Encode_DummyMethod_Response, 43 | append(opts, http.ServerBefore( 44 | opentracing.HTTPToContext(tracer, "DummyMethod", logger)))...)) 45 | return mux 46 | } 47 | -------------------------------------------------------------------------------- /examples/generated/transport/server.microgen.go: -------------------------------------------------------------------------------- 1 | // Code generated by microgen 0.9.0. DO NOT EDIT. 2 | 3 | package transport 4 | 5 | import ( 6 | "context" 7 | generated "github.com/devimteam/microgen/examples/generated" 8 | endpoint "github.com/go-kit/kit/endpoint" 9 | opentracing "github.com/go-kit/kit/tracing/opentracing" 10 | opentracinggo "github.com/opentracing/opentracing-go" 11 | ) 12 | 13 | func Endpoints(svc generated.StringService) EndpointsSet { 14 | return EndpointsSet{ 15 | CountEndpoint: CountEndpoint(svc), 16 | DummyMethodEndpoint: DummyMethodEndpoint(svc), 17 | TestCaseEndpoint: TestCaseEndpoint(svc), 18 | UppercaseEndpoint: UppercaseEndpoint(svc), 19 | } 20 | } 21 | 22 | // TraceServerEndpoints is used for tracing endpoints on server side. 23 | func TraceServerEndpoints(endpoints EndpointsSet, tracer opentracinggo.Tracer) EndpointsSet { 24 | return EndpointsSet{ 25 | CountEndpoint: opentracing.TraceServer(tracer, "Count")(endpoints.CountEndpoint), 26 | DummyMethodEndpoint: opentracing.TraceServer(tracer, "DummyMethod")(endpoints.DummyMethodEndpoint), 27 | TestCaseEndpoint: opentracing.TraceServer(tracer, "TestCase")(endpoints.TestCaseEndpoint), 28 | UppercaseEndpoint: opentracing.TraceServer(tracer, "Uppercase")(endpoints.UppercaseEndpoint), 29 | } 30 | } 31 | 32 | func UppercaseEndpoint(svc generated.StringService) endpoint.Endpoint { 33 | return func(arg0 context.Context, request interface{}) (interface{}, error) { 34 | req := request.(*UppercaseRequest) 35 | res0, res1 := svc.Uppercase(arg0, req.StringsMap) 36 | return &UppercaseResponse{Ans: res0}, res1 37 | } 38 | } 39 | 40 | func CountEndpoint(svc generated.StringService) endpoint.Endpoint { 41 | return func(arg0 context.Context, request interface{}) (interface{}, error) { 42 | req := request.(*CountRequest) 43 | res0, res1, res2 := svc.Count(arg0, req.Text, req.Symbol) 44 | return &CountResponse{ 45 | Count: res0, 46 | Positions: res1, 47 | }, res2 48 | } 49 | } 50 | 51 | func TestCaseEndpoint(svc generated.StringService) endpoint.Endpoint { 52 | return func(arg0 context.Context, request interface{}) (interface{}, error) { 53 | req := request.(*TestCaseRequest) 54 | res0, res1 := svc.TestCase(arg0, req.Comments) 55 | return &TestCaseResponse{Tree: res0}, res1 56 | } 57 | } 58 | 59 | func DummyMethodEndpoint(svc generated.StringService) endpoint.Endpoint { 60 | return func(arg0 context.Context, request interface{}) (interface{}, error) { 61 | res0 := svc.DummyMethod(arg0) 62 | return &DummyMethodResponse{}, res0 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /examples/protobuf/gen.go: -------------------------------------------------------------------------------- 1 | //go:generate protoc --go_out=plugins=grpc:./../../../../../ -Ipb pb/service.proto 2 | package protobuf 3 | -------------------------------------------------------------------------------- /examples/protobuf/pb/service.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | option go_package = "github.com/devimteam/microgen/example/protobuf;protobuf"; 4 | 5 | package service.string; 6 | 7 | import "google/protobuf/timestamp.proto"; 8 | 9 | service StringService { 10 | rpc Uppercase(UppercaseRequest) returns (UppercaseResponse); 11 | rpc Count(CountRequest) returns (CountResponse); 12 | rpc TestCase(TestCaseRequest) returns (TestCaseResponse); 13 | } 14 | 15 | message UppercaseRequest { 16 | map strings_map = 1; 17 | } 18 | 19 | message UppercaseResponse { 20 | string ans = 1; 21 | } 22 | 23 | message CountRequest { 24 | string text = 1; 25 | string symbol = 2; 26 | } 27 | 28 | message CountResponse { 29 | int64 count = 1; 30 | repeated int64 positions = 2; 31 | } 32 | 33 | message Comment { 34 | string text = 1; 35 | Comment relates = 2; 36 | google.protobuf.Timestamp PostedAt = 3; 37 | } 38 | 39 | message TestCaseRequest { 40 | repeated Comment comments = 1; 41 | } 42 | 43 | message TestCaseResponse { 44 | map tree = 1; 45 | } -------------------------------------------------------------------------------- /examples/svc/entity/comment.go: -------------------------------------------------------------------------------- 1 | package entity 2 | 3 | import "time" 4 | 5 | // Example structure 6 | type Comment struct { 7 | Text string 8 | Relates *Comment 9 | PostedAt time.Time 10 | } 11 | -------------------------------------------------------------------------------- /examples/svc/svc.go: -------------------------------------------------------------------------------- 1 | package stringsvc 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/devimteam/microgen/examples/svc/entity" 7 | ) 8 | 9 | // @microgen middleware, logging, grpc, http, recover, main, error-logging 10 | // @grpc-addr service.string 11 | // @protobuf github.com/devimteam/microgen/examples/protobuf 12 | type StringService interface { 13 | // @logs-ignore ans, err 14 | Uppercase(ctx context.Context, str ...map[string]interface{}) (ans string, err error) 15 | Count(ctx context.Context, text string, symbol string) (count int, positions []int, err error) 16 | // @logs-len comments 17 | TestCase(ctx context.Context, comments []*entity.Comment) (tree map[string]int, err error) 18 | } 19 | -------------------------------------------------------------------------------- /examples/usersvc/Makefile: -------------------------------------------------------------------------------- 1 | gen: ; microgen -file=./pkg/usersvc/api.go -out=./pkg/ -main -------------------------------------------------------------------------------- /examples/usersvc/README.md: -------------------------------------------------------------------------------- 1 | # usersvc 2 | Usersvc is an example, that shows features of microgen in complecated cases. 3 | 4 | Everything begins from `./usersvc/api.go` file. -------------------------------------------------------------------------------- /examples/usersvc/pb/api.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | option go_package = "github.com/devimteam/microgen/examples/usersvc/pb;pb"; 4 | 5 | package service.usersvc; 6 | 7 | import "google/protobuf/timestamp.proto"; 8 | 9 | service UserService { 10 | rpc CreateUser(CreateUserRequest) returns (CreateUserResponse); 11 | rpc UpdateUser(UpdateUserRequest) returns (UpdateUserResponse); 12 | rpc GetUser(GetUserRequest) returns (GetUserResponse); 13 | rpc FindUsers(FindUsersRequest) returns (FindUsersResponse); 14 | rpc CreateComment(CreateCommentRequest) returns (CreateCommentResponse); 15 | rpc GetComment(GetCommentRequest) returns (GetCommentResponse); 16 | rpc GetUserComments(GetUserCommentsRequest) returns (GetUserCommentsResponse); 17 | } 18 | -------------------------------------------------------------------------------- /examples/usersvc/pkg/cmd/user_service/main.go: -------------------------------------------------------------------------------- 1 | // Microgen appends missed functions. 2 | package main 3 | 4 | import ( 5 | "context" 6 | "errors" 7 | "fmt" 8 | protobuf "github.com/devimteam/microgen/examples/protobuf" 9 | service "github.com/devimteam/microgen/examples/usersvc/pkg/service" 10 | transport "github.com/devimteam/microgen/examples/usersvc/pkg/transport" 11 | grpc "github.com/devimteam/microgen/examples/usersvc/pkg/transport/grpc" 12 | http "github.com/devimteam/microgen/examples/usersvc/pkg/transport/http" 13 | usersvc "github.com/devimteam/microgen/examples/usersvc/pkg/usersvc" 14 | log "github.com/go-kit/kit/log" 15 | opentracinggo "github.com/opentracing/opentracing-go" 16 | errgroup "golang.org/x/sync/errgroup" 17 | grpc1 "google.golang.org/grpc" 18 | "io" 19 | "net" 20 | http1 "net/http" 21 | "os" 22 | "os/signal" 23 | "syscall" 24 | ) 25 | 26 | func main() { 27 | logger := log.With(InitLogger(os.Stdout), "level", "info") 28 | errorLogger := log.With(InitLogger(os.Stderr), "level", "error") 29 | logger.Log("message", "Hello, I am alive") 30 | defer logger.Log("message", "goodbye, good luck") 31 | 32 | g, ctx := errgroup.WithContext(context.Background()) 33 | g.Go(func() error { 34 | return InterruptHandler(ctx) 35 | }) 36 | 37 | var svc usersvc.UserService // TODO: = service.NewUserService () // Create new service. 38 | svc = service.LoggingMiddleware(logger)(svc) // Setup service logging. 39 | svc = service.ErrorLoggingMiddleware(logger)(svc) // Setup error logging. 40 | svc = service.RecoveringMiddleware(errorLogger)(svc) // Setup service recovering. 41 | 42 | endpoints := transport.Endpoints(svc) 43 | endpoints = transport.TraceServerEndpoints(endpoints, opentracinggo.NoopTracer{}) // TODO: Add tracer 44 | 45 | grpcAddr := ":8081" // TODO: use normal address 46 | // Start grpc server. 47 | g.Go(func() error { 48 | return ServeGRPC(ctx, &endpoints, grpcAddr, log.With(logger, "transport", "GRPC")) 49 | }) 50 | 51 | httpAddr := ":8080" // TODO: use normal address 52 | // Start http server. 53 | g.Go(func() error { 54 | return ServeHTTP(ctx, &endpoints, httpAddr, log.With(logger, "transport", "HTTP")) 55 | }) 56 | 57 | if err := g.Wait(); err != nil { 58 | logger.Log("error", err) 59 | } 60 | } 61 | 62 | // InitLogger initialize go-kit JSON logger with timestamp and caller. 63 | func InitLogger(writer io.Writer) log.Logger { 64 | logger := log.NewJSONLogger(writer) 65 | logger = log.With(logger, "@timestamp", log.DefaultTimestampUTC) 66 | logger = log.With(logger, "caller", log.DefaultCaller) 67 | return logger 68 | } 69 | 70 | // InterruptHandler handles first SIGINT and SIGTERM and returns it as error. 71 | func InterruptHandler(ctx context.Context) error { 72 | interruptHandler := make(chan os.Signal, 1) 73 | signal.Notify(interruptHandler, syscall.SIGINT, syscall.SIGTERM) 74 | select { 75 | case sig := <-interruptHandler: 76 | return fmt.Errorf("signal received: %v", sig.String()) 77 | case <-ctx.Done(): 78 | return errors.New("signal listener: context canceled") 79 | } 80 | } 81 | 82 | // ServeGRPC starts new GRPC server on address and sends first error to channel. 83 | func ServeGRPC(ctx context.Context, endpoints *transport.EndpointsSet, addr string, logger log.Logger) error { 84 | listener, err := net.Listen("tcp", addr) 85 | if err != nil { 86 | return err 87 | } 88 | // Here you can add middlewares for grpc server. 89 | server := grpc.NewGRPCServer(endpoints, 90 | logger, 91 | opentracinggo.NoopTracer{}, // TODO: Add tracer 92 | ) 93 | grpcServer := grpc1.NewServer() 94 | protobuf.RegisterUserServiceServer(grpcServer, server) 95 | logger.Log("listen on", addr) 96 | ch := make(chan error) 97 | go func() { 98 | ch <- grpcServer.Serve(listener) 99 | }() 100 | select { 101 | case err := <-ch: 102 | return fmt.Errorf("grpc server: serve: %v", err) 103 | case <-ctx.Done(): 104 | grpcServer.GracefulStop() 105 | return errors.New("grpc server: context canceled") 106 | } 107 | } 108 | 109 | // ServeHTTP starts new HTTP server on address and sends first error to channel. 110 | func ServeHTTP(ctx context.Context, endpoints *transport.EndpointsSet, addr string, logger log.Logger) error { 111 | handler := http.NewHTTPHandler(endpoints, 112 | logger, 113 | opentracinggo.NoopTracer{}, // TODO: Add tracer 114 | ) 115 | httpServer := &http1.Server{ 116 | Addr: addr, 117 | Handler: handler, 118 | } 119 | logger.Log("listen on", addr) 120 | ch := make(chan error) 121 | go func() { 122 | ch <- httpServer.ListenAndServe() 123 | }() 124 | select { 125 | case err := <-ch: 126 | if err == http1.ErrServerClosed { 127 | return nil 128 | } 129 | return fmt.Errorf("http server: serve: %v", err) 130 | case <-ctx.Done(): 131 | return httpServer.Shutdown(context.Background()) 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /examples/usersvc/pkg/service/caching.microgen.go: -------------------------------------------------------------------------------- 1 | // Code generated by microgen 0.9.0. DO NOT EDIT. 2 | 3 | package service 4 | 5 | import ( 6 | "context" 7 | service "github.com/devimteam/microgen/examples/usersvc/pkg/usersvc" 8 | log "github.com/go-kit/kit/log" 9 | ) 10 | 11 | // Cache interface uses for middleware as key-value storage for requests. 12 | type Cache interface { 13 | Set(key, value interface{}) (err error) 14 | Get(key interface{}) (value interface{}, err error) 15 | } 16 | 17 | func CachingMiddleware(cache Cache) Middleware { 18 | return func(next service.UserService) service.UserService { 19 | return &cachingMiddleware{ 20 | cache: cache, 21 | next: next, 22 | } 23 | } 24 | } 25 | 26 | type cachingMiddleware struct { 27 | cache Cache 28 | logger log.Logger 29 | next service.UserService 30 | } 31 | 32 | func (M cachingMiddleware) CreateUser(ctx context.Context, user service.User) (res0 string, res1 error) { 33 | return M.next.CreateUser(ctx, user) 34 | } 35 | 36 | func (M cachingMiddleware) UpdateUser(ctx context.Context, user service.User) (res0 error) { 37 | return M.next.UpdateUser(ctx, user) 38 | } 39 | 40 | func (M cachingMiddleware) GetUser(ctx context.Context, id string) (res0 service.User, res1 error) { 41 | return M.next.GetUser(ctx, id) 42 | } 43 | 44 | func (M cachingMiddleware) FindUsers(ctx context.Context) (res0 map[string]service.User, res1 error) { 45 | return M.next.FindUsers(ctx) 46 | } 47 | 48 | func (M cachingMiddleware) CreateComment(ctx context.Context, comment service.Comment) (res0 string, res1 error) { 49 | return M.next.CreateComment(ctx, comment) 50 | } 51 | 52 | func (M cachingMiddleware) GetComment(ctx context.Context, id string) (res0 service.Comment, res1 error) { 53 | return M.next.GetComment(ctx, id) 54 | } 55 | 56 | func (M cachingMiddleware) GetUserComments(ctx context.Context, userId string) (res0 []service.Comment, res1 error) { 57 | return M.next.GetUserComments(ctx, userId) 58 | } 59 | 60 | type createUserResponseCacheEntity struct { 61 | Id string 62 | } 63 | type updateUserResponseCacheEntity struct{} 64 | type getUserResponseCacheEntity struct { 65 | User service.User 66 | } 67 | type findUsersResponseCacheEntity struct { 68 | Results map[string]service.User 69 | } 70 | type createCommentResponseCacheEntity struct { 71 | Id string 72 | } 73 | type getCommentResponseCacheEntity struct { 74 | Comment service.Comment 75 | } 76 | type getUserCommentsResponseCacheEntity struct { 77 | List []service.Comment 78 | } 79 | -------------------------------------------------------------------------------- /examples/usersvc/pkg/service/error_logging.microgen.go: -------------------------------------------------------------------------------- 1 | // Code generated by microgen 0.9.0. DO NOT EDIT. 2 | 3 | package service 4 | 5 | import ( 6 | "context" 7 | service "github.com/devimteam/microgen/examples/usersvc/pkg/usersvc" 8 | log "github.com/go-kit/kit/log" 9 | ) 10 | 11 | // ErrorLoggingMiddleware writes to logger any error, if it is not nil. 12 | func ErrorLoggingMiddleware(logger log.Logger) Middleware { 13 | return func(next service.UserService) service.UserService { 14 | return &errorLoggingMiddleware{ 15 | logger: logger, 16 | next: next, 17 | } 18 | } 19 | } 20 | 21 | type errorLoggingMiddleware struct { 22 | logger log.Logger 23 | next service.UserService 24 | } 25 | 26 | func (M errorLoggingMiddleware) CreateUser(ctx context.Context, user service.User) (id string, err error) { 27 | defer func() { 28 | if err != nil { 29 | M.logger.Log("method", "CreateUser", "message", err) 30 | } 31 | }() 32 | return M.next.CreateUser(ctx, user) 33 | } 34 | 35 | func (M errorLoggingMiddleware) UpdateUser(ctx context.Context, user service.User) (err error) { 36 | defer func() { 37 | if err != nil { 38 | M.logger.Log("method", "UpdateUser", "message", err) 39 | } 40 | }() 41 | return M.next.UpdateUser(ctx, user) 42 | } 43 | 44 | func (M errorLoggingMiddleware) GetUser(ctx context.Context, id string) (user service.User, err error) { 45 | defer func() { 46 | if err != nil { 47 | M.logger.Log("method", "GetUser", "message", err) 48 | } 49 | }() 50 | return M.next.GetUser(ctx, id) 51 | } 52 | 53 | func (M errorLoggingMiddleware) FindUsers(ctx context.Context) (results map[string]service.User, err error) { 54 | defer func() { 55 | if err != nil { 56 | M.logger.Log("method", "FindUsers", "message", err) 57 | } 58 | }() 59 | return M.next.FindUsers(ctx) 60 | } 61 | 62 | func (M errorLoggingMiddleware) CreateComment(ctx context.Context, comment service.Comment) (id string, err error) { 63 | defer func() { 64 | if err != nil { 65 | M.logger.Log("method", "CreateComment", "message", err) 66 | } 67 | }() 68 | return M.next.CreateComment(ctx, comment) 69 | } 70 | 71 | func (M errorLoggingMiddleware) GetComment(ctx context.Context, id string) (comment service.Comment, err error) { 72 | defer func() { 73 | if err != nil { 74 | M.logger.Log("method", "GetComment", "message", err) 75 | } 76 | }() 77 | return M.next.GetComment(ctx, id) 78 | } 79 | 80 | func (M errorLoggingMiddleware) GetUserComments(ctx context.Context, userId string) (list []service.Comment, err error) { 81 | defer func() { 82 | if err != nil { 83 | M.logger.Log("method", "GetUserComments", "message", err) 84 | } 85 | }() 86 | return M.next.GetUserComments(ctx, userId) 87 | } 88 | -------------------------------------------------------------------------------- /examples/usersvc/pkg/service/logging.microgen.go: -------------------------------------------------------------------------------- 1 | // Code generated by microgen 0.9.0. DO NOT EDIT. 2 | 3 | package service 4 | 5 | import ( 6 | "context" 7 | service "github.com/devimteam/microgen/examples/usersvc/pkg/usersvc" 8 | log "github.com/go-kit/kit/log" 9 | "time" 10 | ) 11 | 12 | // LoggingMiddleware writes params, results and working time of method call to provided logger after its execution. 13 | func LoggingMiddleware(logger log.Logger) Middleware { 14 | return func(next service.UserService) service.UserService { 15 | return &loggingMiddleware{ 16 | logger: logger, 17 | next: next, 18 | } 19 | } 20 | } 21 | 22 | type loggingMiddleware struct { 23 | logger log.Logger 24 | next service.UserService 25 | } 26 | 27 | func (M loggingMiddleware) CreateUser(arg0 context.Context, arg1 service.User) (res0 string, res1 error) { 28 | defer func(begin time.Time) { 29 | M.logger.Log( 30 | "method", "CreateUser", 31 | "request", logCreateUserRequest{User: arg1}, 32 | "response", logCreateUserResponse{Id: res0}, 33 | "err", res1, 34 | "took", time.Since(begin)) 35 | }(time.Now()) 36 | return M.next.CreateUser(arg0, arg1) 37 | } 38 | 39 | func (M loggingMiddleware) UpdateUser(arg0 context.Context, arg1 service.User) (res0 error) { 40 | defer func(begin time.Time) { 41 | M.logger.Log( 42 | "method", "UpdateUser", 43 | "request", logUpdateUserRequest{User: arg1}, 44 | "err", res0, 45 | "took", time.Since(begin)) 46 | }(time.Now()) 47 | return M.next.UpdateUser(arg0, arg1) 48 | } 49 | 50 | func (M loggingMiddleware) GetUser(arg0 context.Context, arg1 string) (res0 service.User, res1 error) { 51 | defer func(begin time.Time) { 52 | M.logger.Log( 53 | "method", "GetUser", 54 | "request", logGetUserRequest{Id: arg1}, 55 | "response", logGetUserResponse{User: res0}, 56 | "err", res1, 57 | "took", time.Since(begin)) 58 | }(time.Now()) 59 | return M.next.GetUser(arg0, arg1) 60 | } 61 | 62 | func (M loggingMiddleware) FindUsers(arg0 context.Context) (res0 map[string]service.User, res1 error) { 63 | defer func(begin time.Time) { 64 | M.logger.Log( 65 | "method", "FindUsers", 66 | "response", logFindUsersResponse{Results: res0}, 67 | "err", res1, 68 | "took", time.Since(begin)) 69 | }(time.Now()) 70 | return M.next.FindUsers(arg0) 71 | } 72 | 73 | func (M loggingMiddleware) CreateComment(arg0 context.Context, arg1 service.Comment) (res0 string, res1 error) { 74 | defer func(begin time.Time) { 75 | M.logger.Log( 76 | "method", "CreateComment", 77 | "request", logCreateCommentRequest{Comment: arg1}, 78 | "response", logCreateCommentResponse{Id: res0}, 79 | "err", res1, 80 | "took", time.Since(begin)) 81 | }(time.Now()) 82 | return M.next.CreateComment(arg0, arg1) 83 | } 84 | 85 | func (M loggingMiddleware) GetComment(arg0 context.Context, arg1 string) (res0 service.Comment, res1 error) { 86 | defer func(begin time.Time) { 87 | M.logger.Log( 88 | "method", "GetComment", 89 | "request", logGetCommentRequest{Id: arg1}, 90 | "response", logGetCommentResponse{Comment: res0}, 91 | "err", res1, 92 | "took", time.Since(begin)) 93 | }(time.Now()) 94 | return M.next.GetComment(arg0, arg1) 95 | } 96 | 97 | func (M loggingMiddleware) GetUserComments(arg0 context.Context, arg1 string) (res0 []service.Comment, res1 error) { 98 | defer func(begin time.Time) { 99 | M.logger.Log( 100 | "method", "GetUserComments", 101 | "request", logGetUserCommentsRequest{UserId: arg1}, 102 | "response", logGetUserCommentsResponse{List: res0}, 103 | "err", res1, 104 | "took", time.Since(begin)) 105 | }(time.Now()) 106 | return M.next.GetUserComments(arg0, arg1) 107 | } 108 | 109 | type ( 110 | logCreateUserRequest struct { 111 | User service.User 112 | } 113 | logCreateUserResponse struct { 114 | Id string 115 | } 116 | logUpdateUserRequest struct { 117 | User service.User 118 | } 119 | logGetUserRequest struct { 120 | Id string 121 | } 122 | logGetUserResponse struct { 123 | User service.User 124 | } 125 | logFindUsersResponse struct { 126 | Results map[string]service.User 127 | } 128 | logCreateCommentRequest struct { 129 | Comment service.Comment 130 | } 131 | logCreateCommentResponse struct { 132 | Id string 133 | } 134 | logGetCommentRequest struct { 135 | Id string 136 | } 137 | logGetCommentResponse struct { 138 | Comment service.Comment 139 | } 140 | logGetUserCommentsRequest struct { 141 | UserId string 142 | } 143 | logGetUserCommentsResponse struct { 144 | List []service.Comment 145 | } 146 | ) 147 | -------------------------------------------------------------------------------- /examples/usersvc/pkg/service/middleware.microgen.go: -------------------------------------------------------------------------------- 1 | // Code generated by microgen 0.9.0. DO NOT EDIT. 2 | 3 | package service 4 | 5 | import service "github.com/devimteam/microgen/examples/usersvc/pkg/usersvc" 6 | 7 | // Service middleware (closure). 8 | type Middleware func(service.UserService) service.UserService 9 | -------------------------------------------------------------------------------- /examples/usersvc/pkg/service/recovering.microgen.go: -------------------------------------------------------------------------------- 1 | // Code generated by microgen 0.9.0. DO NOT EDIT. 2 | 3 | package service 4 | 5 | import ( 6 | "context" 7 | "fmt" 8 | service "github.com/devimteam/microgen/examples/usersvc/pkg/usersvc" 9 | log "github.com/go-kit/kit/log" 10 | ) 11 | 12 | // RecoveringMiddleware recovers panics from method calls, writes to provided logger and returns the error of panic as method error. 13 | func RecoveringMiddleware(logger log.Logger) Middleware { 14 | return func(next service.UserService) service.UserService { 15 | return &recoveringMiddleware{ 16 | logger: logger, 17 | next: next, 18 | } 19 | } 20 | } 21 | 22 | type recoveringMiddleware struct { 23 | logger log.Logger 24 | next service.UserService 25 | } 26 | 27 | func (M recoveringMiddleware) CreateUser(ctx context.Context, user service.User) (id string, err error) { 28 | defer func() { 29 | if r := recover(); r != nil { 30 | M.logger.Log("method", "CreateUser", "message", r) 31 | err = fmt.Errorf("%v", r) 32 | } 33 | }() 34 | return M.next.CreateUser(ctx, user) 35 | } 36 | 37 | func (M recoveringMiddleware) UpdateUser(ctx context.Context, user service.User) (err error) { 38 | defer func() { 39 | if r := recover(); r != nil { 40 | M.logger.Log("method", "UpdateUser", "message", r) 41 | err = fmt.Errorf("%v", r) 42 | } 43 | }() 44 | return M.next.UpdateUser(ctx, user) 45 | } 46 | 47 | func (M recoveringMiddleware) GetUser(ctx context.Context, id string) (user service.User, err error) { 48 | defer func() { 49 | if r := recover(); r != nil { 50 | M.logger.Log("method", "GetUser", "message", r) 51 | err = fmt.Errorf("%v", r) 52 | } 53 | }() 54 | return M.next.GetUser(ctx, id) 55 | } 56 | 57 | func (M recoveringMiddleware) FindUsers(ctx context.Context) (results map[string]service.User, err error) { 58 | defer func() { 59 | if r := recover(); r != nil { 60 | M.logger.Log("method", "FindUsers", "message", r) 61 | err = fmt.Errorf("%v", r) 62 | } 63 | }() 64 | return M.next.FindUsers(ctx) 65 | } 66 | 67 | func (M recoveringMiddleware) CreateComment(ctx context.Context, comment service.Comment) (id string, err error) { 68 | defer func() { 69 | if r := recover(); r != nil { 70 | M.logger.Log("method", "CreateComment", "message", r) 71 | err = fmt.Errorf("%v", r) 72 | } 73 | }() 74 | return M.next.CreateComment(ctx, comment) 75 | } 76 | 77 | func (M recoveringMiddleware) GetComment(ctx context.Context, id string) (comment service.Comment, err error) { 78 | defer func() { 79 | if r := recover(); r != nil { 80 | M.logger.Log("method", "GetComment", "message", r) 81 | err = fmt.Errorf("%v", r) 82 | } 83 | }() 84 | return M.next.GetComment(ctx, id) 85 | } 86 | 87 | func (M recoveringMiddleware) GetUserComments(ctx context.Context, userId string) (list []service.Comment, err error) { 88 | defer func() { 89 | if r := recover(); r != nil { 90 | M.logger.Log("method", "GetUserComments", "message", r) 91 | err = fmt.Errorf("%v", r) 92 | } 93 | }() 94 | return M.next.GetUserComments(ctx, userId) 95 | } 96 | -------------------------------------------------------------------------------- /examples/usersvc/pkg/transport/client.microgen.go: -------------------------------------------------------------------------------- 1 | // Code generated by microgen 0.9.0. DO NOT EDIT. 2 | 3 | package transport 4 | 5 | import ( 6 | "context" 7 | "errors" 8 | usersvc "github.com/devimteam/microgen/examples/usersvc/pkg/usersvc" 9 | opentracing "github.com/go-kit/kit/tracing/opentracing" 10 | opentracinggo "github.com/opentracing/opentracing-go" 11 | codes "google.golang.org/grpc/codes" 12 | status "google.golang.org/grpc/status" 13 | ) 14 | 15 | // TraceClientEndpoints is used for tracing endpoints on client side. 16 | func TraceClientEndpoints(endpoints EndpointsSet, tracer opentracinggo.Tracer) EndpointsSet { 17 | return EndpointsSet{ 18 | CreateCommentEndpoint: opentracing.TraceClient(tracer, "CreateComment")(endpoints.CreateCommentEndpoint), 19 | CreateUserEndpoint: opentracing.TraceClient(tracer, "CreateUser")(endpoints.CreateUserEndpoint), 20 | FindUsersEndpoint: opentracing.TraceClient(tracer, "FindUsers")(endpoints.FindUsersEndpoint), 21 | GetCommentEndpoint: opentracing.TraceClient(tracer, "GetComment")(endpoints.GetCommentEndpoint), 22 | GetUserCommentsEndpoint: opentracing.TraceClient(tracer, "GetUserComments")(endpoints.GetUserCommentsEndpoint), 23 | GetUserEndpoint: opentracing.TraceClient(tracer, "GetUser")(endpoints.GetUserEndpoint), 24 | UpdateUserEndpoint: opentracing.TraceClient(tracer, "UpdateUser")(endpoints.UpdateUserEndpoint), 25 | } 26 | } 27 | 28 | func (set EndpointsSet) CreateUser(arg0 context.Context, arg1 usersvc.User) (res0 string, res1 error) { 29 | request := CreateUserRequest{User: arg1} 30 | response, res1 := set.CreateUserEndpoint(arg0, &request) 31 | if res1 != nil { 32 | if e, ok := status.FromError(res1); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { 33 | res1 = errors.New(e.Message()) 34 | } 35 | return 36 | } 37 | return response.(*CreateUserResponse).Id, res1 38 | } 39 | 40 | func (set EndpointsSet) UpdateUser(arg0 context.Context, arg1 usersvc.User) (res0 error) { 41 | request := UpdateUserRequest{User: arg1} 42 | _, res0 = set.UpdateUserEndpoint(arg0, &request) 43 | if res0 != nil { 44 | if e, ok := status.FromError(res0); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { 45 | res0 = errors.New(e.Message()) 46 | } 47 | return 48 | } 49 | return res0 50 | } 51 | 52 | func (set EndpointsSet) GetUser(arg0 context.Context, arg1 string) (res0 usersvc.User, res1 error) { 53 | request := GetUserRequest{Id: arg1} 54 | response, res1 := set.GetUserEndpoint(arg0, &request) 55 | if res1 != nil { 56 | if e, ok := status.FromError(res1); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { 57 | res1 = errors.New(e.Message()) 58 | } 59 | return 60 | } 61 | return response.(*GetUserResponse).User, res1 62 | } 63 | 64 | func (set EndpointsSet) FindUsers(arg0 context.Context) (res0 map[string]usersvc.User, res1 error) { 65 | request := FindUsersRequest{} 66 | response, res1 := set.FindUsersEndpoint(arg0, &request) 67 | if res1 != nil { 68 | if e, ok := status.FromError(res1); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { 69 | res1 = errors.New(e.Message()) 70 | } 71 | return 72 | } 73 | return response.(*FindUsersResponse).Results, res1 74 | } 75 | 76 | func (set EndpointsSet) CreateComment(arg0 context.Context, arg1 usersvc.Comment) (res0 string, res1 error) { 77 | request := CreateCommentRequest{Comment: arg1} 78 | response, res1 := set.CreateCommentEndpoint(arg0, &request) 79 | if res1 != nil { 80 | if e, ok := status.FromError(res1); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { 81 | res1 = errors.New(e.Message()) 82 | } 83 | return 84 | } 85 | return response.(*CreateCommentResponse).Id, res1 86 | } 87 | 88 | func (set EndpointsSet) GetComment(arg0 context.Context, arg1 string) (res0 usersvc.Comment, res1 error) { 89 | request := GetCommentRequest{Id: arg1} 90 | response, res1 := set.GetCommentEndpoint(arg0, &request) 91 | if res1 != nil { 92 | if e, ok := status.FromError(res1); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { 93 | res1 = errors.New(e.Message()) 94 | } 95 | return 96 | } 97 | return response.(*GetCommentResponse).Comment, res1 98 | } 99 | 100 | func (set EndpointsSet) GetUserComments(arg0 context.Context, arg1 string) (res0 []usersvc.Comment, res1 error) { 101 | request := GetUserCommentsRequest{UserId: arg1} 102 | response, res1 := set.GetUserCommentsEndpoint(arg0, &request) 103 | if res1 != nil { 104 | if e, ok := status.FromError(res1); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { 105 | res1 = errors.New(e.Message()) 106 | } 107 | return 108 | } 109 | return response.(*GetUserCommentsResponse).List, res1 110 | } 111 | -------------------------------------------------------------------------------- /examples/usersvc/pkg/transport/endpoints.microgen.go: -------------------------------------------------------------------------------- 1 | // Code generated by microgen 0.9.0. DO NOT EDIT. 2 | 3 | package transport 4 | 5 | import ( 6 | "context" 7 | "fmt" 8 | endpoint "github.com/go-kit/kit/endpoint" 9 | metrics "github.com/go-kit/kit/metrics" 10 | opentracing "github.com/go-kit/kit/tracing/opentracing" 11 | opentracinggo "github.com/opentracing/opentracing-go" 12 | "time" 13 | ) 14 | 15 | // EndpointsSet implements UserService API and used for transport purposes. 16 | type EndpointsSet struct { 17 | CreateUserEndpoint endpoint.Endpoint 18 | UpdateUserEndpoint endpoint.Endpoint 19 | GetUserEndpoint endpoint.Endpoint 20 | FindUsersEndpoint endpoint.Endpoint 21 | CreateCommentEndpoint endpoint.Endpoint 22 | GetCommentEndpoint endpoint.Endpoint 23 | GetUserCommentsEndpoint endpoint.Endpoint 24 | } 25 | 26 | func InstrumentingEndpoints(endpoints EndpointsSet, tracer opentracinggo.Tracer) EndpointsSet { 27 | return EndpointsSet{ 28 | CreateCommentEndpoint: opentracing.TraceServer(tracer, "CreateComment")(endpoints.CreateCommentEndpoint), 29 | CreateUserEndpoint: opentracing.TraceServer(tracer, "CreateUser")(endpoints.CreateUserEndpoint), 30 | FindUsersEndpoint: opentracing.TraceServer(tracer, "FindUsers")(endpoints.FindUsersEndpoint), 31 | GetCommentEndpoint: opentracing.TraceServer(tracer, "GetComment")(endpoints.GetCommentEndpoint), 32 | GetUserCommentsEndpoint: opentracing.TraceServer(tracer, "GetUserComments")(endpoints.GetUserCommentsEndpoint), 33 | GetUserEndpoint: opentracing.TraceServer(tracer, "GetUser")(endpoints.GetUserEndpoint), 34 | UpdateUserEndpoint: opentracing.TraceServer(tracer, "UpdateUser")(endpoints.UpdateUserEndpoint), 35 | } 36 | } 37 | 38 | func LatencyMiddleware(dur metrics.Histogram, methodName string) endpoint.Middleware { 39 | return func(next endpoint.Endpoint) endpoint.Endpoint { 40 | dur := dur.With("method", methodName) 41 | return func(ctx context.Context, request interface{}) (response interface{}, err error) { 42 | defer func(begin time.Time) { 43 | dur.With("success", fmt.Sprint(err == nil)).Observe(time.Since(begin).Seconds()) 44 | }(time.Now()) 45 | return next(ctx, request) 46 | } 47 | } 48 | } 49 | 50 | func RequestFrequencyMiddleware(freq metrics.Gauge, methodName string) endpoint.Middleware { 51 | return func(next endpoint.Endpoint) endpoint.Endpoint { 52 | freq := freq.With("method", methodName) 53 | return func(ctx context.Context, request interface{}) (interface{}, error) { 54 | freq.Add(1) 55 | response, err := next(ctx, request) 56 | freq.Add(-1) 57 | return response, err 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /examples/usersvc/pkg/transport/exchanges.microgen.go: -------------------------------------------------------------------------------- 1 | // Code generated by microgen 0.9.0. DO NOT EDIT. 2 | 3 | package transport 4 | 5 | import usersvc "github.com/devimteam/microgen/examples/usersvc/pkg/usersvc" 6 | 7 | type ( 8 | CreateUserRequest struct { 9 | User usersvc.User `json:"user"` 10 | } 11 | CreateUserResponse struct { 12 | Id string `json:"id"` 13 | } 14 | 15 | UpdateUserRequest struct { 16 | User usersvc.User `json:"user"` 17 | } 18 | // Formal exchange type, please do not delete. 19 | UpdateUserResponse struct{} 20 | 21 | GetUserRequest struct { 22 | Id string `json:"id"` 23 | } 24 | GetUserResponse struct { 25 | User usersvc.User `json:"user"` 26 | } 27 | 28 | // Formal exchange type, please do not delete. 29 | FindUsersRequest struct{} 30 | FindUsersResponse struct { 31 | Results map[string]usersvc.User `json:"results"` 32 | } 33 | 34 | CreateCommentRequest struct { 35 | Comment usersvc.Comment `json:"comment"` 36 | } 37 | CreateCommentResponse struct { 38 | Id string `json:"id"` 39 | } 40 | 41 | GetCommentRequest struct { 42 | Id string `json:"id"` 43 | } 44 | GetCommentResponse struct { 45 | Comment usersvc.Comment `json:"comment"` 46 | } 47 | 48 | GetUserCommentsRequest struct { 49 | UserId string `json:"user_id"` 50 | } 51 | GetUserCommentsResponse struct { 52 | List []usersvc.Comment `json:"list"` 53 | } 54 | ) 55 | -------------------------------------------------------------------------------- /examples/usersvc/pkg/transport/grpc/client.microgen.go: -------------------------------------------------------------------------------- 1 | // Code generated by microgen 0.9.0. DO NOT EDIT. 2 | 3 | package transportgrpc 4 | 5 | import ( 6 | pb "github.com/devimteam/microgen/examples/protobuf" 7 | transport "github.com/devimteam/microgen/examples/usersvc/pkg/transport" 8 | log "github.com/go-kit/kit/log" 9 | opentracing "github.com/go-kit/kit/tracing/opentracing" 10 | grpckit "github.com/go-kit/kit/transport/grpc" 11 | empty "github.com/golang/protobuf/ptypes/empty" 12 | opentracinggo "github.com/opentracing/opentracing-go" 13 | grpc "google.golang.org/grpc" 14 | ) 15 | 16 | func NewGRPCClient(conn *grpc.ClientConn, addr string, opts ...grpckit.ClientOption) transport.EndpointsSet { 17 | return transport.EndpointsSet{ 18 | CreateCommentEndpoint: grpckit.NewClient( 19 | conn, addr, "CreateComment", 20 | _Encode_CreateComment_Request, 21 | _Decode_CreateComment_Response, 22 | pb.CreateCommentResponse{}, 23 | opts..., 24 | ).Endpoint(), 25 | CreateUserEndpoint: grpckit.NewClient( 26 | conn, addr, "CreateUser", 27 | _Encode_CreateUser_Request, 28 | _Decode_CreateUser_Response, 29 | pb.CreateUserResponse{}, 30 | opts..., 31 | ).Endpoint(), 32 | FindUsersEndpoint: grpckit.NewClient( 33 | conn, addr, "FindUsers", 34 | _Encode_FindUsers_Request, 35 | _Decode_FindUsers_Response, 36 | pb.FindUsersResponse{}, 37 | opts..., 38 | ).Endpoint(), 39 | GetCommentEndpoint: grpckit.NewClient( 40 | conn, addr, "GetComment", 41 | _Encode_GetComment_Request, 42 | _Decode_GetComment_Response, 43 | pb.GetCommentResponse{}, 44 | opts..., 45 | ).Endpoint(), 46 | GetUserCommentsEndpoint: grpckit.NewClient( 47 | conn, addr, "GetUserComments", 48 | _Encode_GetUserComments_Request, 49 | _Decode_GetUserComments_Response, 50 | pb.GetUserCommentsResponse{}, 51 | opts..., 52 | ).Endpoint(), 53 | GetUserEndpoint: grpckit.NewClient( 54 | conn, addr, "GetUser", 55 | _Encode_GetUser_Request, 56 | _Decode_GetUser_Response, 57 | pb.GetUserResponse{}, 58 | opts..., 59 | ).Endpoint(), 60 | UpdateUserEndpoint: grpckit.NewClient( 61 | conn, addr, "UpdateUser", 62 | _Encode_UpdateUser_Request, 63 | _Decode_UpdateUser_Response, 64 | empty.Empty{}, 65 | opts..., 66 | ).Endpoint(), 67 | } 68 | } 69 | 70 | func TracingGRPCClientOptions(tracer opentracinggo.Tracer, logger log.Logger) func([]grpckit.ClientOption) []grpckit.ClientOption { 71 | return func(opts []grpckit.ClientOption) []grpckit.ClientOption { 72 | return append(opts, grpckit.ClientBefore( 73 | opentracing.ContextToGRPC(tracer, logger), 74 | )) 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /examples/usersvc/pkg/transport/grpc/protobuf_type_converters.microgen.go: -------------------------------------------------------------------------------- 1 | // Code generated by microgen 1.0.0-beta. DO NOT EDIT. 2 | 3 | // It is better for you if you do not change functions names! 4 | // This file will never be overwritten. 5 | package transportgrpc 6 | 7 | import ( 8 | pb "github.com/devimteam/microgen/examples/protobuf" 9 | service "github.com/devimteam/microgen/examples/usersvc/pkg/usersvc" 10 | ) 11 | 12 | func UserToProto(user service.User) (pb.User, error) { 13 | panic("function not provided") // TODO: provide converter 14 | } 15 | 16 | func ProtoToUser(protoUser pb.User) (service.User, error) { 17 | panic("function not provided") // TODO: provide converter 18 | } 19 | 20 | func MapStringUserToProto(results map[string]service.User) (map[string]pb.User, error) { 21 | panic("function not provided") // TODO: provide converter 22 | } 23 | 24 | func ProtoToMapStringUser(protoResults map[string]pb.User) (map[string]service.User, error) { 25 | panic("function not provided") // TODO: provide converter 26 | } 27 | 28 | func CommentToProto(comment service.Comment) (pb.Comment, error) { 29 | panic("function not provided") // TODO: provide converter 30 | } 31 | 32 | func ProtoToComment(protoComment pb.Comment) (service.Comment, error) { 33 | panic("function not provided") // TODO: provide converter 34 | } 35 | 36 | func ListCommentToProto(list []service.Comment) ([]pb.Comment, error) { 37 | panic("function not provided") // TODO: provide converter 38 | } 39 | 40 | func ProtoToListComment(protoList []pb.Comment) ([]service.Comment, error) { 41 | panic("function not provided") // TODO: provide converter 42 | } 43 | -------------------------------------------------------------------------------- /examples/usersvc/pkg/transport/grpc/server.microgen.go: -------------------------------------------------------------------------------- 1 | // Code generated by microgen 0.9.0. DO NOT EDIT. 2 | 3 | // DO NOT EDIT. 4 | package transportgrpc 5 | 6 | import ( 7 | pb "github.com/devimteam/microgen/examples/protobuf" 8 | transport "github.com/devimteam/microgen/examples/usersvc/pkg/transport" 9 | log "github.com/go-kit/kit/log" 10 | opentracing "github.com/go-kit/kit/tracing/opentracing" 11 | grpc "github.com/go-kit/kit/transport/grpc" 12 | empty "github.com/golang/protobuf/ptypes/empty" 13 | opentracinggo "github.com/opentracing/opentracing-go" 14 | context "golang.org/x/net/context" 15 | ) 16 | 17 | type userServiceServer struct { 18 | createUser grpc.Handler 19 | updateUser grpc.Handler 20 | getUser grpc.Handler 21 | findUsers grpc.Handler 22 | createComment grpc.Handler 23 | getComment grpc.Handler 24 | getUserComments grpc.Handler 25 | } 26 | 27 | func NewGRPCServer(endpoints *transport.EndpointsSet, logger log.Logger, tracer opentracinggo.Tracer, opts ...grpc.ServerOption) pb.UserServiceServer { 28 | return &userServiceServer{ 29 | createComment: grpc.NewServer( 30 | endpoints.CreateCommentEndpoint, 31 | _Decode_CreateComment_Request, 32 | _Encode_CreateComment_Response, 33 | append(opts, grpc.ServerBefore( 34 | opentracing.GRPCToContext(tracer, "CreateComment", logger)))..., 35 | ), 36 | createUser: grpc.NewServer( 37 | endpoints.CreateUserEndpoint, 38 | _Decode_CreateUser_Request, 39 | _Encode_CreateUser_Response, 40 | append(opts, grpc.ServerBefore( 41 | opentracing.GRPCToContext(tracer, "CreateUser", logger)))..., 42 | ), 43 | findUsers: grpc.NewServer( 44 | endpoints.FindUsersEndpoint, 45 | _Decode_FindUsers_Request, 46 | _Encode_FindUsers_Response, 47 | append(opts, grpc.ServerBefore( 48 | opentracing.GRPCToContext(tracer, "FindUsers", logger)))..., 49 | ), 50 | getComment: grpc.NewServer( 51 | endpoints.GetCommentEndpoint, 52 | _Decode_GetComment_Request, 53 | _Encode_GetComment_Response, 54 | append(opts, grpc.ServerBefore( 55 | opentracing.GRPCToContext(tracer, "GetComment", logger)))..., 56 | ), 57 | getUser: grpc.NewServer( 58 | endpoints.GetUserEndpoint, 59 | _Decode_GetUser_Request, 60 | _Encode_GetUser_Response, 61 | append(opts, grpc.ServerBefore( 62 | opentracing.GRPCToContext(tracer, "GetUser", logger)))..., 63 | ), 64 | getUserComments: grpc.NewServer( 65 | endpoints.GetUserCommentsEndpoint, 66 | _Decode_GetUserComments_Request, 67 | _Encode_GetUserComments_Response, 68 | append(opts, grpc.ServerBefore( 69 | opentracing.GRPCToContext(tracer, "GetUserComments", logger)))..., 70 | ), 71 | updateUser: grpc.NewServer( 72 | endpoints.UpdateUserEndpoint, 73 | _Decode_UpdateUser_Request, 74 | _Encode_UpdateUser_Response, 75 | append(opts, grpc.ServerBefore( 76 | opentracing.GRPCToContext(tracer, "UpdateUser", logger)))..., 77 | ), 78 | } 79 | } 80 | 81 | func (S *userServiceServer) CreateUser(ctx context.Context, req *pb.CreateUserRequest) (*pb.CreateUserResponse, error) { 82 | _, resp, err := S.createUser.ServeGRPC(ctx, req) 83 | if err != nil { 84 | return nil, err 85 | } 86 | return resp.(*pb.CreateUserResponse), nil 87 | } 88 | 89 | func (S *userServiceServer) UpdateUser(ctx context.Context, req *pb.UpdateUserRequest) (*empty.Empty, error) { 90 | _, resp, err := S.updateUser.ServeGRPC(ctx, req) 91 | if err != nil { 92 | return nil, err 93 | } 94 | return resp.(*empty.Empty), nil 95 | } 96 | 97 | func (S *userServiceServer) GetUser(ctx context.Context, req *pb.GetUserRequest) (*pb.GetUserResponse, error) { 98 | _, resp, err := S.getUser.ServeGRPC(ctx, req) 99 | if err != nil { 100 | return nil, err 101 | } 102 | return resp.(*pb.GetUserResponse), nil 103 | } 104 | 105 | func (S *userServiceServer) FindUsers(ctx context.Context, req *empty.Empty) (*pb.FindUsersResponse, error) { 106 | _, resp, err := S.findUsers.ServeGRPC(ctx, req) 107 | if err != nil { 108 | return nil, err 109 | } 110 | return resp.(*pb.FindUsersResponse), nil 111 | } 112 | 113 | func (S *userServiceServer) CreateComment(ctx context.Context, req *pb.CreateCommentRequest) (*pb.CreateCommentResponse, error) { 114 | _, resp, err := S.createComment.ServeGRPC(ctx, req) 115 | if err != nil { 116 | return nil, err 117 | } 118 | return resp.(*pb.CreateCommentResponse), nil 119 | } 120 | 121 | func (S *userServiceServer) GetComment(ctx context.Context, req *pb.GetCommentRequest) (*pb.GetCommentResponse, error) { 122 | _, resp, err := S.getComment.ServeGRPC(ctx, req) 123 | if err != nil { 124 | return nil, err 125 | } 126 | return resp.(*pb.GetCommentResponse), nil 127 | } 128 | 129 | func (S *userServiceServer) GetUserComments(ctx context.Context, req *pb.GetUserCommentsRequest) (*pb.GetUserCommentsResponse, error) { 130 | _, resp, err := S.getUserComments.ServeGRPC(ctx, req) 131 | if err != nil { 132 | return nil, err 133 | } 134 | return resp.(*pb.GetUserCommentsResponse), nil 135 | } 136 | -------------------------------------------------------------------------------- /examples/usersvc/pkg/transport/http/client.microgen.go: -------------------------------------------------------------------------------- 1 | // Code generated by microgen 0.9.0. DO NOT EDIT. 2 | 3 | package transporthttp 4 | 5 | import ( 6 | transport "github.com/devimteam/microgen/examples/usersvc/pkg/transport" 7 | log "github.com/go-kit/kit/log" 8 | opentracing "github.com/go-kit/kit/tracing/opentracing" 9 | httpkit "github.com/go-kit/kit/transport/http" 10 | opentracinggo "github.com/opentracing/opentracing-go" 11 | "net/url" 12 | ) 13 | 14 | func NewHTTPClient(u *url.URL, opts ...httpkit.ClientOption) transport.EndpointsSet { 15 | return transport.EndpointsSet{ 16 | CreateCommentEndpoint: httpkit.NewClient( 17 | "POST", u, 18 | _Encode_CreateComment_Request, 19 | _Decode_CreateComment_Response, 20 | opts..., 21 | ).Endpoint(), 22 | CreateUserEndpoint: httpkit.NewClient( 23 | "POST", u, 24 | _Encode_CreateUser_Request, 25 | _Decode_CreateUser_Response, 26 | opts..., 27 | ).Endpoint(), 28 | FindUsersEndpoint: httpkit.NewClient( 29 | "POST", u, 30 | _Encode_FindUsers_Request, 31 | _Decode_FindUsers_Response, 32 | opts..., 33 | ).Endpoint(), 34 | GetCommentEndpoint: httpkit.NewClient( 35 | "POST", u, 36 | _Encode_GetComment_Request, 37 | _Decode_GetComment_Response, 38 | opts..., 39 | ).Endpoint(), 40 | GetUserCommentsEndpoint: httpkit.NewClient( 41 | "POST", u, 42 | _Encode_GetUserComments_Request, 43 | _Decode_GetUserComments_Response, 44 | opts..., 45 | ).Endpoint(), 46 | GetUserEndpoint: httpkit.NewClient( 47 | "POST", u, 48 | _Encode_GetUser_Request, 49 | _Decode_GetUser_Response, 50 | opts..., 51 | ).Endpoint(), 52 | UpdateUserEndpoint: httpkit.NewClient( 53 | "POST", u, 54 | _Encode_UpdateUser_Request, 55 | _Decode_UpdateUser_Response, 56 | opts..., 57 | ).Endpoint(), 58 | } 59 | } 60 | 61 | func TracingHTTPClientOptions(tracer opentracinggo.Tracer, logger log.Logger) func([]httpkit.ClientOption) []httpkit.ClientOption { 62 | return func(opts []httpkit.ClientOption) []httpkit.ClientOption { 63 | return append(opts, httpkit.ClientBefore( 64 | opentracing.ContextToHTTP(tracer, logger), 65 | )) 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /examples/usersvc/pkg/transport/http/server.microgen.go: -------------------------------------------------------------------------------- 1 | // Code generated by microgen 0.9.0. DO NOT EDIT. 2 | 3 | package transporthttp 4 | 5 | import ( 6 | transport "github.com/devimteam/microgen/examples/usersvc/pkg/transport" 7 | log "github.com/go-kit/kit/log" 8 | opentracing "github.com/go-kit/kit/tracing/opentracing" 9 | http "github.com/go-kit/kit/transport/http" 10 | mux "github.com/gorilla/mux" 11 | opentracinggo "github.com/opentracing/opentracing-go" 12 | http1 "net/http" 13 | ) 14 | 15 | func NewHTTPHandler(endpoints *transport.EndpointsSet, logger log.Logger, tracer opentracinggo.Tracer, opts ...http.ServerOption) http1.Handler { 16 | mux := mux.NewRouter() 17 | mux.Methods("POST").Path("/create-user").Handler( 18 | http.NewServer( 19 | endpoints.CreateUserEndpoint, 20 | _Decode_CreateUser_Request, 21 | _Encode_CreateUser_Response, 22 | append(opts, http.ServerBefore( 23 | opentracing.HTTPToContext(tracer, "CreateUser", logger)))...)) 24 | mux.Methods("POST").Path("/update-user").Handler( 25 | http.NewServer( 26 | endpoints.UpdateUserEndpoint, 27 | _Decode_UpdateUser_Request, 28 | _Encode_UpdateUser_Response, 29 | append(opts, http.ServerBefore( 30 | opentracing.HTTPToContext(tracer, "UpdateUser", logger)))...)) 31 | mux.Methods("POST").Path("/get-user").Handler( 32 | http.NewServer( 33 | endpoints.GetUserEndpoint, 34 | _Decode_GetUser_Request, 35 | _Encode_GetUser_Response, 36 | append(opts, http.ServerBefore( 37 | opentracing.HTTPToContext(tracer, "GetUser", logger)))...)) 38 | mux.Methods("POST").Path("/find-users").Handler( 39 | http.NewServer( 40 | endpoints.FindUsersEndpoint, 41 | _Decode_FindUsers_Request, 42 | _Encode_FindUsers_Response, 43 | append(opts, http.ServerBefore( 44 | opentracing.HTTPToContext(tracer, "FindUsers", logger)))...)) 45 | mux.Methods("POST").Path("/create-comment").Handler( 46 | http.NewServer( 47 | endpoints.CreateCommentEndpoint, 48 | _Decode_CreateComment_Request, 49 | _Encode_CreateComment_Response, 50 | append(opts, http.ServerBefore( 51 | opentracing.HTTPToContext(tracer, "CreateComment", logger)))...)) 52 | mux.Methods("POST").Path("/get-comment").Handler( 53 | http.NewServer( 54 | endpoints.GetCommentEndpoint, 55 | _Decode_GetComment_Request, 56 | _Encode_GetComment_Response, 57 | append(opts, http.ServerBefore( 58 | opentracing.HTTPToContext(tracer, "GetComment", logger)))...)) 59 | mux.Methods("POST").Path("/get-user-comments").Handler( 60 | http.NewServer( 61 | endpoints.GetUserCommentsEndpoint, 62 | _Decode_GetUserComments_Request, 63 | _Encode_GetUserComments_Response, 64 | append(opts, http.ServerBefore( 65 | opentracing.HTTPToContext(tracer, "GetUserComments", logger)))...)) 66 | return mux 67 | } 68 | -------------------------------------------------------------------------------- /examples/usersvc/pkg/transport/server.microgen.go: -------------------------------------------------------------------------------- 1 | // Code generated by microgen 0.9.0. DO NOT EDIT. 2 | 3 | package transport 4 | 5 | import ( 6 | "context" 7 | usersvc "github.com/devimteam/microgen/examples/usersvc/pkg/usersvc" 8 | endpoint "github.com/go-kit/kit/endpoint" 9 | opentracing "github.com/go-kit/kit/tracing/opentracing" 10 | opentracinggo "github.com/opentracing/opentracing-go" 11 | ) 12 | 13 | func Endpoints(svc usersvc.UserService) EndpointsSet { 14 | return EndpointsSet{ 15 | CreateCommentEndpoint: CreateCommentEndpoint(svc), 16 | CreateUserEndpoint: CreateUserEndpoint(svc), 17 | FindUsersEndpoint: FindUsersEndpoint(svc), 18 | GetCommentEndpoint: GetCommentEndpoint(svc), 19 | GetUserCommentsEndpoint: GetUserCommentsEndpoint(svc), 20 | GetUserEndpoint: GetUserEndpoint(svc), 21 | UpdateUserEndpoint: UpdateUserEndpoint(svc), 22 | } 23 | } 24 | 25 | // TraceServerEndpoints is used for tracing endpoints on server side. 26 | func TraceServerEndpoints(endpoints EndpointsSet, tracer opentracinggo.Tracer) EndpointsSet { 27 | return EndpointsSet{ 28 | CreateCommentEndpoint: opentracing.TraceServer(tracer, "CreateComment")(endpoints.CreateCommentEndpoint), 29 | CreateUserEndpoint: opentracing.TraceServer(tracer, "CreateUser")(endpoints.CreateUserEndpoint), 30 | FindUsersEndpoint: opentracing.TraceServer(tracer, "FindUsers")(endpoints.FindUsersEndpoint), 31 | GetCommentEndpoint: opentracing.TraceServer(tracer, "GetComment")(endpoints.GetCommentEndpoint), 32 | GetUserCommentsEndpoint: opentracing.TraceServer(tracer, "GetUserComments")(endpoints.GetUserCommentsEndpoint), 33 | GetUserEndpoint: opentracing.TraceServer(tracer, "GetUser")(endpoints.GetUserEndpoint), 34 | UpdateUserEndpoint: opentracing.TraceServer(tracer, "UpdateUser")(endpoints.UpdateUserEndpoint), 35 | } 36 | } 37 | 38 | func CreateUserEndpoint(svc usersvc.UserService) endpoint.Endpoint { 39 | return func(arg0 context.Context, request interface{}) (interface{}, error) { 40 | req := request.(*CreateUserRequest) 41 | res0, res1 := svc.CreateUser(arg0, req.User) 42 | return &CreateUserResponse{Id: res0}, res1 43 | } 44 | } 45 | 46 | func UpdateUserEndpoint(svc usersvc.UserService) endpoint.Endpoint { 47 | return func(arg0 context.Context, request interface{}) (interface{}, error) { 48 | req := request.(*UpdateUserRequest) 49 | res0 := svc.UpdateUser(arg0, req.User) 50 | return &UpdateUserResponse{}, res0 51 | } 52 | } 53 | 54 | func GetUserEndpoint(svc usersvc.UserService) endpoint.Endpoint { 55 | return func(arg0 context.Context, request interface{}) (interface{}, error) { 56 | req := request.(*GetUserRequest) 57 | res0, res1 := svc.GetUser(arg0, req.Id) 58 | return &GetUserResponse{User: res0}, res1 59 | } 60 | } 61 | 62 | func FindUsersEndpoint(svc usersvc.UserService) endpoint.Endpoint { 63 | return func(arg0 context.Context, request interface{}) (interface{}, error) { 64 | res0, res1 := svc.FindUsers(arg0) 65 | return &FindUsersResponse{Results: res0}, res1 66 | } 67 | } 68 | 69 | func CreateCommentEndpoint(svc usersvc.UserService) endpoint.Endpoint { 70 | return func(arg0 context.Context, request interface{}) (interface{}, error) { 71 | req := request.(*CreateCommentRequest) 72 | res0, res1 := svc.CreateComment(arg0, req.Comment) 73 | return &CreateCommentResponse{Id: res0}, res1 74 | } 75 | } 76 | 77 | func GetCommentEndpoint(svc usersvc.UserService) endpoint.Endpoint { 78 | return func(arg0 context.Context, request interface{}) (interface{}, error) { 79 | req := request.(*GetCommentRequest) 80 | res0, res1 := svc.GetComment(arg0, req.Id) 81 | return &GetCommentResponse{Comment: res0}, res1 82 | } 83 | } 84 | 85 | func GetUserCommentsEndpoint(svc usersvc.UserService) endpoint.Endpoint { 86 | return func(arg0 context.Context, request interface{}) (interface{}, error) { 87 | req := request.(*GetUserCommentsRequest) 88 | res0, res1 := svc.GetUserComments(arg0, req.UserId) 89 | return &GetUserCommentsResponse{List: res0}, res1 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /examples/usersvc/pkg/usersvc/api.go: -------------------------------------------------------------------------------- 1 | package usersvc 2 | 3 | import "context" 4 | 5 | // @microgen middleware, logging, grpc, http, recovering, error-logging, tracing, caching, metrics 6 | // @protobuf github.com/devimteam/microgen/examples/protobuf 7 | type UserService interface { 8 | CreateUser(ctx context.Context, user User) (id string, err error) 9 | UpdateUser(ctx context.Context, user User) (err error) 10 | GetUser(ctx context.Context, id string) (user User, err error) 11 | FindUsers(ctx context.Context) (results map[string]User, err error) 12 | CreateComment(ctx context.Context, comment Comment) (id string, err error) 13 | GetComment(ctx context.Context, id string) (comment Comment, err error) 14 | GetUserComments(ctx context.Context, userId string) (list []Comment, err error) 15 | } 16 | -------------------------------------------------------------------------------- /examples/usersvc/pkg/usersvc/user.go: -------------------------------------------------------------------------------- 1 | package usersvc 2 | 3 | type User struct { 4 | Id string 5 | Name string 6 | Gender int 7 | Comments []Comment 8 | } 9 | 10 | type Comment struct { 11 | Id string 12 | Text string 13 | } 14 | -------------------------------------------------------------------------------- /generator/generator.go: -------------------------------------------------------------------------------- 1 | package generator 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "fmt" 7 | 8 | "github.com/devimteam/microgen/generator/template" 9 | "github.com/devimteam/microgen/generator/write_strategy" 10 | ) 11 | 12 | const ( 13 | Version = "0.9.1" 14 | defaultFileHeader = `Code generated by microgen ` + Version + `. DO NOT EDIT.` 15 | ) 16 | 17 | var ( 18 | EmptyTemplateError = errors.New("empty template") 19 | EmptyStrategyError = errors.New("empty strategy") 20 | ) 21 | 22 | type Generator interface { 23 | Generate() error 24 | } 25 | 26 | type GenerationUnit struct { 27 | template template.Template 28 | 29 | writeStrategy write_strategy.Strategy 30 | absOutPath string 31 | } 32 | 33 | func NewGenUnit(ctx context.Context, tmpl template.Template, outPath string) (*GenerationUnit, error) { 34 | err := tmpl.Prepare(ctx) 35 | if err != nil { 36 | return nil, fmt.Errorf("%s: prepare error: %v", tmpl.DefaultPath(), err) 37 | } 38 | strategy, err := tmpl.ChooseStrategy(ctx) 39 | if err != nil { 40 | return nil, fmt.Errorf("%s: choose strategy: %v", tmpl.DefaultPath(), err) 41 | } 42 | return &GenerationUnit{ 43 | template: tmpl, 44 | absOutPath: outPath, 45 | writeStrategy: strategy, 46 | }, nil 47 | } 48 | 49 | func (g *GenerationUnit) Generate(ctx context.Context) error { 50 | if g.template == nil { 51 | return EmptyTemplateError 52 | } 53 | if g.writeStrategy == nil { 54 | return EmptyStrategyError 55 | } 56 | code := g.template.Render(ctx) 57 | err := g.writeStrategy.Write(code) 58 | if err != nil { 59 | return fmt.Errorf("write error: %v", err) 60 | } 61 | return nil 62 | } 63 | 64 | func (g GenerationUnit) Path() string { 65 | return g.absOutPath 66 | } 67 | -------------------------------------------------------------------------------- /generator/generator_test.go: -------------------------------------------------------------------------------- 1 | package generator 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "path/filepath" 7 | "strings" 8 | "testing" 9 | 10 | "context" 11 | 12 | strings2 "github.com/devimteam/microgen/generator/strings" 13 | "github.com/devimteam/microgen/generator/template" 14 | "github.com/stretchr/testify/assert" 15 | "github.com/vetcher/go-astra" 16 | "github.com/vetcher/go-astra/types" 17 | ) 18 | 19 | func findInterface(file *types.File, ifaceName string) *types.Interface { 20 | for i := range file.Interfaces { 21 | if file.Interfaces[i].Name == ifaceName { 22 | return &file.Interfaces[i] 23 | } 24 | } 25 | return nil 26 | } 27 | 28 | func loadInterface(sourceFile, ifaceName string) (*types.Interface, error) { 29 | info, err := astra.ParseFile(sourceFile) 30 | if err != nil { 31 | return nil, err 32 | } 33 | i := findInterface(info, ifaceName) 34 | if i == nil { 35 | return nil, fmt.Errorf("could not find %s interface", ifaceName) 36 | } 37 | return i, nil 38 | } 39 | 40 | func TestTemplates(t *testing.T) { 41 | outPath := "./test_out/" 42 | sourcePath := "./test_assets/service.go.txt" 43 | absSourcePath, err := filepath.Abs(sourcePath) 44 | importPackagePath, err := resolvePackagePath(outPath) 45 | iface, err := loadInterface(sourcePath, "StringService") 46 | if err != nil { 47 | t.Fatal(err) 48 | } 49 | 50 | genInfo := &template.GenerationInfo{ 51 | SourcePackageImport: importPackagePath, 52 | Iface: iface, 53 | OutputFilePath: outPath, 54 | SourceFilePath: absSourcePath, 55 | ProtobufPackageImport: strings2.FetchMetaInfo(TagMark+ProtobufTag, iface.Docs), 56 | } 57 | t.Log("protobuf pkg", genInfo.ProtobufPackageImport) 58 | 59 | allTemplateTests := []struct { 60 | TestName string 61 | Template template.Template 62 | OutFilePath string 63 | }{ 64 | { 65 | TestName: "Endpoints", 66 | Template: template.NewEndpointsTemplate(genInfo), 67 | OutFilePath: "transport_endpoints.go.txt", 68 | }, 69 | { 70 | TestName: "Exchange", 71 | Template: template.NewExchangeTemplate(genInfo), 72 | OutFilePath: "transport_exchanges.go.txt", 73 | }, 74 | { 75 | TestName: "Middleware", 76 | Template: template.NewMiddlewareTemplate(genInfo), 77 | OutFilePath: "middleware.go.txt", 78 | }, 79 | { 80 | TestName: "Logging", 81 | Template: template.NewLoggingTemplate(genInfo), 82 | OutFilePath: "logging.go.txt", 83 | }, 84 | { 85 | TestName: "GRPC Server", 86 | Template: template.NewGRPCServerTemplate(genInfo), 87 | OutFilePath: "grpc_server.go.txt", 88 | }, 89 | { 90 | TestName: "GRPC Client", 91 | Template: template.NewGRPCClientTemplate(genInfo), 92 | OutFilePath: "grpc_client.go.txt", 93 | }, 94 | { 95 | TestName: "GRPC Converter", 96 | Template: template.NewGRPCEndpointConverterTemplate(genInfo), 97 | OutFilePath: "grpc_converters.go.txt", 98 | }, 99 | { 100 | TestName: "GRPC Type Converter", 101 | Template: template.NewStubGRPCTypeConverterTemplate(genInfo), 102 | OutFilePath: "grpc_type.go.txt", 103 | }, 104 | } 105 | for _, test := range allTemplateTests { 106 | t.Run(test.TestName, func(t *testing.T) { 107 | expected, err := ioutil.ReadFile("test_assets/" + test.OutFilePath) 108 | if err != nil { 109 | t.Fatalf("read expected file error: %v", err) 110 | } 111 | 112 | absOutPath := "./test_out/" 113 | gen, err := NewGenUnit(context.Background(), test.Template, absOutPath) 114 | if err != nil { 115 | t.Fatalf("NewGenUnit: %v", err) 116 | } 117 | err = gen.Generate(context.Background()) 118 | if err != nil { 119 | t.Fatalf("unable to generate: %v", err) 120 | } 121 | actual, err := ioutil.ReadFile("./test_out/" + test.Template.DefaultPath()) 122 | if err != nil { 123 | t.Fatalf("read actual file error: %v", err) 124 | } 125 | assert.Equal(t, 126 | strings.Split(string(expected[:]), "\n"), 127 | strings.Split(string(actual[:]), "\n"), 128 | ) 129 | }) 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /generator/strings/string.go: -------------------------------------------------------------------------------- 1 | package strings 2 | 3 | import ( 4 | "strings" 5 | "unicode" 6 | ) 7 | 8 | func ToUpperFirst(s string) string { 9 | if len(s) == 0 { 10 | return "" 11 | } 12 | return strings.ToUpper(string(s[0])) + s[1:] 13 | } 14 | 15 | func ToSomeCaseWithSep(sep rune, runeConv func(rune) rune) func(string) string { 16 | return func(s string) string { 17 | in := []rune(s) 18 | n := len(in) 19 | var runes []rune 20 | for i, r := range in { 21 | if isExtendedSpace(r) { 22 | runes = append(runes, sep) 23 | continue 24 | } 25 | if unicode.IsUpper(r) { 26 | if i > 0 && sep != runes[i-1] && ((i+1 < n && unicode.IsLower(in[i+1])) || unicode.IsLower(in[i-1])) { 27 | runes = append(runes, sep) 28 | } 29 | r = runeConv(r) 30 | } 31 | runes = append(runes, r) 32 | } 33 | return string(runes) 34 | } 35 | } 36 | 37 | func isExtendedSpace(r rune) bool { 38 | return unicode.IsSpace(r) || r == '_' || r == '-' || r == '.' 39 | } 40 | 41 | var ( 42 | ToSnakeCase = ToSomeCaseWithSep('_', unicode.ToLower) 43 | ToURLSnakeCase = ToSomeCaseWithSep('-', unicode.ToLower) 44 | ) 45 | 46 | func ToLowerFirst(s string) string { 47 | if len(s) == 0 { 48 | return "" 49 | } 50 | return strings.ToLower(string(s[0])) + s[1:] 51 | } 52 | 53 | func IsInStringSlice(what string, where []string) bool { 54 | for _, item := range where { 55 | if item == what { 56 | return true 57 | } 58 | } 59 | return false 60 | } 61 | 62 | func FetchTags(strs []string, prefix string) (tags []string) { 63 | for _, comment := range strs { 64 | if strings.HasPrefix(comment, prefix) { 65 | tags = append(tags, strings.Split(strings.Replace(comment[len(prefix):], " ", "", -1), ",")...) 66 | } 67 | } 68 | return 69 | } 70 | 71 | func HasTag(strs []string, prefix string) bool { 72 | return ContainTag(strs, prefix) 73 | } 74 | 75 | func ToLower(str string) string { 76 | if len(str) > 0 && unicode.IsLower(rune(str[0])) { 77 | return str 78 | } 79 | for i := range str { 80 | if unicode.IsLower(rune(str[i])) { 81 | // Case, when only first char is upper. 82 | if i == 1 { 83 | return strings.ToLower(str[:1]) + str[1:] 84 | } 85 | return strings.ToLower(str[:i-1]) + str[i-1:] 86 | } 87 | } 88 | return strings.ToLower(str) 89 | } 90 | 91 | // Return last upper char in string or first char if no upper characters founded. 92 | func LastUpperOrFirst(str string) string { 93 | for i := len(str) - 1; i >= 0; i-- { 94 | if unicode.IsUpper(rune(str[i])) { 95 | return string(str[i]) 96 | } 97 | } 98 | return string(str[0]) 99 | } 100 | -------------------------------------------------------------------------------- /generator/strings/string_test.go: -------------------------------------------------------------------------------- 1 | package strings 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | var strs = []string{ 8 | "stringService", 9 | "StringService", 10 | "Stringservice", 11 | "string_service", 12 | "String_service", 13 | "string_Service", 14 | "JSONService", 15 | "jsonService", 16 | "JSONServicE", 17 | } 18 | 19 | func TestToLower(t *testing.T) { 20 | anss := []string{ 21 | "stringService", 22 | "stringService", 23 | "stringservice", 24 | "string_service", 25 | "string_service", 26 | "string_Service", 27 | "jsonService", 28 | "jsonService", 29 | "jsonServicE", 30 | } 31 | if len(strs) != len(anss) { 32 | t.Fatal("len(strs) != len(anss)") 33 | } 34 | 35 | for i, s := range strs { 36 | if ToLower(s) != anss[i] { 37 | t.Error(i+1, "(", strs[i], "):", ToLower(s), "!=", anss[i]) 38 | } 39 | } 40 | } 41 | 42 | func TestLastUpperOrFirst(t *testing.T) { 43 | anss := []string{ 44 | "S", 45 | "S", 46 | "S", 47 | "s", 48 | "S", 49 | "S", 50 | "S", 51 | "S", 52 | "E", 53 | } 54 | if len(strs) != len(anss) { 55 | t.Fatal("len(strs) != len(anss)") 56 | } 57 | 58 | for i, s := range strs { 59 | if LastUpperOrFirst(s) != anss[i] { 60 | t.Error(i+1, "(", strs[i], "):", LastUpperOrFirst(s), "!=", anss[i]) 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /generator/strings/strings.go: -------------------------------------------------------------------------------- 1 | package strings 2 | 3 | import ( 4 | "strings" 5 | "unicode" 6 | ) 7 | 8 | // Fetch information from slice of comments (docs). 9 | // Returns appendix of first comment which has tag as prefix. 10 | func FetchMetaInfo(tag string, comments []string) string { 11 | for _, comment := range comments { 12 | if len(comment) > len(tag) && strings.HasPrefix(comment, tag) { 13 | return comment[len(tag)+1:] 14 | } 15 | } 16 | return "" 17 | } 18 | 19 | func ContainTag(strs []string, prefix string) bool { 20 | for _, comment := range strs { 21 | if strings.HasPrefix(comment, prefix) { 22 | return true 23 | } 24 | } 25 | return false 26 | } 27 | 28 | func LastWordFromName(name string) string { 29 | lastUpper := strings.LastIndexFunc(name, unicode.IsUpper) 30 | if lastUpper == -1 { 31 | lastUpper = 0 32 | } 33 | return strings.ToLower(name[lastUpper:]) 34 | } 35 | -------------------------------------------------------------------------------- /generator/template/buffer_adapter.go: -------------------------------------------------------------------------------- 1 | package template 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io" 7 | ) 8 | 9 | type BufferAdapter struct { 10 | b bytes.Buffer 11 | } 12 | 13 | func (b BufferAdapter) Render(w io.Writer) error { 14 | _, err := w.Write(b.b.Bytes()) 15 | return err 16 | } 17 | 18 | func (b *BufferAdapter) Raw(data []byte) { 19 | b.b.Write(data) 20 | } 21 | 22 | func (b *BufferAdapter) Printf(format string, a ...interface{}) { 23 | fmt.Fprintf(&b.b, format, a...) 24 | } 25 | 26 | func (b *BufferAdapter) Println(a ...interface{}) { 27 | fmt.Fprintln(&b.b, a...) 28 | } 29 | 30 | func (b *BufferAdapter) Ln(a ...interface{}) { 31 | b.Println(a...) 32 | } 33 | 34 | func (b *BufferAdapter) Lnf(format string, a ...interface{}) { 35 | b.Printf(format+"\n", a...) 36 | } 37 | 38 | func (b *BufferAdapter) Hold() *DelayBuffer { 39 | return &DelayBuffer{t: b} 40 | } 41 | 42 | type DelayBuffer struct { 43 | t *BufferAdapter 44 | BufferAdapter 45 | } 46 | 47 | func (b *DelayBuffer) Release() { 48 | b.t.Raw(b.b.Bytes()) 49 | } 50 | -------------------------------------------------------------------------------- /generator/template/context.go: -------------------------------------------------------------------------------- 1 | package template 2 | 3 | import "context" 4 | 5 | const ( 6 | spi = "SourcePackageImport" 7 | ael = "AllowEllipsis" 8 | mainTagsContextKey = "MainTags" 9 | ) 10 | 11 | func WithSourcePackageImport(parent context.Context, val string) context.Context { 12 | return context.WithValue(parent, spi, val) 13 | } 14 | 15 | func SourcePackageImport(ctx context.Context) string { 16 | return ctx.Value(spi).(string) 17 | } 18 | 19 | func WithTags(parent context.Context, tt TagsSet) context.Context { 20 | return context.WithValue(parent, mainTagsContextKey, tt) 21 | } 22 | 23 | func Tags(ctx context.Context) TagsSet { 24 | return ctx.Value(mainTagsContextKey).(TagsSet) 25 | } 26 | 27 | type TagsSet map[string]struct{} 28 | 29 | func (s TagsSet) Has(item string) bool { 30 | _, ok := s[item] 31 | return ok 32 | } 33 | 34 | func (s TagsSet) HasAny(items ...string) bool { 35 | if len(items) == 0 { 36 | return false 37 | } 38 | return s.Has(items[0]) || s.HasAny(items[1:]...) 39 | } 40 | 41 | func (s TagsSet) Add(item string) { 42 | s[item] = struct{}{} 43 | } 44 | 45 | func AllowEllipsis(ctx context.Context) bool { 46 | v, ok := ctx.Value(ael).(bool) 47 | return ok && v 48 | } 49 | -------------------------------------------------------------------------------- /generator/template/prepare_utils.go: -------------------------------------------------------------------------------- 1 | package template 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "path/filepath" 7 | 8 | "github.com/vetcher/go-astra" 9 | "github.com/vetcher/go-astra/types" 10 | ) 11 | 12 | func ParseFile(filename string) (*types.File, error) { 13 | return astra.ParseFile(filename) 14 | } 15 | 16 | var parsedCache = map[string]*types.File{} 17 | 18 | func parsePackage(path string) (*types.File, error) { 19 | path = filepath.Dir(path) 20 | if file, ok := parsedCache[path]; ok { 21 | return file, nil 22 | } 23 | files, err := astra.ParsePackage(path, astra.AllowAnyImportAliases) 24 | if err != nil { 25 | return nil, err 26 | } 27 | file, err := astra.MergeFiles(files) 28 | if err != nil { 29 | return nil, err 30 | } 31 | parsedCache[path] = file 32 | return file, nil 33 | } 34 | 35 | func statFile(absPath, relPath string) error { 36 | outpath, err := filepath.Abs(filepath.Join(absPath, relPath)) 37 | if err != nil { 38 | return fmt.Errorf("unable to resolve path: %v", err) 39 | } 40 | 41 | fileInfo, err := os.Stat(outpath) 42 | if os.IsNotExist(err) || os.IsPermission(err) { 43 | return err 44 | } 45 | if fileInfo.IsDir() { 46 | return fmt.Errorf("%s is dir", outpath) 47 | } 48 | return nil 49 | } 50 | -------------------------------------------------------------------------------- /generator/template/service.go: -------------------------------------------------------------------------------- 1 | package template 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "os" 7 | "path/filepath" 8 | 9 | . "github.com/dave/jennifer/jen" 10 | mstrings "github.com/devimteam/microgen/generator/strings" 11 | "github.com/devimteam/microgen/generator/write_strategy" 12 | "github.com/vetcher/go-astra/types" 13 | ) 14 | 15 | type stubInterfaceTemplate struct { 16 | info *GenerationInfo 17 | 18 | alreadyRenderedMethods []string 19 | isStructExist bool 20 | isConstructorExist bool 21 | } 22 | 23 | func NewStubInterfaceTemplate(info *GenerationInfo) Template { 24 | return &stubInterfaceTemplate{ 25 | info: info, 26 | } 27 | } 28 | 29 | // Renders stub code for service, its methods and constructor, that implements service interface. 30 | // 31 | // // Generated by "microgen" tool. 32 | // // Structure stringService implements StringService interface. 33 | // type stringService struct { 34 | // } 35 | // 36 | // func NewStringService() StringService { 37 | // panic("constructor not provided") 38 | // } 39 | // 40 | // func (s *stringService) Count(ctx context.Context, text string, symbol string) (count int, positions []int) { 41 | // panic("method not provided") 42 | // } 43 | // 44 | func (t *stubInterfaceTemplate) Render(ctx context.Context) write_strategy.Renderer { 45 | f := &Statement{} 46 | 47 | if !t.isStructExist { 48 | f.Comment(`Generated by "microgen" tool.`).Line(). 49 | Commentf(`Struct %s implements %s interface.`, mstrings.ToLower(t.info.Iface.Name), t.info.Iface.Name).Line(). 50 | Type().Id(mstrings.ToLower(t.info.Iface.Name)).Struct(Line()).Line() 51 | } 52 | 53 | if !t.isConstructorExist { 54 | f.Func().Id(constructorName(t.info.Iface)).Params().Id(t.info.Iface.Name).Block( 55 | Panic(Lit("constructor not provided")).Comment("// TODO: provide constructor"), 56 | ).Line() 57 | } 58 | 59 | for _, signature := range t.info.Iface.Methods { 60 | if !mstrings.IsInStringSlice(signature.Name, t.alreadyRenderedMethods) { 61 | f.Line().Add(methodDefinition(ctx, mstrings.ToLower(t.info.Iface.Name), signature)).Block( 62 | Panic(Lit("method not provided")).Comment("// TODO: provide method"), 63 | ).Line() 64 | } 65 | } 66 | return f 67 | } 68 | 69 | func (stubInterfaceTemplate) DefaultPath() string { 70 | return "." 71 | } 72 | 73 | func (t *stubInterfaceTemplate) Prepare(ctx context.Context) error { 74 | if err := statFile(t.info.SourceFilePath, t.DefaultPath()); os.IsNotExist(err) { 75 | fmt.Println("warning:", err) 76 | return nil 77 | } 78 | file, err := parsePackage(filepath.Join(t.info.SourceFilePath, t.DefaultPath())) 79 | if err != nil { 80 | return err 81 | } 82 | 83 | // Remove already provided service methods 84 | for i := range file.Methods { 85 | name := types.TypeName(file.Methods[i].Receiver.Type) 86 | if name != nil && *name == mstrings.ToLowerFirst(t.info.Iface.Name) && types.TypeImport(file.Methods[i].Receiver.Type) == nil { 87 | t.alreadyRenderedMethods = append(t.alreadyRenderedMethods, file.Methods[i].Name) 88 | } 89 | } 90 | 91 | // Remove already provided service structure 92 | for i := range file.Structures { 93 | if file.Structures[i].Name == mstrings.ToLowerFirst(t.info.Iface.Name) { 94 | t.isStructExist = true 95 | break 96 | } 97 | } 98 | 99 | // Remove already provided service constructor 100 | for i := range file.Functions { 101 | if file.Functions[i].Name == constructorName(t.info.Iface) { 102 | t.isConstructorExist = true 103 | break 104 | } 105 | } 106 | 107 | return nil 108 | } 109 | 110 | func (t *stubInterfaceTemplate) ChooseStrategy(ctx context.Context) (write_strategy.Strategy, error) { 111 | return write_strategy.NewAppendToFileStrategy(t.info.SourceFilePath, t.DefaultPath()), nil 112 | } 113 | 114 | func constructorName(p *types.Interface) string { 115 | return "New" + p.Name 116 | } 117 | -------------------------------------------------------------------------------- /generator/template/service_error_logging.go: -------------------------------------------------------------------------------- 1 | package template 2 | 3 | import ( 4 | "context" 5 | 6 | . "github.com/dave/jennifer/jen" 7 | mstrings "github.com/devimteam/microgen/generator/strings" 8 | "github.com/devimteam/microgen/generator/write_strategy" 9 | "github.com/vetcher/go-astra/types" 10 | ) 11 | 12 | const ( 13 | serviceErrorLoggingStructName = "errorLoggingMiddleware" 14 | ) 15 | 16 | var ServiceErrorLoggingMiddlewareName = mstrings.ToUpperFirst(serviceErrorLoggingStructName) 17 | 18 | type errorLoggingTemplate struct { 19 | info *GenerationInfo 20 | } 21 | 22 | func NewErrorLoggingTemplate(info *GenerationInfo) Template { 23 | return &errorLoggingTemplate{ 24 | info: info, 25 | } 26 | } 27 | 28 | func (t *errorLoggingTemplate) Render(ctx context.Context) write_strategy.Renderer { 29 | f := NewFile("service") 30 | f.ImportAlias(t.info.SourcePackageImport, serviceAlias) 31 | f.HeaderComment(t.info.FileHeader) 32 | 33 | f.Comment("ErrorLoggingMiddleware writes to logger any error, if it is not nil."). 34 | Line().Func().Id(ServiceErrorLoggingMiddlewareName).Params(Id(_logger_).Qual(PackagePathGoKitLog, "Logger")).Params(Id(MiddlewareTypeName)). 35 | Block(t.newRecoverBody(t.info.Iface)) 36 | 37 | f.Line() 38 | 39 | // Render type logger 40 | f.Type().Id(serviceErrorLoggingStructName).Struct( 41 | Id(_logger_).Qual(PackagePathGoKitLog, "Logger"), 42 | Id(_next_).Qual(t.info.SourcePackageImport, t.info.Iface.Name), 43 | ) 44 | 45 | // Render functions 46 | for _, signature := range t.info.Iface.Methods { 47 | f.Line() 48 | f.Add(t.recoverFunc(ctx, signature)).Line() 49 | } 50 | 51 | return f 52 | } 53 | 54 | func (errorLoggingTemplate) DefaultPath() string { 55 | return filenameBuilder(PathService, "error_logging") 56 | } 57 | 58 | func (t *errorLoggingTemplate) Prepare(ctx context.Context) error { 59 | return nil 60 | } 61 | 62 | func (t *errorLoggingTemplate) ChooseStrategy(ctx context.Context) (write_strategy.Strategy, error) { 63 | return write_strategy.NewCreateFileStrategy(t.info.OutputFilePath, t.DefaultPath()), nil 64 | } 65 | 66 | func (t *errorLoggingTemplate) newRecoverBody(i *types.Interface) *Statement { 67 | return Return(Func().Params( 68 | Id(_next_).Qual(t.info.SourcePackageImport, i.Name), 69 | ).Params( 70 | Qual(t.info.SourcePackageImport, i.Name), 71 | ).BlockFunc(func(g *Group) { 72 | g.Return(Op("&").Id(serviceErrorLoggingStructName).Values( 73 | Dict{ 74 | Id(_logger_): Id(_logger_), 75 | Id(_next_): Id(_next_), 76 | }, 77 | )) 78 | })) 79 | } 80 | 81 | func (t *errorLoggingTemplate) recoverFunc(ctx context.Context, signature *types.Function) *Statement { 82 | return methodDefinition(ctx, serviceErrorLoggingStructName, signature). 83 | BlockFunc(t.recoverFuncBody(signature)) 84 | } 85 | 86 | func (t *errorLoggingTemplate) recoverFuncBody(signature *types.Function) func(g *Group) { 87 | return func(g *Group) { 88 | if !t.info.AllowedMethods[signature.Name] { 89 | s := &Statement{} 90 | if len(signature.Results) > 0 { 91 | s.Return() 92 | } 93 | s.Id(rec(serviceErrorLoggingStructName)).Dot(_next_).Dot(signature.Name).Call(paramNames(signature.Args)) 94 | g.Add(s) 95 | return 96 | } 97 | g.Defer().Func().Params().Block( 98 | If(Id(nameOfLastResultError(signature)).Op("!=").Nil()).Block( 99 | Id(rec(serviceErrorLoggingStructName)).Dot(_logger_).Dot("Log").Call( 100 | Lit("method"), Lit(signature.Name), 101 | Lit("message"), Id(nameOfLastResultError(signature)), 102 | ), 103 | ), 104 | ).Call() 105 | 106 | g.Return().Id(rec(serviceErrorLoggingStructName)).Dot(_next_).Dot(signature.Name).Call(paramNames(signature.Args)) 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /generator/template/service_middleware.go: -------------------------------------------------------------------------------- 1 | package template 2 | 3 | import ( 4 | "context" 5 | 6 | . "github.com/dave/jennifer/jen" 7 | "github.com/devimteam/microgen/generator/write_strategy" 8 | ) 9 | 10 | const ( 11 | MiddlewareTypeName = "Middleware" 12 | ) 13 | 14 | type middlewareTemplate struct { 15 | info *GenerationInfo 16 | } 17 | 18 | func NewMiddlewareTemplate(info *GenerationInfo) Template { 19 | return &middlewareTemplate{ 20 | info: info, 21 | } 22 | } 23 | 24 | // Render middleware decorator 25 | // 26 | // // This file was automatically generated by "microgen" utility. 27 | // // DO NOT EDIT. 28 | // package middleware 29 | // 30 | // import svc "github.com/devimteam/microgen/examples/svc" 31 | // 32 | // type Middleware func(svc.StringService) svc.StringService 33 | // 34 | func (t *middlewareTemplate) Render(ctx context.Context) write_strategy.Renderer { 35 | f := NewFile("service") 36 | f.ImportAlias(t.info.SourcePackageImport, serviceAlias) 37 | f.HeaderComment(t.info.FileHeader) 38 | f.Comment("Service middleware (closure)."). 39 | Line().Type().Id(MiddlewareTypeName).Func().Call(Qual(t.info.SourcePackageImport, t.info.Iface.Name)).Qual(t.info.SourcePackageImport, t.info.Iface.Name) 40 | return f 41 | } 42 | 43 | func (middlewareTemplate) DefaultPath() string { 44 | return filenameBuilder(PathService, "middleware") 45 | } 46 | 47 | func (middlewareTemplate) Prepare(ctx context.Context) error { 48 | return nil 49 | } 50 | 51 | func (t *middlewareTemplate) ChooseStrategy(ctx context.Context) (write_strategy.Strategy, error) { 52 | return write_strategy.NewCreateFileStrategy(t.info.OutputFilePath, t.DefaultPath()), nil 53 | } 54 | -------------------------------------------------------------------------------- /generator/template/service_recovering.go: -------------------------------------------------------------------------------- 1 | package template 2 | 3 | import ( 4 | "context" 5 | 6 | . "github.com/dave/jennifer/jen" 7 | mstrings "github.com/devimteam/microgen/generator/strings" 8 | "github.com/devimteam/microgen/generator/write_strategy" 9 | "github.com/vetcher/go-astra/types" 10 | ) 11 | 12 | const ( 13 | serviceRecoveringStructName = "recoveringMiddleware" 14 | ) 15 | 16 | var ServiceRecoveringMiddlewareName = mstrings.ToUpperFirst(serviceRecoveringStructName) 17 | 18 | type recoverTemplate struct { 19 | info *GenerationInfo 20 | } 21 | 22 | func NewRecoverTemplate(info *GenerationInfo) Template { 23 | return &recoverTemplate{ 24 | info: info, 25 | } 26 | } 27 | 28 | func (t *recoverTemplate) Render(ctx context.Context) write_strategy.Renderer { 29 | f := NewFile("service") 30 | f.ImportAlias(t.info.SourcePackageImport, serviceAlias) 31 | f.HeaderComment(t.info.FileHeader) 32 | 33 | f.Comment(ServiceRecoveringMiddlewareName + " recovers panics from method calls, writes to provided logger and returns the error of panic as method error."). 34 | Line().Func().Id(ServiceRecoveringMiddlewareName).Params(Id(_logger_).Qual(PackagePathGoKitLog, "Logger")).Params(Id(MiddlewareTypeName)). 35 | Block(t.newRecoverBody(t.info.Iface)) 36 | 37 | f.Line() 38 | 39 | // Render type logger 40 | f.Type().Id(serviceRecoveringStructName).Struct( 41 | Id(_logger_).Qual(PackagePathGoKitLog, "Logger"), 42 | Id(_next_).Qual(t.info.SourcePackageImport, t.info.Iface.Name), 43 | ) 44 | 45 | // Render functions 46 | for _, signature := range t.info.Iface.Methods { 47 | f.Line() 48 | f.Add(t.recoverFunc(ctx, signature)).Line() 49 | } 50 | 51 | return f 52 | } 53 | 54 | func (recoverTemplate) DefaultPath() string { 55 | return filenameBuilder(PathService, "recovering") 56 | } 57 | 58 | func (t *recoverTemplate) Prepare(ctx context.Context) error { 59 | return nil 60 | } 61 | 62 | func (t *recoverTemplate) ChooseStrategy(ctx context.Context) (write_strategy.Strategy, error) { 63 | return write_strategy.NewCreateFileStrategy(t.info.OutputFilePath, t.DefaultPath()), nil 64 | } 65 | 66 | func (t *recoverTemplate) newRecoverBody(i *types.Interface) *Statement { 67 | return Return(Func().Params( 68 | Id(_next_).Qual(t.info.SourcePackageImport, i.Name), 69 | ).Params( 70 | Qual(t.info.SourcePackageImport, i.Name), 71 | ).BlockFunc(func(g *Group) { 72 | g.Return(Op("&").Id(serviceRecoveringStructName).Values( 73 | Dict{ 74 | Id(_logger_): Id(_logger_), 75 | Id(_next_): Id(_next_), 76 | }, 77 | )) 78 | })) 79 | } 80 | 81 | func (t *recoverTemplate) recoverFunc(ctx context.Context, signature *types.Function) *Statement { 82 | return methodDefinition(ctx, serviceRecoveringStructName, signature). 83 | BlockFunc(t.recoverFuncBody(signature)) 84 | } 85 | 86 | func (t *recoverTemplate) recoverFuncBody(signature *types.Function) func(g *Group) { 87 | return func(g *Group) { 88 | if !t.info.AllowedMethods[signature.Name] { 89 | s := &Statement{} 90 | if len(signature.Results) > 0 { 91 | s.Return() 92 | } 93 | s.Id(rec(serviceRecoveringStructName)).Dot(_next_).Dot(signature.Name).Call(paramNames(signature.Args)) 94 | g.Add(s) 95 | return 96 | } 97 | g.Defer().Func().Params().Block( 98 | If(Id("r").Op(":=").Recover(), Id("r").Op("!=").Nil()).Block( 99 | Id(rec(serviceRecoveringStructName)).Dot(_logger_).Dot("Log").Call( 100 | Lit("method"), Lit(signature.Name), 101 | Lit("message"), Id("r"), 102 | ), 103 | Id(nameOfLastResultError(signature)).Op("=").Qual(PackagePathFmt, "Errorf").Call(Lit("%v"), Id("r")), 104 | ), 105 | ).Call() 106 | g.Return().Id(rec(serviceRecoveringStructName)).Dot(_next_).Dot(signature.Name).Call(paramNames(signature.Args)) 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /generator/template/template.go: -------------------------------------------------------------------------------- 1 | package template 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/devimteam/microgen/generator/write_strategy" 7 | ) 8 | 9 | type Template interface { 10 | // Do all preparing actions, e.g. scan file. 11 | // Should be called first. 12 | Prepare(ctx context.Context) error 13 | // Default relative path for template (=file) 14 | DefaultPath() string 15 | // Template chooses generation strategy, e.g. appends to file or create new. 16 | ChooseStrategy(ctx context.Context) (write_strategy.Strategy, error) 17 | // Main render function, where template produce code. 18 | Render(ctx context.Context) write_strategy.Renderer 19 | } 20 | 21 | // Template for tags, that not produce any files. 22 | type EmptyTemplate struct{} 23 | 24 | func (EmptyTemplate) Prepare(context.Context) error { return nil } 25 | func (EmptyTemplate) DefaultPath() string { return "" } 26 | func (EmptyTemplate) ChooseStrategy(context.Context) (write_strategy.Strategy, error) { 27 | return write_strategy.NewNopStrategy("", ""), nil 28 | } 29 | func (EmptyTemplate) Render(context.Context) write_strategy.Renderer { return nil } 30 | -------------------------------------------------------------------------------- /generator/template/transport_converter_jsonrpc_exchange_converters.go: -------------------------------------------------------------------------------- 1 | package template 2 | 3 | import ( 4 | "context" 5 | "path/filepath" 6 | 7 | . "github.com/dave/jennifer/jen" 8 | "github.com/devimteam/microgen/generator/write_strategy" 9 | "github.com/vetcher/go-astra/types" 10 | ) 11 | 12 | type jsonrpcEndpointConverterTemplate struct { 13 | info *GenerationInfo 14 | requestEncoders []*types.Function 15 | requestDecoders []*types.Function 16 | responseEncoders []*types.Function 17 | responseDecoders []*types.Function 18 | state WriteStrategyState 19 | } 20 | 21 | func NewJSONRPCEndpointConverterTemplate(info *GenerationInfo) Template { 22 | return &jsonrpcEndpointConverterTemplate{ 23 | info: info, 24 | } 25 | } 26 | 27 | func (t *jsonrpcEndpointConverterTemplate) Render(ctx context.Context) write_strategy.Renderer { 28 | f := &Statement{} 29 | 30 | for _, signature := range t.requestEncoders { 31 | f.Line().Add(t.encodeRequest(signature)) 32 | } 33 | for _, signature := range t.responseEncoders { 34 | f.Line().Add(t.encodeResponse(signature)) 35 | } 36 | for _, signature := range t.requestDecoders { 37 | f.Line().Add(t.decodeRequest(signature)) 38 | } 39 | for _, signature := range t.responseDecoders { 40 | f.Line().Add(t.decodeResponse(signature)) 41 | } 42 | 43 | if t.state == AppendStrat { 44 | return f 45 | } 46 | 47 | file := NewFile("jsonrpcconv") 48 | file.ImportAlias(t.info.SourcePackageImport, serviceAlias) 49 | file.HeaderComment(t.info.FileHeader) 50 | file.PackageComment(`Please, do not change functions names!`) 51 | file.Add(f) 52 | 53 | return file 54 | } 55 | 56 | func (jsonrpcEndpointConverterTemplate) DefaultPath() string { 57 | return "./transport/converter/jsonrpc/exchange_converters.go" 58 | } 59 | 60 | func (t *jsonrpcEndpointConverterTemplate) Prepare(ctx context.Context) error { 61 | for _, fn := range t.info.Iface.Methods { 62 | t.requestDecoders = append(t.requestDecoders, fn) 63 | t.requestEncoders = append(t.requestEncoders, fn) 64 | t.responseDecoders = append(t.responseDecoders, fn) 65 | t.responseEncoders = append(t.responseEncoders, fn) 66 | } 67 | return nil 68 | } 69 | 70 | func (t *jsonrpcEndpointConverterTemplate) ChooseStrategy(ctx context.Context) (write_strategy.Strategy, error) { 71 | if err := statFile(t.info.OutputFilePath, t.DefaultPath()); err != nil { 72 | t.state = FileStrat 73 | return write_strategy.NewCreateFileStrategy(t.info.OutputFilePath, t.DefaultPath()), nil 74 | } 75 | file, err := parsePackage(filepath.Join(t.info.OutputFilePath, t.DefaultPath())) 76 | if err != nil { 77 | return nil, err 78 | } 79 | 80 | removeAlreadyExistingFunctions(file.Functions, &t.requestEncoders, encodeRequestName) 81 | removeAlreadyExistingFunctions(file.Functions, &t.requestDecoders, decodeRequestName) 82 | removeAlreadyExistingFunctions(file.Functions, &t.responseEncoders, encodeResponseName) 83 | removeAlreadyExistingFunctions(file.Functions, &t.responseDecoders, decodeResponseName) 84 | 85 | t.state = AppendStrat 86 | return write_strategy.NewAppendToFileStrategy(t.info.OutputFilePath, t.DefaultPath()), nil 87 | } 88 | 89 | func (t *jsonrpcEndpointConverterTemplate) encodeRequest(fn *types.Function) Code { 90 | fullName := "request" 91 | return Line().Func().Id(encodeRequestName(fn)).Params(Op("_").Qual(PackagePathContext, "Context"), Id(fullName).Interface()). 92 | Params(Qual(PackagePathJson, "RawMessage"), Error()).BlockFunc( 93 | func(group *Group) { 94 | group.Return().Qual(PackagePathJson, "Marshal").Call(Id(fullName)) 95 | }) 96 | } 97 | 98 | func (t *jsonrpcEndpointConverterTemplate) encodeResponse(fn *types.Function) Code { 99 | fullName := "response" 100 | return Line().Func().Id(encodeResponseName(fn)).Params(Op("_").Qual(PackagePathContext, "Context"), Id(fullName).Interface()). 101 | Params(Qual(PackagePathJson, "RawMessage"), Error()).BlockFunc( 102 | func(group *Group) { 103 | group.Return().Qual(PackagePathJson, "Marshal").Call(Id(fullName)) 104 | }) 105 | } 106 | 107 | func (t *jsonrpcEndpointConverterTemplate) decodeRequest(fn *types.Function) Code { 108 | fullName := "request" 109 | shortName := "req" 110 | return Line().Func().Id(decodeRequestName(fn)).Params(Op("_").Qual(PackagePathContext, "Context"), Id(fullName).Qual(PackagePathGoKitTransportJSONRPC, "Response")). 111 | Params(Interface(), Error()).BlockFunc( 112 | func(group *Group) { 113 | group.If(Id(fullName).Dot("Error").Op("!=").Nil()).Block( 114 | Return(Nil(), Id(fullName).Dot("Error")), 115 | ) 116 | group.Var().Id(shortName).Qual(t.info.SourcePackageImport, requestStructName(fn)) 117 | group.Err().Op(":=").Qual(PackagePathJson, "Unmarshal").Call(Id(fullName), Op("&").Id(shortName)) 118 | group.Return(Op("&").Id(shortName), Err()) 119 | }) 120 | } 121 | 122 | func (t *jsonrpcEndpointConverterTemplate) decodeResponse(fn *types.Function) Code { 123 | fullName := "response" 124 | shortName := "resp" 125 | return Line().Func().Id(decodeResponseName(fn)).Params(Op("_").Qual(PackagePathContext, "Context"), Id(fullName).Qual(PackagePathGoKitTransportJSONRPC, "Response")). 126 | Params(Interface(), Error()).BlockFunc( 127 | func(group *Group) { 128 | group.If(Id(fullName).Dot("Error").Op("!=").Nil()).Block( 129 | Return(Nil(), Id(fullName).Dot("Error")), 130 | ) 131 | group.Var().Id(shortName).Qual(t.info.SourcePackageImport, responseStructName(fn)) 132 | group.Err().Op(":=").Qual(PackagePathJson, "Unmarshal").Call(Id(fullName), Op("&").Id(shortName)) 133 | group.Return(Op("&").Id(shortName), Err()) 134 | }) 135 | } 136 | -------------------------------------------------------------------------------- /generator/template/transport_endpoints.go: -------------------------------------------------------------------------------- 1 | package template 2 | 3 | import ( 4 | "context" 5 | 6 | "fmt" 7 | 8 | . "github.com/dave/jennifer/jen" 9 | "github.com/devimteam/microgen/generator/write_strategy" 10 | ) 11 | 12 | const ( 13 | EndpointsSetName = "EndpointsSet" 14 | ) 15 | 16 | type endpointsTemplate struct { 17 | info *GenerationInfo 18 | } 19 | 20 | func NewEndpointsTemplate(info *GenerationInfo) Template { 21 | return &endpointsTemplate{ 22 | info: info, 23 | } 24 | } 25 | 26 | func endpointsStructFieldName(str string) string { 27 | return str + "Endpoint" 28 | } 29 | 30 | // Renders endpoints file. 31 | // 32 | // // This file was automatically generated by "microgen" utility. 33 | // // DO NOT EDIT. 34 | // package stringsvc 35 | // 36 | // import ( 37 | // context "context" 38 | // endpoint "github.com/go-kit/kit/endpoint" 39 | // ) 40 | // 41 | // type Endpoints struct { 42 | // CountEndpoint endpoint.Endpoint 43 | // } 44 | // 45 | func (t *endpointsTemplate) Render(ctx context.Context) write_strategy.Renderer { 46 | f := NewFile("transport") 47 | f.HeaderComment(t.info.FileHeader) 48 | 49 | f.Comment(fmt.Sprintf("%s implements %s API and used for transport purposes.", EndpointsSetName, t.info.Iface.Name)) 50 | f.Type().Id(EndpointsSetName).StructFunc(func(g *Group) { 51 | for _, signature := range t.info.Iface.Methods { 52 | if t.info.AllowedMethods[signature.Name] { 53 | g.Id(endpointsStructFieldName(signature.Name)).Qual(PackagePathGoKitEndpoint, "Endpoint") 54 | } 55 | } 56 | }).Line() 57 | f.Add(t.serverMetrics(ctx)).Line() 58 | return f 59 | } 60 | 61 | func (endpointsTemplate) DefaultPath() string { 62 | return filenameBuilder(PathTransport, "endpoints") 63 | } 64 | 65 | func (t *endpointsTemplate) Prepare(ctx context.Context) error { 66 | return nil 67 | } 68 | 69 | func (t *endpointsTemplate) ChooseStrategy(ctx context.Context) (write_strategy.Strategy, error) { 70 | return write_strategy.NewCreateFileStrategy(t.info.OutputFilePath, t.DefaultPath()), nil 71 | } 72 | 73 | func (t *endpointsTemplate) serverMetrics(ctx context.Context) *Statement { 74 | s := &Statement{} 75 | if !Tags(ctx).Has(MetricsMiddlewareTag) { 76 | return s 77 | } 78 | const _name_ = "methodName" 79 | s.Func().Id("InstrumentingEndpoints").Call(Id("endpoints").Id(EndpointsSetName), Id("tracer").Qual(PackagePathOpenTracingGo, "Tracer")).Id(EndpointsSetName).BlockFunc(func(g *Group) { 80 | g.Return(Id(EndpointsSetName).Values(DictFunc(func(d Dict) { 81 | for _, signature := range t.info.Iface.Methods { 82 | if t.info.AllowedMethods[signature.Name] { 83 | d[Id(endpointsStructFieldName(signature.Name))] = Qual(PackagePathGoKitTracing, "TraceServer").Call(Id("tracer"), Lit(signature.Name)).Call(Id("endpoints").Dot(endpointsStructFieldName(signature.Name))) 84 | } 85 | } 86 | }))) 87 | }) 88 | s.Line() 89 | s.Line().Func().Id("LatencyMiddleware").Params(Id("dur").Qual(PackagePathGoKitMetrics, "Histogram"), Id(_name_).String()).Qual(PackagePathGoKitEndpoint, "Middleware").Block( 90 | Return().Func().Params(Id("next").Qual(PackagePathGoKitEndpoint, "Endpoint")).Qual(PackagePathGoKitEndpoint, "Endpoint").Block( 91 | Id("dur").Op(":=").Id("dur").Dot("With").Call(Lit("method"), Id(_name_)), 92 | Return().Func().Params(ctx_contextContext, Id("request").Interface()).Params(Id("response").Interface(), Err().Error()).Block( 93 | Defer().Func().Params(Id("begin").Qual(PackagePathTime, "Time")).Block( 94 | Id("dur").Dot("With").Call(Lit("success"), Qual(PackagePathFmt, "Sprint").Call(Err().Op("==").Nil())). 95 | Dot("Observe").Call(Qual(PackagePathTime, "Since").Call(Id("begin")).Dot("Seconds").Call()), 96 | ).Call(Qual(PackagePathTime, "Now").Call()), 97 | Return().Id("next").Call(Id(_ctx_), Id("request")), 98 | ), 99 | ), 100 | ) 101 | s.Line() 102 | s.Line().Func().Id("RequestFrequencyMiddleware").Params(Id("freq").Qual(PackagePathGoKitMetrics, "Gauge"), Id(_name_).String()).Qual(PackagePathGoKitEndpoint, "Middleware").Block( 103 | Return().Func().Params(Id("next").Qual(PackagePathGoKitEndpoint, "Endpoint")).Qual(PackagePathGoKitEndpoint, "Endpoint").Block( 104 | Id("freq").Op(":=").Id("freq").Dot("With").Call(Lit("method"), Id(_name_)), 105 | Return().Func().Params(ctx_contextContext, Id("request").Interface()).Params(Interface(), Error()).Block( 106 | Id("freq").Dot("Add").Call(Lit(1)), 107 | List(Id("response"), Err()).Op(":=").Id("next").Call(Id(_ctx_), Id("request")), 108 | Id("freq").Dot("Add").Call(Lit(-1)), 109 | Return(Id("response"), Err()), 110 | ), 111 | ), 112 | ) 113 | return s 114 | } 115 | -------------------------------------------------------------------------------- /generator/template/transport_exchanges.go: -------------------------------------------------------------------------------- 1 | package template 2 | 3 | import ( 4 | "context" 5 | 6 | . "github.com/dave/jennifer/jen" 7 | "github.com/devimteam/microgen/generator/write_strategy" 8 | "github.com/vetcher/go-astra/types" 9 | ) 10 | 11 | type exchangeTemplate struct { 12 | info *GenerationInfo 13 | } 14 | 15 | func NewExchangeTemplate(info *GenerationInfo) Template { 16 | return &exchangeTemplate{ 17 | info: info, 18 | } 19 | } 20 | 21 | func requestStructName(signature *types.Function) string { 22 | return signature.Name + "Request" 23 | } 24 | 25 | func responseStructName(signature *types.Function) string { 26 | return signature.Name + "Response" 27 | } 28 | 29 | // Renders exchanges file. 30 | // 31 | // package visitsvc 32 | // 33 | // import ( 34 | // "gitlab.devim.team/microservices/visitsvc/entity" 35 | // ) 36 | // 37 | // type CreateVisitRequest struct { 38 | // Visit *entity.Visit `json:"visit"` 39 | // } 40 | // 41 | // type CreateVisitResponse struct { 42 | // Res *entity.Visit `json:"res"` 43 | // Err error `json:"err"` 44 | // } 45 | // 46 | func (t *exchangeTemplate) Render(ctx context.Context) write_strategy.Renderer { 47 | f := NewFile("transport") 48 | f.HeaderComment(t.info.FileHeader) 49 | 50 | if len(t.info.Iface.Methods) > 0 { 51 | f.Type().Op("(") 52 | } 53 | for _, signature := range t.info.Iface.Methods { 54 | if t.info.AllowedMethods[signature.Name] { 55 | f.Add(exchange(ctx, requestStructName(signature), RemoveContextIfFirst(signature.Args))) //.Line() 56 | f.Add(exchange(ctx, responseStructName(signature), removeErrorIfLast(signature.Results))).Line() 57 | } 58 | } 59 | if len(t.info.Iface.Methods) > 0 { 60 | f.Op(")") 61 | } 62 | 63 | return f 64 | } 65 | 66 | func (exchangeTemplate) DefaultPath() string { 67 | return filenameBuilder(PathTransport, "exchanges") 68 | } 69 | 70 | func (exchangeTemplate) Prepare(ctx context.Context) error { 71 | return nil 72 | } 73 | 74 | func (t *exchangeTemplate) ChooseStrategy(ctx context.Context) (write_strategy.Strategy, error) { 75 | return write_strategy.NewCreateFileStrategy(t.info.OutputFilePath, t.DefaultPath()), nil 76 | } 77 | 78 | // Renders exchanges that represents requests and responses. 79 | // 80 | // type CreateVisitRequest struct { 81 | // Visit *entity.Visit `json:"visit"` 82 | // } 83 | // 84 | func exchange(ctx context.Context, name string, params []types.Variable) Code { 85 | if len(params) == 0 { 86 | return Comment("Formal exchange type, please do not delete.").Line(). 87 | Id(name).Struct() 88 | //Line() 89 | } 90 | return Id(name).StructFunc(func(g *Group) { 91 | for _, param := range params { 92 | g.Add(structField(ctx, ¶m)) 93 | } 94 | }) //.Line() 95 | } 96 | -------------------------------------------------------------------------------- /generator/template/transport_grpc_client.go: -------------------------------------------------------------------------------- 1 | package template 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | 7 | . "github.com/dave/jennifer/jen" 8 | "github.com/devimteam/microgen/generator/write_strategy" 9 | "github.com/vetcher/go-astra/types" 10 | ) 11 | 12 | var ( 13 | ErrProtobufEmpty = errors.New("protobuf package is empty") 14 | ) 15 | 16 | type gRPCClientTemplate struct { 17 | info *GenerationInfo 18 | } 19 | 20 | func NewGRPCClientTemplate(info *GenerationInfo) Template { 21 | return &gRPCClientTemplate{ 22 | info: info, 23 | } 24 | } 25 | 26 | // Render whole grpc client file. 27 | // 28 | // // This file was automatically generated by "microgen" utility. 29 | // // DO NOT EDIT. 30 | // package transportgrpc 31 | // 32 | // import ( 33 | // svc "github.com/devimteam/microgen/examples/svc" 34 | // protobuf "github.com/devimteam/microgen/examples/svc/transport/converter/protobuf" 35 | // grpc1 "github.com/go-kit/kit/transport/grpc" 36 | // stringsvc "gitlab.devim.team/protobuf/stringsvc" 37 | // grpc "google.golang.org/grpc" 38 | // ) 39 | // 40 | // func NewGRPCClient(conn *grpc.ClientConn, opts ...grpc1.ClientOption) svc.StringService { 41 | // return &svc.Endpoints{CountEndpoint: grpc1.NewClient( 42 | // conn, 43 | // "devim.string.protobuf.StringService", 44 | // "Count", 45 | // protobuf.EncodeCountRequest, 46 | // protobuf.DecodeCountResponse, 47 | // stringsvc.CountResponse{}, 48 | // opts..., 49 | // ).Endpoint()} 50 | // } 51 | // 52 | func (t *gRPCClientTemplate) Render(ctx context.Context) write_strategy.Renderer { 53 | f := NewFile("transportgrpc") 54 | f.ImportAlias(t.info.ProtobufPackageImport, "pb") 55 | f.ImportAlias(t.info.SourcePackageImport, serviceAlias) 56 | f.ImportAlias(PackagePathGoKitTransportGRPC, "grpckit") 57 | f.HeaderComment(t.info.FileHeader) 58 | 59 | f.Func().Id("NewGRPCClient"). 60 | ParamsFunc(func(p *Group) { 61 | p.Id("conn").Op("*").Qual(PackagePathGoogleGRPC, "ClientConn") 62 | p.Id("addr").Id("string") 63 | p.Id("opts").Op("...").Qual(PackagePathGoKitTransportGRPC, "ClientOption") 64 | }).Qual(t.info.OutputPackageImport+"/transport", EndpointsSetName). 65 | BlockFunc(func(g *Group) { 66 | if t.info.ProtobufClientAddr != "" { 67 | g.If(Id("addr").Op("==").Lit("")).Block( 68 | Id("addr").Op("=").Lit(t.info.ProtobufClientAddr), 69 | ) 70 | } 71 | g.Return().Qual(t.info.OutputPackageImport+"/transport", EndpointsSetName).Values(DictFunc(func(d Dict) { 72 | for _, m := range t.info.Iface.Methods { 73 | if !t.info.AllowedMethods[m.Name] { 74 | continue 75 | } 76 | client := &Statement{} 77 | client.Qual(PackagePathGoKitTransportGRPC, "NewClient").Call( 78 | Line().Id("conn"), Id("addr"), Lit(m.Name), 79 | Line().Id(encodeRequestName(m)), 80 | Line().Id(decodeResponseName(m)), 81 | Line().Add(t.replyType(m)), 82 | Line().Add(t.clientOpts(m)).Op("...").Line(), 83 | ).Dot("Endpoint").Call() 84 | d[Id(endpointsStructFieldName(m.Name))] = client 85 | } 86 | })) 87 | }) 88 | 89 | if Tags(ctx).Has(TracingMiddlewareTag) { 90 | f.Line().Func().Id("TracingGRPCClientOptions").Params( 91 | Id("tracer").Qual(PackagePathOpenTracingGo, "Tracer"), 92 | Id("logger").Qual(PackagePathGoKitLog, "Logger"), 93 | ).Params( 94 | Func().Params(Op("[]").Qual(PackagePathGoKitTransportGRPC, "ClientOption")).Params(Op("[]").Qual(PackagePathGoKitTransportGRPC, "ClientOption")), 95 | ).Block( 96 | Return().Func().Params(Id("opts").Op("[]").Qual(PackagePathGoKitTransportGRPC, "ClientOption")).Params(Op("[]").Qual(PackagePathGoKitTransportGRPC, "ClientOption")).Block( 97 | Return().Append(Id("opts"), Qual(PackagePathGoKitTransportGRPC, "ClientBefore").Call( 98 | Line().Qual(PackagePathGoKitTracing, "ContextToGRPC").Call(Id("tracer"), Id("logger")).Op(",").Line(), 99 | )), 100 | ), 101 | ) 102 | } 103 | 104 | return f 105 | } 106 | 107 | // Renders reply type argument 108 | // stringsvc.CountResponse{} 109 | func (t *gRPCClientTemplate) replyType(signature *types.Function) *Statement { 110 | results := removeErrorIfLast(signature.Results) 111 | if len(results) == 0 { 112 | return Qual(PackagePathEmptyProtobuf, "Empty").Values() 113 | } 114 | if len(results) == 1 { 115 | sp := specialReplyType(results[0].Type) 116 | if sp != nil { 117 | return sp 118 | } 119 | } 120 | return Qual(t.info.ProtobufPackageImport, responseStructName(signature)).Values() 121 | } 122 | 123 | func specialReplyType(p types.Type) *Statement { 124 | name := types.TypeName(p) 125 | imp := types.TypeImport(p) 126 | // *string -> *wrappers.StringValue 127 | if name != nil && *name == "string" && imp == nil { 128 | ptr, ok := p.(types.TPointer) 129 | if ok && ptr.NumberOfPointers == 1 { 130 | return (&Statement{}).Qual(GolangProtobufWrappers, "StringValue").Values() 131 | } 132 | } 133 | // *float64 -> *wrappers.DoubleValue 134 | if name != nil && *name == "float64" && imp == nil { 135 | ptr, ok := p.(types.TPointer) 136 | if ok && ptr.NumberOfPointers == 1 { 137 | return (&Statement{}).Qual(GolangProtobufWrappers, "DoubleValue").Values() 138 | } 139 | } 140 | return nil 141 | } 142 | 143 | func (gRPCClientTemplate) DefaultPath() string { 144 | return filenameBuilder(PathTransport, "grpc", "client") 145 | } 146 | 147 | func (t *gRPCClientTemplate) Prepare(ctx context.Context) error { 148 | return nil 149 | } 150 | 151 | func (t *gRPCClientTemplate) ChooseStrategy(ctx context.Context) (write_strategy.Strategy, error) { 152 | return write_strategy.NewCreateFileStrategy(t.info.OutputFilePath, t.DefaultPath()), nil 153 | } 154 | 155 | func (t *gRPCClientTemplate) clientOpts(fn *types.Function) *Statement { 156 | s := &Statement{} 157 | s.Id("opts") 158 | return s 159 | } 160 | -------------------------------------------------------------------------------- /generator/template/transport_http_server.go: -------------------------------------------------------------------------------- 1 | package template 2 | 3 | import ( 4 | "context" 5 | "path" 6 | "path/filepath" 7 | "strings" 8 | 9 | . "github.com/dave/jennifer/jen" 10 | mstrings "github.com/devimteam/microgen/generator/strings" 11 | "github.com/devimteam/microgen/generator/write_strategy" 12 | "github.com/vetcher/go-astra/types" 13 | ) 14 | 15 | const ( 16 | defaultHTTPMethod = "POST" 17 | 18 | HttpMethodTag = "http-method" 19 | HttpMethodPath = "http-path" 20 | ) 21 | 22 | type httpServerTemplate struct { 23 | info *GenerationInfo 24 | methods map[string]string 25 | paths map[string]string 26 | } 27 | 28 | func NewHttpServerTemplate(info *GenerationInfo) Template { 29 | return &httpServerTemplate{ 30 | info: info, 31 | } 32 | } 33 | 34 | func (t *httpServerTemplate) DefaultPath() string { 35 | return filenameBuilder(PathTransport, "http", "server") 36 | } 37 | 38 | func (t *httpServerTemplate) ChooseStrategy(ctx context.Context) (write_strategy.Strategy, error) { 39 | return write_strategy.NewCreateFileStrategy(t.info.OutputFilePath, t.DefaultPath()), nil 40 | } 41 | 42 | func (t *httpServerTemplate) Prepare(ctx context.Context) error { 43 | t.methods = make(map[string]string) 44 | t.paths = make(map[string]string) 45 | for _, fn := range t.info.Iface.Methods { 46 | t.methods[fn.Name] = FetchHttpMethodTag(fn.Docs) 47 | t.paths[fn.Name] = buildMethodPath(fn) 48 | } 49 | return nil 50 | } 51 | 52 | func FetchHttpMethodTag(rawString []string) string { 53 | tags := mstrings.FetchTags(rawString, TagMark+HttpMethodTag) 54 | if len(tags) == 1 { 55 | return strings.ToTitle(tags[0]) 56 | } 57 | return defaultHTTPMethod 58 | } 59 | 60 | func buildMethodPath(fn *types.Function) string { 61 | url := strings.Replace(mstrings.FetchMetaInfo(TagMark+HttpMethodPath, fn.Docs), " ", "", -1) 62 | if url == "" { 63 | return buildDefaultMethodPath(fn) 64 | } 65 | return url 66 | } 67 | 68 | func buildDefaultMethodPath(fn *types.Function) string { 69 | edges := []string{mstrings.ToURLSnakeCase(fn.Name)} // parts of full path 70 | if FetchHttpMethodTag(fn.Docs) == "GET" { 71 | edges = append(edges, gorillaMuxUrlTemplateVarList(RemoveContextIfFirst(fn.Args))...) 72 | } 73 | return path.Join(edges...) 74 | } 75 | 76 | func gorillaMuxUrlTemplateVarList(vars []types.Variable) []string { 77 | var list []string 78 | for i := range vars { 79 | list = append(list, "{"+mstrings.ToURLSnakeCase(vars[i].Name)+"}") 80 | } 81 | return list 82 | } 83 | 84 | // Render http server constructor. 85 | // // This file was automatically generated by "microgen" utility. 86 | // // DO NOT EDIT. 87 | // package transporthttp 88 | // 89 | // import ( 90 | // svc "github.com/devimteam/microgen/examples/svc" 91 | // http2 "github.com/devimteam/microgen/examples/svc/transport/converter/http" 92 | // http "github.com/go-kit/kit/transport/http" 93 | // http1 "net/http" 94 | // ) 95 | // 96 | // func NewHTTPHandler(endpoints *svc.Endpoints, opts ...http.ServerOption) http1.Handler { 97 | // handler := http1.NewServeMux() 98 | // handler.Handle("/test_case", http.NewServer( 99 | // endpoints.TestCaseEndpoint, 100 | // http2.DecodeHTTPTestCaseRequest, 101 | // http2.EncodeHTTPTestCaseResponse, 102 | // opts...)) 103 | // handler.Handle("/empty_req", http.NewServer( 104 | // endpoints.EmptyReqEndpoint, 105 | // http2.DecodeHTTPEmptyReqRequest, 106 | // http2.EncodeHTTPEmptyReqResponse, 107 | // opts...)) 108 | // handler.Handle("/empty_resp", http.NewServer( 109 | // endpoints.EmptyRespEndpoint, 110 | // http2.DecodeHTTPEmptyRespRequest, 111 | // http2.EncodeHTTPEmptyRespResponse, 112 | // opts...)) 113 | // return handler 114 | // } 115 | // 116 | func (t *httpServerTemplate) Render(ctx context.Context) write_strategy.Renderer { 117 | f := NewFile("transporthttp") 118 | f.ImportAlias(t.info.SourcePackageImport, serviceAlias) 119 | f.HeaderComment(t.info.FileHeader) 120 | 121 | f.Func().Id("NewHTTPHandler").ParamsFunc(func(p *Group) { 122 | p.Id("endpoints").Op("*").Qual(t.info.OutputPackageImport+"/transport", EndpointsSetName) 123 | if Tags(ctx).Has(TracingMiddlewareTag) { 124 | p.Id("logger").Qual(PackagePathGoKitLog, "Logger") 125 | } 126 | if Tags(ctx).Has(TracingMiddlewareTag) { 127 | p.Id("tracer").Qual(PackagePathOpenTracingGo, "Tracer") 128 | } 129 | p.Id("opts").Op("...").Qual(PackagePathGoKitTransportHTTP, "ServerOption") 130 | }).Params( 131 | Qual(PackagePathHttp, "Handler"), 132 | ).BlockFunc(func(g *Group) { 133 | g.Id("mux").Op(":=").Qual(PackagePathGorillaMux, "NewRouter").Call() 134 | for _, fn := range t.info.Iface.Methods { 135 | if !t.info.AllowedMethods[fn.Name] { 136 | continue 137 | } 138 | g.Id("mux").Dot("Methods").Call(Lit(t.methods[fn.Name])).Dot("Path"). 139 | Call(Lit("/" + t.paths[fn.Name])).Dot("Handler").Call( 140 | Line().Qual(PackagePathGoKitTransportHTTP, "NewServer").Call( 141 | Line().Id("endpoints").Dot(endpointsStructFieldName(fn.Name)), 142 | Line().Id(decodeRequestName(fn)), 143 | Line().Id(encodeResponseName(fn)), 144 | Line().Add(t.serverOpts(ctx, fn)).Op("...")), 145 | ) 146 | } 147 | g.Return(Id("mux")) 148 | }) 149 | 150 | return f 151 | } 152 | 153 | func (t *httpServerTemplate) serverOpts(ctx context.Context, fn *types.Function) *Statement { 154 | s := &Statement{} 155 | if Tags(ctx).Has(TracingMiddlewareTag) { 156 | s.Op("append(") 157 | defer s.Op(")") 158 | } 159 | s.Id("opts") 160 | if Tags(ctx).Has(TracingMiddlewareTag) { 161 | s.Op(",").Qual(PackagePathGoKitTransportHTTP, "ServerBefore").Call( 162 | Line().Qual(PackagePathGoKitTracing, "HTTPToContext").Call(Id("tracer"), Lit(fn.Name), Id("logger")), 163 | ) 164 | } 165 | return s 166 | } 167 | 168 | func pathToHttpConverter(servicePath string) string { 169 | return filepath.Join(servicePath, "transport/converter/http") 170 | } 171 | -------------------------------------------------------------------------------- /generator/test_assets/endpoints.go.txt: -------------------------------------------------------------------------------- 1 | // This file was automatically generated by "microgen 0.6.0" utility. 2 | // Please, do not edit. 3 | package stringsvc 4 | 5 | import ( 6 | context "context" 7 | errors "errors" 8 | entity "github.com/devimteam/microgen/example/svc/entity" 9 | endpoint "github.com/go-kit/kit/endpoint" 10 | grpc "google.golang.org/grpc" 11 | codes "google.golang.org/grpc/codes" 12 | ) 13 | 14 | type Endpoints struct { 15 | UppercaseEndpoint endpoint.Endpoint 16 | CountEndpoint endpoint.Endpoint 17 | TestCaseEndpoint endpoint.Endpoint 18 | } 19 | 20 | func (E *Endpoints) Uppercase(ctx context.Context, str ...map[string]interface{}) (ans string, err error) { 21 | endpointUppercaseRequest := UppercaseRequest{Str: str} 22 | endpointUppercaseResponse, err := E.UppercaseEndpoint(ctx, &endpointUppercaseRequest) 23 | if err != nil { 24 | if grpc.Code(err) == codes.Internal || grpc.Code(err) == codes.Unknown { 25 | err = errors.New(grpc.ErrorDesc(err)) 26 | } 27 | return 28 | } 29 | return endpointUppercaseResponse.(*UppercaseResponse).Ans, err 30 | } 31 | 32 | func (E *Endpoints) Count(ctx context.Context, text string, symbol string) (count int, positions []int, err error) { 33 | endpointCountRequest := CountRequest{ 34 | Symbol: symbol, 35 | Text: text, 36 | } 37 | endpointCountResponse, err := E.CountEndpoint(ctx, &endpointCountRequest) 38 | if err != nil { 39 | if grpc.Code(err) == codes.Internal || grpc.Code(err) == codes.Unknown { 40 | err = errors.New(grpc.ErrorDesc(err)) 41 | } 42 | return 43 | } 44 | return endpointCountResponse.(*CountResponse).Count, endpointCountResponse.(*CountResponse).Positions, err 45 | } 46 | 47 | func (E *Endpoints) TestCase(ctx context.Context, comments []*entity.Comment) (tree map[string]int, err error) { 48 | endpointTestCaseRequest := TestCaseRequest{Comments: comments} 49 | endpointTestCaseResponse, err := E.TestCaseEndpoint(ctx, &endpointTestCaseRequest) 50 | if err != nil { 51 | if grpc.Code(err) == codes.Internal || grpc.Code(err) == codes.Unknown { 52 | err = errors.New(grpc.ErrorDesc(err)) 53 | } 54 | return 55 | } 56 | return endpointTestCaseResponse.(*TestCaseResponse).Tree, err 57 | } 58 | 59 | func UppercaseEndpoint(svc StringService) endpoint.Endpoint { 60 | return func(ctx context.Context, request interface{}) (interface{}, error) { 61 | _req := request.(*UppercaseRequest) 62 | ans, err := svc.Uppercase(ctx, _req.Str...) 63 | return &UppercaseResponse{Ans: ans}, err 64 | } 65 | } 66 | 67 | func CountEndpoint(svc StringService) endpoint.Endpoint { 68 | return func(ctx context.Context, request interface{}) (interface{}, error) { 69 | _req := request.(*CountRequest) 70 | count, positions, err := svc.Count(ctx, _req.Text, _req.Symbol) 71 | return &CountResponse{ 72 | Count: count, 73 | Positions: positions, 74 | }, err 75 | } 76 | } 77 | 78 | func TestCaseEndpoint(svc StringService) endpoint.Endpoint { 79 | return func(ctx context.Context, request interface{}) (interface{}, error) { 80 | _req := request.(*TestCaseRequest) 81 | tree, err := svc.TestCase(ctx, _req.Comments) 82 | return &TestCaseResponse{Tree: tree}, err 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /generator/test_assets/exchanges.go.txt: -------------------------------------------------------------------------------- 1 | // This file was automatically generated by "microgen 0.6.0" utility. 2 | // Please, do not edit. 3 | package stringsvc 4 | 5 | import entity "github.com/devimteam/microgen/example/svc/entity" 6 | 7 | type UppercaseRequest struct { 8 | Str []map[string]interface{} `json:"str"` // This field was defined with ellipsis (...). 9 | } 10 | 11 | type UppercaseResponse struct { 12 | Ans string `json:"ans"` 13 | } 14 | 15 | type CountRequest struct { 16 | Text string `json:"text"` 17 | Symbol string `json:"symbol"` 18 | } 19 | 20 | type CountResponse struct { 21 | Count int `json:"count"` 22 | Positions []int `json:"positions"` 23 | } 24 | 25 | type TestCaseRequest struct { 26 | Comments []*entity.Comment `json:"comments"` 27 | } 28 | 29 | type TestCaseResponse struct { 30 | Tree map[string]int `json:"tree"` 31 | } 32 | -------------------------------------------------------------------------------- /generator/test_assets/grpc_client.go.txt: -------------------------------------------------------------------------------- 1 | // This file was automatically generated by "microgen 0.6.0" utility. 2 | // Please, do not edit. 3 | package transportgrpc 4 | 5 | import ( 6 | testout "github.com/devimteam/microgen/generator/test_out" 7 | protobuf "github.com/devimteam/microgen/generator/test_out/transport/converter/protobuf" 8 | stringsvc "github.com/devimteam/protobuf/stringsvc" 9 | grpc1 "github.com/go-kit/kit/transport/grpc" 10 | grpc "google.golang.org/grpc" 11 | ) 12 | 13 | func NewGRPCClient(conn *grpc.ClientConn, opts ...grpc1.ClientOption) testout.StringService { 14 | return &testout.Endpoints{ 15 | CountEndpoint: grpc1.NewClient( 16 | conn, 17 | "devim.string.team", 18 | "Count", 19 | protobuf.EncodeCountRequest, 20 | protobuf.DecodeCountResponse, 21 | stringsvc.CountResponse{}, 22 | opts..., 23 | ).Endpoint(), 24 | TestCaseEndpoint: grpc1.NewClient( 25 | conn, 26 | "devim.string.team", 27 | "TestCase", 28 | protobuf.EncodeTestCaseRequest, 29 | protobuf.DecodeTestCaseResponse, 30 | stringsvc.TestCaseResponse{}, 31 | opts..., 32 | ).Endpoint(), 33 | UppercaseEndpoint: grpc1.NewClient( 34 | conn, 35 | "devim.string.team", 36 | "Uppercase", 37 | protobuf.EncodeUppercaseRequest, 38 | protobuf.DecodeUppercaseResponse, 39 | stringsvc.UppercaseResponse{}, 40 | opts..., 41 | ).Endpoint(), 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /generator/test_assets/grpc_converters.go.txt: -------------------------------------------------------------------------------- 1 | // This file was automatically generated by "microgen 0.6.0" utility. 2 | // Please, do not change functions names! 3 | package protobuf 4 | 5 | import ( 6 | context "context" 7 | testout "github.com/devimteam/microgen/generator/test_out" 8 | stringsvc "github.com/devimteam/protobuf/stringsvc" 9 | ) 10 | 11 | func EncodeUppercaseRequest(_ context.Context, request interface{}) (interface{}, error) { 12 | req := request.(*testout.UppercaseRequest) 13 | reqStr, err := ToProto(req.Str) 14 | if err != nil { 15 | return nil, err 16 | } 17 | return &stringsvc.UppercaseRequest{Str: reqStr}, nil 18 | } 19 | 20 | func EncodeCountRequest(_ context.Context, request interface{}) (interface{}, error) { 21 | req := request.(*testout.CountRequest) 22 | return &stringsvc.CountRequest{ 23 | Symbol: req.Symbol, 24 | Text: req.Text, 25 | }, nil 26 | } 27 | 28 | func EncodeTestCaseRequest(_ context.Context, request interface{}) (interface{}, error) { 29 | req := request.(*testout.TestCaseRequest) 30 | reqComments, err := ListPtrEntityCommentToProto(req.Comments) 31 | if err != nil { 32 | return nil, err 33 | } 34 | return &stringsvc.TestCaseRequest{Comments: reqComments}, nil 35 | } 36 | 37 | func EncodeUppercaseResponse(_ context.Context, response interface{}) (interface{}, error) { 38 | resp := response.(*testout.UppercaseResponse) 39 | return &stringsvc.UppercaseResponse{Ans: resp.Ans}, nil 40 | } 41 | 42 | func EncodeCountResponse(_ context.Context, response interface{}) (interface{}, error) { 43 | resp := response.(*testout.CountResponse) 44 | respPositions, err := ListIntToProto(resp.Positions) 45 | if err != nil { 46 | return nil, err 47 | } 48 | return &stringsvc.CountResponse{ 49 | Count: int64(resp.Count), 50 | Positions: respPositions, 51 | }, nil 52 | } 53 | 54 | func EncodeTestCaseResponse(_ context.Context, response interface{}) (interface{}, error) { 55 | resp := response.(*testout.TestCaseResponse) 56 | respTree, err := MapStringIntToProto(resp.Tree) 57 | if err != nil { 58 | return nil, err 59 | } 60 | return &stringsvc.TestCaseResponse{Tree: respTree}, nil 61 | } 62 | 63 | func DecodeUppercaseRequest(_ context.Context, request interface{}) (interface{}, error) { 64 | req := request.(*stringsvc.UppercaseRequest) 65 | reqStr, err := ProtoTo(req.Str) 66 | if err != nil { 67 | return nil, err 68 | } 69 | return &testout.UppercaseRequest{Str: reqStr}, nil 70 | } 71 | 72 | func DecodeCountRequest(_ context.Context, request interface{}) (interface{}, error) { 73 | req := request.(*stringsvc.CountRequest) 74 | return &testout.CountRequest{ 75 | Symbol: string(req.Symbol), 76 | Text: string(req.Text), 77 | }, nil 78 | } 79 | 80 | func DecodeTestCaseRequest(_ context.Context, request interface{}) (interface{}, error) { 81 | req := request.(*stringsvc.TestCaseRequest) 82 | reqComments, err := ProtoToListPtrEntityComment(req.Comments) 83 | if err != nil { 84 | return nil, err 85 | } 86 | return &testout.TestCaseRequest{Comments: reqComments}, nil 87 | } 88 | 89 | func DecodeUppercaseResponse(_ context.Context, response interface{}) (interface{}, error) { 90 | resp := response.(*stringsvc.UppercaseResponse) 91 | return &testout.UppercaseResponse{Ans: string(resp.Ans)}, nil 92 | } 93 | 94 | func DecodeCountResponse(_ context.Context, response interface{}) (interface{}, error) { 95 | resp := response.(*stringsvc.CountResponse) 96 | respPositions, err := ProtoToListInt(resp.Positions) 97 | if err != nil { 98 | return nil, err 99 | } 100 | return &testout.CountResponse{ 101 | Count: int(resp.Count), 102 | Positions: respPositions, 103 | }, nil 104 | } 105 | 106 | func DecodeTestCaseResponse(_ context.Context, response interface{}) (interface{}, error) { 107 | resp := response.(*stringsvc.TestCaseResponse) 108 | respTree, err := ProtoToMapStringInt(resp.Tree) 109 | if err != nil { 110 | return nil, err 111 | } 112 | return &testout.TestCaseResponse{Tree: respTree}, nil 113 | } 114 | -------------------------------------------------------------------------------- /generator/test_assets/grpc_server.go.txt: -------------------------------------------------------------------------------- 1 | // This file was automatically generated by "microgen 0.6.0" utility. 2 | // Please, do not edit. 3 | package transportgrpc 4 | 5 | import ( 6 | testout "github.com/devimteam/microgen/generator/test_out" 7 | protobuf "github.com/devimteam/microgen/generator/test_out/transport/converter/protobuf" 8 | stringsvc "github.com/devimteam/protobuf/stringsvc" 9 | grpc "github.com/go-kit/kit/transport/grpc" 10 | context "golang.org/x/net/context" 11 | ) 12 | 13 | type stringServiceServer struct { 14 | uppercase grpc.Handler 15 | count grpc.Handler 16 | testCase grpc.Handler 17 | } 18 | 19 | func NewGRPCServer(endpoints *testout.Endpoints, opts ...grpc.ServerOption) stringsvc.StringServiceServer { 20 | return &stringServiceServer{ 21 | count: grpc.NewServer( 22 | endpoints.CountEndpoint, 23 | protobuf.DecodeCountRequest, 24 | protobuf.EncodeCountResponse, 25 | opts..., 26 | ), 27 | testCase: grpc.NewServer( 28 | endpoints.TestCaseEndpoint, 29 | protobuf.DecodeTestCaseRequest, 30 | protobuf.EncodeTestCaseResponse, 31 | opts..., 32 | ), 33 | uppercase: grpc.NewServer( 34 | endpoints.UppercaseEndpoint, 35 | protobuf.DecodeUppercaseRequest, 36 | protobuf.EncodeUppercaseResponse, 37 | opts..., 38 | ), 39 | } 40 | } 41 | 42 | func (S *stringServiceServer) Uppercase(ctx context.Context, req *stringsvc.UppercaseRequest) (*stringsvc.UppercaseResponse, error) { 43 | _, resp, err := S.uppercase.ServeGRPC(ctx, req) 44 | if err != nil { 45 | return nil, err 46 | } 47 | return resp.(*stringsvc.UppercaseResponse), nil 48 | } 49 | 50 | func (S *stringServiceServer) Count(ctx context.Context, req *stringsvc.CountRequest) (*stringsvc.CountResponse, error) { 51 | _, resp, err := S.count.ServeGRPC(ctx, req) 52 | if err != nil { 53 | return nil, err 54 | } 55 | return resp.(*stringsvc.CountResponse), nil 56 | } 57 | 58 | func (S *stringServiceServer) TestCase(ctx context.Context, req *stringsvc.TestCaseRequest) (*stringsvc.TestCaseResponse, error) { 59 | _, resp, err := S.testCase.ServeGRPC(ctx, req) 60 | if err != nil { 61 | return nil, err 62 | } 63 | return resp.(*stringsvc.TestCaseResponse), nil 64 | } 65 | -------------------------------------------------------------------------------- /generator/test_assets/grpc_type.go.txt: -------------------------------------------------------------------------------- 1 | // This file was automatically generated by "microgen 0.6.0" utility. 2 | // It is better for you if you do not change functions names! 3 | // This file will never be overwritten. 4 | package protobuf 5 | 6 | import ( 7 | entity "github.com/devimteam/microgen/example/svc/entity" 8 | stringsvc "github.com/devimteam/protobuf/stringsvc" 9 | ) 10 | 11 | func ToProto(str []map[string]interface{}) ([]map[string]interface{}, error) { 12 | panic("function not provided") 13 | } 14 | 15 | func ProtoTo(protoStr []map[string]interface{}) ([]map[string]interface{}, error) { 16 | panic("function not provided") 17 | } 18 | 19 | func ListIntToProto(positions []int) ([]int64, error) { 20 | panic("function not provided") 21 | } 22 | 23 | func ProtoToListInt(protoPositions []int64) ([]int, error) { 24 | panic("function not provided") 25 | } 26 | 27 | func ListPtrEntityCommentToProto(comments []*entity.Comment) ([]*stringsvc.Comment, error) { 28 | panic("function not provided") 29 | } 30 | 31 | func ProtoToListPtrEntityComment(protoComments []*stringsvc.Comment) ([]*entity.Comment, error) { 32 | panic("function not provided") 33 | } 34 | 35 | func MapStringIntToProto(tree map[string]int) (map[string]int64, error) { 36 | panic("function not provided") 37 | } 38 | 39 | func ProtoToMapStringInt(protoTree map[string]int64) (map[string]int, error) { 40 | panic("function not provided") 41 | } 42 | -------------------------------------------------------------------------------- /generator/test_assets/logging.go.txt: -------------------------------------------------------------------------------- 1 | // This file was automatically generated by "microgen 0.6.0" utility. 2 | // Please, do not edit. 3 | package middleware 4 | 5 | import ( 6 | context "context" 7 | entity "github.com/devimteam/microgen/example/svc/entity" 8 | testout "github.com/devimteam/microgen/generator/test_out" 9 | log "github.com/go-kit/kit/log" 10 | time "time" 11 | ) 12 | 13 | // ServiceLogging writes params, results and working time of method call to provided logger after its execution. 14 | func ServiceLogging(logger log.Logger) Middleware { 15 | return func(next testout.StringService) testout.StringService { 16 | return &serviceLogging{ 17 | logger: logger, 18 | next: next, 19 | } 20 | } 21 | } 22 | 23 | type serviceLogging struct { 24 | logger log.Logger 25 | next testout.StringService 26 | } 27 | 28 | func (L *serviceLogging) Uppercase(ctx context.Context, str ...map[string]interface{}) (ans string, err error) { 29 | defer func(begin time.Time) { 30 | L.logger.Log( 31 | "@method", "Uppercase", 32 | "str", str, 33 | "took", time.Since(begin)) 34 | }(time.Now()) 35 | return L.next.Uppercase(ctx, str...) 36 | } 37 | 38 | func (L *serviceLogging) Count(ctx context.Context, text string, symbol string) (count int, positions []int, err error) { 39 | defer func(begin time.Time) { 40 | L.logger.Log( 41 | "@method", "Count", 42 | "text", text, 43 | "symbol", symbol, 44 | "count", count, 45 | "positions", positions, 46 | "err", err, 47 | "took", time.Since(begin)) 48 | }(time.Now()) 49 | return L.next.Count(ctx, text, symbol) 50 | } 51 | 52 | func (L *serviceLogging) TestCase(ctx context.Context, comments []*entity.Comment) (tree map[string]int, err error) { 53 | defer func(begin time.Time) { 54 | L.logger.Log( 55 | "@method", "TestCase", 56 | "comments", comments, 57 | "len(comments)", len(comments), 58 | "tree", tree, 59 | "err", err, 60 | "took", time.Since(begin)) 61 | }(time.Now()) 62 | return L.next.TestCase(ctx, comments) 63 | } 64 | -------------------------------------------------------------------------------- /generator/test_assets/middleware.go.txt: -------------------------------------------------------------------------------- 1 | // This file was automatically generated by "microgen 0.6.0" utility. 2 | // Please, do not edit. 3 | package middleware 4 | 5 | import testout "github.com/devimteam/microgen/generator/test_out" 6 | 7 | // Service middleware 8 | type Middleware func(testout.StringService) testout.StringService 9 | -------------------------------------------------------------------------------- /generator/test_assets/service.go.txt: -------------------------------------------------------------------------------- 1 | package stringsvc 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/devimteam/microgen/example/svc/entity" 7 | ) 8 | 9 | // @microgen middleware, logging, grpc, http, recover, main 10 | // @grpc-addr devim.string.team 11 | // @protobuf github.com/devimteam/protobuf/stringsvc 12 | type StringService interface { 13 | // @logs-ignore ans, err 14 | Uppercase(ctx context.Context, str ...map[string]interface{}) (ans string, err error) 15 | Count(ctx context.Context, text string, symbol string) (count int, positions []int, err error) 16 | // @logs-len comments 17 | TestCase(ctx context.Context, comments []*entity.Comment) (tree map[string]int, err error) 18 | } -------------------------------------------------------------------------------- /generator/validate.go: -------------------------------------------------------------------------------- 1 | package generator 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | 7 | mstrings "github.com/devimteam/microgen/generator/strings" 8 | "github.com/devimteam/microgen/generator/template" 9 | "github.com/vetcher/go-astra/types" 10 | ) 11 | 12 | func ValidateInterface(iface *types.Interface) error { 13 | var errs []error 14 | if len(iface.Methods) == 0 { 15 | errs = append(errs, fmt.Errorf("%s does not have any methods", iface.Name)) 16 | } 17 | for _, m := range iface.Methods { 18 | errs = append(errs, validateFunction(m)...) 19 | } 20 | return composeErrors(errs...) 21 | } 22 | 23 | // Rules: 24 | // * First argument is context.Context. 25 | // * Last result is error. 26 | // * All params have names. 27 | func validateFunction(fn *types.Function) (errs []error) { 28 | // don't validate when `@microgen -` provided 29 | if mstrings.ContainTag(mstrings.FetchTags(fn.Docs, TagMark+MicrogenMainTag), "-") { 30 | return 31 | } 32 | if !template.IsContextFirst(fn.Args) { 33 | errs = append(errs, fmt.Errorf("%s: first argument should be of type context.Context", fn.Name)) 34 | } 35 | if !template.IsErrorLast(fn.Results) { 36 | errs = append(errs, fmt.Errorf("%s: last result should be of type error", fn.Name)) 37 | } 38 | for _, param := range append(fn.Args, fn.Results...) { 39 | if param.Name == "" { 40 | errs = append(errs, fmt.Errorf("%s: unnamed parameter of type %s", fn.Name, param.Type.String())) 41 | } 42 | if iface := types.TypeInterface(param.Type); iface != nil && !iface.(types.TInterface).Interface.IsEmpty() { 43 | errs = append(errs, fmt.Errorf("%s: non empty interface %s is not allowed, delcare it outside", fn.Name, param.String())) 44 | } 45 | if strct := types.TypeStruct(param.Type); strct != nil { 46 | errs = append(errs, fmt.Errorf("%s: raw struct %s is not allowed, declare it outside", fn.Name, param.Name)) 47 | } 48 | if f := types.TypeFunction(param.Type); f != nil { 49 | errs = append(errs, fmt.Errorf("%s: raw function %s is not allowed, declare it outside", fn.Name, param.Name)) 50 | } 51 | } 52 | if template.FetchHttpMethodTag(fn.Docs) == "GET" && !isArgumentsAllowSmartPath(fn) { 53 | errs = append(errs, fmt.Errorf("%s: can't use GET method with provided arguments", fn.Name)) 54 | } 55 | return 56 | } 57 | 58 | func isArgumentsAllowSmartPath(fn *types.Function) bool { 59 | for _, arg := range template.RemoveContextIfFirst(fn.Args) { 60 | if !canInsertToPath(&arg) { 61 | return false 62 | } 63 | } 64 | return true 65 | } 66 | 67 | var insertableToUrlTypes = []string{"string", "int", "int32", "int64", "uint", "uint32", "uint64"} 68 | 69 | // We can make url variable from string, int, int32, int64, uint, uint32, uint64 70 | func canInsertToPath(p *types.Variable) bool { 71 | name := types.TypeName(p.Type) 72 | return name != nil && mstrings.IsInStringSlice(*name, insertableToUrlTypes) 73 | } 74 | 75 | func composeErrors(errs ...error) error { 76 | if len(errs) > 0 { 77 | var strs []string 78 | for _, err := range errs { 79 | if err != nil { 80 | strs = append(strs, err.Error()) 81 | } 82 | } 83 | if len(strs) == 1 { 84 | return fmt.Errorf(strs[0]) 85 | } 86 | if len(strs) > 0 { 87 | return fmt.Errorf("many errors:\n%v", strings.Join(strs, "\n")) 88 | } 89 | } 90 | return nil 91 | } 92 | -------------------------------------------------------------------------------- /generator/write_strategy/common.go: -------------------------------------------------------------------------------- 1 | package write_strategy 2 | 3 | import "io" 4 | 5 | type Renderer interface { 6 | Render(io.Writer) error 7 | } 8 | 9 | type Strategy interface { 10 | Write(Renderer) error 11 | } 12 | -------------------------------------------------------------------------------- /generator/write_strategy/file.go: -------------------------------------------------------------------------------- 1 | package write_strategy 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "go/format" 7 | "io/ioutil" 8 | "os" 9 | "path" 10 | "path/filepath" 11 | 12 | lg "github.com/devimteam/microgen/logger" 13 | ) 14 | 15 | const ( 16 | MkdirPermissions = 0777 17 | 18 | // This hack needs for normal code formatting. 19 | // It makes formatter think, that declared code is top-level. 20 | // Without this hack formatter adds separators (tabs) to beginning of every line. 21 | formatTrick = "package T\n" 22 | 23 | NewFileMark = "New" 24 | AppendFileMark = "Add" 25 | ) 26 | 27 | type createFileStrategy struct { 28 | absPath string 29 | relPath string 30 | 31 | formatOn bool 32 | } 33 | 34 | func (s createFileStrategy) Write(renderer Renderer) error { 35 | outpath, err := filepath.Abs(filepath.Join(s.absPath, s.relPath)) 36 | if err != nil { 37 | return fmt.Errorf("unable to resolve path: %v", err) 38 | } 39 | dir := path.Dir(outpath) 40 | 41 | _, err = os.Stat(dir) 42 | 43 | if os.IsNotExist(err) { 44 | err = os.MkdirAll(dir, MkdirPermissions) 45 | if err != nil { 46 | return fmt.Errorf("unable to create directory %s: %v", outpath, err) 47 | } 48 | } else if err != nil { 49 | return fmt.Errorf("could not stat file: %v", err) 50 | } 51 | 52 | err = s.Save(renderer, outpath) 53 | if err != nil { 54 | return fmt.Errorf("error when save file: %v", err) 55 | } 56 | return nil 57 | } 58 | 59 | // Copied from original github.com/dave/jennifer/jen.go func Save() 60 | func (s createFileStrategy) Save(f Renderer, filename string) error { 61 | buf := &bytes.Buffer{} 62 | if err := f.Render(buf); err != nil { 63 | return err 64 | } 65 | // Stop saving because nothing to save 66 | if len(buf.Bytes()) == 0 { 67 | return nil 68 | } 69 | var err error 70 | formatted := buf.Bytes() 71 | if s.formatOn { 72 | formatted, err = format.Source(formatted) 73 | if err != nil { 74 | fmt.Println(buf.String()) 75 | return fmt.Errorf("error when format source: %v", err) 76 | } 77 | } 78 | if err := ioutil.WriteFile(filename, formatted, 0644); err != nil { 79 | return err 80 | } 81 | lg.Logger.Logln(2, NewFileMark, filepath.Join(s.absPath, s.relPath)) 82 | return nil 83 | } 84 | 85 | func NewCreateFileStrategy(absPath, relPath string) Strategy { 86 | return createFileStrategy{ 87 | absPath: absPath, 88 | relPath: relPath, 89 | formatOn: true, 90 | } 91 | } 92 | 93 | func NewCreateRawFileStrategy(absPath, relPath string) Strategy { 94 | return createFileStrategy{ 95 | absPath: absPath, 96 | relPath: relPath, 97 | formatOn: false, 98 | } 99 | } 100 | 101 | type appendFileStrategy struct { 102 | absPath string 103 | relPath string 104 | } 105 | 106 | func NewAppendToFileStrategy(absPath, relPath string) Strategy { 107 | return appendFileStrategy{ 108 | absPath: absPath, 109 | relPath: relPath, 110 | } 111 | } 112 | 113 | func (s appendFileStrategy) Write(renderer Renderer) error { 114 | outpath, err := filepath.Abs(filepath.Join(s.absPath, s.relPath)) 115 | if err != nil { 116 | return fmt.Errorf("unable to resolve path: %v", err) 117 | } 118 | dir := path.Dir(outpath) 119 | 120 | _, err = os.Stat(dir) 121 | 122 | if os.IsNotExist(err) { 123 | err = os.MkdirAll(dir, MkdirPermissions) 124 | if err != nil { 125 | return fmt.Errorf("unable to create directory %s: %v", outpath, err) 126 | } 127 | } else if err != nil { 128 | return fmt.Errorf("could not stat file: %v", err) 129 | } 130 | 131 | if _, err = os.Stat(outpath); os.IsNotExist(err) { 132 | f, err := os.Create(outpath) 133 | if err != nil { 134 | return fmt.Errorf("can't create %s: error: %v", outpath, err) 135 | } 136 | f.Close() 137 | } 138 | 139 | err = s.Save(renderer, outpath) 140 | if err != nil { 141 | return fmt.Errorf("error when save file: %v", err) 142 | } 143 | return nil 144 | } 145 | 146 | func (s appendFileStrategy) Save(renderer Renderer, filename string) error { 147 | buf := &bytes.Buffer{} 148 | if err := renderer.Render(buf); err != nil { 149 | return err 150 | } 151 | 152 | // Stop saving because nothing 153 | if len(buf.Bytes()) == 0 { 154 | return nil 155 | } 156 | // Use trick for top-level formatting. 157 | formatted, err := format.Source(append([]byte(formatTrick), buf.Bytes()...)) 158 | if err != nil { 159 | fmt.Println(buf.String()) 160 | return fmt.Errorf("error when format source: %v", err) 161 | } 162 | 163 | f, err := os.OpenFile(filename, os.O_APPEND|os.O_WRONLY, 0644) 164 | if err != nil { 165 | return err 166 | } 167 | if _, err = f.Write(formatted[len(formatTrick):]); err != nil { 168 | return err 169 | } 170 | lg.Logger.Logln(2, AppendFileMark, filepath.Join(s.absPath, s.relPath)) 171 | return nil 172 | } 173 | -------------------------------------------------------------------------------- /generator/write_strategy/nop.go: -------------------------------------------------------------------------------- 1 | package write_strategy 2 | 3 | type nopStrategy struct { 4 | } 5 | 6 | // Do nothing strategy 7 | func NewNopStrategy(string, string) Strategy { 8 | return nopStrategy{} 9 | } 10 | 11 | func (s nopStrategy) Write(Renderer) error { 12 | return nil 13 | } 14 | 15 | func (s nopStrategy) Save(Renderer, string) error { 16 | return nil 17 | } 18 | -------------------------------------------------------------------------------- /generator/write_strategy/writer.go: -------------------------------------------------------------------------------- 1 | package write_strategy 2 | 3 | /* 4 | import ( 5 | "fmt" 6 | "io" 7 | 8 | "github.com/devimteam/microgen/generator/template" 9 | ) 10 | 11 | type writerStrategy struct { 12 | writer io.Writer 13 | } 14 | 15 | func (s writerStrategy) Write(f template.Renderer, t template.Template) error { 16 | err := f.Render(s.writer) 17 | if err != nil { 18 | return fmt.Errorf("render error: %v", err) 19 | } 20 | return nil 21 | } 22 | 23 | func NewWriterStrategy(writer io.Writer) template.Strategy { 24 | return writerStrategy{ 25 | writer: writer, 26 | } 27 | } 28 | */ 29 | -------------------------------------------------------------------------------- /logger/logger.go: -------------------------------------------------------------------------------- 1 | package logger 2 | 3 | import "fmt" 4 | 5 | var Logger = &LevelLogger{} 6 | 7 | type LevelLogger struct { 8 | Level int 9 | } 10 | 11 | func (l *LevelLogger) Log(lvl int, a ...interface{}) { 12 | if lvl <= l.Level { 13 | fmt.Print(a...) 14 | } 15 | } 16 | 17 | func (l *LevelLogger) Logf(lvl int, format string, a ...interface{}) { 18 | if lvl <= l.Level { 19 | fmt.Printf(format, a...) 20 | } 21 | } 22 | 23 | func (l *LevelLogger) Logln(lvl int, a ...interface{}) { 24 | if lvl <= l.Level { 25 | fmt.Println(a...) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /test/microgen_test.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | import ( 4 | "io/ioutil" 5 | "os" 6 | "path/filepath" 7 | "testing" 8 | ) 9 | 10 | type TestCase struct { 11 | Name string 12 | Got string 13 | Want string 14 | } 15 | 16 | const ( 17 | assestsPath = "./assets" 18 | wantSubPath = "./want" 19 | gotSubPath = "./got" 20 | ) 21 | 22 | func TestMain(m *testing.M) { 23 | m.Run() 24 | } 25 | 26 | func TestAssets(t *testing.T) { 27 | cases, err := ioutil.ReadDir(assestsPath) 28 | if err != nil { 29 | t.Fatal(err) 30 | } 31 | for _, c := range cases { 32 | if !c.IsDir() { 33 | continue 34 | } 35 | t.Run(c.Name(), func(t *testing.T) { 36 | path := filepath.Join(c.Name(), wantSubPath) 37 | wantFiles := make(map[string][]byte) 38 | err := filepath.Walk(path, func(path string, info os.FileInfo, err error) error { 39 | if err != nil { 40 | return err 41 | } 42 | if info.IsDir() { 43 | return nil 44 | } 45 | data, err := ioutil.ReadFile(path) 46 | if err != nil { 47 | t.Fatal(err) 48 | } 49 | wantFiles[path] = data 50 | return nil 51 | }) 52 | if err != nil { 53 | t.Fatal(err) 54 | } 55 | 56 | path = filepath.Join(c.Name(), gotSubPath) 57 | gotFiles := make(map[string][]byte) 58 | err = filepath.Walk(path, func(path string, info os.FileInfo, err error) error { 59 | if err != nil { 60 | return err 61 | } 62 | if info.IsDir() { 63 | return nil 64 | } 65 | data, err := ioutil.ReadFile(path) 66 | if err != nil { 67 | t.Fatal(err) 68 | } 69 | gotFiles[path] = data 70 | return nil 71 | }) 72 | if err != nil { 73 | t.Fatal(err) 74 | } 75 | for k, v := range wantFiles { 76 | if v2, ok := gotFiles[k]; !ok { 77 | t.Fatal(k, "not found") 78 | } else if string(v) != string(v2) { 79 | t.Fatal("not same") 80 | } 81 | } 82 | }) 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /test/util_test.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | "testing" 7 | ) 8 | 9 | var cases = []TestCase{ 10 | { 11 | Name: "1", 12 | Got: `1234567890`, 13 | Want: `qwertyuiop`, 14 | }, 15 | { 16 | Name: "2", 17 | Got: `1234567890 18 | 1234567890`, 19 | Want: `qwertyuiop 20 | qwertyuiop`, 21 | }, 22 | { 23 | Name: "3", 24 | Got: `1234567890 25 | 1234567890 26 | 1234567890 27 | 1234567890 28 | 1234567890 29 | 1234567890 30 | 1234567890`, 31 | Want: `1234567890 32 | 1234567890 33 | 1234567890 34 | 1234567890 35 | 1234567890 36 | qwertyuiop 37 | qwertyuiop 38 | 1234567890`, 39 | }, 40 | } 41 | 42 | func TestGenerationCases(t *testing.T) { 43 | for _, tt := range cases { 44 | t.Run(tt.Name, func(t *testing.T) { 45 | line, _ := findStringDifference(tt.Want, tt.Got) 46 | fmt.Println(cutWithLinesAround(tt.Want, line)) 47 | fmt.Println(cutWithLinesAround(tt.Got, line)) 48 | }) 49 | } 50 | } 51 | 52 | func findStringDifference(str1, str2 string) (lineNum, symbolNum int) { 53 | splited1 := strings.Split(str1, "\n") 54 | splited2 := strings.Split(str2, "\n") 55 | for ; lineNum < len(splited1) && lineNum < len(splited2); lineNum++ { 56 | if splited1[lineNum] == splited2[lineNum] { 57 | continue 58 | } 59 | line1, line2 := splited1[lineNum], splited2[lineNum] 60 | for i := 0; i < len(line1) && i < len(line2); i++ { 61 | if line1[i] != line2[i] { 62 | symbolNum = i 63 | break 64 | } 65 | } 66 | } 67 | return 68 | } 69 | 70 | const around = 2 71 | 72 | func cutWithLinesAround(str string, lineNum int) string { 73 | splited := strings.Split(str, "\n") 74 | i := 0 75 | var ans []string 76 | for lineNum-around < i && i < lineNum+around && i < len(splited) { 77 | if lineNum-around < i && i < lineNum+around { 78 | ans = append(ans, fmt.Sprintf("%d\t%s", i+1, splited[i])) 79 | } 80 | i++ 81 | } 82 | return strings.Join(ans, "\n") 83 | } 84 | --------------------------------------------------------------------------------