├── .gitignore ├── Makefile ├── README.md ├── client ├── client.go ├── grpc_client.go ├── http_client.go └── http_client_test.go ├── count.go ├── duration.go ├── go.mod ├── go.sum ├── gui ├── app.go ├── call │ └── stream_call.go ├── history.go ├── history_test.go ├── io │ ├── log.pb.go │ ├── log.proto │ ├── serialize.go │ └── serialize_test.go ├── lru.go ├── lru_test.go ├── main.go └── reflect.go ├── main.go ├── meta └── meta.go ├── model └── model.go ├── pic ├── bd-stream-min.gif ├── client-stream-min.gif ├── gopher.png ├── ptg-min.gif ├── ptg.gif ├── search.gif ├── server-stream-min.gif └── show.gif ├── reflect ├── gen │ ├── common.pb.go │ ├── common.proto │ ├── test.pb.go │ ├── test.proto │ ├── test_grpc.pb.go │ ├── user.proto │ └── user │ │ ├── user.pb.go │ │ └── user_grpc.pb.go ├── reflect.go └── reflect_test.go └── test.json /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### macOS template 3 | # General 4 | .DS_Store 5 | .AppleDouble 6 | .LSOverride 7 | 8 | # Icon must end with two \r 9 | Icon 10 | 11 | # Thumbnails 12 | ._* 13 | 14 | # Files that might appear in the root of a volume 15 | .DocumentRevisions-V100 16 | .fseventsd 17 | .Spotlight-V100 18 | .TemporaryItems 19 | .Trashes 20 | .VolumeIcon.icns 21 | .com.apple.timemachine.donotpresent 22 | 23 | # Directories potentially created on remote AFP share 24 | .AppleDB 25 | .AppleDesktop 26 | Network Trash Folder 27 | Temporary Items 28 | .apdisk 29 | 30 | ### JetBrains template 31 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm 32 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 33 | .idea 34 | # User-specific stuff 35 | .idea/**/workspace.xml 36 | .idea/**/tasks.xml 37 | .idea/**/usage.statistics.xml 38 | .idea/**/dictionaries 39 | .idea/**/shelf 40 | 41 | # Generated files 42 | .idea/**/contentModel.xml 43 | 44 | # Sensitive or high-churn files 45 | .idea/**/dataSources/ 46 | .idea/**/dataSources.ids 47 | .idea/**/dataSources.local.xml 48 | .idea/**/sqlDataSources.xml 49 | .idea/**/dynamic.xml 50 | .idea/**/uiDesigner.xml 51 | .idea/**/dbnavigator.xml 52 | 53 | # Gradle 54 | .idea/**/gradle.xml 55 | .idea/**/libraries 56 | 57 | # Gradle and Maven with auto-import 58 | # When using Gradle or Maven with auto-import, you should exclude module files, 59 | # since they will be recreated, and may cause churn. Uncomment if using 60 | # auto-import. 61 | # .idea/artifacts 62 | # .idea/compiler.xml 63 | # .idea/modules.xml 64 | # .idea/*.iml 65 | # .idea/modules 66 | # *.iml 67 | # *.ipr 68 | 69 | # CMake 70 | cmake-build-*/ 71 | 72 | # Mongo Explorer plugin 73 | .idea/**/mongoSettings.xml 74 | 75 | # File-based project format 76 | *.iws 77 | 78 | # IntelliJ 79 | out/ 80 | 81 | # mpeltonen/sbt-idea plugin 82 | .idea_modules/ 83 | 84 | # JIRA plugin 85 | atlassian-ide-plugin.xml 86 | 87 | # Cursive Clojure plugin 88 | .idea/replstate.xml 89 | 90 | # Crashlytics plugin (for Android Studio and IntelliJ) 91 | com_crashlytics_export_strings.xml 92 | crashlytics.properties 93 | crashlytics-build.properties 94 | fabric.properties 95 | 96 | # Editor-based Rest Client 97 | .idea/httpRequests 98 | 99 | # Android studio 3.1+ serialized cache file 100 | .idea/caches/build_file_checksums.ser 101 | 102 | ### Go template 103 | # Binaries for programs and plugins 104 | *.exe 105 | *.exe~ 106 | *.dll 107 | *.so 108 | *.dylib 109 | 110 | # Test binary, built with `go test -c` 111 | *.test 112 | 113 | # Output of the go coverage tool, specifically when used with LiteIDE 114 | *.out 115 | 116 | # Dependency directories (remove the comment below to include it) 117 | # vendor/ 118 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Binary name 2 | BINARY=ptg 3 | GOBUILD=go build -ldflags "-s -w" -o ${BINARY} 4 | GOCLEAN=go clean 5 | RMTARGZ=rm -rf *.gz 6 | RMMACAPP=rm -rf ptg.app 7 | VERSION=1.0.5 8 | 9 | # Build 10 | build: 11 | $(GOCLEAN) 12 | $(GOBUILD) 13 | 14 | 15 | clean: 16 | $(GOCLEAN) 17 | $(RMTARGZ) 18 | 19 | 20 | git-tag: 21 | git tag $(VERSION); \ 22 | git push origin $(VERSION); \ 23 | 24 | release: 25 | # Clean 26 | $(GOCLEAN) 27 | $(RMTARGZ) 28 | # Build for mac 29 | CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 $(GOBUILD) 30 | tar czvf ${BINARY}-mac64-${VERSION}.tar.gz ./${BINARY} 31 | # Build for arm 32 | $(GOCLEAN) 33 | CGO_ENABLED=0 GOOS=linux GOARCH=arm64 $(GOBUILD) 34 | tar czvf ${BINARY}-arm64-${VERSION}.tar.gz ./${BINARY} 35 | # Build for linux 36 | $(GOCLEAN) 37 | CGO_ENABLED=0 GOOS=linux GOARCH=amd64 $(GOBUILD) 38 | tar czvf ${BINARY}-linux64-${VERSION}.tar.gz ./${BINARY} 39 | # Build for win 40 | $(GOCLEAN) 41 | CGO_ENABLED=0 GOOS=windows GOARCH=amd64 $(GOBUILD).exe 42 | tar czvf ${BINARY}-win64-${VERSION}.tar.gz ./${BINARY}.exe 43 | $(GOCLEAN) 44 | 45 | 46 | gen-go-proto: 47 | @protoc --go_out=. --go_opt=paths=source_relative \ 48 | --go-grpc_out=. --go-grpc_opt=paths=source_relative \ 49 | reflect/gen/test.proto 50 | 51 | gen-log-proto: 52 | @protoc --go_out=. --go_opt=paths=source_relative \ 53 | --go-grpc_out=. --go-grpc_opt=paths=source_relative \ 54 | gui/io/log.proto 55 | 56 | pkg-win: 57 | fyne package -os windows -src gui/ -icon pic/gopher.png -name ${BINARY} -appVersion $(VERSION) 58 | 59 | pkg-macos: 60 | fyne package -os darwin -src gui/ -icon pic/gopher.png -name ${BINARY} -appVersion $(VERSION) 61 | tar czvf ${BINARY}-mac-gui.tar ./${BINARY}.app 62 | $(RMMACAPP) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ptg 2 | Performance testing tool (Go), It is also a **GUI** `gRPC` client. 3 | 4 | Test the `gRPC` service like `postman`. 5 | 6 | 7 | ![](pic/show.gif) 8 | ![](pic/ptg.gif) 9 | ![](pic/search.gif) 10 |
11 | More screenshot 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | # Features 20 | - [x] CLI performance test support. 21 | - [x] GUI support. 22 | - [x] Metadata support. 23 | - [x] Data persistence. 24 | - [x] Search history. 25 | - [X] Stream call. 26 | - [ ] Benchmark GUI. 27 | 28 | # Install 29 | 30 | ## CLI app 31 | ```go 32 | go get github.com/crossoverJie/ptg 33 | ``` 34 | 35 | ```shell script 36 | wget https://github.com/crossoverJie/ptg/releases/download/${version}/ptg-${os}-${version}.tar.gz 37 | ``` 38 | 39 | ## GUI app 40 | 41 | To download the installer, go to the [Releases Page](https://github.com/crossoverJie/ptg/releases). 42 | 43 | ## Build from source 44 | 45 | ```shell 46 | git clone git@github.com:crossoverJie/ptg.git 47 | cd ptg 48 | make release 49 | make pkg-win 50 | make pkg-macos 51 | ``` 52 | 53 | 54 | # Usage 55 | 56 | ```shell script 57 | NAME: 58 | ptg - Performance testing tool (Go) 59 | 60 | USAGE: 61 | ptg [global options] command [command options] [arguments...] 62 | 63 | COMMANDS: 64 | help, h Shows a list of commands or help for one command 65 | 66 | GLOBAL OPTIONS: 67 | --thread value, -t value -t 10 (default: 1 thread) 68 | --Request value, --proto value -proto http/grpc (default: http) 69 | --protocol value, --pf value -pf /file/order.proto 70 | --fully-qualified value, --fqn value -fqn package.Service.Method 71 | --duration value, -d value -d 10s (default: Duration of test in seconds, Default 10s) 72 | --request value, -c value -c 100 (default: 100) 73 | --HTTP value, -M value -m GET (default: GET) 74 | --bodyPath value, --body value -body bodyPath.json 75 | --header value, -H value HTTP header to add to request, e.g. "-H Content-Type: application/json" 76 | --target value, --tg value http://gobyexample.com/grpc:127.0.0.1:5000 77 | --help, -h show help (default: false) 78 | ``` 79 | ## http 80 | ```shell script 81 | ptg -t 20 -d 10 -proto http -tg "http://gobyexample.com" 82 | ``` 83 | 84 | Benchmark test for 10 seconds, using 20 goroutines. 85 | 86 | output: 87 | ```shell script 88 | Requesting: http://gobyexample.com <---------------> 1 p/s 100.00% 89 | 90 | 43 requests in 10 seconds, 13.88MB read. 91 | Avg Req Time: 358.512071ms 92 | Fastest Request: 93.518704ms 93 | Slowest Request: 840.680771ms 94 | Number of Errors: 0 95 | ``` 96 | 97 | > POST example 98 | 99 | ```shell script 100 | ptg -t 2 -proto http -c 2 -M POST -H "Content-Type: application/json" -body test.json -tg "http://xx/create" 101 | ``` 102 | 103 | ## gRPC(unary call) 104 | 105 | ```shell script 106 | ptg -t 10 -c 100 -proto grpc -pf /xx/xx.proto -fqn hello.Hi.Say -body test.json -tg "127.0.0.1:5000" 107 | ``` 108 | 109 | output: 110 | ```shell script 111 | thread: 10, duration: 0, count 100 112 | Requesting: 127.0.0.1:5000 <---------------> 102 p/s 100.00% 113 | 100 requests in 11 seconds, 230.6kB read, and cost 1 second. 114 | Avg Req Time: 116.602652ms 115 | Fastest Request: 111.563179ms 116 | Slowest Request: 128.587886ms 117 | Number of Errors: 0 118 | ``` 119 | 120 | 121 | # Acknowledgements 122 | - [go-wrk](https://github.com/tsliwowicz/go-wrk) 123 | - [bloomrpc](https://github.com/bloomrpc/bloomrpc) 124 | 125 | -------------------------------------------------------------------------------- /client/client.go: -------------------------------------------------------------------------------- 1 | package client 2 | 3 | import ( 4 | "github.com/crossoverJie/ptg/meta" 5 | "net/http" 6 | "time" 7 | ) 8 | 9 | type ( 10 | Client interface { 11 | Request() (*meta.Response, error) 12 | } 13 | ) 14 | 15 | const ( 16 | Http = "http" 17 | Grpc = "grpc" 18 | ) 19 | 20 | func NewClient(method, url, requestBody string, meta *meta.Meta) Client { 21 | if meta.Protocol() == Http { 22 | return &httpClient{ 23 | Method: method, 24 | Url: url, 25 | RequestBody: requestBody, 26 | httpClient: &http.Client{ 27 | Transport: &http.Transport{ 28 | DisableCompression: false, 29 | ResponseHeaderTimeout: time.Millisecond * time.Duration(10000), 30 | DisableKeepAlives: false, 31 | }, 32 | }, 33 | meta: meta, 34 | } 35 | } else { 36 | return NewGrpcClient(meta) 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /client/grpc_client.go: -------------------------------------------------------------------------------- 1 | package client 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "github.com/crossoverJie/ptg/meta" 7 | "github.com/crossoverJie/ptg/reflect" 8 | "github.com/jhump/protoreflect/desc" 9 | "github.com/jhump/protoreflect/dynamic/grpcdynamic" 10 | "google.golang.org/grpc" 11 | "sync" 12 | "time" 13 | ) 14 | 15 | var ( 16 | one sync.Once 17 | g *grpcClient 18 | ) 19 | 20 | type grpcClient struct { 21 | stub grpcdynamic.Stub 22 | mds *desc.MethodDescriptor 23 | meta *meta.Meta 24 | parseReflect *reflect.ParseReflect 25 | } 26 | 27 | func NewGrpcClient(meta *meta.Meta) Client { 28 | one.Do(func() { 29 | if g == nil { 30 | var ( 31 | opts []grpc.DialOption 32 | ) 33 | 34 | g = &grpcClient{ 35 | meta: meta, 36 | } 37 | opts = append(opts, grpc.WithInsecure()) 38 | conn, err := grpc.DialContext(context.Background(), meta.Target(), opts...) 39 | if err != nil { 40 | panic(fmt.Sprintf("create grpc connection err %v", err)) 41 | } 42 | g.stub = grpcdynamic.NewStub(conn) 43 | 44 | parse, err := reflect.NewParse(meta.ProtocolFile()) 45 | if err != nil { 46 | panic(fmt.Sprintf("create grpc parse reflect err %v", err)) 47 | } 48 | g.parseReflect = parse 49 | serviceName, methodName, err := reflect.ParseServiceMethod(meta.Fqn()) 50 | if err != nil { 51 | panic(fmt.Sprintf("parse MethodDescriptor err %v", err)) 52 | } 53 | g.mds, err = g.parseReflect.MethodDescriptor(serviceName, methodName) 54 | if err != nil { 55 | panic(fmt.Sprintf("create grpc MethodDescriptor err %v", err)) 56 | } 57 | 58 | } 59 | }) 60 | return g 61 | } 62 | 63 | func (g *grpcClient) Request() (*meta.Response, error) { 64 | //fmt.Printf("%p \n", &*g)\ 65 | start := time.Now() 66 | rpc, err := g.parseReflect.InvokeRpc(context.Background(), g.stub, g.mds, g.meta.Body()) 67 | r := &meta.Response{ 68 | RequestTime: time.Since(start), 69 | } 70 | //SlowRequestTime = r.slowRequest() 71 | //FastRequestTime = r.fastRequest() 72 | meta.GetResult().SetSlowRequestTime(r.SlowRequest()). 73 | SetFastRequestTime(r.FastRequest()) 74 | if err != nil { 75 | return nil, err 76 | } 77 | r.ResponseSize = len(rpc.String()) 78 | return r, nil 79 | } 80 | -------------------------------------------------------------------------------- /client/http_client.go: -------------------------------------------------------------------------------- 1 | package client 2 | 3 | import ( 4 | "fmt" 5 | "github.com/crossoverJie/ptg/meta" 6 | "github.com/pkg/errors" 7 | "io" 8 | "io/ioutil" 9 | "net/http" 10 | "strings" 11 | "time" 12 | ) 13 | 14 | type httpClient struct { 15 | Method string 16 | Url string 17 | RequestBody string 18 | httpClient *http.Client 19 | meta *meta.Meta 20 | } 21 | 22 | func (c *httpClient) Request() (*meta.Response, error) { 23 | var payload io.Reader 24 | if len(c.RequestBody) > 0 { 25 | payload = strings.NewReader(c.RequestBody) 26 | } 27 | req, err := http.NewRequest(c.Method, c.Url, payload) 28 | //req.Close = true 29 | if err != nil { 30 | fmt.Println("An error occured doing request", err) 31 | return nil, err 32 | } 33 | req.Header.Add("User-Agent", "ptg") 34 | for k, v := range c.meta.HeaderMap() { 35 | req.Header.Add(k, v) 36 | } 37 | 38 | //httpClient := &http.Client{ 39 | // Transport: &http.Transport{ 40 | // ResponseHeaderTimeout: time.Millisecond * time.Duration(1000), 41 | // DisableKeepAlives: true, 42 | // }, 43 | //} 44 | 45 | start := time.Now() 46 | response, err := c.httpClient.Do(req) 47 | r := &meta.Response{ 48 | RequestTime: time.Since(start), 49 | } 50 | meta.GetResult().SetSlowRequestTime(r.SlowRequest()). 51 | SetFastRequestTime(r.FastRequest()) 52 | if err != nil { 53 | return nil, err 54 | } 55 | 56 | if response == nil { 57 | return nil, errors.New("response is nil") 58 | } 59 | defer func() { 60 | if response != nil && response.Body != nil { 61 | _ = response.Body.Close() 62 | } 63 | }() 64 | 65 | if response.StatusCode != http.StatusOK { 66 | return nil, errors.New(fmt.Sprintf("http code not OK: %v", response.StatusCode)) 67 | } 68 | body, err := ioutil.ReadAll(response.Body) 69 | if err != nil { 70 | return nil, errors.New(fmt.Sprintf("response bodyPath read err:%v", err)) 71 | } 72 | r.ResponseSize = len(body) 73 | return r, nil 74 | } 75 | -------------------------------------------------------------------------------- /client/http_client_test.go: -------------------------------------------------------------------------------- 1 | package client 2 | 3 | import ( 4 | "fmt" 5 | "github.com/crossoverJie/ptg/meta" 6 | "github.com/docker/go-units" 7 | "testing" 8 | ) 9 | 10 | func Test_httpClient_Request(t *testing.T) { 11 | meta.NewResult() 12 | httpClient := NewClient("GET", 13 | "http://gobyexample.com", "", 14 | meta.NewMeta("http://gobyexample.com", "GET", "", "", Http, "", 15 | "", 1, 1, nil, nil)) 16 | request, err := httpClient.Request() 17 | if err != nil { 18 | fmt.Println(err) 19 | } 20 | fmt.Println(request) 21 | } 22 | 23 | func TestHuman(t *testing.T) { 24 | size := units.HumanSize(1024) 25 | fmt.Println(size) 26 | } 27 | 28 | func TestBytes(t *testing.T) { 29 | body := []byte{3, 14, 159, 2, 65, 35, 9} 30 | fmt.Println(string(body)) 31 | 32 | } 33 | -------------------------------------------------------------------------------- /count.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | ptgclient "github.com/crossoverJie/ptg/client" 5 | "github.com/crossoverJie/ptg/meta" 6 | "github.com/crossoverJie/ptg/model" 7 | "github.com/docker/go-units" 8 | "github.com/fatih/color" 9 | "os" 10 | "sync" 11 | "time" 12 | ) 13 | 14 | type CountModel struct { 15 | wait sync.WaitGroup 16 | count int 17 | workCh chan struct{} 18 | start time.Time 19 | result *meta.Result 20 | meta *meta.Meta 21 | } 22 | 23 | func NewCountModel(count int) model.Model { 24 | return &CountModel{count: count, start: time.Now(), result: meta.GetResult(), meta: meta.GetMeta()} 25 | } 26 | 27 | func (c *CountModel) Init() { 28 | c.wait.Add(c.count) 29 | c.workCh = make(chan struct{}, c.count) 30 | for i := 0; i < c.count; i++ { 31 | go func() { 32 | c.workCh <- struct{}{} 33 | }() 34 | } 35 | } 36 | func (c *CountModel) Run() { 37 | for i := 0; i < thread; i++ { 38 | httpClient := ptgclient.NewClient(method, target, body, c.meta) 39 | go func() { 40 | for { 41 | select { 42 | case _, ok := <-c.workCh: 43 | if !ok { 44 | return 45 | } 46 | response, err := httpClient.Request() 47 | c.meta.RespCh() <- response 48 | if err != nil { 49 | color.Red("request err %v\n", err) 50 | //atomic.AddInt32(&ErrorCount, 1) 51 | c.result.IncrementErrorCount() 52 | } 53 | Bar.Increment() 54 | c.wait.Done() 55 | } 56 | } 57 | 58 | }() 59 | } 60 | c.wait.Wait() 61 | } 62 | func (c *CountModel) Finish() { 63 | for i := 0; i < c.count; i++ { 64 | select { 65 | case res := <-c.meta.RespCh(): 66 | if res != nil { 67 | meta.GetResult().SetTotalRequestTime(res.RequestTime). 68 | SetTotalResponseSize(res.ResponseSize) 69 | } 70 | } 71 | } 72 | Bar.Finish() 73 | close(c.workCh) 74 | } 75 | 76 | func (c *CountModel) Shutdown() { 77 | close(c.workCh) 78 | os.Exit(-1) 79 | } 80 | 81 | func (c *CountModel) PrintSate() { 82 | color.Green("%v requests in %v, %v read, and cost %v.\n", c.count, units.HumanDuration(c.result.TotalRequestTime()), units.HumanSize(float64(c.result.TotalResponseSize())), units.HumanDuration(time.Since(c.start))) 83 | color.Green("Requests/sec:\t\t%.2f\n", float64(c.count)/time.Since(c.start).Seconds()) 84 | color.Green("Avg Req Time:\t\t%v\n", c.result.TotalRequestTime()/time.Duration(c.count)) 85 | color.Green("Fastest Request:\t%v\n", c.result.FastRequestTime()) 86 | color.Green("Slowest Request:\t%v\n", c.result.SlowRequestTime()) 87 | color.Green("Number of Errors:\t%v\n", c.result.ErrorCount()) 88 | } 89 | -------------------------------------------------------------------------------- /duration.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ptgclient "github.com/crossoverJie/ptg/client" 6 | "github.com/crossoverJie/ptg/meta" 7 | "github.com/crossoverJie/ptg/model" 8 | "github.com/docker/go-units" 9 | "github.com/fatih/color" 10 | "sync/atomic" 11 | "time" 12 | ) 13 | 14 | type DurationModel struct { 15 | duration int64 16 | timeCh chan struct{} 17 | close chan struct{} 18 | totalRequest int32 19 | shutdown int32 20 | result *meta.Result 21 | meta *meta.Meta 22 | } 23 | 24 | func NewDurationModel(duration int64) model.Model { 25 | return &DurationModel{ 26 | duration: duration, 27 | timeCh: make(chan struct{}), 28 | close: make(chan struct{}), 29 | result: meta.GetResult(), 30 | meta: meta.GetMeta(), 31 | } 32 | } 33 | 34 | func (c *DurationModel) Init() { 35 | go func() { 36 | for { 37 | select { 38 | case <-time.Tick(1 * time.Second): 39 | if atomic.LoadInt32(&c.shutdown) == 1 { 40 | return 41 | } 42 | Bar.Increment() 43 | } 44 | } 45 | }() 46 | go func() { 47 | select { 48 | case <-time.After(time.Second * time.Duration(c.duration)): 49 | close(c.close) 50 | return 51 | } 52 | }() 53 | 54 | } 55 | func (c *DurationModel) Run() { 56 | for i := 0; i < thread; i++ { 57 | ptgClient := ptgclient.NewClient(method, target, body, c.meta) 58 | go func() { 59 | for { 60 | if atomic.LoadInt32(&c.shutdown) == 1 { 61 | return 62 | } 63 | response, err := ptgClient.Request() 64 | atomic.AddInt32(&c.totalRequest, 1) 65 | c.meta.RespCh() <- response 66 | if err != nil { 67 | color.Red("request err %v\n", err) 68 | c.result.IncrementErrorCount() 69 | } 70 | } 71 | }() 72 | } 73 | } 74 | func (c *DurationModel) Finish() { 75 | for { 76 | select { 77 | case _, ok := <-c.close: 78 | if !ok { 79 | Bar.SetCurrent(duration) 80 | Bar.Finish() 81 | atomic.StoreInt32(&c.shutdown, 1) 82 | return 83 | } 84 | case res := <-c.meta.RespCh(): 85 | if res != nil { 86 | c.result.SetTotalRequestTime(res.RequestTime). 87 | SetTotalResponseSize(res.ResponseSize) 88 | } 89 | } 90 | } 91 | } 92 | 93 | func (c *DurationModel) Shutdown() { 94 | close(c.close) 95 | } 96 | 97 | func (c *DurationModel) PrintSate() { 98 | fmt.Println("") 99 | color.Green("%v requests in %v, %v read.\n", c.totalRequest, units.HumanDuration(c.result.TotalRequestTime()), units.HumanSize(float64(c.result.TotalResponseSize()))) 100 | color.Green("Requests/sec:\t\t%.2f\n", float64(c.totalRequest)/float64(duration)) 101 | color.Green("Avg Req Time:\t\t%v\n", c.result.TotalRequestTime()/time.Duration(c.totalRequest)) 102 | color.Green("Fastest Request:\t%v\n", c.result.FastRequestTime()) 103 | color.Green("Slowest Request:\t%v\n", c.result.SlowRequestTime()) 104 | color.Green("Number of Errors:\t%v\n", c.result.ErrorCount()) 105 | } 106 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/crossoverJie/ptg 2 | 3 | go 1.16 4 | 5 | require ( 6 | fyne.io/fyne/v2 v2.1.1 7 | github.com/cheggaaa/pb/v3 v3.0.5 8 | github.com/docker/go-units v0.4.0 9 | github.com/fatih/color v1.13.0 10 | github.com/flopp/go-findfont v0.1.0 // indirect 11 | github.com/golang/protobuf v1.5.2 12 | github.com/jhump/protoreflect v1.10.1 13 | github.com/pkg/errors v0.9.1 14 | github.com/stretchr/testify v1.5.1 15 | github.com/urfave/cli/v2 v2.3.0 16 | google.golang.org/grpc v1.38.0 17 | google.golang.org/protobuf v1.27.1 18 | ) 19 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 2 | fyne.io/fyne/v2 v2.1.1 h1:3p39SwQ/rBiYODVYI4ggTuwMufWYmqaRMJvXTFg7jSw= 3 | fyne.io/fyne/v2 v2.1.1/go.mod h1:c1vwI38Ebd0dAdxVa6H1Pj6/+cK1xtDy61+I31g+s14= 4 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 5 | github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= 6 | github.com/Kodeworks/golang-image-ico v0.0.0-20141118225523-73f0f4cfade9/go.mod h1:7uhhqiBaR4CpN0k9rMjOtjpcfGd6DG2m04zQxKnWQ0I= 7 | github.com/VividCortex/ewma v1.1.1 h1:MnEK4VOv6n0RSY4vtRe3h11qjxL3+t0B8yOL8iMXdcM= 8 | github.com/VividCortex/ewma v1.1.1/go.mod h1:2Tkkvm3sRDVXaiyucHiACn4cqf7DpdyLvmxzcbUokwA= 9 | github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c= 10 | github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= 11 | github.com/cheggaaa/pb/v3 v3.0.5 h1:lmZOti7CraK9RSjzExsY53+WWfub9Qv13B5m4ptEoPE= 12 | github.com/cheggaaa/pb/v3 v3.0.5/go.mod h1:X1L61/+36nz9bjIsrDU52qHKOQukUQe2Ge+YvGuquCw= 13 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 14 | github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= 15 | github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY= 16 | github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= 17 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 18 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 19 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 20 | github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= 21 | github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= 22 | github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 23 | github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 24 | github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= 25 | github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= 26 | github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= 27 | github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= 28 | github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= 29 | github.com/flopp/go-findfont v0.1.0 h1:lPn0BymDUtJo+ZkV01VS3661HL6F4qFlkhcJN55u6mU= 30 | github.com/flopp/go-findfont v0.1.0/go.mod h1:wKKxRDjD024Rh7VMwoU90i6ikQRCr+JTHB5n4Ejkqvw= 31 | github.com/fredbi/uri v0.0.0-20181227131451-3dcfdacbaaf3 h1:FDqhDm7pcsLhhWl1QtD8vlzI4mm59llRvNzrFg6/LAA= 32 | github.com/fredbi/uri v0.0.0-20181227131451-3dcfdacbaaf3/go.mod h1:CzM2G82Q9BDUvMTGHnXf/6OExw/Dz2ivDj48nVg7Lg8= 33 | github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= 34 | github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= 35 | github.com/go-gl/gl v0.0.0-20210813123233-e4099ee2221f h1:s0O46d8fPwk9kU4k1jj76wBquMVETx7uveQD9MCIQoU= 36 | github.com/go-gl/gl v0.0.0-20210813123233-e4099ee2221f/go.mod h1:wjpnOv6ONl2SuJSxqCPVaPZibGFdSci9HFocT9qtVYM= 37 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20210410170116-ea3d685f79fb h1:T6gaWBvRzJjuOrdCtg8fXXjKai2xSDqWTcKFUPuw8Tw= 38 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20210410170116-ea3d685f79fb/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= 39 | github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= 40 | github.com/godbus/dbus/v5 v5.0.4 h1:9349emZab16e7zQvpmsbtjc18ykshndd8y2PG3sgJbA= 41 | github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= 42 | github.com/goki/freetype v0.0.0-20181231101311-fa8a33aabaff h1:W71vTCKoxtdXgnm1ECDFkfQnpdqAO00zzGXLA5yaEX8= 43 | github.com/goki/freetype v0.0.0-20181231101311-fa8a33aabaff/go.mod h1:wfqRWLHRBsRgkp5dmbG56SA0DmVtwrF5N3oPdI8t+Aw= 44 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 45 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 46 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 47 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 48 | github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= 49 | github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= 50 | github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= 51 | github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= 52 | github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= 53 | github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= 54 | github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 55 | github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= 56 | github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= 57 | github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= 58 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 59 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 60 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 61 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 62 | github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 63 | github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= 64 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 65 | github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= 66 | github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 67 | github.com/gordonklaus/ineffassign v0.0.0-20200309095847-7953dde2c7bf/go.mod h1:cuNKsD1zp2v6XfE/orVX2QE1LC+i254ceGcVeDT3pTU= 68 | github.com/jackmordaunt/icns v0.0.0-20181231085925-4f16af745526/go.mod h1:UQkeMHVoNcyXYq9otUupF7/h/2tmHlhrS2zw7ZVvUqc= 69 | github.com/jhump/protoreflect v1.10.1 h1:iH+UZfsbRE6vpyZH7asAjTPWJf7RJbpZ9j/N3lDlKs0= 70 | github.com/jhump/protoreflect v1.10.1/go.mod h1:7GcYQDdMU/O/BBrl/cX6PNHpXh6cenjd8pneu5yW7Tg= 71 | github.com/josephspurrier/goversioninfo v0.0.0-20200309025242-14b0ab84c6ca/go.mod h1:eJTEwMjXb7kZ633hO3Ln9mBUCOjX2+FlTljvpl9SYdE= 72 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= 73 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 74 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 75 | github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= 76 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 77 | github.com/lucor/goinfo v0.0.0-20210802170112-c078a2b0f08b/go.mod h1:PRq09yoB+Q2OJReAmwzKivcYyremnibWGbK7WfftHzc= 78 | github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= 79 | github.com/mattn/go-colorable v0.1.9 h1:sqDoxXbdeALODt0DAeJCVp38ps9ZogZEAXjus69YV3U= 80 | github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= 81 | github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= 82 | github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= 83 | github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= 84 | github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= 85 | github.com/mattn/go-runewidth v0.0.7 h1:Ei8KR0497xHyKJPAv59M1dkC+rOZCMBJ+t3fZ+twI54= 86 | github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= 87 | github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= 88 | github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= 89 | github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= 90 | github.com/nishanths/predeclared v0.0.0-20200524104333-86fad755b4d3/go.mod h1:nt3d53pc1VYcphSCIaYAJtnPYnr3Zyn8fMq2wvPGPso= 91 | github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 92 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 93 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 94 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 95 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 96 | github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 97 | github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= 98 | github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= 99 | github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= 100 | github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= 101 | github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= 102 | github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= 103 | github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= 104 | github.com/srwiley/oksvg v0.0.0-20200311192757-870daf9aa564 h1:HunZiaEKNGVdhTRQOVpMmj5MQnGnv+e8uZNu3xFLgyM= 105 | github.com/srwiley/oksvg v0.0.0-20200311192757-870daf9aa564/go.mod h1:afMbS0qvv1m5tfENCwnOdZGOF8RGR/FsZ7bvBxQGZG4= 106 | github.com/srwiley/rasterx v0.0.0-20200120212402-85cb7272f5e9 h1:m59mIOBO4kfcNCEzJNy71UkeF4XIx2EVmL9KLwDQdmM= 107 | github.com/srwiley/rasterx v0.0.0-20200120212402-85cb7272f5e9/go.mod h1:mvWM0+15UqyrFKqdRjY6LuAVJR0HOVhJlEgZ5JWtSWU= 108 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 109 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 110 | github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= 111 | github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= 112 | github.com/urfave/cli/v2 v2.3.0 h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M= 113 | github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= 114 | github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 115 | github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 116 | github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= 117 | github.com/yuin/goldmark v1.3.8 h1:Nw158Q8QN+CPgTmVRByhVwapp8Mm1e2blinhmx4wx5E= 118 | github.com/yuin/goldmark v1.3.8/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= 119 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 120 | golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 121 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 122 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 123 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 124 | golang.org/x/image v0.0.0-20200430140353-33d19683fad8 h1:6WW6V3x1P/jokJBpRQYUJnMHRP6isStQwCozxnU7XQw= 125 | golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= 126 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 127 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= 128 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 129 | golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= 130 | golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 131 | golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 132 | golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 133 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 134 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 135 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 136 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 137 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 138 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 139 | golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 140 | golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 141 | golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0= 142 | golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= 143 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 144 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 145 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 146 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 147 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 148 | golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 149 | golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 150 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 151 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 152 | golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 153 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 154 | golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 155 | golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 156 | golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 157 | golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 158 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 159 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 160 | golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 161 | golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 162 | golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I= 163 | golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 164 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 165 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 166 | golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= 167 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 168 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 169 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 170 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= 171 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 172 | golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 173 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 174 | golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 175 | golang.org/x/tools v0.0.0-20200522201501-cb1345f3a375/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 176 | golang.org/x/tools v0.0.0-20200717024301-6ddee64345a6/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 177 | golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= 178 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 179 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 180 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 181 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= 182 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 183 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 184 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 185 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 186 | google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 187 | google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY= 188 | google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= 189 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= 190 | google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= 191 | google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= 192 | google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 193 | google.golang.org/grpc v1.38.0 h1:/9BgsAsa5nWe26HqOlvlgJnqBuktYOLCgjCPqsa56W0= 194 | google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= 195 | google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= 196 | google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= 197 | google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= 198 | google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= 199 | google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= 200 | google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 201 | google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 202 | google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 203 | google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= 204 | google.golang.org/protobuf v1.25.1-0.20200805231151-a709e31e5d12/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= 205 | google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= 206 | google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= 207 | google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= 208 | google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= 209 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 210 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 211 | gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= 212 | gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 213 | gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= 214 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 215 | gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 216 | gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= 217 | gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 218 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 219 | honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 220 | honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= 221 | -------------------------------------------------------------------------------- /gui/app.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/flopp/go-findfont" 5 | "os" 6 | "strings" 7 | ) 8 | 9 | const ( 10 | AppName = "PTG gRPC client" 11 | AppWeight = 1000 12 | AppHeight = 800 13 | HelpUrl = "https://github.com/crossoverJie/ptg" 14 | SearchFormText = "SearchResult" 15 | SearchFormPlaceHolder = "keyword" 16 | TargetFormText = "Target:" 17 | TargetFormHintText = "Input target url" 18 | RequestEntryPlaceHolder = "Input request json" 19 | MetaDataAccordion = "metadata" 20 | MetaDataInputPlaceHolder = "Input metadata json" 21 | TargetInputText = "127.0.0.1:6001" 22 | RequestButtonText = "RUN" 23 | ResponseLabelText = "Response:" 24 | ) 25 | 26 | type App struct { 27 | AppName string 28 | AppWidth, AppHeight float32 29 | HelpUrl string 30 | SearchFormText string 31 | SearchFormPlaceHolder string 32 | RightRequest *RightRequest 33 | RightResponse *RightResponse 34 | } 35 | 36 | type RightRequest struct { 37 | TargetFormText, TargetFormHintText string 38 | RequestEntryPlaceHolder, TargetInputText string 39 | MetaDataAccordionTitle, MetaDataInputPlaceHolder string 40 | RequestButtonText string 41 | } 42 | 43 | type RightResponse struct { 44 | ResponseLabelText string 45 | } 46 | 47 | func InitApp() *App { 48 | // init font 49 | fontPaths := findfont.List() 50 | for _, path := range fontPaths { 51 | //楷体:simkai.ttf 52 | //黑体:simhei.ttf 53 | if strings.Contains(path, "阿里汉仪智能黑体") || strings.Contains(path, "simkai.ttf") || strings.Contains(path, "msyhl.ttc") { 54 | os.Setenv("FYNE_FONT", path) 55 | break 56 | } 57 | } 58 | return &App{ 59 | AppName: AppName, 60 | AppWidth: AppWeight, 61 | AppHeight: AppHeight, 62 | HelpUrl: HelpUrl, 63 | SearchFormText: SearchFormText, 64 | SearchFormPlaceHolder: SearchFormPlaceHolder, 65 | RightRequest: &RightRequest{ 66 | TargetFormText: TargetFormText, 67 | TargetFormHintText: TargetFormHintText, 68 | RequestEntryPlaceHolder: RequestEntryPlaceHolder, 69 | TargetInputText: TargetInputText, 70 | MetaDataAccordionTitle: MetaDataAccordion, 71 | MetaDataInputPlaceHolder: MetaDataInputPlaceHolder, 72 | RequestButtonText: RequestButtonText, 73 | }, 74 | RightResponse: &RightResponse{ResponseLabelText: ResponseLabelText}, 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /gui/call/stream_call.go: -------------------------------------------------------------------------------- 1 | package call 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "fmt" 7 | "fyne.io/fyne/v2" 8 | "fyne.io/fyne/v2/container" 9 | "fyne.io/fyne/v2/theme" 10 | "fyne.io/fyne/v2/widget" 11 | "github.com/crossoverJie/ptg/reflect" 12 | "github.com/golang/protobuf/proto" 13 | "github.com/jhump/protoreflect/desc" 14 | "github.com/jhump/protoreflect/dynamic/grpcdynamic" 15 | "io" 16 | ) 17 | 18 | type ( 19 | Call struct { 20 | parse *reflect.ParseReflect 21 | responseEntry, requestEntry *widget.Entry 22 | processBar *widget.ProgressBarInfinite 23 | mds *desc.MethodDescriptor 24 | stub grpcdynamic.Stub 25 | errorHandle errorHandle 26 | } 27 | errorHandle func(window fyne.Window, processBar *widget.ProgressBarInfinite, err error) 28 | ) 29 | 30 | func NewCallBuilder() *Call { 31 | return &Call{} 32 | } 33 | func (c *Call) Parse(parse *reflect.ParseReflect) *Call { 34 | c.parse = parse 35 | return c 36 | } 37 | func (c *Call) ResponseEntry(responseEntry *widget.Entry) *Call { 38 | c.responseEntry = responseEntry 39 | return c 40 | } 41 | func (c *Call) Mds(mds *desc.MethodDescriptor) *Call { 42 | c.mds = mds 43 | return c 44 | } 45 | func (c *Call) Stub(stub grpcdynamic.Stub) *Call { 46 | c.stub = stub 47 | return c 48 | } 49 | func (c *Call) RequestEntry(requestEntry *widget.Entry) *Call { 50 | c.requestEntry = requestEntry 51 | return c 52 | } 53 | func (c *Call) ProcessBar(processBar *widget.ProgressBarInfinite) *Call { 54 | c.processBar = processBar 55 | return c 56 | } 57 | func (c *Call) ErrorHandle(e errorHandle) *Call { 58 | c.errorHandle = e 59 | return c 60 | } 61 | 62 | func (c *Call) Run(ctx context.Context) (string, error) { 63 | c.responseEntry.SetText("") 64 | mds := c.mds 65 | parse := c.parse 66 | responseEntry := c.responseEntry 67 | stub := c.stub 68 | data := c.requestEntry.Text 69 | 70 | if !mds.IsClientStreaming() && !mds.IsServerStreaming() { 71 | // unary RPC 72 | rpc, err := parse.InvokeRpc(ctx, stub, mds, data) 73 | if err != nil { 74 | return "", err 75 | } 76 | viewCallBack := &unaryCallBack{} 77 | return viewCallBack.ViewCallBack(rpc, responseEntry), nil 78 | } 79 | 80 | if !mds.IsClientStreaming() && mds.IsServerStreaming() { 81 | // server stream 82 | rpc, err := parse.InvokeServerStreamRpc(ctx, stub, mds, data) 83 | if err != nil { 84 | return "", err 85 | } 86 | viewCallBack := &serverStreamCallBack{ 87 | ch: make(chan proto.Message, 10), 88 | responseEntry: responseEntry, 89 | } 90 | viewCallBack.receive() 91 | for { 92 | msg, err := rpc.RecvMsg() 93 | fmt.Printf("stream call %s \n", msg) 94 | if err == io.EOF { 95 | close(viewCallBack.ch) 96 | } 97 | if err != nil { 98 | return "", nil 99 | } 100 | viewCallBack.ViewCallBack(msg, responseEntry) 101 | } 102 | 103 | } 104 | 105 | if mds.IsClientStreaming() && !mds.IsServerStreaming() { 106 | // client stream 107 | rpc, err := parse.InvokeClientStreamRpc(ctx, stub, mds) 108 | if err != nil { 109 | return "", err 110 | } 111 | w := fyne.CurrentApp().NewWindow("Client stream call") 112 | w.Resize(fyne.NewSize(300, 100)) 113 | request := widget.NewMultiLineEntry() 114 | request.SetText(data) 115 | var totalRequest string 116 | requestButton := widget.NewButtonWithIcon("Push", theme.MediaPlayIcon(), func() { 117 | messages, err := reflect.CreatePayloadsFromJSON(mds, request.Text) 118 | if err != nil { 119 | c.errorHandle(w, c.processBar, err) 120 | return 121 | } 122 | rpc.SendMsg(messages[0]) 123 | totalRequest += request.Text + "\n" 124 | }) 125 | finishButton := widget.NewButtonWithIcon("Finish", theme.ConfirmIcon(), func() { 126 | receive, err := rpc.CloseAndReceive() 127 | if err != nil { 128 | c.errorHandle(w, c.processBar, err) 129 | return 130 | } 131 | marshalIndent, _ := json.MarshalIndent(receive, "", "\t") 132 | c.responseEntry.SetText(string(marshalIndent)) 133 | w.Close() 134 | c.requestEntry.SetText(totalRequest) 135 | 136 | }) 137 | w.SetContent(container.NewVBox(request, requestButton, finishButton)) 138 | w.CenterOnScreen() 139 | w.Show() 140 | 141 | } 142 | if mds.IsClientStreaming() && mds.IsServerStreaming() { 143 | // bidi stream 144 | rpc, err := parse.InvokeBidiStreamRpc(ctx, stub, mds) 145 | if err != nil { 146 | return "", err 147 | } 148 | w := fyne.CurrentApp().NewWindow("Bidi stream call") 149 | w.Resize(fyne.NewSize(300, 100)) 150 | request := widget.NewMultiLineEntry() 151 | request.SetText(data) 152 | var totalRequest string 153 | 154 | streamCallBack := bidiStreamCallBack{ 155 | ch: make(chan proto.Message, 10), 156 | responseEntry: responseEntry, 157 | } 158 | streamCallBack.receive() 159 | 160 | requestButton := widget.NewButtonWithIcon("Push", theme.MediaPlayIcon(), func() { 161 | messages, err := reflect.CreatePayloadsFromJSON(mds, request.Text) 162 | if err != nil { 163 | c.errorHandle(w, c.processBar, err) 164 | return 165 | } 166 | rpc.SendMsg(messages[0]) 167 | totalRequest += request.Text + "\n" 168 | 169 | receive, _ := rpc.RecvMsg() 170 | streamCallBack.ViewCallBack(receive) 171 | }) 172 | finishButton := widget.NewButtonWithIcon("Finish", theme.ConfirmIcon(), func() { 173 | err := rpc.CloseSend() 174 | if err != nil { 175 | c.errorHandle(w, c.processBar, err) 176 | return 177 | } 178 | w.Close() 179 | c.requestEntry.SetText(totalRequest) 180 | 181 | }) 182 | w.SetContent(container.NewVBox(request, requestButton, finishButton)) 183 | w.CenterOnScreen() 184 | w.Show() 185 | } 186 | 187 | return "", nil 188 | } 189 | 190 | type unaryCallBack struct{} 191 | 192 | func (u unaryCallBack) ViewCallBack(message proto.Message, responseEntry *widget.Entry) string { 193 | marshalIndent, _ := json.MarshalIndent(message, "", "\t") 194 | responseEntry.SetText(string(marshalIndent)) 195 | return string(marshalIndent) 196 | } 197 | 198 | type serverStreamCallBack struct { 199 | ch chan proto.Message 200 | responseEntry *widget.Entry 201 | } 202 | 203 | func (s *serverStreamCallBack) ViewCallBack(message proto.Message, responseEntry *widget.Entry) string { 204 | s.ch <- message 205 | return "" 206 | } 207 | 208 | func (s *serverStreamCallBack) receive() { 209 | go func() { 210 | for { 211 | select { 212 | case message, ok := <-s.ch: 213 | if !ok { 214 | fmt.Println("break") 215 | return 216 | } 217 | marshalIndent, _ := json.MarshalIndent(message, "", "\t") 218 | s.responseEntry.SetText(s.responseEntry.Text + string(marshalIndent) + "\n") 219 | } 220 | } 221 | }() 222 | 223 | } 224 | 225 | type clientStreamCallBack struct{} 226 | 227 | func (u clientStreamCallBack) ViewCallBack(message proto.Message, responseEntry *widget.Entry) string { 228 | marshalIndent, _ := json.MarshalIndent(message, "", "\t") 229 | responseEntry.SetText(string(marshalIndent)) 230 | return string(marshalIndent) 231 | } 232 | 233 | type bidiStreamCallBack struct { 234 | ch chan proto.Message 235 | responseEntry *widget.Entry 236 | } 237 | 238 | func (b bidiStreamCallBack) ViewCallBack(message proto.Message) string { 239 | b.ch <- message 240 | return "" 241 | } 242 | 243 | func (b *bidiStreamCallBack) receive() { 244 | go func() { 245 | for { 246 | select { 247 | case message, ok := <-b.ch: 248 | if !ok { 249 | fmt.Println("break") 250 | return 251 | } 252 | marshalIndent, _ := json.MarshalIndent(message, "", "\t") 253 | b.responseEntry.SetText(b.responseEntry.Text + string(marshalIndent) + "\n") 254 | } 255 | } 256 | }() 257 | 258 | } 259 | -------------------------------------------------------------------------------- /gui/history.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "fyne.io/fyne/v2" 6 | "fyne.io/fyne/v2/theme" 7 | "fyne.io/fyne/v2/widget" 8 | "github.com/crossoverJie/ptg/gui/io" 9 | "github.com/golang/protobuf/proto" 10 | "strings" 11 | ) 12 | 13 | type ( 14 | History struct { 15 | lruCache *LruCache 16 | writeSearchChan chan struct{} 17 | searchChan chan []*io.SearchLog 18 | historyButton *fyne.Container 19 | alreadyButtonList []*widget.Button 20 | targetInput *widget.Entry 21 | requestEntry *widget.Entry 22 | metadataEntry *widget.Entry 23 | responseEntry *widget.Entry 24 | requestLabel *widget.Label 25 | } 26 | 27 | //HistoryValue struct { 28 | // Id int `json:"id"` 29 | // Value *io.Log `json:"value"` 30 | // MethodInfo string `json:"method_info"` 31 | //} 32 | ) 33 | 34 | func NewHistory(size int, historyButton *fyne.Container, targetInput, requestEntry, metadataEntry, responseEntry *widget.Entry, reqLabel *widget.Label) *History { 35 | h := &History{ 36 | lruCache: NewLruList(size), 37 | writeSearchChan: make(chan struct{}, size), 38 | searchChan: make(chan []*io.SearchLog, size), 39 | historyButton: historyButton, 40 | targetInput: targetInput, 41 | requestEntry: requestEntry, 42 | metadataEntry: metadataEntry, 43 | responseEntry: responseEntry, 44 | requestLabel: reqLabel, 45 | } 46 | go h.viewHistory() 47 | go h.ViewSearch() 48 | return h 49 | 50 | } 51 | 52 | func (h *History) Put(k int, v *io.SearchLog) { 53 | h.lruCache.Put(k, v) 54 | h.writeSearchChan <- struct{}{} 55 | } 56 | 57 | func (h *History) viewHistory() { 58 | for { 59 | select { 60 | case <-h.writeSearchChan: 61 | 62 | // Reset view. 63 | for _, button := range h.alreadyButtonList { 64 | h.historyButton.Remove(button) 65 | } 66 | h.alreadyButtonList = make([]*widget.Button, 0) 67 | 68 | // Draw view. 69 | for _, v := range h.lruCache.List() { 70 | //index := i 71 | historyValue := v.(*io.SearchLog) 72 | h.drawHistoryButton(historyValue) 73 | } 74 | } 75 | } 76 | } 77 | 78 | func (h *History) SearchResult(kw string) []*io.SearchLog { 79 | var result []*io.SearchLog 80 | for _, v := range h.lruCache.List() { 81 | historyValue := v.(*io.SearchLog) 82 | if kw == "" { 83 | result = append(result, historyValue) 84 | continue 85 | } 86 | if strings.Contains(strings.ToLower(historyValue.MethodInfo), kw) { 87 | result = append(result, historyValue) 88 | continue 89 | } 90 | if strings.Contains(strings.ToLower(historyValue.Value.Target), kw) { 91 | result = append(result, historyValue) 92 | continue 93 | } 94 | if strings.Contains(strings.ToLower(historyValue.Value.Request), kw) { 95 | result = append(result, historyValue) 96 | continue 97 | } 98 | if strings.Contains(strings.ToLower(historyValue.Value.Response), kw) { 99 | result = append(result, historyValue) 100 | continue 101 | } 102 | if strings.Contains(strings.ToLower(historyValue.Value.Metadata), kw) { 103 | result = append(result, historyValue) 104 | continue 105 | } 106 | 107 | } 108 | h.searchChan <- result 109 | 110 | return result 111 | } 112 | 113 | func (h *History) ViewSearch() { 114 | for { 115 | select { 116 | case searchList := <-h.searchChan: 117 | // Reset view. 118 | for _, button := range h.alreadyButtonList { 119 | h.historyButton.Remove(button) 120 | } 121 | h.alreadyButtonList = make([]*widget.Button, 0) 122 | for _, v := range searchList { 123 | historyValue := v 124 | h.drawHistoryButton(historyValue) 125 | } 126 | } 127 | } 128 | 129 | } 130 | 131 | func (h *History) drawHistoryButton(historyValue *io.SearchLog) { 132 | button := widget.NewButtonWithIcon(historyValue.MethodInfo, theme.HistoryIcon(), func() { 133 | fmt.Println("Search tapped", historyValue.Id) 134 | h.lruCache.Get(historyValue.Id) 135 | h.targetInput.SetText(historyValue.Value.Target) 136 | h.requestEntry.SetText(historyValue.Value.Request) 137 | h.metadataEntry.SetText(historyValue.Value.Metadata) 138 | h.responseEntry.SetText(historyValue.Value.Response) 139 | h.requestLabel.SetText(historyValue.MethodInfo) 140 | }) 141 | h.historyButton.Add(button) 142 | h.alreadyButtonList = append(h.alreadyButtonList, button) 143 | } 144 | 145 | func (h *History) SaveLog() error { 146 | searchLogList := &io.SearchLogList{} 147 | for _, v := range h.lruCache.List() { 148 | historyValue := v.(*io.SearchLog) 149 | searchLogList.SearchLogList = append(searchLogList.SearchLogList, historyValue) 150 | } 151 | marshal, err := proto.Marshal(searchLogList) 152 | if err != nil { 153 | return err 154 | } 155 | return io.SaveLog(io.AppSearchLog, marshal) 156 | } 157 | 158 | func (h *History) InitSearchLog(searchLog *io.SearchLogList) { 159 | for _, log := range searchLog.SearchLogList { 160 | h.drawHistoryButton(log) 161 | h.lruCache.Put(log.Id, log) 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /gui/history_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "github.com/crossoverJie/ptg/gui/io" 7 | "github.com/stretchr/testify/assert" 8 | "testing" 9 | ) 10 | 11 | func TestHistory_Search(t *testing.T) { 12 | history := NewHistory(10, nil, nil, nil, nil, nil) 13 | history.Put(1, &HistoryValue{ 14 | Id: 1, 15 | Value: &io.Log{ 16 | Target: "127.0.0.1:6001", 17 | Request: "{\"order_id\":0,\"reason_id\":null,\"remark\":\"\",\"user_id\":null}", 18 | Metadata: "{\"name\":\"abc\"}", 19 | Response: "", 20 | }, 21 | MethodInfo: "order.v1.OrderService.Create", 22 | }) 23 | history.Put(2, &HistoryValue{ 24 | Id: 2, 25 | Value: &io.Log{ 26 | Target: "127.0.0.1:6002", 27 | Request: "{\"order_id\":99999,\"reason_id\":null,\"remark\":\"\",\"user_id\":null}", 28 | Metadata: "{\"name\":\"zhangsan\"}", 29 | Response: "", 30 | }, 31 | MethodInfo: "order.v1.OrderService.Close", 32 | }) 33 | history.Put(3, &HistoryValue{ 34 | Id: 3, 35 | Value: &io.Log{ 36 | Target: "127.0.0.1:6003", 37 | Request: "{\"order_id\":99999,\"reason_id\":null,\"remark\":\"\",\"user_id\":null}", 38 | Metadata: "{\"name\":\"zhangsan\"}", 39 | Response: "", 40 | }, 41 | MethodInfo: "order.v1.OrderService.List", 42 | }) 43 | 44 | search := history.SearchResult("6001") 45 | for _, value := range search { 46 | marshal, _ := json.Marshal(value) 47 | fmt.Println(string(marshal)) 48 | assert.Equal(t, value.Id, 1) 49 | } 50 | search = history.SearchResult("9999") 51 | for _, value := range search { 52 | marshal, _ := json.Marshal(value) 53 | fmt.Println(string(marshal)) 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /gui/io/log.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. DO NOT EDIT. 2 | // versions: 3 | // protoc-gen-go v1.27.1 4 | // protoc v3.5.1 5 | // source: gui/io/log.proto 6 | 7 | package io 8 | 9 | import ( 10 | protoreflect "google.golang.org/protobuf/reflect/protoreflect" 11 | protoimpl "google.golang.org/protobuf/runtime/protoimpl" 12 | reflect "reflect" 13 | sync "sync" 14 | ) 15 | 16 | const ( 17 | // Verify that this generated code is sufficiently up-to-date. 18 | _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) 19 | // Verify that runtime/protoimpl is sufficiently up-to-date. 20 | _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) 21 | ) 22 | 23 | type Log struct { 24 | state protoimpl.MessageState 25 | sizeCache protoimpl.SizeCache 26 | unknownFields protoimpl.UnknownFields 27 | 28 | Filenames []string `protobuf:"bytes,1,rep,name=filenames,proto3" json:"filenames,omitempty"` 29 | Target string `protobuf:"bytes,2,opt,name=target,proto3" json:"target,omitempty"` 30 | Request string `protobuf:"bytes,3,opt,name=request,proto3" json:"request,omitempty"` 31 | Metadata string `protobuf:"bytes,4,opt,name=metadata,proto3" json:"metadata,omitempty"` 32 | Response string `protobuf:"bytes,5,opt,name=response,proto3" json:"response,omitempty"` 33 | } 34 | 35 | func (x *Log) Reset() { 36 | *x = Log{} 37 | if protoimpl.UnsafeEnabled { 38 | mi := &file_gui_io_log_proto_msgTypes[0] 39 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 40 | ms.StoreMessageInfo(mi) 41 | } 42 | } 43 | 44 | func (x *Log) String() string { 45 | return protoimpl.X.MessageStringOf(x) 46 | } 47 | 48 | func (*Log) ProtoMessage() {} 49 | 50 | func (x *Log) ProtoReflect() protoreflect.Message { 51 | mi := &file_gui_io_log_proto_msgTypes[0] 52 | if protoimpl.UnsafeEnabled && x != nil { 53 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 54 | if ms.LoadMessageInfo() == nil { 55 | ms.StoreMessageInfo(mi) 56 | } 57 | return ms 58 | } 59 | return mi.MessageOf(x) 60 | } 61 | 62 | // Deprecated: Use Log.ProtoReflect.Descriptor instead. 63 | func (*Log) Descriptor() ([]byte, []int) { 64 | return file_gui_io_log_proto_rawDescGZIP(), []int{0} 65 | } 66 | 67 | func (x *Log) GetFilenames() []string { 68 | if x != nil { 69 | return x.Filenames 70 | } 71 | return nil 72 | } 73 | 74 | func (x *Log) GetTarget() string { 75 | if x != nil { 76 | return x.Target 77 | } 78 | return "" 79 | } 80 | 81 | func (x *Log) GetRequest() string { 82 | if x != nil { 83 | return x.Request 84 | } 85 | return "" 86 | } 87 | 88 | func (x *Log) GetMetadata() string { 89 | if x != nil { 90 | return x.Metadata 91 | } 92 | return "" 93 | } 94 | 95 | func (x *Log) GetResponse() string { 96 | if x != nil { 97 | return x.Response 98 | } 99 | return "" 100 | } 101 | 102 | type SearchLog struct { 103 | state protoimpl.MessageState 104 | sizeCache protoimpl.SizeCache 105 | unknownFields protoimpl.UnknownFields 106 | 107 | Id int32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` 108 | Value *Log `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"` 109 | MethodInfo string `protobuf:"bytes,3,opt,name=method_info,json=methodInfo,proto3" json:"method_info,omitempty"` 110 | } 111 | 112 | func (x *SearchLog) Reset() { 113 | *x = SearchLog{} 114 | if protoimpl.UnsafeEnabled { 115 | mi := &file_gui_io_log_proto_msgTypes[1] 116 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 117 | ms.StoreMessageInfo(mi) 118 | } 119 | } 120 | 121 | func (x *SearchLog) String() string { 122 | return protoimpl.X.MessageStringOf(x) 123 | } 124 | 125 | func (*SearchLog) ProtoMessage() {} 126 | 127 | func (x *SearchLog) ProtoReflect() protoreflect.Message { 128 | mi := &file_gui_io_log_proto_msgTypes[1] 129 | if protoimpl.UnsafeEnabled && x != nil { 130 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 131 | if ms.LoadMessageInfo() == nil { 132 | ms.StoreMessageInfo(mi) 133 | } 134 | return ms 135 | } 136 | return mi.MessageOf(x) 137 | } 138 | 139 | // Deprecated: Use SearchLog.ProtoReflect.Descriptor instead. 140 | func (*SearchLog) Descriptor() ([]byte, []int) { 141 | return file_gui_io_log_proto_rawDescGZIP(), []int{1} 142 | } 143 | 144 | func (x *SearchLog) GetId() int32 { 145 | if x != nil { 146 | return x.Id 147 | } 148 | return 0 149 | } 150 | 151 | func (x *SearchLog) GetValue() *Log { 152 | if x != nil { 153 | return x.Value 154 | } 155 | return nil 156 | } 157 | 158 | func (x *SearchLog) GetMethodInfo() string { 159 | if x != nil { 160 | return x.MethodInfo 161 | } 162 | return "" 163 | } 164 | 165 | type SearchLogList struct { 166 | state protoimpl.MessageState 167 | sizeCache protoimpl.SizeCache 168 | unknownFields protoimpl.UnknownFields 169 | 170 | SearchLogList []*SearchLog `protobuf:"bytes,1,rep,name=search_log_list,json=searchLogList,proto3" json:"search_log_list,omitempty"` 171 | } 172 | 173 | func (x *SearchLogList) Reset() { 174 | *x = SearchLogList{} 175 | if protoimpl.UnsafeEnabled { 176 | mi := &file_gui_io_log_proto_msgTypes[2] 177 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 178 | ms.StoreMessageInfo(mi) 179 | } 180 | } 181 | 182 | func (x *SearchLogList) String() string { 183 | return protoimpl.X.MessageStringOf(x) 184 | } 185 | 186 | func (*SearchLogList) ProtoMessage() {} 187 | 188 | func (x *SearchLogList) ProtoReflect() protoreflect.Message { 189 | mi := &file_gui_io_log_proto_msgTypes[2] 190 | if protoimpl.UnsafeEnabled && x != nil { 191 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 192 | if ms.LoadMessageInfo() == nil { 193 | ms.StoreMessageInfo(mi) 194 | } 195 | return ms 196 | } 197 | return mi.MessageOf(x) 198 | } 199 | 200 | // Deprecated: Use SearchLogList.ProtoReflect.Descriptor instead. 201 | func (*SearchLogList) Descriptor() ([]byte, []int) { 202 | return file_gui_io_log_proto_rawDescGZIP(), []int{2} 203 | } 204 | 205 | func (x *SearchLogList) GetSearchLogList() []*SearchLog { 206 | if x != nil { 207 | return x.SearchLogList 208 | } 209 | return nil 210 | } 211 | 212 | var File_gui_io_log_proto protoreflect.FileDescriptor 213 | 214 | var file_gui_io_log_proto_rawDesc = []byte{ 215 | 0x0a, 0x10, 0x67, 0x75, 0x69, 0x2f, 0x69, 0x6f, 0x2f, 0x6c, 0x6f, 0x67, 0x2e, 0x70, 0x72, 0x6f, 216 | 0x74, 0x6f, 0x12, 0x02, 0x69, 0x6f, 0x22, 0x8d, 0x01, 0x0a, 0x03, 0x4c, 0x6f, 0x67, 0x12, 0x1c, 217 | 0x0a, 0x09, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 218 | 0x09, 0x52, 0x09, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x16, 0x0a, 0x06, 219 | 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x74, 0x61, 220 | 0x72, 0x67, 0x65, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 221 | 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 222 | 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 223 | 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 224 | 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 225 | 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x5b, 0x0a, 0x09, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 226 | 0x4c, 0x6f, 0x67, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 227 | 0x02, 0x69, 0x64, 0x12, 0x1d, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 228 | 0x28, 0x0b, 0x32, 0x07, 0x2e, 0x69, 0x6f, 0x2e, 0x4c, 0x6f, 0x67, 0x52, 0x05, 0x76, 0x61, 0x6c, 229 | 0x75, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x5f, 0x69, 0x6e, 0x66, 230 | 0x6f, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x49, 231 | 0x6e, 0x66, 0x6f, 0x22, 0x46, 0x0a, 0x0d, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x4c, 0x6f, 0x67, 232 | 0x4c, 0x69, 0x73, 0x74, 0x12, 0x35, 0x0a, 0x0f, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x5f, 0x6c, 233 | 0x6f, 0x67, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 234 | 0x69, 0x6f, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x4c, 0x6f, 0x67, 0x52, 0x0d, 0x73, 0x65, 235 | 0x61, 0x72, 0x63, 0x68, 0x4c, 0x6f, 0x67, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x24, 0x5a, 0x22, 0x67, 236 | 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x72, 0x6f, 0x73, 0x73, 0x6f, 237 | 0x76, 0x65, 0x72, 0x4a, 0x69, 0x65, 0x2f, 0x70, 0x74, 0x67, 0x2f, 0x67, 0x75, 0x69, 0x2f, 0x69, 238 | 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 239 | } 240 | 241 | var ( 242 | file_gui_io_log_proto_rawDescOnce sync.Once 243 | file_gui_io_log_proto_rawDescData = file_gui_io_log_proto_rawDesc 244 | ) 245 | 246 | func file_gui_io_log_proto_rawDescGZIP() []byte { 247 | file_gui_io_log_proto_rawDescOnce.Do(func() { 248 | file_gui_io_log_proto_rawDescData = protoimpl.X.CompressGZIP(file_gui_io_log_proto_rawDescData) 249 | }) 250 | return file_gui_io_log_proto_rawDescData 251 | } 252 | 253 | var file_gui_io_log_proto_msgTypes = make([]protoimpl.MessageInfo, 3) 254 | var file_gui_io_log_proto_goTypes = []interface{}{ 255 | (*Log)(nil), // 0: io.Log 256 | (*SearchLog)(nil), // 1: io.SearchLog 257 | (*SearchLogList)(nil), // 2: io.SearchLogList 258 | } 259 | var file_gui_io_log_proto_depIdxs = []int32{ 260 | 0, // 0: io.SearchLog.value:type_name -> io.Log 261 | 1, // 1: io.SearchLogList.search_log_list:type_name -> io.SearchLog 262 | 2, // [2:2] is the sub-list for method output_type 263 | 2, // [2:2] is the sub-list for method input_type 264 | 2, // [2:2] is the sub-list for extension type_name 265 | 2, // [2:2] is the sub-list for extension extendee 266 | 0, // [0:2] is the sub-list for field type_name 267 | } 268 | 269 | func init() { file_gui_io_log_proto_init() } 270 | func file_gui_io_log_proto_init() { 271 | if File_gui_io_log_proto != nil { 272 | return 273 | } 274 | if !protoimpl.UnsafeEnabled { 275 | file_gui_io_log_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { 276 | switch v := v.(*Log); i { 277 | case 0: 278 | return &v.state 279 | case 1: 280 | return &v.sizeCache 281 | case 2: 282 | return &v.unknownFields 283 | default: 284 | return nil 285 | } 286 | } 287 | file_gui_io_log_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { 288 | switch v := v.(*SearchLog); i { 289 | case 0: 290 | return &v.state 291 | case 1: 292 | return &v.sizeCache 293 | case 2: 294 | return &v.unknownFields 295 | default: 296 | return nil 297 | } 298 | } 299 | file_gui_io_log_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { 300 | switch v := v.(*SearchLogList); i { 301 | case 0: 302 | return &v.state 303 | case 1: 304 | return &v.sizeCache 305 | case 2: 306 | return &v.unknownFields 307 | default: 308 | return nil 309 | } 310 | } 311 | } 312 | type x struct{} 313 | out := protoimpl.TypeBuilder{ 314 | File: protoimpl.DescBuilder{ 315 | GoPackagePath: reflect.TypeOf(x{}).PkgPath(), 316 | RawDescriptor: file_gui_io_log_proto_rawDesc, 317 | NumEnums: 0, 318 | NumMessages: 3, 319 | NumExtensions: 0, 320 | NumServices: 0, 321 | }, 322 | GoTypes: file_gui_io_log_proto_goTypes, 323 | DependencyIndexes: file_gui_io_log_proto_depIdxs, 324 | MessageInfos: file_gui_io_log_proto_msgTypes, 325 | }.Build() 326 | File_gui_io_log_proto = out.File 327 | file_gui_io_log_proto_rawDesc = nil 328 | file_gui_io_log_proto_goTypes = nil 329 | file_gui_io_log_proto_depIdxs = nil 330 | } 331 | -------------------------------------------------------------------------------- /gui/io/log.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | option go_package = "github.com/crossoverJie/ptg/gui/io"; 3 | 4 | package io; 5 | 6 | message Log{ 7 | repeated string filenames = 1; 8 | string target = 2; 9 | string request = 3; 10 | string metadata = 4; 11 | string response = 5; 12 | } 13 | 14 | message SearchLog{ 15 | int32 id=1; 16 | Log value=2; 17 | string method_info=3; 18 | } 19 | message SearchLogList{ 20 | repeated SearchLog search_log_list=1; 21 | } -------------------------------------------------------------------------------- /gui/io/serialize.go: -------------------------------------------------------------------------------- 1 | package io 2 | 3 | import ( 4 | "github.com/golang/protobuf/proto" 5 | "io/ioutil" 6 | "os" 7 | "os/user" 8 | ) 9 | 10 | const ( 11 | AppLog = "log" 12 | AppSearchLog = "search_log" 13 | Path = "path" 14 | FileName = "filename" 15 | ) 16 | 17 | var ( 18 | LogMeta = map[string]map[string]string{ 19 | AppLog: { 20 | Path: "/.ptg/", 21 | FileName: "/.ptg/ptg.log", 22 | }, 23 | AppSearchLog: { 24 | Path: "/.ptg/", 25 | FileName: "/.ptg/search.log", 26 | }, 27 | } 28 | ) 29 | 30 | func SaveLog(logType string, data []byte) error { 31 | filename, err := initLog(logType) 32 | if err != nil { 33 | return err 34 | } 35 | 36 | return ioutil.WriteFile(filename, data, 0666) 37 | } 38 | 39 | func initLog(logType string) (string, error) { 40 | home, err := user.Current() 41 | if err != nil { 42 | return "", err 43 | } 44 | m := LogMeta[logType] 45 | filename := home.HomeDir + m[FileName] 46 | 47 | if !exist(filename) { 48 | err := os.MkdirAll(home.HomeDir+m[Path], 0777) 49 | if err != nil { 50 | return "", err 51 | } 52 | _, err = os.Create(filename) 53 | if err != nil { 54 | return "", err 55 | } 56 | } 57 | return filename, nil 58 | } 59 | 60 | func LoadLog(logType string) ([]byte, error) { 61 | filename, err := initLog(logType) 62 | if err != nil { 63 | return nil, err 64 | } 65 | return ioutil.ReadFile(filename) 66 | } 67 | 68 | func LoadLogWithStruct() (*Log, error) { 69 | bytes, err := LoadLog(AppLog) 70 | var read Log 71 | err = proto.Unmarshal(bytes, &read) 72 | if err != nil { 73 | return nil, err 74 | } 75 | return &read, nil 76 | } 77 | func LoadSearchLogWithStruct() (*SearchLogList, error) { 78 | bytes, err := LoadLog(AppSearchLog) 79 | var read SearchLogList 80 | err = proto.Unmarshal(bytes, &read) 81 | if err != nil { 82 | return nil, err 83 | } 84 | return &read, nil 85 | } 86 | 87 | func exist(filename string) bool { 88 | _, err := os.Stat(filename) 89 | return err == nil || os.IsExist(err) 90 | } 91 | -------------------------------------------------------------------------------- /gui/io/serialize_test.go: -------------------------------------------------------------------------------- 1 | package io 2 | 3 | import ( 4 | "fmt" 5 | "github.com/golang/protobuf/proto" 6 | "testing" 7 | ) 8 | 9 | func TestSaveLog(t *testing.T) { 10 | creat := Log{ 11 | Filenames: []string{"test.proto", "user.proto"}, 12 | Target: "127.0.0.1:6001", 13 | Request: `{"order_id":1123120,"reason_id":null,"remark":"","user_id":null}`, 14 | Metadata: `{"lang":"zh"}`, 15 | Response: `{"orderId":"1123120"}`, 16 | } 17 | marshal, err := proto.Marshal(&creat) 18 | if err != nil { 19 | panic(err) 20 | } 21 | err = SaveLog(AppLog, marshal) 22 | if err != nil { 23 | panic(err) 24 | } 25 | } 26 | 27 | func TestLoadLog(t *testing.T) { 28 | bytes, err := LoadLog(AppLog) 29 | if err != nil { 30 | panic(err) 31 | } 32 | 33 | var read Log 34 | err = proto.Unmarshal(bytes, &read) 35 | if err != nil { 36 | panic(err) 37 | } 38 | fmt.Println(read) 39 | } 40 | 41 | func TestLoadLogWithStruct(t *testing.T) { 42 | withStruct, err := LoadLogWithStruct() 43 | if err != nil { 44 | panic(err) 45 | } 46 | fmt.Println(withStruct) 47 | } 48 | 49 | func TestSaveLog1(t *testing.T) { 50 | searchLogList := &SearchLogList{} 51 | searchLogList.SearchLogList = append(searchLogList.SearchLogList, &SearchLog{ 52 | Id: 1, 53 | Value: &Log{ 54 | Target: "1212", 55 | Request: "4334", 56 | Metadata: "434", 57 | Response: "434", 58 | }, 59 | MethodInfo: "23232", 60 | }) 61 | marshal, err := proto.Marshal(searchLogList) 62 | if err != nil { 63 | panic(err) 64 | } 65 | err = SaveLog(AppSearchLog, marshal) 66 | if err != nil { 67 | panic(err) 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /gui/lru.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "container/list" 5 | "fmt" 6 | "sync" 7 | ) 8 | 9 | type LruCache struct { 10 | size int 11 | values *list.List 12 | cacheMap map[interface{}]*list.Element 13 | lock sync.Mutex 14 | } 15 | 16 | func NewLruList(size int) *LruCache { 17 | values := list.New() 18 | 19 | return &LruCache{ 20 | size: size, 21 | values: values, 22 | cacheMap: make(map[interface{}]*list.Element, size), 23 | } 24 | } 25 | 26 | func (l *LruCache) Put(k, v interface{}) { 27 | l.lock.Lock() 28 | defer l.lock.Unlock() 29 | if l.values.Len() == l.size { 30 | back := l.values.Back() 31 | l.values.Remove(back) 32 | delete(l.cacheMap, back) 33 | } 34 | 35 | front := l.values.PushFront(v) 36 | l.cacheMap[k] = front 37 | } 38 | 39 | func (l *LruCache) Get(k interface{}) (interface{}, bool) { 40 | v, ok := l.cacheMap[k] 41 | if ok { 42 | l.values.MoveToFront(v) 43 | return v, true 44 | } else { 45 | return nil, false 46 | } 47 | } 48 | 49 | func (l *LruCache) Size() int { 50 | return l.values.Len() 51 | } 52 | func (l *LruCache) String() { 53 | for i := l.values.Front(); i != nil; i = i.Next() { 54 | fmt.Print(i.Value, "\t") 55 | } 56 | } 57 | func (l *LruCache) List() []interface{} { 58 | var data []interface{} 59 | for i := l.values.Front(); i != nil; i = i.Next() { 60 | data = append(data, i.Value) 61 | } 62 | return data 63 | } 64 | 65 | func (l *LruCache) Clear() { 66 | l.lock.Lock() 67 | defer l.lock.Unlock() 68 | l.values = list.New() 69 | l.cacheMap = make(map[interface{}]*list.Element, l.size) 70 | 71 | } 72 | -------------------------------------------------------------------------------- /gui/lru_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "container/list" 5 | "fmt" 6 | "testing" 7 | ) 8 | 9 | func TestLruCache_Add(t *testing.T) { 10 | l := list.New() 11 | l.PushBack(1) 12 | back := l.PushBack(2) 13 | l.PushBack(3) 14 | len := l.Len() 15 | 16 | l.MoveToFront(back) 17 | 18 | for i := 0; i < len; i++ { 19 | front := l.Front() 20 | fmt.Println(front) 21 | l.Remove(front) 22 | } 23 | 24 | } 25 | 26 | func TestLruCache_Put(t *testing.T) { 27 | l := NewLruList(3) 28 | l.Put(1, 1) 29 | l.Put(2, 2) 30 | l.Put(3, 3) 31 | l.String() 32 | fmt.Println("=====") 33 | l.Put(4, 4) 34 | l.String() 35 | fmt.Println("=====") 36 | l.Get(3) 37 | l.String() 38 | } 39 | func TestLruCache_Put2(t *testing.T) { 40 | l := NewLruList(3) 41 | l.Put(1, 11) 42 | l.Put(2, 22) 43 | l.Put(3, 33) 44 | i := l.List() 45 | fmt.Println(i) 46 | fmt.Println("=====") 47 | l.Put(4, 44) 48 | i = l.List() 49 | fmt.Println(i) 50 | fmt.Println("=====") 51 | l.Get(3) 52 | i = l.List() 53 | fmt.Println(i) 54 | 55 | } 56 | -------------------------------------------------------------------------------- /gui/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "errors" 7 | "fmt" 8 | "fyne.io/fyne/v2" 9 | "fyne.io/fyne/v2/app" 10 | "fyne.io/fyne/v2/canvas" 11 | "fyne.io/fyne/v2/container" 12 | "fyne.io/fyne/v2/dialog" 13 | "fyne.io/fyne/v2/layout" 14 | "fyne.io/fyne/v2/theme" 15 | "fyne.io/fyne/v2/widget" 16 | "github.com/crossoverJie/ptg/gui/call" 17 | "github.com/crossoverJie/ptg/gui/io" 18 | "github.com/crossoverJie/ptg/reflect" 19 | _ "github.com/crossoverJie/ptg/reflect" 20 | "github.com/golang/protobuf/proto" 21 | "github.com/jhump/protoreflect/dynamic/grpcdynamic" 22 | "google.golang.org/grpc" 23 | "google.golang.org/grpc/metadata" 24 | "image/color" 25 | gio "io" 26 | "net/url" 27 | "os" 28 | "strings" 29 | ) 30 | 31 | func main() { 32 | ptgApp := InitApp() 33 | app := app.New() 34 | window := app.NewWindow(ptgApp.AppName) 35 | window.Resize(fyne.NewSize(ptgApp.AppWidth, ptgApp.AppHeight)) 36 | 37 | requestEntry := widget.NewMultiLineEntry() 38 | requestEntry.SetPlaceHolder(ptgApp.RightRequest.RequestEntryPlaceHolder) 39 | requestEntry.Wrapping = fyne.TextWrapWord 40 | responseEntry := widget.NewMultiLineEntry() 41 | responseEntry.Wrapping = fyne.TextWrapWord 42 | reqLabel := widget.NewLabel("") 43 | targetInput := widget.NewEntry() 44 | targetInput.SetText(ptgApp.RightRequest.TargetInputText) 45 | targetInput.SetPlaceHolder("") 46 | metadataEntry := widget.NewMultiLineEntry() 47 | metadataEntry.SetPlaceHolder(ptgApp.RightRequest.MetaDataInputPlaceHolder) 48 | processBar := widget.NewProgressBarInfinite() 49 | processBar.Hide() 50 | serviceAccordionRemove := false 51 | serviceAccordion := widget.NewAccordion() 52 | searchAccordion := widget.NewAccordion() 53 | searchEntry := widget.NewEntry() 54 | historyButton := container.NewVBox() 55 | history := NewHistory(10, historyButton, targetInput, requestEntry, metadataEntry, responseEntry, reqLabel) 56 | historyId := 0 57 | 58 | content := container.NewVBox() 59 | newProto := func(uri fyne.URIReadCloser, err error) { 60 | if err != nil { 61 | dialog.ShowError(err, window) 62 | return 63 | } 64 | if uri == nil { 65 | return 66 | } 67 | 68 | parseAdapter, exit, err := RegisterReflect(uri.URI().Path()) 69 | if err != nil { 70 | dialog.ShowError(err, window) 71 | return 72 | } 73 | if exit { 74 | dialog.ShowError(errors.New("proto file already exists"), window) 75 | return 76 | } 77 | 78 | maps := parseAdapter.Parse().ServiceInfoMaps() 79 | if serviceAccordionRemove { 80 | content.Add(serviceAccordion) 81 | serviceAccordionRemove = false 82 | } 83 | for k, v := range maps { 84 | var methods []string 85 | for _, s := range v { 86 | methods = append(methods, k+"."+s+"-"+fmt.Sprint(parseAdapter.Index())) 87 | } 88 | serviceAccordion.Append(&widget.AccordionItem{ 89 | Title: k, 90 | Detail: widget.NewRadioGroup(methods, func(s string) { 91 | if s == "" { 92 | return 93 | } 94 | methodInfo := strings.Split(s, "-") 95 | service, method, err := reflect.ParseServiceMethod(methodInfo[0]) 96 | if err != nil { 97 | dialog.ShowError(err, window) 98 | return 99 | } 100 | adapter, err := GetParseAdapter(methodInfo[1]) 101 | if err != nil { 102 | dialog.ShowError(err, window) 103 | return 104 | } 105 | json, err := adapter.Parse().RequestJSON(service, method) 106 | if err != nil { 107 | dialog.ShowError(err, window) 108 | return 109 | } 110 | requestEntry.SetText(json) 111 | reqLabel.SetText(s) 112 | 113 | }), 114 | Open: false, 115 | }) 116 | } 117 | 118 | } 119 | fileOpen := dialog.NewFileOpen(newProto, window) 120 | 121 | toolbar := widget.NewToolbar( 122 | widget.NewToolbarAction(theme.ContentAddIcon(), func() { 123 | fileOpen.Show() 124 | }), 125 | widget.NewToolbarAction(theme.ViewRefreshIcon(), func() { 126 | content.Remove(serviceAccordion) 127 | serviceAccordionRemove = true 128 | serviceAccordion.Items = nil 129 | dialog.ShowInformation("Notice", "Reload success.", window) 130 | ReloadReflect(newProto) 131 | }), 132 | widget.NewToolbarAction(theme.DeleteIcon(), func() { 133 | ClearReflect() 134 | content.Remove(serviceAccordion) 135 | serviceAccordionRemove = true 136 | serviceAccordion.Items = nil 137 | dialog.ShowInformation("Notice", "All proto files have been reset", window) 138 | }), 139 | widget.NewToolbarSeparator(), 140 | widget.NewToolbarAction(theme.HelpIcon(), func() { 141 | w := fyne.CurrentApp().NewWindow("Help") 142 | u, _ := url.Parse(ptgApp.HelpUrl) 143 | w.SetContent(container.New(layout.NewCenterLayout(), widget.NewHyperlink("help?", u))) 144 | w.Resize(fyne.NewSize(130, 100)) 145 | w.SetFixedSize(true) 146 | w.Show() 147 | }), 148 | //widget.NewToolbarAction(theme.RadioButtonIcon(), func() { 149 | // w := fyne.CurrentApp().NewWindow("Performance test") 150 | // w.Resize(fyne.NewSize(ptgApp.AppWidth, ptgApp.AppHeight)) 151 | // 152 | // myCanvas := w.Canvas() 153 | // //blue := color.NRGBA{R: 0, G: 0, B: 180, A: 255} 154 | // //rect := canvas.NewRectangle(blue) 155 | // //myCanvas.SetContent(rect) 156 | // 157 | // red := color.NRGBA{R: 0xff, G: 0x33, B: 0x33, A: 0xff} 158 | // circle := canvas.NewCircle(color.White) 159 | // circle.StrokeWidth = 4 160 | // circle.StrokeColor = red 161 | // 162 | // line := canvas.NewLine(red) 163 | // myCanvas.SetContent(line) 164 | // 165 | // w.SetFixedSize(true) 166 | // w.Show() 167 | //}), 168 | ) 169 | content.Add(toolbar) 170 | content.Add(searchAccordion) 171 | content.Add(serviceAccordion) 172 | 173 | // Search 174 | searchEntry.SetPlaceHolder(ptgApp.SearchFormPlaceHolder) 175 | searchForm := widget.NewForm(&widget.FormItem{ 176 | Widget: searchEntry, 177 | HintText: ptgApp.SearchFormText, 178 | }, &widget.FormItem{ 179 | Widget: widget.NewButtonWithIcon(ptgApp.SearchFormText, theme.SearchIcon(), func() { 180 | history.SearchResult(strings.ToLower(searchEntry.Text)) 181 | }), 182 | }) 183 | 184 | searchList := container.NewVScroll(historyButton) 185 | searchAccordion.Append(widget.NewAccordionItem(ptgApp.SearchFormText, searchForm)) 186 | leftTool := container.New(layout.NewGridLayout(1), content, searchList) 187 | 188 | // Right 189 | form := widget.NewForm(&widget.FormItem{ 190 | Text: ptgApp.RightRequest.TargetFormText, 191 | Widget: targetInput, 192 | HintText: ptgApp.RightRequest.TargetFormHintText, 193 | }) 194 | 195 | requestContainer := container.New(layout.NewGridLayoutWithColumns(1)) 196 | requestContainer.Add(requestEntry) 197 | requestButton := widget.NewButtonWithIcon("RUN", theme.MediaPlayIcon(), func() { 198 | if requestEntry.Text == "" { 199 | dialog.ShowError(errors.New("request json can not nil"), window) 200 | return 201 | } 202 | if reqLabel.Text == "" { 203 | dialog.ShowError(errors.New("proto can not nil"), window) 204 | return 205 | } 206 | methodInfo := strings.Split(reqLabel.Text, "-") 207 | service, method, err := reflect.ParseServiceMethod(methodInfo[0]) 208 | if err != nil { 209 | dialog.ShowError(err, window) 210 | return 211 | } 212 | index := methodInfo[1] 213 | adapter, err := GetParseAdapter(index) 214 | if err != nil { 215 | dialog.ShowError(err, window) 216 | return 217 | } 218 | parse := adapter.Parse() 219 | mds, err := parse.MethodDescriptor(service, method) 220 | if err != nil { 221 | dialog.ShowError(err, window) 222 | return 223 | } 224 | var opts []grpc.DialOption 225 | opts = append(opts, grpc.WithInsecure()) 226 | ctx := context.Background() 227 | ctx, err = buildWithMetadata(ctx, metadataEntry.Text) 228 | if err != nil { 229 | dialog.ShowError(err, window) 230 | return 231 | } 232 | 233 | conn, err := grpc.DialContext(ctx, targetInput.Text, opts...) 234 | if err != nil { 235 | dialog.ShowError(err, window) 236 | return 237 | } 238 | stub := grpcdynamic.NewStub(conn) 239 | processBar.Show() 240 | // call 241 | callBuilder := call.NewCallBuilder().Parse(parse). 242 | ResponseEntry(responseEntry). 243 | RequestEntry(requestEntry). 244 | Mds(mds). 245 | Stub(stub). 246 | RequestEntry(requestEntry). 247 | ProcessBar(processBar). 248 | ErrorHandle(func(window fyne.Window, processBar *widget.ProgressBarInfinite, err error) { 249 | processBar.Hide() 250 | dialog.ShowError(err, window) 251 | }) 252 | response, err := callBuilder.Run(ctx) 253 | if err != nil { 254 | processBar.Hide() 255 | dialog.ShowError(err, window) 256 | return 257 | } 258 | processBar.Hide() 259 | 260 | // Write history 261 | historyId++ 262 | history.Put(historyId, &io.SearchLog{ 263 | Id: int32(historyId), 264 | Value: &io.Log{ 265 | Target: targetInput.Text, 266 | Request: requestEntry.Text, 267 | Metadata: metadataEntry.Text, 268 | Response: response, 269 | }, 270 | MethodInfo: reqLabel.Text}, 271 | ) 272 | 273 | }) 274 | bottomBox := container.NewVBox(widget.NewAccordion(&widget.AccordionItem{ 275 | Title: ptgApp.RightRequest.MetaDataAccordionTitle, 276 | Detail: metadataEntry, 277 | Open: false, 278 | })) 279 | bottomBox.Add(canvas.NewLine(color.Black)) 280 | bottomBox.Add(requestButton) 281 | bottomBox.Add(canvas.NewLine(color.Black)) 282 | bottomBox.Add(processBar) 283 | requestPanel := container.NewBorder(form, bottomBox, nil, nil) 284 | requestPanel.Add(requestContainer) 285 | 286 | responseContainer := container.New(layout.NewGridLayoutWithColumns(1)) 287 | responseContainer.Add(responseEntry) 288 | responseLabel := widget.NewLabel(ptgApp.RightResponse.ResponseLabelText) 289 | responsePanel := container.NewBorder(responseLabel, nil, nil, nil) 290 | responsePanel.Add(responseContainer) 291 | 292 | rightTool := container.NewGridWithColumns(1, 293 | requestPanel, responsePanel) 294 | split := container.NewHSplit(leftTool, rightTool) 295 | 296 | window.SetContent(split) 297 | app.Lifecycle().SetOnStarted(func() { 298 | log, err := io.LoadLogWithStruct() 299 | if err != nil { 300 | dialog.ShowError(err, window) 301 | return 302 | } 303 | for _, filename := range log.Filenames { 304 | newProto(&ResetUri{ 305 | Filename: filename, 306 | }, nil) 307 | } 308 | if log.Target != "" { 309 | targetInput.SetText(log.Target) 310 | } 311 | if log.Request != "" { 312 | requestEntry.SetText(log.Request) 313 | } 314 | if log.Response != "" { 315 | responseEntry.SetText(log.Response) 316 | } 317 | if log.Metadata != "" { 318 | metadataEntry.SetText(log.Metadata) 319 | } 320 | searchLog, err := io.LoadSearchLogWithStruct() 321 | if err != nil { 322 | dialog.ShowError(err, window) 323 | return 324 | } 325 | history.InitSearchLog(searchLog) 326 | 327 | }) 328 | app.Lifecycle().SetOnStopped(func() { 329 | var filenames []string 330 | for filename, _ := range ParseContainer() { 331 | filenames = append(filenames, filename) 332 | } 333 | err := SaveLog(filenames, targetInput.Text, requestEntry.Text, responseEntry.Text, metadataEntry.Text) 334 | if err != nil { 335 | dialog.ShowError(err, window) 336 | return 337 | } 338 | err = history.SaveLog() 339 | if err != nil { 340 | dialog.ShowError(err, window) 341 | return 342 | } 343 | }) 344 | window.ShowAndRun() 345 | os.Unsetenv("FYNE_FONT") 346 | } 347 | 348 | func buildWithMetadata(ctx context.Context, meta string) (context.Context, error) { 349 | if strings.Trim(meta, "") != "" { 350 | var m map[string]string 351 | err := json.Unmarshal([]byte(meta), &m) 352 | if err != nil { 353 | return nil, err 354 | } 355 | md := metadata.New(m) 356 | ctx := metadata.NewOutgoingContext(ctx, md) 357 | return ctx, nil 358 | } 359 | return ctx, nil 360 | 361 | } 362 | 363 | func SaveLog(filenames []string, target, request, response, metadata string) error { 364 | log := io.Log{ 365 | Filenames: filenames, 366 | Target: target, 367 | Request: request, 368 | Metadata: metadata, 369 | Response: response, 370 | } 371 | marshal, err := proto.Marshal(&log) 372 | if err != nil { 373 | return err 374 | } 375 | return io.SaveLog(io.AppLog, marshal) 376 | } 377 | 378 | type ResetUri struct { 379 | gio.ReadCloser 380 | Filename string 381 | } 382 | 383 | func (r *ResetUri) URI() fyne.URI { 384 | return &uri{path: r.Filename} 385 | } 386 | 387 | type uri struct { 388 | path string 389 | } 390 | 391 | func (u *uri) Extension() string { 392 | return "" 393 | } 394 | 395 | func (u *uri) Name() string { 396 | return "" 397 | } 398 | 399 | func (u *uri) MimeType() string { 400 | return "" 401 | } 402 | 403 | func (u *uri) Scheme() string { 404 | return "" 405 | } 406 | 407 | func (u *uri) String() string { 408 | return "" 409 | } 410 | 411 | func (u *uri) Authority() string { 412 | return "" 413 | } 414 | 415 | func (u *uri) Path() string { 416 | return u.path 417 | } 418 | 419 | func (u *uri) Query() string { 420 | return "" 421 | } 422 | 423 | func (u *uri) Fragment() string { 424 | return "" 425 | } 426 | -------------------------------------------------------------------------------- /gui/reflect.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "fyne.io/fyne/v2" 6 | "github.com/crossoverJie/ptg/reflect" 7 | "github.com/pkg/errors" 8 | "sync/atomic" 9 | ) 10 | 11 | var ( 12 | // filename->*ParseReflectAdapter 13 | parseContainerMap map[string]*ParseReflectAdapter 14 | // index->filename 15 | containerMap map[string]string 16 | index int64 17 | ) 18 | 19 | type ParseReflectAdapter struct { 20 | parse *reflect.ParseReflect 21 | index string 22 | } 23 | 24 | func (p *ParseReflectAdapter) Parse() *reflect.ParseReflect { 25 | return p.parse 26 | } 27 | func (p *ParseReflectAdapter) Index() string { 28 | return p.index 29 | } 30 | 31 | func RegisterReflect(filename string) (*ParseReflectAdapter, bool, error) { 32 | parseAdapter, ok := parseContainerMap[filename] 33 | if ok { 34 | return parseAdapter, true, nil 35 | } 36 | newParse, err := reflect.NewParse(filename) 37 | if err != nil { 38 | return nil, false, err 39 | } 40 | if parseContainerMap == nil { 41 | parseContainerMap = make(map[string]*ParseReflectAdapter) 42 | } 43 | if containerMap == nil { 44 | containerMap = make(map[string]string) 45 | } 46 | 47 | index := genIndex() 48 | containerMap[index] = filename 49 | parseAdapter = &ParseReflectAdapter{ 50 | parse: newParse, 51 | index: index, 52 | } 53 | parseContainerMap[filename] = parseAdapter 54 | 55 | return parseAdapter, false, nil 56 | } 57 | 58 | func ClearReflect() { 59 | parseContainerMap = nil 60 | containerMap = nil 61 | index = 0 62 | } 63 | 64 | func ReloadReflect(f func(uri fyne.URIReadCloser, err error)) { 65 | var filenameList []string 66 | for k := range parseContainerMap { 67 | filenameList = append(filenameList, k) 68 | } 69 | ClearReflect() 70 | for _, filename := range filenameList { 71 | f(&ResetUri{Filename: filename}, nil) 72 | } 73 | } 74 | 75 | func ParseContainer() map[string]*ParseReflectAdapter { 76 | return parseContainerMap 77 | } 78 | 79 | func genIndex() string { 80 | return fmt.Sprint(atomic.AddInt64(&index, 1)) 81 | } 82 | 83 | func GetParseAdapter(index string) (*ParseReflectAdapter, error) { 84 | filename := containerMap[index] 85 | registerReflect, exit, _ := RegisterReflect(filename) 86 | if !exit { 87 | return nil, errors.New("proto not register") 88 | } 89 | return registerReflect, nil 90 | } 91 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "github.com/cheggaaa/pb/v3" 6 | "github.com/crossoverJie/ptg/meta" 7 | "github.com/crossoverJie/ptg/model" 8 | "github.com/fatih/color" 9 | "github.com/urfave/cli/v2" 10 | "io/ioutil" 11 | "log" 12 | "os" 13 | "os/signal" 14 | "runtime" 15 | "strings" 16 | ) 17 | 18 | // init bind variable 19 | var ( 20 | target string 21 | //respCh chan *meta.Response 22 | thread int 23 | duration int64 24 | method string 25 | bodyPath string 26 | body string 27 | headerSlice cli.StringSlice 28 | headerMap map[string]string 29 | protocol string // http/grpc 30 | protocolFile string // xx/xx/xx.proto 31 | fqn string // fully-qualified method name:[package.Service.Method] 32 | ) 33 | 34 | var ( 35 | //totalRequestTime time.Duration 36 | //totalResponseSize int 37 | //SlowRequestTime time.Duration 38 | //FastRequestTime = time.Minute 39 | //ErrorCount int32 40 | Bar *pb.ProgressBar 41 | ) 42 | 43 | const ( 44 | PbTmpl = `{{ green "Requesting:" }} {{string . "target" | blue}} {{ bar . "<" "-" (cycle . "↖" "↗" "↘" "↙" ) "." ">"}} {{speed . | rndcolor }} {{percent .}}` 45 | Http = "http" 46 | Grpc = "grpc" 47 | ) 48 | 49 | func main() { 50 | var count int 51 | app := &cli.App{Name: "ptg", Usage: "Performance testing tool (Go)", 52 | Flags: []cli.Flag{ 53 | &cli.IntFlag{ 54 | Name: "thread", 55 | Usage: "-t 10", 56 | //Value: 1000, 57 | DefaultText: "1", 58 | Aliases: []string{"t"}, 59 | Required: true, 60 | Destination: &thread, 61 | }, 62 | &cli.StringFlag{ 63 | Name: "Request protocol", 64 | Usage: "-proto http/grpc", 65 | DefaultText: "http", 66 | Aliases: []string{"proto"}, 67 | Required: true, 68 | Destination: &protocol, 69 | }, 70 | &cli.StringFlag{ 71 | Name: "protocol buffer file path", 72 | Usage: "-pf /file/order.proto", 73 | DefaultText: "", 74 | Aliases: []string{"pf"}, 75 | Required: false, 76 | Destination: &protocolFile, 77 | }, 78 | &cli.StringFlag{ 79 | Name: "fully-qualified method name", 80 | Usage: "-fqn package.Service.Method", 81 | DefaultText: "", 82 | Aliases: []string{"fqn"}, 83 | Required: false, 84 | Destination: &fqn, 85 | }, 86 | &cli.Int64Flag{ 87 | Name: "duration", 88 | Usage: "-d 10s", 89 | DefaultText: "Duration of test in seconds, Default 10s", 90 | Aliases: []string{"d"}, 91 | Required: false, 92 | Destination: &duration, 93 | }, 94 | &cli.IntFlag{ 95 | Name: "request count", 96 | Usage: "-c 100", 97 | DefaultText: "100", 98 | Aliases: []string{"c"}, 99 | Required: false, 100 | Destination: &count, 101 | }, 102 | &cli.StringFlag{ 103 | Name: "HTTP method", 104 | Usage: "-m GET", 105 | DefaultText: "GET", 106 | Aliases: []string{"M"}, 107 | Required: false, 108 | Destination: &method, 109 | }, 110 | &cli.StringFlag{ 111 | Name: "bodyPath", 112 | Usage: "-body bodyPath.json", 113 | DefaultText: "", 114 | Aliases: []string{"body"}, 115 | Required: false, 116 | Destination: &bodyPath, 117 | }, 118 | &cli.StringSliceFlag{ 119 | Name: "header", 120 | Aliases: []string{"H"}, 121 | Usage: "HTTP header to add to request, e.g. -H \"Content-Type: application/json\"", 122 | Required: false, 123 | DefaultText: "", 124 | Destination: &headerSlice, 125 | }, 126 | &cli.StringFlag{ 127 | Name: "target", 128 | Usage: "http://gobyexample.com/grpc:127.0.0.1:5000", 129 | DefaultText: "", 130 | Aliases: []string{"tg"}, 131 | Required: true, 132 | Destination: &target, 133 | }, 134 | }, 135 | Action: func(c *cli.Context) error { 136 | color.White("thread: %v, duration: %v, count %v", thread, duration, count) 137 | runtime.GOMAXPROCS(runtime.NumCPU() + thread) 138 | // ##########App init########## 139 | if count == 0 && duration == 0 { 140 | return errors.New("request count and duration must choose one") 141 | } 142 | 143 | if count > 0 && duration > 0 { 144 | return errors.New("request count and duration can only choose one") 145 | } 146 | 147 | if method == "" { 148 | method = "GET" 149 | } 150 | if bodyPath != "" { 151 | bytes, err := ioutil.ReadFile(bodyPath) 152 | if err != nil { 153 | color.Red("could not read file: %s", bodyPath) 154 | return err 155 | } 156 | body = string(bytes) 157 | } 158 | if headerSlice.Value() != nil { 159 | headerMap = make(map[string]string, len(headerSlice.Value())) 160 | for _, s := range headerSlice.Value() { 161 | splitN := strings.SplitN(s, ":", 2) 162 | headerMap[splitN[0]] = splitN[1] 163 | } 164 | } 165 | meta.NewResult() 166 | newMeta := meta.NewMeta(target, method, bodyPath, body, protocol, protocolFile, fqn, thread, duration, &headerSlice, headerMap) 167 | var model model.Model 168 | if count > 0 { 169 | respCh := make(chan *meta.Response, count) 170 | newMeta.SetRespCh(respCh) 171 | model = NewCountModel(count) 172 | Bar = pb.ProgressBarTemplate(PbTmpl).Start(count) 173 | } else { 174 | // 防止写入 goroutine 阻塞,导致泄露。 175 | respCh := make(chan *meta.Response, 3*thread) 176 | newMeta.SetRespCh(respCh) 177 | model = NewDurationModel(duration) 178 | Bar = pb.ProgressBarTemplate(PbTmpl).Start(int(duration)) 179 | } 180 | Bar.Set("target", target). 181 | SetWidth(120) 182 | // ##########App init########## 183 | 184 | // shutdown 185 | signCh := make(chan os.Signal, 1) 186 | signal.Notify(signCh, os.Interrupt) 187 | go func() { 188 | select { 189 | case <-signCh: 190 | color.Red("shutdown....") 191 | model.Shutdown() 192 | } 193 | }() 194 | 195 | model.Init() 196 | model.Run() 197 | model.Finish() 198 | model.PrintSate() 199 | 200 | return nil 201 | }, 202 | } 203 | 204 | err := app.Run(os.Args) 205 | if err != nil { 206 | log.Fatal(err) 207 | } 208 | } 209 | -------------------------------------------------------------------------------- /meta/meta.go: -------------------------------------------------------------------------------- 1 | package meta 2 | 3 | import ( 4 | "github.com/urfave/cli/v2" 5 | "sync/atomic" 6 | "time" 7 | ) 8 | 9 | type Response struct { 10 | RequestTime time.Duration 11 | ResponseSize int 12 | } 13 | 14 | func (r *Response) FastRequest() time.Duration { 15 | if r.RequestTime < GetResult().FastRequestTime() { 16 | return r.RequestTime 17 | } 18 | return GetResult().FastRequestTime() 19 | } 20 | func (r *Response) SlowRequest() time.Duration { 21 | if r.RequestTime > GetResult().SlowRequestTime() { 22 | return r.RequestTime 23 | } 24 | return GetResult().SlowRequestTime() 25 | } 26 | 27 | var result *Result 28 | 29 | type Result struct { 30 | totalRequestTime time.Duration 31 | totalResponseSize int 32 | slowRequestTime time.Duration 33 | fastRequestTime time.Duration 34 | errorCount int32 35 | } 36 | 37 | func GetResult() *Result { 38 | return result 39 | } 40 | 41 | func NewResult() *Result { 42 | if result != nil { 43 | return result 44 | } 45 | result = &Result{fastRequestTime: time.Minute} 46 | return GetResult() 47 | } 48 | 49 | func (m *Result) SetTotalRequestTime(req time.Duration) *Result { 50 | m.totalRequestTime += req 51 | return m 52 | } 53 | 54 | func (m *Result) TotalRequestTime() time.Duration { 55 | return m.totalRequestTime 56 | } 57 | 58 | func (m *Result) SetTotalResponseSize(req int) *Result { 59 | m.totalResponseSize += req 60 | return m 61 | } 62 | 63 | func (m *Result) TotalResponseSize() int { 64 | return m.totalResponseSize 65 | } 66 | 67 | func (m *Result) SetSlowRequestTime(req time.Duration) *Result { 68 | GetResult().slowRequestTime = req 69 | return m 70 | } 71 | func (m *Result) SlowRequestTime() time.Duration { 72 | return m.slowRequestTime 73 | } 74 | 75 | func (m *Result) SetFastRequestTime(req time.Duration) *Result { 76 | GetResult().fastRequestTime = req 77 | return m 78 | } 79 | func (m *Result) FastRequestTime() time.Duration { 80 | return m.fastRequestTime 81 | } 82 | 83 | func (m *Result) IncrementErrorCount() *Result { 84 | atomic.AddInt32(&m.errorCount, 1) 85 | return m 86 | } 87 | 88 | func (m *Result) ErrorCount() int32 { 89 | return m.errorCount 90 | } 91 | 92 | type Meta struct { 93 | target string 94 | respCh chan *Response 95 | thread int 96 | duration int64 97 | method string 98 | bodyPath string 99 | body string 100 | headerSlice *cli.StringSlice 101 | headerMap map[string]string 102 | protocol string // http/grpc 103 | protocolFile string // xx/xx/xx.proto 104 | fqn string // fully-qualified method name:[package.Service.Method] 105 | } 106 | 107 | var meta *Meta 108 | 109 | func NewMeta(target, method, bodyPath, body, protocol, protocolFile, fqn string, thread int, duration int64, 110 | headerSlice *cli.StringSlice, headerMap map[string]string) *Meta { 111 | 112 | if meta != nil { 113 | return meta 114 | } 115 | 116 | meta = &Meta{ 117 | target: target, 118 | thread: thread, 119 | duration: duration, 120 | method: method, 121 | bodyPath: bodyPath, 122 | body: body, 123 | headerSlice: headerSlice, 124 | headerMap: headerMap, 125 | protocol: protocol, 126 | protocolFile: protocolFile, 127 | fqn: fqn, 128 | } 129 | return meta 130 | } 131 | 132 | func GetMeta() *Meta { 133 | return meta 134 | } 135 | 136 | func (m *Meta) Protocol() string { 137 | return m.protocol 138 | } 139 | func (m *Meta) ProtocolFile() string { 140 | return m.protocolFile 141 | } 142 | func (m *Meta) Fqn() string { 143 | return m.fqn 144 | } 145 | func (m *Meta) Target() string { 146 | return m.target 147 | } 148 | func (m *Meta) Body() string { 149 | return m.body 150 | } 151 | 152 | func (m *Meta) HeaderMap() map[string]string { 153 | return m.headerMap 154 | } 155 | 156 | func (m *Meta) SetRespCh(respCh chan *Response) *Meta { 157 | m.respCh = respCh 158 | return meta 159 | } 160 | 161 | func (m *Meta) RespCh() chan *Response { 162 | return meta.respCh 163 | } 164 | -------------------------------------------------------------------------------- /model/model.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type ( 4 | Model interface { 5 | Init() 6 | Run() 7 | Finish() 8 | PrintSate() 9 | Shutdown() 10 | } 11 | ) 12 | -------------------------------------------------------------------------------- /pic/bd-stream-min.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crossoverJie/ptg/62f900dc122c0d5c811e8b6f4edac0128e30bd72/pic/bd-stream-min.gif -------------------------------------------------------------------------------- /pic/client-stream-min.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crossoverJie/ptg/62f900dc122c0d5c811e8b6f4edac0128e30bd72/pic/client-stream-min.gif -------------------------------------------------------------------------------- /pic/gopher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crossoverJie/ptg/62f900dc122c0d5c811e8b6f4edac0128e30bd72/pic/gopher.png -------------------------------------------------------------------------------- /pic/ptg-min.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crossoverJie/ptg/62f900dc122c0d5c811e8b6f4edac0128e30bd72/pic/ptg-min.gif -------------------------------------------------------------------------------- /pic/ptg.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crossoverJie/ptg/62f900dc122c0d5c811e8b6f4edac0128e30bd72/pic/ptg.gif -------------------------------------------------------------------------------- /pic/search.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crossoverJie/ptg/62f900dc122c0d5c811e8b6f4edac0128e30bd72/pic/search.gif -------------------------------------------------------------------------------- /pic/server-stream-min.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crossoverJie/ptg/62f900dc122c0d5c811e8b6f4edac0128e30bd72/pic/server-stream-min.gif -------------------------------------------------------------------------------- /pic/show.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crossoverJie/ptg/62f900dc122c0d5c811e8b6f4edac0128e30bd72/pic/show.gif -------------------------------------------------------------------------------- /reflect/gen/common.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. DO NOT EDIT. 2 | // versions: 3 | // protoc-gen-go v1.27.1 4 | // protoc v3.5.1 5 | // source: reflect/gen/common.proto 6 | 7 | package v1 8 | 9 | import ( 10 | protoreflect "google.golang.org/protobuf/reflect/protoreflect" 11 | protoimpl "google.golang.org/protobuf/runtime/protoimpl" 12 | reflect "reflect" 13 | sync "sync" 14 | ) 15 | 16 | const ( 17 | // Verify that this generated code is sufficiently up-to-date. 18 | _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) 19 | // Verify that runtime/protoimpl is sufficiently up-to-date. 20 | _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) 21 | ) 22 | 23 | type Common struct { 24 | state protoimpl.MessageState 25 | sizeCache protoimpl.SizeCache 26 | unknownFields protoimpl.UnknownFields 27 | 28 | Header string `protobuf:"bytes,1,opt,name=header,proto3" json:"header,omitempty"` 29 | } 30 | 31 | func (x *Common) Reset() { 32 | *x = Common{} 33 | if protoimpl.UnsafeEnabled { 34 | mi := &file_reflect_gen_common_proto_msgTypes[0] 35 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 36 | ms.StoreMessageInfo(mi) 37 | } 38 | } 39 | 40 | func (x *Common) String() string { 41 | return protoimpl.X.MessageStringOf(x) 42 | } 43 | 44 | func (*Common) ProtoMessage() {} 45 | 46 | func (x *Common) ProtoReflect() protoreflect.Message { 47 | mi := &file_reflect_gen_common_proto_msgTypes[0] 48 | if protoimpl.UnsafeEnabled && x != nil { 49 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 50 | if ms.LoadMessageInfo() == nil { 51 | ms.StoreMessageInfo(mi) 52 | } 53 | return ms 54 | } 55 | return mi.MessageOf(x) 56 | } 57 | 58 | // Deprecated: Use Common.ProtoReflect.Descriptor instead. 59 | func (*Common) Descriptor() ([]byte, []int) { 60 | return file_reflect_gen_common_proto_rawDescGZIP(), []int{0} 61 | } 62 | 63 | func (x *Common) GetHeader() string { 64 | if x != nil { 65 | return x.Header 66 | } 67 | return "" 68 | } 69 | 70 | var File_reflect_gen_common_proto protoreflect.FileDescriptor 71 | 72 | var file_reflect_gen_common_proto_rawDesc = []byte{ 73 | 0x0a, 0x18, 0x72, 0x65, 0x66, 0x6c, 0x65, 0x63, 0x74, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x63, 0x6f, 74 | 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x08, 0x6f, 0x72, 0x64, 0x65, 75 | 0x72, 0x2e, 0x76, 0x31, 0x22, 0x20, 0x0a, 0x06, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x12, 0x16, 76 | 0x0a, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 77 | 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x42, 0x2c, 0x5a, 0x2a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 78 | 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x72, 0x6f, 0x73, 0x73, 0x6f, 0x76, 0x65, 0x72, 0x4a, 0x69, 79 | 0x65, 0x2f, 0x70, 0x74, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x6f, 0x72, 0x64, 0x65, 80 | 0x72, 0x2f, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 81 | } 82 | 83 | var ( 84 | file_reflect_gen_common_proto_rawDescOnce sync.Once 85 | file_reflect_gen_common_proto_rawDescData = file_reflect_gen_common_proto_rawDesc 86 | ) 87 | 88 | func file_reflect_gen_common_proto_rawDescGZIP() []byte { 89 | file_reflect_gen_common_proto_rawDescOnce.Do(func() { 90 | file_reflect_gen_common_proto_rawDescData = protoimpl.X.CompressGZIP(file_reflect_gen_common_proto_rawDescData) 91 | }) 92 | return file_reflect_gen_common_proto_rawDescData 93 | } 94 | 95 | var file_reflect_gen_common_proto_msgTypes = make([]protoimpl.MessageInfo, 1) 96 | var file_reflect_gen_common_proto_goTypes = []interface{}{ 97 | (*Common)(nil), // 0: order.v1.Common 98 | } 99 | var file_reflect_gen_common_proto_depIdxs = []int32{ 100 | 0, // [0:0] is the sub-list for method output_type 101 | 0, // [0:0] is the sub-list for method input_type 102 | 0, // [0:0] is the sub-list for extension type_name 103 | 0, // [0:0] is the sub-list for extension extendee 104 | 0, // [0:0] is the sub-list for field type_name 105 | } 106 | 107 | func init() { file_reflect_gen_common_proto_init() } 108 | func file_reflect_gen_common_proto_init() { 109 | if File_reflect_gen_common_proto != nil { 110 | return 111 | } 112 | if !protoimpl.UnsafeEnabled { 113 | file_reflect_gen_common_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { 114 | switch v := v.(*Common); i { 115 | case 0: 116 | return &v.state 117 | case 1: 118 | return &v.sizeCache 119 | case 2: 120 | return &v.unknownFields 121 | default: 122 | return nil 123 | } 124 | } 125 | } 126 | type x struct{} 127 | out := protoimpl.TypeBuilder{ 128 | File: protoimpl.DescBuilder{ 129 | GoPackagePath: reflect.TypeOf(x{}).PkgPath(), 130 | RawDescriptor: file_reflect_gen_common_proto_rawDesc, 131 | NumEnums: 0, 132 | NumMessages: 1, 133 | NumExtensions: 0, 134 | NumServices: 0, 135 | }, 136 | GoTypes: file_reflect_gen_common_proto_goTypes, 137 | DependencyIndexes: file_reflect_gen_common_proto_depIdxs, 138 | MessageInfos: file_reflect_gen_common_proto_msgTypes, 139 | }.Build() 140 | File_reflect_gen_common_proto = out.File 141 | file_reflect_gen_common_proto_rawDesc = nil 142 | file_reflect_gen_common_proto_goTypes = nil 143 | file_reflect_gen_common_proto_depIdxs = nil 144 | } 145 | -------------------------------------------------------------------------------- /reflect/gen/common.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | option go_package = "github.com/crossoverJie/ptg/proto/order/v1"; 3 | package order.v1; 4 | 5 | message Common{ 6 | string header=1; 7 | } -------------------------------------------------------------------------------- /reflect/gen/test.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. DO NOT EDIT. 2 | // versions: 3 | // protoc-gen-go v1.27.1 4 | // protoc v3.5.1 5 | // source: reflect/gen/test.proto 6 | 7 | package v1 8 | 9 | import ( 10 | protoreflect "google.golang.org/protobuf/reflect/protoreflect" 11 | protoimpl "google.golang.org/protobuf/runtime/protoimpl" 12 | reflect "reflect" 13 | sync "sync" 14 | ) 15 | 16 | const ( 17 | // Verify that this generated code is sufficiently up-to-date. 18 | _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) 19 | // Verify that runtime/protoimpl is sufficiently up-to-date. 20 | _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) 21 | ) 22 | 23 | type ReasonApi struct { 24 | state protoimpl.MessageState 25 | sizeCache protoimpl.SizeCache 26 | unknownFields protoimpl.UnknownFields 27 | 28 | Id int32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` 29 | } 30 | 31 | func (x *ReasonApi) Reset() { 32 | *x = ReasonApi{} 33 | if protoimpl.UnsafeEnabled { 34 | mi := &file_reflect_gen_test_proto_msgTypes[0] 35 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 36 | ms.StoreMessageInfo(mi) 37 | } 38 | } 39 | 40 | func (x *ReasonApi) String() string { 41 | return protoimpl.X.MessageStringOf(x) 42 | } 43 | 44 | func (*ReasonApi) ProtoMessage() {} 45 | 46 | func (x *ReasonApi) ProtoReflect() protoreflect.Message { 47 | mi := &file_reflect_gen_test_proto_msgTypes[0] 48 | if protoimpl.UnsafeEnabled && x != nil { 49 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 50 | if ms.LoadMessageInfo() == nil { 51 | ms.StoreMessageInfo(mi) 52 | } 53 | return ms 54 | } 55 | return mi.MessageOf(x) 56 | } 57 | 58 | // Deprecated: Use ReasonApi.ProtoReflect.Descriptor instead. 59 | func (*ReasonApi) Descriptor() ([]byte, []int) { 60 | return file_reflect_gen_test_proto_rawDescGZIP(), []int{0} 61 | } 62 | 63 | func (x *ReasonApi) GetId() int32 { 64 | if x != nil { 65 | return x.Id 66 | } 67 | return 0 68 | } 69 | 70 | type Reasons struct { 71 | state protoimpl.MessageState 72 | sizeCache protoimpl.SizeCache 73 | unknownFields protoimpl.UnknownFields 74 | 75 | Reason []*Reason `protobuf:"bytes,1,rep,name=reason,proto3" json:"reason,omitempty"` 76 | } 77 | 78 | func (x *Reasons) Reset() { 79 | *x = Reasons{} 80 | if protoimpl.UnsafeEnabled { 81 | mi := &file_reflect_gen_test_proto_msgTypes[1] 82 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 83 | ms.StoreMessageInfo(mi) 84 | } 85 | } 86 | 87 | func (x *Reasons) String() string { 88 | return protoimpl.X.MessageStringOf(x) 89 | } 90 | 91 | func (*Reasons) ProtoMessage() {} 92 | 93 | func (x *Reasons) ProtoReflect() protoreflect.Message { 94 | mi := &file_reflect_gen_test_proto_msgTypes[1] 95 | if protoimpl.UnsafeEnabled && x != nil { 96 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 97 | if ms.LoadMessageInfo() == nil { 98 | ms.StoreMessageInfo(mi) 99 | } 100 | return ms 101 | } 102 | return mi.MessageOf(x) 103 | } 104 | 105 | // Deprecated: Use Reasons.ProtoReflect.Descriptor instead. 106 | func (*Reasons) Descriptor() ([]byte, []int) { 107 | return file_reflect_gen_test_proto_rawDescGZIP(), []int{1} 108 | } 109 | 110 | func (x *Reasons) GetReason() []*Reason { 111 | if x != nil { 112 | return x.Reason 113 | } 114 | return nil 115 | } 116 | 117 | type Reason struct { 118 | state protoimpl.MessageState 119 | sizeCache protoimpl.SizeCache 120 | unknownFields protoimpl.UnknownFields 121 | 122 | Id int32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` 123 | Remark string `protobuf:"bytes,2,opt,name=remark,proto3" json:"remark,omitempty"` 124 | } 125 | 126 | func (x *Reason) Reset() { 127 | *x = Reason{} 128 | if protoimpl.UnsafeEnabled { 129 | mi := &file_reflect_gen_test_proto_msgTypes[2] 130 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 131 | ms.StoreMessageInfo(mi) 132 | } 133 | } 134 | 135 | func (x *Reason) String() string { 136 | return protoimpl.X.MessageStringOf(x) 137 | } 138 | 139 | func (*Reason) ProtoMessage() {} 140 | 141 | func (x *Reason) ProtoReflect() protoreflect.Message { 142 | mi := &file_reflect_gen_test_proto_msgTypes[2] 143 | if protoimpl.UnsafeEnabled && x != nil { 144 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 145 | if ms.LoadMessageInfo() == nil { 146 | ms.StoreMessageInfo(mi) 147 | } 148 | return ms 149 | } 150 | return mi.MessageOf(x) 151 | } 152 | 153 | // Deprecated: Use Reason.ProtoReflect.Descriptor instead. 154 | func (*Reason) Descriptor() ([]byte, []int) { 155 | return file_reflect_gen_test_proto_rawDescGZIP(), []int{2} 156 | } 157 | 158 | func (x *Reason) GetId() int32 { 159 | if x != nil { 160 | return x.Id 161 | } 162 | return 0 163 | } 164 | 165 | func (x *Reason) GetRemark() string { 166 | if x != nil { 167 | return x.Remark 168 | } 169 | return "" 170 | } 171 | 172 | type CloseApiCreate struct { 173 | state protoimpl.MessageState 174 | sizeCache protoimpl.SizeCache 175 | unknownFields protoimpl.UnknownFields 176 | 177 | OrderId int64 `protobuf:"varint,1,opt,name=order_id,json=orderId,proto3" json:"order_id,omitempty"` 178 | Remark string `protobuf:"bytes,3,opt,name=remark,proto3" json:"remark,omitempty"` 179 | } 180 | 181 | func (x *CloseApiCreate) Reset() { 182 | *x = CloseApiCreate{} 183 | if protoimpl.UnsafeEnabled { 184 | mi := &file_reflect_gen_test_proto_msgTypes[3] 185 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 186 | ms.StoreMessageInfo(mi) 187 | } 188 | } 189 | 190 | func (x *CloseApiCreate) String() string { 191 | return protoimpl.X.MessageStringOf(x) 192 | } 193 | 194 | func (*CloseApiCreate) ProtoMessage() {} 195 | 196 | func (x *CloseApiCreate) ProtoReflect() protoreflect.Message { 197 | mi := &file_reflect_gen_test_proto_msgTypes[3] 198 | if protoimpl.UnsafeEnabled && x != nil { 199 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 200 | if ms.LoadMessageInfo() == nil { 201 | ms.StoreMessageInfo(mi) 202 | } 203 | return ms 204 | } 205 | return mi.MessageOf(x) 206 | } 207 | 208 | // Deprecated: Use CloseApiCreate.ProtoReflect.Descriptor instead. 209 | func (*CloseApiCreate) Descriptor() ([]byte, []int) { 210 | return file_reflect_gen_test_proto_rawDescGZIP(), []int{3} 211 | } 212 | 213 | func (x *CloseApiCreate) GetOrderId() int64 { 214 | if x != nil { 215 | return x.OrderId 216 | } 217 | return 0 218 | } 219 | 220 | func (x *CloseApiCreate) GetRemark() string { 221 | if x != nil { 222 | return x.Remark 223 | } 224 | return "" 225 | } 226 | 227 | type OrderApiCreate struct { 228 | state protoimpl.MessageState 229 | sizeCache protoimpl.SizeCache 230 | unknownFields protoimpl.UnknownFields 231 | 232 | OrderId int64 `protobuf:"varint,1,opt,name=order_id,json=orderId,proto3" json:"order_id,omitempty"` 233 | UserId []int64 `protobuf:"varint,2,rep,packed,name=user_id,json=userId,proto3" json:"user_id,omitempty"` 234 | Remark string `protobuf:"bytes,3,opt,name=remark,proto3" json:"remark,omitempty"` 235 | ReasonId []int32 `protobuf:"varint,4,rep,packed,name=reason_id,json=reasonId,proto3" json:"reason_id,omitempty"` 236 | } 237 | 238 | func (x *OrderApiCreate) Reset() { 239 | *x = OrderApiCreate{} 240 | if protoimpl.UnsafeEnabled { 241 | mi := &file_reflect_gen_test_proto_msgTypes[4] 242 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 243 | ms.StoreMessageInfo(mi) 244 | } 245 | } 246 | 247 | func (x *OrderApiCreate) String() string { 248 | return protoimpl.X.MessageStringOf(x) 249 | } 250 | 251 | func (*OrderApiCreate) ProtoMessage() {} 252 | 253 | func (x *OrderApiCreate) ProtoReflect() protoreflect.Message { 254 | mi := &file_reflect_gen_test_proto_msgTypes[4] 255 | if protoimpl.UnsafeEnabled && x != nil { 256 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 257 | if ms.LoadMessageInfo() == nil { 258 | ms.StoreMessageInfo(mi) 259 | } 260 | return ms 261 | } 262 | return mi.MessageOf(x) 263 | } 264 | 265 | // Deprecated: Use OrderApiCreate.ProtoReflect.Descriptor instead. 266 | func (*OrderApiCreate) Descriptor() ([]byte, []int) { 267 | return file_reflect_gen_test_proto_rawDescGZIP(), []int{4} 268 | } 269 | 270 | func (x *OrderApiCreate) GetOrderId() int64 { 271 | if x != nil { 272 | return x.OrderId 273 | } 274 | return 0 275 | } 276 | 277 | func (x *OrderApiCreate) GetUserId() []int64 { 278 | if x != nil { 279 | return x.UserId 280 | } 281 | return nil 282 | } 283 | 284 | func (x *OrderApiCreate) GetRemark() string { 285 | if x != nil { 286 | return x.Remark 287 | } 288 | return "" 289 | } 290 | 291 | func (x *OrderApiCreate) GetReasonId() []int32 { 292 | if x != nil { 293 | return x.ReasonId 294 | } 295 | return nil 296 | } 297 | 298 | type Order struct { 299 | state protoimpl.MessageState 300 | sizeCache protoimpl.SizeCache 301 | unknownFields protoimpl.UnknownFields 302 | 303 | OrderId int64 `protobuf:"varint,1,opt,name=order_id,json=orderId,proto3" json:"order_id,omitempty"` 304 | Reason []*Reason `protobuf:"bytes,2,rep,name=reason,proto3" json:"reason,omitempty"` 305 | Common *Common `protobuf:"bytes,3,opt,name=common,proto3" json:"common,omitempty"` 306 | } 307 | 308 | func (x *Order) Reset() { 309 | *x = Order{} 310 | if protoimpl.UnsafeEnabled { 311 | mi := &file_reflect_gen_test_proto_msgTypes[5] 312 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 313 | ms.StoreMessageInfo(mi) 314 | } 315 | } 316 | 317 | func (x *Order) String() string { 318 | return protoimpl.X.MessageStringOf(x) 319 | } 320 | 321 | func (*Order) ProtoMessage() {} 322 | 323 | func (x *Order) ProtoReflect() protoreflect.Message { 324 | mi := &file_reflect_gen_test_proto_msgTypes[5] 325 | if protoimpl.UnsafeEnabled && x != nil { 326 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 327 | if ms.LoadMessageInfo() == nil { 328 | ms.StoreMessageInfo(mi) 329 | } 330 | return ms 331 | } 332 | return mi.MessageOf(x) 333 | } 334 | 335 | // Deprecated: Use Order.ProtoReflect.Descriptor instead. 336 | func (*Order) Descriptor() ([]byte, []int) { 337 | return file_reflect_gen_test_proto_rawDescGZIP(), []int{5} 338 | } 339 | 340 | func (x *Order) GetOrderId() int64 { 341 | if x != nil { 342 | return x.OrderId 343 | } 344 | return 0 345 | } 346 | 347 | func (x *Order) GetReason() []*Reason { 348 | if x != nil { 349 | return x.Reason 350 | } 351 | return nil 352 | } 353 | 354 | func (x *Order) GetCommon() *Common { 355 | if x != nil { 356 | return x.Common 357 | } 358 | return nil 359 | } 360 | 361 | var File_reflect_gen_test_proto protoreflect.FileDescriptor 362 | 363 | var file_reflect_gen_test_proto_rawDesc = []byte{ 364 | 0x0a, 0x16, 0x72, 0x65, 0x66, 0x6c, 0x65, 0x63, 0x74, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x74, 0x65, 365 | 0x73, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x08, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x2e, 366 | 0x76, 0x31, 0x1a, 0x18, 0x72, 0x65, 0x66, 0x6c, 0x65, 0x63, 0x74, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 367 | 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x1b, 0x0a, 0x09, 368 | 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x41, 0x70, 0x69, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 369 | 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x69, 0x64, 0x22, 0x33, 0x0a, 0x07, 0x52, 0x65, 0x61, 370 | 0x73, 0x6f, 0x6e, 0x73, 0x12, 0x28, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x01, 371 | 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 372 | 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x22, 0x30, 373 | 0x0a, 0x06, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 374 | 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x69, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x6d, 0x61, 375 | 0x72, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x6d, 0x61, 0x72, 0x6b, 376 | 0x22, 0x43, 0x0a, 0x0e, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x41, 0x70, 0x69, 0x43, 0x72, 0x65, 0x61, 377 | 0x74, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 378 | 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x49, 0x64, 0x12, 0x16, 0x0a, 379 | 0x06, 0x72, 0x65, 0x6d, 0x61, 0x72, 0x6b, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 380 | 0x65, 0x6d, 0x61, 0x72, 0x6b, 0x22, 0x79, 0x0a, 0x0e, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x41, 0x70, 381 | 0x69, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x6f, 0x72, 0x64, 0x65, 0x72, 382 | 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x6f, 0x72, 0x64, 0x65, 0x72, 383 | 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 384 | 0x03, 0x28, 0x03, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x72, 385 | 0x65, 0x6d, 0x61, 0x72, 0x6b, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x6d, 386 | 0x61, 0x72, 0x6b, 0x12, 0x1b, 0x0a, 0x09, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 387 | 0x18, 0x04, 0x20, 0x03, 0x28, 0x05, 0x52, 0x08, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x49, 0x64, 388 | 0x22, 0x76, 0x0a, 0x05, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x19, 0x0a, 0x08, 0x6f, 0x72, 0x64, 389 | 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x6f, 0x72, 0x64, 390 | 0x65, 0x72, 0x49, 0x64, 0x12, 0x28, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x02, 391 | 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 392 | 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x28, 393 | 0x0a, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 394 | 0x2e, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 395 | 0x52, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x32, 0xb6, 0x02, 0x0a, 0x0c, 0x4f, 0x72, 0x64, 396 | 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x35, 0x0a, 0x06, 0x43, 0x72, 0x65, 397 | 0x61, 0x74, 0x65, 0x12, 0x18, 0x2e, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 398 | 0x72, 0x64, 0x65, 0x72, 0x41, 0x70, 0x69, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x1a, 0x0f, 0x2e, 399 | 0x6f, 0x72, 0x64, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x22, 0x00, 400 | 0x12, 0x34, 0x0a, 0x05, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x12, 0x18, 0x2e, 0x6f, 0x72, 0x64, 0x65, 401 | 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x41, 0x70, 0x69, 0x43, 0x72, 0x65, 402 | 0x61, 0x74, 0x65, 0x1a, 0x0f, 0x2e, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 403 | 0x72, 0x64, 0x65, 0x72, 0x22, 0x00, 0x12, 0x3d, 0x0a, 0x0c, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 404 | 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x18, 0x2e, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x2e, 0x76, 405 | 0x31, 0x2e, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x41, 0x70, 0x69, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 406 | 0x1a, 0x0f, 0x2e, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x72, 0x64, 0x65, 407 | 0x72, 0x22, 0x00, 0x30, 0x01, 0x12, 0x3d, 0x0a, 0x0c, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x53, 408 | 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x18, 0x2e, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x2e, 0x76, 0x31, 409 | 0x2e, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x41, 0x70, 0x69, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x1a, 410 | 0x0f, 0x2e, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x72, 0x64, 0x65, 0x72, 411 | 0x22, 0x00, 0x28, 0x01, 0x12, 0x3b, 0x0a, 0x08, 0x42, 0x64, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 412 | 0x12, 0x18, 0x2e, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x72, 0x64, 0x65, 413 | 0x72, 0x41, 0x70, 0x69, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x1a, 0x0f, 0x2e, 0x6f, 0x72, 0x64, 414 | 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x22, 0x00, 0x28, 0x01, 0x30, 415 | 0x01, 0x32, 0x43, 0x0a, 0x0b, 0x54, 0x65, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 416 | 0x12, 0x34, 0x0a, 0x08, 0x54, 0x65, 0x73, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x13, 0x2e, 0x6f, 417 | 0x72, 0x64, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x41, 0x70, 418 | 0x69, 0x1a, 0x11, 0x2e, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x61, 419 | 0x73, 0x6f, 0x6e, 0x73, 0x22, 0x00, 0x42, 0x2c, 0x5a, 0x2a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 420 | 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x72, 0x6f, 0x73, 0x73, 0x6f, 0x76, 0x65, 0x72, 0x4a, 0x69, 421 | 0x65, 0x2f, 0x70, 0x74, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x6f, 0x72, 0x64, 0x65, 422 | 0x72, 0x2f, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 423 | } 424 | 425 | var ( 426 | file_reflect_gen_test_proto_rawDescOnce sync.Once 427 | file_reflect_gen_test_proto_rawDescData = file_reflect_gen_test_proto_rawDesc 428 | ) 429 | 430 | func file_reflect_gen_test_proto_rawDescGZIP() []byte { 431 | file_reflect_gen_test_proto_rawDescOnce.Do(func() { 432 | file_reflect_gen_test_proto_rawDescData = protoimpl.X.CompressGZIP(file_reflect_gen_test_proto_rawDescData) 433 | }) 434 | return file_reflect_gen_test_proto_rawDescData 435 | } 436 | 437 | var file_reflect_gen_test_proto_msgTypes = make([]protoimpl.MessageInfo, 6) 438 | var file_reflect_gen_test_proto_goTypes = []interface{}{ 439 | (*ReasonApi)(nil), // 0: order.v1.ReasonApi 440 | (*Reasons)(nil), // 1: order.v1.Reasons 441 | (*Reason)(nil), // 2: order.v1.Reason 442 | (*CloseApiCreate)(nil), // 3: order.v1.CloseApiCreate 443 | (*OrderApiCreate)(nil), // 4: order.v1.OrderApiCreate 444 | (*Order)(nil), // 5: order.v1.Order 445 | (*Common)(nil), // 6: order.v1.Common 446 | } 447 | var file_reflect_gen_test_proto_depIdxs = []int32{ 448 | 2, // 0: order.v1.Reasons.reason:type_name -> order.v1.Reason 449 | 2, // 1: order.v1.Order.reason:type_name -> order.v1.Reason 450 | 6, // 2: order.v1.Order.common:type_name -> order.v1.Common 451 | 4, // 3: order.v1.OrderService.Create:input_type -> order.v1.OrderApiCreate 452 | 3, // 4: order.v1.OrderService.Close:input_type -> order.v1.CloseApiCreate 453 | 4, // 5: order.v1.OrderService.ServerStream:input_type -> order.v1.OrderApiCreate 454 | 4, // 6: order.v1.OrderService.ClientStream:input_type -> order.v1.OrderApiCreate 455 | 4, // 7: order.v1.OrderService.BdStream:input_type -> order.v1.OrderApiCreate 456 | 0, // 8: order.v1.TestService.TestList:input_type -> order.v1.ReasonApi 457 | 5, // 9: order.v1.OrderService.Create:output_type -> order.v1.Order 458 | 5, // 10: order.v1.OrderService.Close:output_type -> order.v1.Order 459 | 5, // 11: order.v1.OrderService.ServerStream:output_type -> order.v1.Order 460 | 5, // 12: order.v1.OrderService.ClientStream:output_type -> order.v1.Order 461 | 5, // 13: order.v1.OrderService.BdStream:output_type -> order.v1.Order 462 | 1, // 14: order.v1.TestService.TestList:output_type -> order.v1.Reasons 463 | 9, // [9:15] is the sub-list for method output_type 464 | 3, // [3:9] is the sub-list for method input_type 465 | 3, // [3:3] is the sub-list for extension type_name 466 | 3, // [3:3] is the sub-list for extension extendee 467 | 0, // [0:3] is the sub-list for field type_name 468 | } 469 | 470 | func init() { file_reflect_gen_test_proto_init() } 471 | func file_reflect_gen_test_proto_init() { 472 | if File_reflect_gen_test_proto != nil { 473 | return 474 | } 475 | file_reflect_gen_common_proto_init() 476 | if !protoimpl.UnsafeEnabled { 477 | file_reflect_gen_test_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { 478 | switch v := v.(*ReasonApi); i { 479 | case 0: 480 | return &v.state 481 | case 1: 482 | return &v.sizeCache 483 | case 2: 484 | return &v.unknownFields 485 | default: 486 | return nil 487 | } 488 | } 489 | file_reflect_gen_test_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { 490 | switch v := v.(*Reasons); i { 491 | case 0: 492 | return &v.state 493 | case 1: 494 | return &v.sizeCache 495 | case 2: 496 | return &v.unknownFields 497 | default: 498 | return nil 499 | } 500 | } 501 | file_reflect_gen_test_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { 502 | switch v := v.(*Reason); i { 503 | case 0: 504 | return &v.state 505 | case 1: 506 | return &v.sizeCache 507 | case 2: 508 | return &v.unknownFields 509 | default: 510 | return nil 511 | } 512 | } 513 | file_reflect_gen_test_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { 514 | switch v := v.(*CloseApiCreate); i { 515 | case 0: 516 | return &v.state 517 | case 1: 518 | return &v.sizeCache 519 | case 2: 520 | return &v.unknownFields 521 | default: 522 | return nil 523 | } 524 | } 525 | file_reflect_gen_test_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { 526 | switch v := v.(*OrderApiCreate); i { 527 | case 0: 528 | return &v.state 529 | case 1: 530 | return &v.sizeCache 531 | case 2: 532 | return &v.unknownFields 533 | default: 534 | return nil 535 | } 536 | } 537 | file_reflect_gen_test_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { 538 | switch v := v.(*Order); i { 539 | case 0: 540 | return &v.state 541 | case 1: 542 | return &v.sizeCache 543 | case 2: 544 | return &v.unknownFields 545 | default: 546 | return nil 547 | } 548 | } 549 | } 550 | type x struct{} 551 | out := protoimpl.TypeBuilder{ 552 | File: protoimpl.DescBuilder{ 553 | GoPackagePath: reflect.TypeOf(x{}).PkgPath(), 554 | RawDescriptor: file_reflect_gen_test_proto_rawDesc, 555 | NumEnums: 0, 556 | NumMessages: 6, 557 | NumExtensions: 0, 558 | NumServices: 2, 559 | }, 560 | GoTypes: file_reflect_gen_test_proto_goTypes, 561 | DependencyIndexes: file_reflect_gen_test_proto_depIdxs, 562 | MessageInfos: file_reflect_gen_test_proto_msgTypes, 563 | }.Build() 564 | File_reflect_gen_test_proto = out.File 565 | file_reflect_gen_test_proto_rawDesc = nil 566 | file_reflect_gen_test_proto_goTypes = nil 567 | file_reflect_gen_test_proto_depIdxs = nil 568 | } 569 | -------------------------------------------------------------------------------- /reflect/gen/test.proto: -------------------------------------------------------------------------------- 1 | 2 | syntax = "proto3"; 3 | option go_package = "github.com/crossoverJie/ptg/proto/order/v1"; 4 | 5 | import "reflect/gen/common.proto"; 6 | 7 | package order.v1; 8 | 9 | service OrderService{ 10 | 11 | rpc Create(OrderApiCreate) returns (Order) {} 12 | 13 | rpc Close(CloseApiCreate) returns (Order) {} 14 | 15 | rpc ServerStream(OrderApiCreate) returns (stream Order) {} 16 | 17 | rpc ClientStream(stream OrderApiCreate) returns (Order) {} 18 | 19 | rpc BdStream(stream OrderApiCreate) returns (stream Order) {} 20 | } 21 | 22 | service TestService{ 23 | rpc TestList(ReasonApi) returns (Reasons){} 24 | } 25 | message ReasonApi{ 26 | int32 id = 1; 27 | } 28 | 29 | message Reasons{ 30 | repeated Reason reason = 1; 31 | } 32 | 33 | message Reason{ 34 | int32 id = 1; 35 | string remark = 2; 36 | } 37 | 38 | 39 | 40 | message CloseApiCreate{ 41 | int64 order_id = 1; 42 | string remark = 3; 43 | } 44 | 45 | 46 | message OrderApiCreate{ 47 | int64 order_id = 1; 48 | repeated int64 user_id = 2; 49 | string remark = 3; 50 | repeated int32 reason_id = 4; 51 | } 52 | 53 | message Order{ 54 | int64 order_id = 1; 55 | repeated Reason reason = 2; 56 | Common common=3; 57 | } 58 | 59 | -------------------------------------------------------------------------------- /reflect/gen/test_grpc.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go-grpc. DO NOT EDIT. 2 | 3 | package v1 4 | 5 | import ( 6 | context "context" 7 | grpc "google.golang.org/grpc" 8 | codes "google.golang.org/grpc/codes" 9 | status "google.golang.org/grpc/status" 10 | ) 11 | 12 | // This is a compile-time assertion to ensure that this generated file 13 | // is compatible with the grpc package it is being compiled against. 14 | // Requires gRPC-Go v1.32.0 or later. 15 | const _ = grpc.SupportPackageIsVersion7 16 | 17 | // OrderServiceClient is the client API for OrderService service. 18 | // 19 | // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. 20 | type OrderServiceClient interface { 21 | Create(ctx context.Context, in *OrderApiCreate, opts ...grpc.CallOption) (*Order, error) 22 | Close(ctx context.Context, in *CloseApiCreate, opts ...grpc.CallOption) (*Order, error) 23 | ServerStream(ctx context.Context, in *OrderApiCreate, opts ...grpc.CallOption) (OrderService_ServerStreamClient, error) 24 | ClientStream(ctx context.Context, opts ...grpc.CallOption) (OrderService_ClientStreamClient, error) 25 | BdStream(ctx context.Context, opts ...grpc.CallOption) (OrderService_BdStreamClient, error) 26 | } 27 | 28 | type orderServiceClient struct { 29 | cc grpc.ClientConnInterface 30 | } 31 | 32 | func NewOrderServiceClient(cc grpc.ClientConnInterface) OrderServiceClient { 33 | return &orderServiceClient{cc} 34 | } 35 | 36 | func (c *orderServiceClient) Create(ctx context.Context, in *OrderApiCreate, opts ...grpc.CallOption) (*Order, error) { 37 | out := new(Order) 38 | err := c.cc.Invoke(ctx, "/order.v1.OrderService/Create", in, out, opts...) 39 | if err != nil { 40 | return nil, err 41 | } 42 | return out, nil 43 | } 44 | 45 | func (c *orderServiceClient) Close(ctx context.Context, in *CloseApiCreate, opts ...grpc.CallOption) (*Order, error) { 46 | out := new(Order) 47 | err := c.cc.Invoke(ctx, "/order.v1.OrderService/Close", in, out, opts...) 48 | if err != nil { 49 | return nil, err 50 | } 51 | return out, nil 52 | } 53 | 54 | func (c *orderServiceClient) ServerStream(ctx context.Context, in *OrderApiCreate, opts ...grpc.CallOption) (OrderService_ServerStreamClient, error) { 55 | stream, err := c.cc.NewStream(ctx, &OrderService_ServiceDesc.Streams[0], "/order.v1.OrderService/ServerStream", opts...) 56 | if err != nil { 57 | return nil, err 58 | } 59 | x := &orderServiceServerStreamClient{stream} 60 | if err := x.ClientStream.SendMsg(in); err != nil { 61 | return nil, err 62 | } 63 | if err := x.ClientStream.CloseSend(); err != nil { 64 | return nil, err 65 | } 66 | return x, nil 67 | } 68 | 69 | type OrderService_ServerStreamClient interface { 70 | Recv() (*Order, error) 71 | grpc.ClientStream 72 | } 73 | 74 | type orderServiceServerStreamClient struct { 75 | grpc.ClientStream 76 | } 77 | 78 | func (x *orderServiceServerStreamClient) Recv() (*Order, error) { 79 | m := new(Order) 80 | if err := x.ClientStream.RecvMsg(m); err != nil { 81 | return nil, err 82 | } 83 | return m, nil 84 | } 85 | 86 | func (c *orderServiceClient) ClientStream(ctx context.Context, opts ...grpc.CallOption) (OrderService_ClientStreamClient, error) { 87 | stream, err := c.cc.NewStream(ctx, &OrderService_ServiceDesc.Streams[1], "/order.v1.OrderService/ClientStream", opts...) 88 | if err != nil { 89 | return nil, err 90 | } 91 | x := &orderServiceClientStreamClient{stream} 92 | return x, nil 93 | } 94 | 95 | type OrderService_ClientStreamClient interface { 96 | Send(*OrderApiCreate) error 97 | CloseAndRecv() (*Order, error) 98 | grpc.ClientStream 99 | } 100 | 101 | type orderServiceClientStreamClient struct { 102 | grpc.ClientStream 103 | } 104 | 105 | func (x *orderServiceClientStreamClient) Send(m *OrderApiCreate) error { 106 | return x.ClientStream.SendMsg(m) 107 | } 108 | 109 | func (x *orderServiceClientStreamClient) CloseAndRecv() (*Order, error) { 110 | if err := x.ClientStream.CloseSend(); err != nil { 111 | return nil, err 112 | } 113 | m := new(Order) 114 | if err := x.ClientStream.RecvMsg(m); err != nil { 115 | return nil, err 116 | } 117 | return m, nil 118 | } 119 | 120 | func (c *orderServiceClient) BdStream(ctx context.Context, opts ...grpc.CallOption) (OrderService_BdStreamClient, error) { 121 | stream, err := c.cc.NewStream(ctx, &OrderService_ServiceDesc.Streams[2], "/order.v1.OrderService/BdStream", opts...) 122 | if err != nil { 123 | return nil, err 124 | } 125 | x := &orderServiceBdStreamClient{stream} 126 | return x, nil 127 | } 128 | 129 | type OrderService_BdStreamClient interface { 130 | Send(*OrderApiCreate) error 131 | Recv() (*Order, error) 132 | grpc.ClientStream 133 | } 134 | 135 | type orderServiceBdStreamClient struct { 136 | grpc.ClientStream 137 | } 138 | 139 | func (x *orderServiceBdStreamClient) Send(m *OrderApiCreate) error { 140 | return x.ClientStream.SendMsg(m) 141 | } 142 | 143 | func (x *orderServiceBdStreamClient) Recv() (*Order, error) { 144 | m := new(Order) 145 | if err := x.ClientStream.RecvMsg(m); err != nil { 146 | return nil, err 147 | } 148 | return m, nil 149 | } 150 | 151 | // OrderServiceServer is the server API for OrderService service. 152 | // All implementations must embed UnimplementedOrderServiceServer 153 | // for forward compatibility 154 | type OrderServiceServer interface { 155 | Create(context.Context, *OrderApiCreate) (*Order, error) 156 | Close(context.Context, *CloseApiCreate) (*Order, error) 157 | ServerStream(*OrderApiCreate, OrderService_ServerStreamServer) error 158 | ClientStream(OrderService_ClientStreamServer) error 159 | BdStream(OrderService_BdStreamServer) error 160 | mustEmbedUnimplementedOrderServiceServer() 161 | } 162 | 163 | // UnimplementedOrderServiceServer must be embedded to have forward compatible implementations. 164 | type UnimplementedOrderServiceServer struct { 165 | } 166 | 167 | func (UnimplementedOrderServiceServer) Create(context.Context, *OrderApiCreate) (*Order, error) { 168 | return nil, status.Errorf(codes.Unimplemented, "method Create not implemented") 169 | } 170 | func (UnimplementedOrderServiceServer) Close(context.Context, *CloseApiCreate) (*Order, error) { 171 | return nil, status.Errorf(codes.Unimplemented, "method Close not implemented") 172 | } 173 | func (UnimplementedOrderServiceServer) ServerStream(*OrderApiCreate, OrderService_ServerStreamServer) error { 174 | return status.Errorf(codes.Unimplemented, "method ServerStream not implemented") 175 | } 176 | func (UnimplementedOrderServiceServer) ClientStream(OrderService_ClientStreamServer) error { 177 | return status.Errorf(codes.Unimplemented, "method ClientStream not implemented") 178 | } 179 | func (UnimplementedOrderServiceServer) BdStream(OrderService_BdStreamServer) error { 180 | return status.Errorf(codes.Unimplemented, "method BdStream not implemented") 181 | } 182 | func (UnimplementedOrderServiceServer) mustEmbedUnimplementedOrderServiceServer() {} 183 | 184 | // UnsafeOrderServiceServer may be embedded to opt out of forward compatibility for this service. 185 | // Use of this interface is not recommended, as added methods to OrderServiceServer will 186 | // result in compilation errors. 187 | type UnsafeOrderServiceServer interface { 188 | mustEmbedUnimplementedOrderServiceServer() 189 | } 190 | 191 | func RegisterOrderServiceServer(s grpc.ServiceRegistrar, srv OrderServiceServer) { 192 | s.RegisterService(&OrderService_ServiceDesc, srv) 193 | } 194 | 195 | func _OrderService_Create_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { 196 | in := new(OrderApiCreate) 197 | if err := dec(in); err != nil { 198 | return nil, err 199 | } 200 | if interceptor == nil { 201 | return srv.(OrderServiceServer).Create(ctx, in) 202 | } 203 | info := &grpc.UnaryServerInfo{ 204 | Server: srv, 205 | FullMethod: "/order.v1.OrderService/Create", 206 | } 207 | handler := func(ctx context.Context, req interface{}) (interface{}, error) { 208 | return srv.(OrderServiceServer).Create(ctx, req.(*OrderApiCreate)) 209 | } 210 | return interceptor(ctx, in, info, handler) 211 | } 212 | 213 | func _OrderService_Close_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { 214 | in := new(CloseApiCreate) 215 | if err := dec(in); err != nil { 216 | return nil, err 217 | } 218 | if interceptor == nil { 219 | return srv.(OrderServiceServer).Close(ctx, in) 220 | } 221 | info := &grpc.UnaryServerInfo{ 222 | Server: srv, 223 | FullMethod: "/order.v1.OrderService/Close", 224 | } 225 | handler := func(ctx context.Context, req interface{}) (interface{}, error) { 226 | return srv.(OrderServiceServer).Close(ctx, req.(*CloseApiCreate)) 227 | } 228 | return interceptor(ctx, in, info, handler) 229 | } 230 | 231 | func _OrderService_ServerStream_Handler(srv interface{}, stream grpc.ServerStream) error { 232 | m := new(OrderApiCreate) 233 | if err := stream.RecvMsg(m); err != nil { 234 | return err 235 | } 236 | return srv.(OrderServiceServer).ServerStream(m, &orderServiceServerStreamServer{stream}) 237 | } 238 | 239 | type OrderService_ServerStreamServer interface { 240 | Send(*Order) error 241 | grpc.ServerStream 242 | } 243 | 244 | type orderServiceServerStreamServer struct { 245 | grpc.ServerStream 246 | } 247 | 248 | func (x *orderServiceServerStreamServer) Send(m *Order) error { 249 | return x.ServerStream.SendMsg(m) 250 | } 251 | 252 | func _OrderService_ClientStream_Handler(srv interface{}, stream grpc.ServerStream) error { 253 | return srv.(OrderServiceServer).ClientStream(&orderServiceClientStreamServer{stream}) 254 | } 255 | 256 | type OrderService_ClientStreamServer interface { 257 | SendAndClose(*Order) error 258 | Recv() (*OrderApiCreate, error) 259 | grpc.ServerStream 260 | } 261 | 262 | type orderServiceClientStreamServer struct { 263 | grpc.ServerStream 264 | } 265 | 266 | func (x *orderServiceClientStreamServer) SendAndClose(m *Order) error { 267 | return x.ServerStream.SendMsg(m) 268 | } 269 | 270 | func (x *orderServiceClientStreamServer) Recv() (*OrderApiCreate, error) { 271 | m := new(OrderApiCreate) 272 | if err := x.ServerStream.RecvMsg(m); err != nil { 273 | return nil, err 274 | } 275 | return m, nil 276 | } 277 | 278 | func _OrderService_BdStream_Handler(srv interface{}, stream grpc.ServerStream) error { 279 | return srv.(OrderServiceServer).BdStream(&orderServiceBdStreamServer{stream}) 280 | } 281 | 282 | type OrderService_BdStreamServer interface { 283 | Send(*Order) error 284 | Recv() (*OrderApiCreate, error) 285 | grpc.ServerStream 286 | } 287 | 288 | type orderServiceBdStreamServer struct { 289 | grpc.ServerStream 290 | } 291 | 292 | func (x *orderServiceBdStreamServer) Send(m *Order) error { 293 | return x.ServerStream.SendMsg(m) 294 | } 295 | 296 | func (x *orderServiceBdStreamServer) Recv() (*OrderApiCreate, error) { 297 | m := new(OrderApiCreate) 298 | if err := x.ServerStream.RecvMsg(m); err != nil { 299 | return nil, err 300 | } 301 | return m, nil 302 | } 303 | 304 | // OrderService_ServiceDesc is the grpc.ServiceDesc for OrderService service. 305 | // It's only intended for direct use with grpc.RegisterService, 306 | // and not to be introspected or modified (even as a copy) 307 | var OrderService_ServiceDesc = grpc.ServiceDesc{ 308 | ServiceName: "order.v1.OrderService", 309 | HandlerType: (*OrderServiceServer)(nil), 310 | Methods: []grpc.MethodDesc{ 311 | { 312 | MethodName: "Create", 313 | Handler: _OrderService_Create_Handler, 314 | }, 315 | { 316 | MethodName: "Close", 317 | Handler: _OrderService_Close_Handler, 318 | }, 319 | }, 320 | Streams: []grpc.StreamDesc{ 321 | { 322 | StreamName: "ServerStream", 323 | Handler: _OrderService_ServerStream_Handler, 324 | ServerStreams: true, 325 | }, 326 | { 327 | StreamName: "ClientStream", 328 | Handler: _OrderService_ClientStream_Handler, 329 | ClientStreams: true, 330 | }, 331 | { 332 | StreamName: "BdStream", 333 | Handler: _OrderService_BdStream_Handler, 334 | ServerStreams: true, 335 | ClientStreams: true, 336 | }, 337 | }, 338 | Metadata: "reflect/gen/test.proto", 339 | } 340 | 341 | // TestServiceClient is the client API for TestService service. 342 | // 343 | // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. 344 | type TestServiceClient interface { 345 | TestList(ctx context.Context, in *ReasonApi, opts ...grpc.CallOption) (*Reasons, error) 346 | } 347 | 348 | type testServiceClient struct { 349 | cc grpc.ClientConnInterface 350 | } 351 | 352 | func NewTestServiceClient(cc grpc.ClientConnInterface) TestServiceClient { 353 | return &testServiceClient{cc} 354 | } 355 | 356 | func (c *testServiceClient) TestList(ctx context.Context, in *ReasonApi, opts ...grpc.CallOption) (*Reasons, error) { 357 | out := new(Reasons) 358 | err := c.cc.Invoke(ctx, "/order.v1.TestService/TestList", in, out, opts...) 359 | if err != nil { 360 | return nil, err 361 | } 362 | return out, nil 363 | } 364 | 365 | // TestServiceServer is the server API for TestService service. 366 | // All implementations must embed UnimplementedTestServiceServer 367 | // for forward compatibility 368 | type TestServiceServer interface { 369 | TestList(context.Context, *ReasonApi) (*Reasons, error) 370 | mustEmbedUnimplementedTestServiceServer() 371 | } 372 | 373 | // UnimplementedTestServiceServer must be embedded to have forward compatible implementations. 374 | type UnimplementedTestServiceServer struct { 375 | } 376 | 377 | func (UnimplementedTestServiceServer) TestList(context.Context, *ReasonApi) (*Reasons, error) { 378 | return nil, status.Errorf(codes.Unimplemented, "method TestList not implemented") 379 | } 380 | func (UnimplementedTestServiceServer) mustEmbedUnimplementedTestServiceServer() {} 381 | 382 | // UnsafeTestServiceServer may be embedded to opt out of forward compatibility for this service. 383 | // Use of this interface is not recommended, as added methods to TestServiceServer will 384 | // result in compilation errors. 385 | type UnsafeTestServiceServer interface { 386 | mustEmbedUnimplementedTestServiceServer() 387 | } 388 | 389 | func RegisterTestServiceServer(s grpc.ServiceRegistrar, srv TestServiceServer) { 390 | s.RegisterService(&TestService_ServiceDesc, srv) 391 | } 392 | 393 | func _TestService_TestList_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { 394 | in := new(ReasonApi) 395 | if err := dec(in); err != nil { 396 | return nil, err 397 | } 398 | if interceptor == nil { 399 | return srv.(TestServiceServer).TestList(ctx, in) 400 | } 401 | info := &grpc.UnaryServerInfo{ 402 | Server: srv, 403 | FullMethod: "/order.v1.TestService/TestList", 404 | } 405 | handler := func(ctx context.Context, req interface{}) (interface{}, error) { 406 | return srv.(TestServiceServer).TestList(ctx, req.(*ReasonApi)) 407 | } 408 | return interceptor(ctx, in, info, handler) 409 | } 410 | 411 | // TestService_ServiceDesc is the grpc.ServiceDesc for TestService service. 412 | // It's only intended for direct use with grpc.RegisterService, 413 | // and not to be introspected or modified (even as a copy) 414 | var TestService_ServiceDesc = grpc.ServiceDesc{ 415 | ServiceName: "order.v1.TestService", 416 | HandlerType: (*TestServiceServer)(nil), 417 | Methods: []grpc.MethodDesc{ 418 | { 419 | MethodName: "TestList", 420 | Handler: _TestService_TestList_Handler, 421 | }, 422 | }, 423 | Streams: []grpc.StreamDesc{}, 424 | Metadata: "reflect/gen/test.proto", 425 | } 426 | -------------------------------------------------------------------------------- /reflect/gen/user.proto: -------------------------------------------------------------------------------- 1 | 2 | syntax = "proto3"; 3 | option go_package = "github.com/crossoverJie/ptg/proto/user/v2"; 4 | 5 | package user.v2; 6 | 7 | service UserService{ 8 | 9 | rpc Create(UserApiCreate) returns (User) {} 10 | 11 | rpc List(Empty) returns (UserList) {} 12 | 13 | } 14 | 15 | message Empty{} 16 | 17 | 18 | 19 | message UserApiCreate{ 20 | int64 user_id = 1; 21 | } 22 | message User{ 23 | int64 user_id = 1; 24 | } 25 | 26 | message UserList{ 27 | repeated User userList=1; 28 | } 29 | 30 | -------------------------------------------------------------------------------- /reflect/gen/user/user.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. DO NOT EDIT. 2 | // versions: 3 | // protoc-gen-go v1.27.1 4 | // protoc v3.5.1 5 | // source: reflect/gen/user.proto 6 | 7 | package user 8 | 9 | import ( 10 | protoreflect "google.golang.org/protobuf/reflect/protoreflect" 11 | protoimpl "google.golang.org/protobuf/runtime/protoimpl" 12 | reflect "reflect" 13 | sync "sync" 14 | ) 15 | 16 | const ( 17 | // Verify that this generated code is sufficiently up-to-date. 18 | _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) 19 | // Verify that runtime/protoimpl is sufficiently up-to-date. 20 | _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) 21 | ) 22 | 23 | type Empty struct { 24 | state protoimpl.MessageState 25 | sizeCache protoimpl.SizeCache 26 | unknownFields protoimpl.UnknownFields 27 | } 28 | 29 | func (x *Empty) Reset() { 30 | *x = Empty{} 31 | if protoimpl.UnsafeEnabled { 32 | mi := &file_reflect_gen_user_proto_msgTypes[0] 33 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 34 | ms.StoreMessageInfo(mi) 35 | } 36 | } 37 | 38 | func (x *Empty) String() string { 39 | return protoimpl.X.MessageStringOf(x) 40 | } 41 | 42 | func (*Empty) ProtoMessage() {} 43 | 44 | func (x *Empty) ProtoReflect() protoreflect.Message { 45 | mi := &file_reflect_gen_user_proto_msgTypes[0] 46 | if protoimpl.UnsafeEnabled && x != nil { 47 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 48 | if ms.LoadMessageInfo() == nil { 49 | ms.StoreMessageInfo(mi) 50 | } 51 | return ms 52 | } 53 | return mi.MessageOf(x) 54 | } 55 | 56 | // Deprecated: Use Empty.ProtoReflect.Descriptor instead. 57 | func (*Empty) Descriptor() ([]byte, []int) { 58 | return file_reflect_gen_user_proto_rawDescGZIP(), []int{0} 59 | } 60 | 61 | type UserApiCreate struct { 62 | state protoimpl.MessageState 63 | sizeCache protoimpl.SizeCache 64 | unknownFields protoimpl.UnknownFields 65 | 66 | UserId int64 `protobuf:"varint,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` 67 | } 68 | 69 | func (x *UserApiCreate) Reset() { 70 | *x = UserApiCreate{} 71 | if protoimpl.UnsafeEnabled { 72 | mi := &file_reflect_gen_user_proto_msgTypes[1] 73 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 74 | ms.StoreMessageInfo(mi) 75 | } 76 | } 77 | 78 | func (x *UserApiCreate) String() string { 79 | return protoimpl.X.MessageStringOf(x) 80 | } 81 | 82 | func (*UserApiCreate) ProtoMessage() {} 83 | 84 | func (x *UserApiCreate) ProtoReflect() protoreflect.Message { 85 | mi := &file_reflect_gen_user_proto_msgTypes[1] 86 | if protoimpl.UnsafeEnabled && x != nil { 87 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 88 | if ms.LoadMessageInfo() == nil { 89 | ms.StoreMessageInfo(mi) 90 | } 91 | return ms 92 | } 93 | return mi.MessageOf(x) 94 | } 95 | 96 | // Deprecated: Use UserApiCreate.ProtoReflect.Descriptor instead. 97 | func (*UserApiCreate) Descriptor() ([]byte, []int) { 98 | return file_reflect_gen_user_proto_rawDescGZIP(), []int{1} 99 | } 100 | 101 | func (x *UserApiCreate) GetUserId() int64 { 102 | if x != nil { 103 | return x.UserId 104 | } 105 | return 0 106 | } 107 | 108 | type User struct { 109 | state protoimpl.MessageState 110 | sizeCache protoimpl.SizeCache 111 | unknownFields protoimpl.UnknownFields 112 | 113 | UserId int64 `protobuf:"varint,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` 114 | } 115 | 116 | func (x *User) Reset() { 117 | *x = User{} 118 | if protoimpl.UnsafeEnabled { 119 | mi := &file_reflect_gen_user_proto_msgTypes[2] 120 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 121 | ms.StoreMessageInfo(mi) 122 | } 123 | } 124 | 125 | func (x *User) String() string { 126 | return protoimpl.X.MessageStringOf(x) 127 | } 128 | 129 | func (*User) ProtoMessage() {} 130 | 131 | func (x *User) ProtoReflect() protoreflect.Message { 132 | mi := &file_reflect_gen_user_proto_msgTypes[2] 133 | if protoimpl.UnsafeEnabled && x != nil { 134 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 135 | if ms.LoadMessageInfo() == nil { 136 | ms.StoreMessageInfo(mi) 137 | } 138 | return ms 139 | } 140 | return mi.MessageOf(x) 141 | } 142 | 143 | // Deprecated: Use User.ProtoReflect.Descriptor instead. 144 | func (*User) Descriptor() ([]byte, []int) { 145 | return file_reflect_gen_user_proto_rawDescGZIP(), []int{2} 146 | } 147 | 148 | func (x *User) GetUserId() int64 { 149 | if x != nil { 150 | return x.UserId 151 | } 152 | return 0 153 | } 154 | 155 | type UserList struct { 156 | state protoimpl.MessageState 157 | sizeCache protoimpl.SizeCache 158 | unknownFields protoimpl.UnknownFields 159 | 160 | UserList []*User `protobuf:"bytes,1,rep,name=userList,proto3" json:"userList,omitempty"` 161 | } 162 | 163 | func (x *UserList) Reset() { 164 | *x = UserList{} 165 | if protoimpl.UnsafeEnabled { 166 | mi := &file_reflect_gen_user_proto_msgTypes[3] 167 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 168 | ms.StoreMessageInfo(mi) 169 | } 170 | } 171 | 172 | func (x *UserList) String() string { 173 | return protoimpl.X.MessageStringOf(x) 174 | } 175 | 176 | func (*UserList) ProtoMessage() {} 177 | 178 | func (x *UserList) ProtoReflect() protoreflect.Message { 179 | mi := &file_reflect_gen_user_proto_msgTypes[3] 180 | if protoimpl.UnsafeEnabled && x != nil { 181 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 182 | if ms.LoadMessageInfo() == nil { 183 | ms.StoreMessageInfo(mi) 184 | } 185 | return ms 186 | } 187 | return mi.MessageOf(x) 188 | } 189 | 190 | // Deprecated: Use UserList.ProtoReflect.Descriptor instead. 191 | func (*UserList) Descriptor() ([]byte, []int) { 192 | return file_reflect_gen_user_proto_rawDescGZIP(), []int{3} 193 | } 194 | 195 | func (x *UserList) GetUserList() []*User { 196 | if x != nil { 197 | return x.UserList 198 | } 199 | return nil 200 | } 201 | 202 | var File_reflect_gen_user_proto protoreflect.FileDescriptor 203 | 204 | var file_reflect_gen_user_proto_rawDesc = []byte{ 205 | 0x0a, 0x16, 0x72, 0x65, 0x66, 0x6c, 0x65, 0x63, 0x74, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x75, 0x73, 206 | 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x07, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 207 | 0x32, 0x22, 0x07, 0x0a, 0x05, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x28, 0x0a, 0x0d, 0x55, 0x73, 208 | 0x65, 0x72, 0x41, 0x70, 0x69, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x75, 209 | 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x75, 0x73, 210 | 0x65, 0x72, 0x49, 0x64, 0x22, 0x1f, 0x0a, 0x04, 0x55, 0x73, 0x65, 0x72, 0x12, 0x17, 0x0a, 0x07, 211 | 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x75, 212 | 0x73, 0x65, 0x72, 0x49, 0x64, 0x22, 0x35, 0x0a, 0x08, 0x55, 0x73, 0x65, 0x72, 0x4c, 0x69, 0x73, 213 | 0x74, 0x12, 0x29, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x4c, 0x69, 0x73, 0x74, 0x18, 0x01, 0x20, 214 | 0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x32, 0x2e, 0x55, 0x73, 215 | 0x65, 0x72, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x4c, 0x69, 0x73, 0x74, 0x32, 0x6d, 0x0a, 0x0b, 216 | 0x55, 0x73, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x31, 0x0a, 0x06, 0x43, 217 | 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, 0x16, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x32, 0x2e, 218 | 0x55, 0x73, 0x65, 0x72, 0x41, 0x70, 0x69, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x1a, 0x0d, 0x2e, 219 | 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x32, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x22, 0x00, 0x12, 0x2b, 220 | 0x0a, 0x04, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x0e, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x32, 221 | 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x11, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x32, 222 | 0x2e, 0x55, 0x73, 0x65, 0x72, 0x4c, 0x69, 0x73, 0x74, 0x22, 0x00, 0x42, 0x2b, 0x5a, 0x29, 0x67, 223 | 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x72, 0x6f, 0x73, 0x73, 0x6f, 224 | 0x76, 0x65, 0x72, 0x4a, 0x69, 0x65, 0x2f, 0x70, 0x74, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 225 | 0x2f, 0x75, 0x73, 0x65, 0x72, 0x2f, 0x76, 0x32, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 226 | } 227 | 228 | var ( 229 | file_reflect_gen_user_proto_rawDescOnce sync.Once 230 | file_reflect_gen_user_proto_rawDescData = file_reflect_gen_user_proto_rawDesc 231 | ) 232 | 233 | func file_reflect_gen_user_proto_rawDescGZIP() []byte { 234 | file_reflect_gen_user_proto_rawDescOnce.Do(func() { 235 | file_reflect_gen_user_proto_rawDescData = protoimpl.X.CompressGZIP(file_reflect_gen_user_proto_rawDescData) 236 | }) 237 | return file_reflect_gen_user_proto_rawDescData 238 | } 239 | 240 | var file_reflect_gen_user_proto_msgTypes = make([]protoimpl.MessageInfo, 4) 241 | var file_reflect_gen_user_proto_goTypes = []interface{}{ 242 | (*Empty)(nil), // 0: user.v2.Empty 243 | (*UserApiCreate)(nil), // 1: user.v2.UserApiCreate 244 | (*User)(nil), // 2: user.v2.User 245 | (*UserList)(nil), // 3: user.v2.UserList 246 | } 247 | var file_reflect_gen_user_proto_depIdxs = []int32{ 248 | 2, // 0: user.v2.UserList.userList:type_name -> user.v2.User 249 | 1, // 1: user.v2.UserService.Create:input_type -> user.v2.UserApiCreate 250 | 0, // 2: user.v2.UserService.List:input_type -> user.v2.Empty 251 | 2, // 3: user.v2.UserService.Create:output_type -> user.v2.User 252 | 3, // 4: user.v2.UserService.List:output_type -> user.v2.UserList 253 | 3, // [3:5] is the sub-list for method output_type 254 | 1, // [1:3] is the sub-list for method input_type 255 | 1, // [1:1] is the sub-list for extension type_name 256 | 1, // [1:1] is the sub-list for extension extendee 257 | 0, // [0:1] is the sub-list for field type_name 258 | } 259 | 260 | func init() { file_reflect_gen_user_proto_init() } 261 | func file_reflect_gen_user_proto_init() { 262 | if File_reflect_gen_user_proto != nil { 263 | return 264 | } 265 | if !protoimpl.UnsafeEnabled { 266 | file_reflect_gen_user_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { 267 | switch v := v.(*Empty); i { 268 | case 0: 269 | return &v.state 270 | case 1: 271 | return &v.sizeCache 272 | case 2: 273 | return &v.unknownFields 274 | default: 275 | return nil 276 | } 277 | } 278 | file_reflect_gen_user_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { 279 | switch v := v.(*UserApiCreate); i { 280 | case 0: 281 | return &v.state 282 | case 1: 283 | return &v.sizeCache 284 | case 2: 285 | return &v.unknownFields 286 | default: 287 | return nil 288 | } 289 | } 290 | file_reflect_gen_user_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { 291 | switch v := v.(*User); i { 292 | case 0: 293 | return &v.state 294 | case 1: 295 | return &v.sizeCache 296 | case 2: 297 | return &v.unknownFields 298 | default: 299 | return nil 300 | } 301 | } 302 | file_reflect_gen_user_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { 303 | switch v := v.(*UserList); i { 304 | case 0: 305 | return &v.state 306 | case 1: 307 | return &v.sizeCache 308 | case 2: 309 | return &v.unknownFields 310 | default: 311 | return nil 312 | } 313 | } 314 | } 315 | type x struct{} 316 | out := protoimpl.TypeBuilder{ 317 | File: protoimpl.DescBuilder{ 318 | GoPackagePath: reflect.TypeOf(x{}).PkgPath(), 319 | RawDescriptor: file_reflect_gen_user_proto_rawDesc, 320 | NumEnums: 0, 321 | NumMessages: 4, 322 | NumExtensions: 0, 323 | NumServices: 1, 324 | }, 325 | GoTypes: file_reflect_gen_user_proto_goTypes, 326 | DependencyIndexes: file_reflect_gen_user_proto_depIdxs, 327 | MessageInfos: file_reflect_gen_user_proto_msgTypes, 328 | }.Build() 329 | File_reflect_gen_user_proto = out.File 330 | file_reflect_gen_user_proto_rawDesc = nil 331 | file_reflect_gen_user_proto_goTypes = nil 332 | file_reflect_gen_user_proto_depIdxs = nil 333 | } 334 | -------------------------------------------------------------------------------- /reflect/gen/user/user_grpc.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go-grpc. DO NOT EDIT. 2 | 3 | package user 4 | 5 | import ( 6 | context "context" 7 | grpc "google.golang.org/grpc" 8 | codes "google.golang.org/grpc/codes" 9 | status "google.golang.org/grpc/status" 10 | ) 11 | 12 | // This is a compile-time assertion to ensure that this generated file 13 | // is compatible with the grpc package it is being compiled against. 14 | // Requires gRPC-Go v1.32.0 or later. 15 | const _ = grpc.SupportPackageIsVersion7 16 | 17 | // UserServiceClient is the client API for UserService service. 18 | // 19 | // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. 20 | type UserServiceClient interface { 21 | Create(ctx context.Context, in *UserApiCreate, opts ...grpc.CallOption) (*User, error) 22 | List(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*UserList, error) 23 | } 24 | 25 | type userServiceClient struct { 26 | cc grpc.ClientConnInterface 27 | } 28 | 29 | func NewUserServiceClient(cc grpc.ClientConnInterface) UserServiceClient { 30 | return &userServiceClient{cc} 31 | } 32 | 33 | func (c *userServiceClient) Create(ctx context.Context, in *UserApiCreate, opts ...grpc.CallOption) (*User, error) { 34 | out := new(User) 35 | err := c.cc.Invoke(ctx, "/user.v2.UserService/Create", in, out, opts...) 36 | if err != nil { 37 | return nil, err 38 | } 39 | return out, nil 40 | } 41 | 42 | func (c *userServiceClient) List(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*UserList, error) { 43 | out := new(UserList) 44 | err := c.cc.Invoke(ctx, "/user.v2.UserService/List", in, out, opts...) 45 | if err != nil { 46 | return nil, err 47 | } 48 | return out, nil 49 | } 50 | 51 | // UserServiceServer is the server API for UserService service. 52 | // All implementations must embed UnimplementedUserServiceServer 53 | // for forward compatibility 54 | type UserServiceServer interface { 55 | Create(context.Context, *UserApiCreate) (*User, error) 56 | List(context.Context, *Empty) (*UserList, error) 57 | mustEmbedUnimplementedUserServiceServer() 58 | } 59 | 60 | // UnimplementedUserServiceServer must be embedded to have forward compatible implementations. 61 | type UnimplementedUserServiceServer struct { 62 | } 63 | 64 | func (UnimplementedUserServiceServer) Create(context.Context, *UserApiCreate) (*User, error) { 65 | return nil, status.Errorf(codes.Unimplemented, "method Create not implemented") 66 | } 67 | func (UnimplementedUserServiceServer) List(context.Context, *Empty) (*UserList, error) { 68 | return nil, status.Errorf(codes.Unimplemented, "method List not implemented") 69 | } 70 | func (UnimplementedUserServiceServer) mustEmbedUnimplementedUserServiceServer() {} 71 | 72 | // UnsafeUserServiceServer may be embedded to opt out of forward compatibility for this service. 73 | // Use of this interface is not recommended, as added methods to UserServiceServer will 74 | // result in compilation errors. 75 | type UnsafeUserServiceServer interface { 76 | mustEmbedUnimplementedUserServiceServer() 77 | } 78 | 79 | func RegisterUserServiceServer(s grpc.ServiceRegistrar, srv UserServiceServer) { 80 | s.RegisterService(&UserService_ServiceDesc, srv) 81 | } 82 | 83 | func _UserService_Create_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { 84 | in := new(UserApiCreate) 85 | if err := dec(in); err != nil { 86 | return nil, err 87 | } 88 | if interceptor == nil { 89 | return srv.(UserServiceServer).Create(ctx, in) 90 | } 91 | info := &grpc.UnaryServerInfo{ 92 | Server: srv, 93 | FullMethod: "/user.v2.UserService/Create", 94 | } 95 | handler := func(ctx context.Context, req interface{}) (interface{}, error) { 96 | return srv.(UserServiceServer).Create(ctx, req.(*UserApiCreate)) 97 | } 98 | return interceptor(ctx, in, info, handler) 99 | } 100 | 101 | func _UserService_List_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { 102 | in := new(Empty) 103 | if err := dec(in); err != nil { 104 | return nil, err 105 | } 106 | if interceptor == nil { 107 | return srv.(UserServiceServer).List(ctx, in) 108 | } 109 | info := &grpc.UnaryServerInfo{ 110 | Server: srv, 111 | FullMethod: "/user.v2.UserService/List", 112 | } 113 | handler := func(ctx context.Context, req interface{}) (interface{}, error) { 114 | return srv.(UserServiceServer).List(ctx, req.(*Empty)) 115 | } 116 | return interceptor(ctx, in, info, handler) 117 | } 118 | 119 | // UserService_ServiceDesc is the grpc.ServiceDesc for UserService service. 120 | // It's only intended for direct use with grpc.RegisterService, 121 | // and not to be introspected or modified (even as a copy) 122 | var UserService_ServiceDesc = grpc.ServiceDesc{ 123 | ServiceName: "user.v2.UserService", 124 | HandlerType: (*UserServiceServer)(nil), 125 | Methods: []grpc.MethodDesc{ 126 | { 127 | MethodName: "Create", 128 | Handler: _UserService_Create_Handler, 129 | }, 130 | { 131 | MethodName: "List", 132 | Handler: _UserService_List_Handler, 133 | }, 134 | }, 135 | Streams: []grpc.StreamDesc{}, 136 | Metadata: "reflect/gen/user.proto", 137 | } 138 | -------------------------------------------------------------------------------- /reflect/reflect.go: -------------------------------------------------------------------------------- 1 | package reflect 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "fmt" 7 | "github.com/golang/protobuf/jsonpb" 8 | "github.com/golang/protobuf/proto" 9 | "github.com/golang/protobuf/protoc-gen-go/descriptor" 10 | "github.com/jhump/protoreflect/desc" 11 | "github.com/jhump/protoreflect/desc/protoparse" 12 | "github.com/jhump/protoreflect/dynamic" 13 | "github.com/jhump/protoreflect/dynamic/grpcdynamic" 14 | "github.com/pkg/errors" 15 | "google.golang.org/grpc" 16 | "strings" 17 | ) 18 | 19 | type ParseReflect struct { 20 | filename string 21 | // serviceInfoMap[sds.GetFullyQualifiedName()] = methodInfos 22 | serviceInfoMap map[string][]string 23 | fds *desc.FileDescriptor 24 | } 25 | 26 | func NewParse(filename string) (*ParseReflect, error) { 27 | p := &ParseReflect{filename: filename} 28 | err := p.parseProto() 29 | return p, err 30 | } 31 | 32 | // Init: parse proto 33 | func (p *ParseReflect) parseProto() error { 34 | var parser protoparse.Parser 35 | fds, err := parser.ParseFiles(p.filename) 36 | if err != nil { 37 | return errors.WithStack(err) 38 | } 39 | p.fds = fds[0] 40 | 41 | serviceInfoMap := make(map[string][]string) 42 | for _, sds := range fds[0].GetServices() { 43 | 44 | var methodInfos []string 45 | for _, mds := range sds.GetMethods() { 46 | methodInfos = append(methodInfos, mds.GetName()) 47 | } 48 | 49 | serviceInfoMap[sds.GetFullyQualifiedName()] = methodInfos 50 | 51 | } 52 | p.serviceInfoMap = serviceInfoMap 53 | return nil 54 | } 55 | 56 | func (p *ParseReflect) ServiceInfoMaps() map[string][]string { 57 | return p.serviceInfoMap 58 | } 59 | 60 | func (p *ParseReflect) RequestJSON(serviceName, methodName string) (string, error) { 61 | _, ok := p.serviceInfoMap[serviceName] 62 | if !ok { 63 | return "", errors.New("service not found!") 64 | } 65 | 66 | sds := p.fds.FindService(serviceName) 67 | mds := sds.FindMethodByName(methodName) 68 | messageToMap := convertMessageToMap(mds.GetInputType()) 69 | marshalIndent, err := json.MarshalIndent(messageToMap, "", "\t") 70 | return string(marshalIndent), err 71 | } 72 | 73 | // Get Method desc 74 | func (p *ParseReflect) MethodDescriptor(serviceName, methodName string) (*desc.MethodDescriptor, error) { 75 | _, ok := p.serviceInfoMap[serviceName] 76 | if !ok { 77 | return nil, errors.New("service not found!") 78 | } 79 | sds := p.fds.FindService(serviceName) 80 | return sds.FindMethodByName(methodName), nil 81 | } 82 | 83 | // make unary RPC 84 | func (p *ParseReflect) InvokeRpc(ctx context.Context, stub grpcdynamic.Stub, mds *desc.MethodDescriptor, data string, opts ...grpc.CallOption) (proto.Message, error) { 85 | 86 | messages, err := CreatePayloadsFromJSON(mds, data) 87 | if err != nil { 88 | return nil, err 89 | } 90 | return stub.InvokeRpc(ctx, mds, messages[0], opts...) 91 | } 92 | 93 | // make unary server stream RPC 94 | func (p *ParseReflect) InvokeServerStreamRpc(ctx context.Context, stub grpcdynamic.Stub, mds *desc.MethodDescriptor, data string, opts ...grpc.CallOption) (*grpcdynamic.ServerStream, error) { 95 | 96 | messages, err := CreatePayloadsFromJSON(mds, data) 97 | if err != nil { 98 | return nil, err 99 | } 100 | return stub.InvokeRpcServerStream(ctx, mds, messages[0], opts...) 101 | } 102 | 103 | // make unary client stream RPC 104 | func (p *ParseReflect) InvokeClientStreamRpc(ctx context.Context, stub grpcdynamic.Stub, mds *desc.MethodDescriptor, opts ...grpc.CallOption) (*grpcdynamic.ClientStream, error) { 105 | return stub.InvokeRpcClientStream(ctx, mds, opts...) 106 | } 107 | 108 | // make unary bidi stream RPC 109 | func (p *ParseReflect) InvokeBidiStreamRpc(ctx context.Context, stub grpcdynamic.Stub, mds *desc.MethodDescriptor, opts ...grpc.CallOption) (*grpcdynamic.BidiStream, error) { 110 | return stub.InvokeRpcBidiStream(ctx, mds, opts...) 111 | } 112 | 113 | func convertMessageToMap(message *desc.MessageDescriptor) map[string]interface{} { 114 | m := make(map[string]interface{}) 115 | for _, fieldDescriptor := range message.GetFields() { 116 | fieldName := fieldDescriptor.GetName() 117 | if fieldDescriptor.IsRepeated() { 118 | // Array temporary nil 119 | m[fieldName] = nil 120 | continue 121 | } 122 | switch fieldDescriptor.GetType() { 123 | case descriptor.FieldDescriptorProto_TYPE_MESSAGE: 124 | m[fieldName] = convertMessageToMap(fieldDescriptor.GetMessageType()) 125 | continue 126 | } 127 | m[fieldName] = fieldDescriptor.GetDefaultValue() 128 | } 129 | return m 130 | } 131 | 132 | func ParseServiceMethod(svcAndMethod string) (string, string, error) { 133 | if len(svcAndMethod) == 0 { 134 | return "", "", errors.New("service not found!") 135 | } 136 | if svcAndMethod[0] == '.' { 137 | svcAndMethod = svcAndMethod[1:] 138 | } 139 | if len(svcAndMethod) == 0 { 140 | return "", "", errors.New("service not found!") 141 | } 142 | switch strings.Count(svcAndMethod, "/") { 143 | case 0: 144 | pos := strings.LastIndex(svcAndMethod, ".") 145 | if pos < 0 { 146 | return "", "", errors.New("service not found!") 147 | } 148 | return svcAndMethod[:pos], svcAndMethod[pos+1:], nil 149 | case 1: 150 | split := strings.Split(svcAndMethod, "/") 151 | return split[0], split[1], nil 152 | default: 153 | return "", "", errors.New("service not found!") 154 | } 155 | } 156 | 157 | func CreatePayloadsFromJSON(mds *desc.MethodDescriptor, data string) ([]*dynamic.Message, error) { 158 | md := mds.GetInputType() 159 | var inputs []*dynamic.Message 160 | 161 | if len(data) > 0 { 162 | inputs = make([]*dynamic.Message, 1) 163 | inputs[0] = dynamic.NewMessage(md) 164 | err := jsonpb.UnmarshalString(data, inputs[0]) 165 | if err != nil { 166 | return nil, errors.New(fmt.Sprintf("create payload json err %v \n", err)) 167 | } 168 | } 169 | 170 | return inputs, nil 171 | } 172 | -------------------------------------------------------------------------------- /reflect/reflect_test.go: -------------------------------------------------------------------------------- 1 | package reflect 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "fmt" 7 | v1 "github.com/crossoverJie/ptg/reflect/gen" 8 | "github.com/crossoverJie/ptg/reflect/gen/user" 9 | "github.com/golang/protobuf/proto" 10 | "github.com/jhump/protoreflect/dynamic/grpcdynamic" 11 | "google.golang.org/grpc" 12 | "google.golang.org/grpc/codes" 13 | "google.golang.org/grpc/metadata" 14 | "google.golang.org/grpc/status" 15 | "io" 16 | "log" 17 | "net" 18 | "strings" 19 | "testing" 20 | "time" 21 | ) 22 | 23 | func TestParseProto(t *testing.T) { 24 | filename := "gen/test.proto" 25 | parse, err := NewParse(filename) 26 | if err != nil { 27 | panic(err) 28 | } 29 | maps := parse.ServiceInfoMaps() 30 | fmt.Println(maps) 31 | } 32 | 33 | func TestRequestJSON(t *testing.T) { 34 | filename := "gen/test.proto" 35 | parse, err := NewParse(filename) 36 | if err != nil { 37 | panic(err) 38 | } 39 | json, err := parse.RequestJSON("order.v1.OrderService", "Create") 40 | if err != nil { 41 | panic(err) 42 | } 43 | fmt.Println(json) 44 | } 45 | 46 | func TestParseReflect_InvokeRpc(t *testing.T) { 47 | data := `{"order_id":20,"user_id":[20],"remark":"Hello","reason_id":[10]}` 48 | metaStr := `{"lang":"zh"}` 49 | var m map[string]string 50 | err := json.Unmarshal([]byte(metaStr), &m) 51 | if err != nil { 52 | panic(err) 53 | } 54 | filename := "gen/test.proto" 55 | parse, err := NewParse(filename) 56 | if err != nil { 57 | panic(err) 58 | } 59 | 60 | mds, err := parse.MethodDescriptor("order.v1.OrderService", "Create") 61 | if err != nil { 62 | panic(err) 63 | } 64 | var opts []grpc.DialOption 65 | opts = append(opts, grpc.WithInsecure()) 66 | conn, err := grpc.DialContext(context.Background(), "127.0.0.1:6001", opts...) 67 | stub := grpcdynamic.NewStub(conn) 68 | 69 | // metadata 70 | // create a new context with some metadata 71 | //md := metadata.Pairs("name", "v1", "k1", "v2", "k2", "v3") 72 | md := metadata.New(m) 73 | ctx := metadata.NewOutgoingContext(context.Background(), md) 74 | rpc, err := parse.InvokeRpc(ctx, stub, mds, data) 75 | if err != nil { 76 | panic(err) 77 | } 78 | fmt.Println(rpc.String()) 79 | fmt.Println("=========") 80 | //marshal ,_:= proto.Marshal(rpc) 81 | marshalIndent, _ := json.MarshalIndent(rpc, "", "\t") 82 | fmt.Println(string(marshalIndent)) 83 | } 84 | func TestParseReflect_InvokeServerStreamRpc(t *testing.T) { 85 | data := `{"order_id":20,"user_id":[20],"remark":"Hello","reason_id":[10]}` 86 | metaStr := `{"lang":"zh"}` 87 | var m map[string]string 88 | err := json.Unmarshal([]byte(metaStr), &m) 89 | if err != nil { 90 | panic(err) 91 | } 92 | filename := "gen/test.proto" 93 | parse, err := NewParse(filename) 94 | if err != nil { 95 | panic(err) 96 | } 97 | 98 | mds, err := parse.MethodDescriptor("order.v1.OrderService", "ServerStream") 99 | if err != nil { 100 | panic(err) 101 | } 102 | var opts []grpc.DialOption 103 | opts = append(opts, grpc.WithInsecure()) 104 | conn, err := grpc.DialContext(context.Background(), "127.0.0.1:6001", opts...) 105 | stub := grpcdynamic.NewStub(conn) 106 | 107 | md := metadata.New(m) 108 | ctx := metadata.NewOutgoingContext(context.Background(), md) 109 | rpc, err := parse.InvokeServerStreamRpc(ctx, stub, mds, data) 110 | if err != nil { 111 | panic(err) 112 | } 113 | var msgs []proto.Message 114 | for { 115 | msg, err := rpc.RecvMsg() 116 | if err == io.EOF { 117 | marshalIndent, _ := json.MarshalIndent(msgs, "", "\t") 118 | fmt.Println(string(marshalIndent)) 119 | return 120 | } 121 | if err != nil { 122 | panic(err) 123 | } 124 | msgs = append(msgs, msg) 125 | } 126 | fmt.Println("=========") 127 | 128 | } 129 | func TestParseReflect_InvokeClientStreamRpc(t *testing.T) { 130 | data := `{"order_id":20,"user_id":[20],"remark":"Hello","reason_id":[10]}` 131 | metaStr := `{"lang":"zh"}` 132 | var m map[string]string 133 | err := json.Unmarshal([]byte(metaStr), &m) 134 | if err != nil { 135 | panic(err) 136 | } 137 | filename := "gen/test.proto" 138 | parse, err := NewParse(filename) 139 | if err != nil { 140 | panic(err) 141 | } 142 | 143 | mds, err := parse.MethodDescriptor("order.v1.OrderService", "ClientStream") 144 | if err != nil { 145 | panic(err) 146 | } 147 | var opts []grpc.DialOption 148 | opts = append(opts, grpc.WithInsecure()) 149 | conn, err := grpc.DialContext(context.Background(), "127.0.0.1:6001", opts...) 150 | stub := grpcdynamic.NewStub(conn) 151 | 152 | md := metadata.New(m) 153 | ctx := metadata.NewOutgoingContext(context.Background(), md) 154 | rpc, err := parse.InvokeClientStreamRpc(ctx, stub, mds) 155 | for i := 0; i < 5; i++ { 156 | if err != nil { 157 | panic(err) 158 | } 159 | time.Sleep(1 * time.Second) 160 | messages, _ := CreatePayloadsFromJSON(mds, data) 161 | rpc.SendMsg(messages[0]) 162 | } 163 | receive, err := rpc.CloseAndReceive() 164 | marshalIndent, _ := json.MarshalIndent(receive, "", "\t") 165 | fmt.Println(string(marshalIndent)) 166 | } 167 | func TestParseReflect_InvokeBidiStreamRpc(t *testing.T) { 168 | data := `{"order_id":20,"user_id":[20],"remark":"Hello","reason_id":[10]}` 169 | metaStr := `{"lang":"zh"}` 170 | var m map[string]string 171 | err := json.Unmarshal([]byte(metaStr), &m) 172 | if err != nil { 173 | panic(err) 174 | } 175 | filename := "gen/test.proto" 176 | parse, err := NewParse(filename) 177 | if err != nil { 178 | panic(err) 179 | } 180 | 181 | mds, err := parse.MethodDescriptor("order.v1.OrderService", "BdStream") 182 | if err != nil { 183 | panic(err) 184 | } 185 | var opts []grpc.DialOption 186 | opts = append(opts, grpc.WithInsecure()) 187 | conn, err := grpc.DialContext(context.Background(), "127.0.0.1:6001", opts...) 188 | stub := grpcdynamic.NewStub(conn) 189 | 190 | md := metadata.New(m) 191 | ctx := metadata.NewOutgoingContext(context.Background(), md) 192 | rpc, err := parse.InvokeBidiStreamRpc(ctx, stub, mds) 193 | for i := 0; i < 5; i++ { 194 | if err != nil { 195 | panic(err) 196 | } 197 | time.Sleep(1 * time.Second) 198 | messages, _ := CreatePayloadsFromJSON(mds, data) 199 | rpc.SendMsg(messages[0]) 200 | 201 | receive, _ := rpc.RecvMsg() 202 | marshalIndent, _ := json.MarshalIndent(receive, "", "\t") 203 | fmt.Println(string(marshalIndent)) 204 | } 205 | rpc.CloseSend() 206 | 207 | } 208 | 209 | func TestServer(t *testing.T) { 210 | port := 6001 211 | lis, err := net.Listen("tcp", fmt.Sprintf("localhost:%d", port)) 212 | if err != nil { 213 | log.Fatalf("failed to listen: %v", err) 214 | } 215 | var opts []grpc.ServerOption 216 | grpcServer := grpc.NewServer(opts...) 217 | v1.RegisterOrderServiceServer(grpcServer, &Order{}) 218 | //reflection.Register(grpcServer) 219 | 220 | fmt.Println("gRPC server started at ", port) 221 | if err := grpcServer.Serve(lis); err != nil { 222 | panic(err) 223 | } 224 | } 225 | 226 | type Order struct { 227 | v1.UnimplementedOrderServiceServer 228 | } 229 | 230 | func (o *Order) Create(ctx context.Context, in *v1.OrderApiCreate) (*v1.Order, error) { 231 | md, ok := metadata.FromIncomingContext(ctx) 232 | if !ok { 233 | return nil, status.Errorf(codes.DataLoss, "failed to get metadata") 234 | } 235 | fmt.Println(md) 236 | 237 | time.Sleep(200 * time.Millisecond) 238 | fmt.Println(in.OrderId) 239 | return &v1.Order{ 240 | OrderId: in.OrderId, 241 | Common: &v1.Common{Header: "header"}, 242 | Reason: []*v1.Reason{{ 243 | Id: 0, 244 | Remark: in.Remark, 245 | }}, 246 | }, nil 247 | } 248 | 249 | func (o *Order) Close(ctx context.Context, req *v1.CloseApiCreate) (*v1.Order, error) { 250 | log.Println(req) 251 | time.Sleep(200 * time.Millisecond) 252 | return &v1.Order{ 253 | OrderId: 1000, 254 | Reason: nil, 255 | }, nil 256 | } 257 | 258 | func (o *Order) ServerStream(in *v1.OrderApiCreate, rs v1.OrderService_ServerStreamServer) error { 259 | for i := 0; i < 5; i++ { 260 | time.Sleep(200 * time.Millisecond) 261 | rs.Send(&v1.Order{ 262 | OrderId: in.OrderId, 263 | Reason: nil, 264 | }) 265 | } 266 | return nil 267 | } 268 | 269 | func (o *Order) ClientStream(rs v1.OrderService_ClientStreamServer) error { 270 | var value []int64 271 | for { 272 | recv, err := rs.Recv() 273 | if err == io.EOF { 274 | rs.SendAndClose(&v1.Order{ 275 | OrderId: 100, 276 | Reason: nil, 277 | }) 278 | log.Println(value) 279 | return nil 280 | } 281 | if err != nil { 282 | return err 283 | } 284 | value = append(value, recv.OrderId) 285 | log.Printf("ClientStream receiv msg %v", recv.OrderId) 286 | } 287 | log.Println("ClientStream finish") 288 | 289 | return nil 290 | } 291 | func (o *Order) BdStream(rs v1.OrderService_BdStreamServer) error { 292 | var value []int64 293 | for { 294 | recv, err := rs.Recv() 295 | if err == io.EOF { 296 | log.Println(value) 297 | return nil 298 | } 299 | if err != nil { 300 | panic(err) 301 | } 302 | value = append(value, recv.OrderId) 303 | log.Printf("BdStream receiv msg %v", recv.OrderId) 304 | rs.SendMsg(&v1.Order{ 305 | OrderId: recv.OrderId, 306 | Reason: nil, 307 | }) 308 | } 309 | 310 | return nil 311 | } 312 | 313 | func TestParseServiceMethod(t *testing.T) { 314 | s, m, err := ParseServiceMethod("order.v1.OrderService.Create") 315 | fmt.Println(s, m, err) 316 | } 317 | 318 | func TestUserServer(t *testing.T) { 319 | port := 7001 320 | lis, err := net.Listen("tcp", fmt.Sprintf("localhost:%d", port)) 321 | if err != nil { 322 | log.Fatalf("failed to listen: %v", err) 323 | } 324 | var opts []grpc.ServerOption 325 | grpcServer := grpc.NewServer(opts...) 326 | user.RegisterUserServiceServer(grpcServer, &User{}) 327 | 328 | fmt.Println("gRPC user server started at ", port) 329 | if err := grpcServer.Serve(lis); err != nil { 330 | panic(err) 331 | } 332 | } 333 | 334 | type User struct { 335 | user.UnimplementedUserServiceServer 336 | } 337 | 338 | func (*User) Create(ctx context.Context, in *user.UserApiCreate) (*user.User, error) { 339 | time.Sleep(200 * time.Millisecond) 340 | return &user.User{UserId: in.UserId}, nil 341 | } 342 | 343 | func TestCommon(t *testing.T) { 344 | x := "order.v1.OrderService.Detail-2" 345 | fmt.Println(strings.Split(x, "-")[1]) 346 | } 347 | -------------------------------------------------------------------------------- /test.json: -------------------------------------------------------------------------------- 1 | {"order_id":6760383805128707} --------------------------------------------------------------------------------