go.uber.org/yarpc@v1.72.1/internal/prototest/example/example.go (about) 1 // Copyright (c) 2022 Uber Technologies, Inc. 2 // 3 // Permission is hereby granted, free of charge, to any person obtaining a copy 4 // of this software and associated documentation files (the "Software"), to deal 5 // in the Software without restriction, including without limitation the rights 6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 // copies of the Software, and to permit persons to whom the Software is 8 // furnished to do so, subject to the following conditions: 9 // 10 // The above copyright notice and this permission notice shall be included in 11 // all copies or substantial portions of the Software. 12 // 13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 // THE SOFTWARE. 20 21 package example 22 23 import ( 24 "context" 25 "io" 26 "sync" 27 "time" 28 29 "go.uber.org/yarpc" 30 "go.uber.org/yarpc/api/transport" 31 "go.uber.org/yarpc/internal/prototest/examplepb" 32 "go.uber.org/yarpc/yarpcerrors" 33 ) 34 35 const ( 36 // FireDoneTimeout is how long fireDone will wait for both sending and receiving. 37 FireDoneTimeout = 3 * time.Second 38 ) 39 40 var ( 41 errRequestNil = yarpcerrors.Newf(yarpcerrors.CodeInvalidArgument, "request nil") 42 errRequestKeyNil = yarpcerrors.Newf(yarpcerrors.CodeInvalidArgument, "request key nil") 43 errRequestMessageNil = yarpcerrors.Newf(yarpcerrors.CodeInvalidArgument, "request message nil") 44 errRequestNumResponsesNil = yarpcerrors.Newf(yarpcerrors.CodeInvalidArgument, "request num responses nil") 45 ) 46 47 // KeyValueYARPCServer implements examplepb.KeyValueYARPCServer. 48 type KeyValueYARPCServer struct { 49 sync.RWMutex 50 items map[string]string 51 // if next error is set it will be returned along with an empty response 52 // from any call to KeyValueYarpcServer, and then set to nil 53 nextError error 54 } 55 56 // NewKeyValueYARPCServer returns a new KeyValueYARPCServer. 57 func NewKeyValueYARPCServer() *KeyValueYARPCServer { 58 return &KeyValueYARPCServer{sync.RWMutex{}, make(map[string]string), nil} 59 } 60 61 // GetValue implements GetValue. 62 func (k *KeyValueYARPCServer) GetValue(ctx context.Context, request *examplepb.GetValueRequest) (*examplepb.GetValueResponse, error) { 63 if request == nil { 64 return nil, errRequestNil 65 } 66 if request.Key == "" { 67 return nil, errRequestKeyNil 68 } 69 k.RLock() 70 if value, ok := k.items[request.Key]; ok { 71 k.RUnlock() 72 var nextError error 73 k.Lock() 74 if k.nextError != nil { 75 nextError = k.nextError 76 k.nextError = nil 77 } 78 k.Unlock() 79 return &examplepb.GetValueResponse{Value: value}, nextError 80 } 81 k.RUnlock() 82 return nil, yarpcerrors.Newf(yarpcerrors.CodeNotFound, request.Key) 83 } 84 85 // SetValue implements SetValue. 86 func (k *KeyValueYARPCServer) SetValue(ctx context.Context, request *examplepb.SetValueRequest) (*examplepb.SetValueResponse, error) { 87 call := yarpc.CallFromContext(ctx) 88 if val := call.Header("test-header"); val != "" { 89 _ = call.WriteResponseHeader("test-header", val) 90 } 91 if request == nil { 92 return nil, errRequestNil 93 } 94 if request.Key == "" { 95 return nil, errRequestKeyNil 96 } 97 k.Lock() 98 if request.Value == "" { 99 delete(k.items, request.Key) 100 } else { 101 k.items[request.Key] = request.Value 102 } 103 var nextError error 104 if k.nextError != nil { 105 nextError = k.nextError 106 k.nextError = nil 107 } 108 k.Unlock() 109 return nil, nextError 110 } 111 112 // SetNextError sets the error to return on the next call to KeyValueYARPCServer. 113 func (k *KeyValueYARPCServer) SetNextError(err error) { 114 k.Lock() 115 defer k.Unlock() 116 k.nextError = err 117 } 118 119 // FooYARPCServer implements examplepb.FooYARPCServer. 120 type FooYARPCServer struct { 121 expectedHeaders transport.Headers 122 } 123 124 // NewFooYARPCServer returns a new FooYARPCServer. 125 func NewFooYARPCServer(expectedHeaders transport.Headers) *FooYARPCServer { 126 return &FooYARPCServer{ 127 expectedHeaders: expectedHeaders, 128 } 129 } 130 131 // EchoOut reads from a stream and echos all requests in the response. 132 func (f *FooYARPCServer) EchoOut(server examplepb.FooServiceEchoOutYARPCServer) (*examplepb.EchoOutResponse, error) { 133 var allMessages []string 134 call := yarpc.CallFromContext(server.Context()) 135 for k, v := range f.expectedHeaders.Items() { 136 if call.Header(k) != v { 137 return nil, yarpcerrors.InvalidArgumentErrorf("did not receive proper headers, missing %q:%q", k, v) 138 } 139 } 140 for request, err := server.Recv(); err != io.EOF; request, err = server.Recv() { 141 if err != nil { 142 return nil, err 143 } 144 if request == nil { 145 return nil, errRequestNil 146 } 147 if request.Message == "" { 148 return nil, errRequestMessageNil 149 } 150 allMessages = append(allMessages, request.Message) 151 } 152 return &examplepb.EchoOutResponse{ 153 AllMessages: allMessages, 154 }, nil 155 } 156 157 // EchoIn echos a series of requests back on a stream. 158 func (f *FooYARPCServer) EchoIn(request *examplepb.EchoInRequest, server examplepb.FooServiceEchoInYARPCServer) error { 159 if request == nil { 160 return errRequestNil 161 } 162 if request.Message == "" { 163 return errRequestMessageNil 164 } 165 if request.NumResponses == 0 { 166 return errRequestNumResponsesNil 167 } 168 call := yarpc.CallFromContext(server.Context()) 169 for k, v := range f.expectedHeaders.Items() { 170 if call.Header(k) != v { 171 return yarpcerrors.InvalidArgumentErrorf("did not receive proper headers, missing %q:%q", k, v) 172 } 173 } 174 for i := 0; i < int(request.NumResponses); i++ { 175 if err := server.Send(&examplepb.EchoInResponse{Message: request.Message}); err != nil { 176 return err 177 } 178 } 179 return nil 180 } 181 182 // EchoBoth immediately echos a request back to the client. 183 func (f *FooYARPCServer) EchoBoth(server examplepb.FooServiceEchoBothYARPCServer) error { 184 call := yarpc.CallFromContext(server.Context()) 185 for k, v := range f.expectedHeaders.Items() { 186 if call.Header(k) != v { 187 return yarpcerrors.InvalidArgumentErrorf("did not receive proper headers, missing %q:%q", k, v) 188 } 189 } 190 for request, err := server.Recv(); err != io.EOF; request, err = server.Recv() { 191 if err != nil { 192 return err 193 } 194 if request == nil { 195 return errRequestNil 196 } 197 if request.Message == "" { 198 return errRequestMessageNil 199 } 200 if request.NumResponses == 0 { 201 return errRequestNumResponsesNil 202 } 203 for i := 0; i < int(request.NumResponses); i++ { 204 if err := server.Send(&examplepb.EchoBothResponse{Message: request.Message}); err != nil { 205 return err 206 } 207 } 208 } 209 return nil 210 }