github.com/gravitational/teleport/api@v0.0.0-20240507183017-3110591cbafc/client/keepaliver.go (about) 1 /* 2 Copyright 2020 Gravitational, Inc. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package client 18 19 import ( 20 "context" 21 "sync" 22 23 "github.com/gravitational/trace" 24 "google.golang.org/protobuf/types/known/emptypb" 25 26 "github.com/gravitational/teleport/api/client/proto" 27 "github.com/gravitational/teleport/api/types" 28 ) 29 30 // NewKeepAliver returns a new instance of keep aliver. 31 // It is the caller's responsibility to invoke Close on the 32 // returned value to release the keepAliver resources. 33 func (c *Client) NewKeepAliver(ctx context.Context) (types.KeepAliver, error) { 34 cancelCtx, cancel := context.WithCancel(ctx) 35 stream, err := c.grpc.SendKeepAlives(cancelCtx) 36 if err != nil { 37 cancel() 38 return nil, trace.Wrap(err) 39 } 40 k := &streamKeepAliver{ 41 stream: stream, 42 ctx: cancelCtx, 43 cancel: cancel, 44 keepAlivesC: make(chan types.KeepAlive), 45 } 46 go k.forwardKeepAlives() 47 go k.recv() 48 return k, nil 49 } 50 51 type streamKeepAliver struct { 52 mu sync.RWMutex 53 stream proto.AuthService_SendKeepAlivesClient 54 ctx context.Context 55 cancel context.CancelFunc 56 keepAlivesC chan types.KeepAlive 57 err error 58 } 59 60 // KeepAlives returns the streamKeepAliver's channel of KeepAlives 61 func (k *streamKeepAliver) KeepAlives() chan<- types.KeepAlive { 62 return k.keepAlivesC 63 } 64 65 func (k *streamKeepAliver) forwardKeepAlives() { 66 for { 67 select { 68 case <-k.ctx.Done(): 69 return 70 case keepAlive := <-k.keepAlivesC: 71 err := k.stream.Send(&keepAlive) 72 if err != nil { 73 k.closeWithError(trace.Wrap(err)) 74 return 75 } 76 } 77 } 78 } 79 80 // Error returns the streamKeepAliver's error after closing 81 func (k *streamKeepAliver) Error() error { 82 k.mu.RLock() 83 defer k.mu.RUnlock() 84 return k.err 85 } 86 87 // Done returns a channel that closes once the streamKeepAliver is Closed 88 func (k *streamKeepAliver) Done() <-chan struct{} { 89 return k.ctx.Done() 90 } 91 92 // recv is necessary to receive errors from the 93 // server, otherwise no errors will be propagated 94 func (k *streamKeepAliver) recv() { 95 err := k.stream.RecvMsg(&emptypb.Empty{}) 96 k.closeWithError(trace.Wrap(err)) 97 } 98 99 func (k *streamKeepAliver) closeWithError(err error) { 100 k.mu.Lock() 101 defer k.mu.Unlock() 102 k.Close() 103 k.err = err 104 } 105 106 // Close the streamKeepAliver 107 func (k *streamKeepAliver) Close() error { 108 k.cancel() 109 return nil 110 }