github.com/Axway/agent-sdk@v1.1.101/pkg/agent/stream/client.go (about) 1 package stream 2 3 import ( 4 "fmt" 5 "net" 6 "net/url" 7 "strconv" 8 "sync" 9 10 "github.com/Axway/agent-sdk/pkg/agent/events" 11 "github.com/Axway/agent-sdk/pkg/harvester" 12 13 "github.com/Axway/agent-sdk/pkg/apic/auth" 14 "github.com/Axway/agent-sdk/pkg/util" 15 "github.com/Axway/agent-sdk/pkg/util/log" 16 17 "github.com/sirupsen/logrus" 18 19 agentcache "github.com/Axway/agent-sdk/pkg/agent/cache" 20 "github.com/Axway/agent-sdk/pkg/agent/handler" 21 22 management "github.com/Axway/agent-sdk/pkg/apic/apiserver/models/management/v1alpha1" 23 "github.com/Axway/agent-sdk/pkg/watchmanager/proto" 24 25 "github.com/Axway/agent-sdk/pkg/util/errors" 26 27 "github.com/Axway/agent-sdk/pkg/config" 28 hc "github.com/Axway/agent-sdk/pkg/util/healthcheck" 29 wm "github.com/Axway/agent-sdk/pkg/watchmanager" 30 ) 31 32 // StreamerClient client for starting a watch controller stream and handling the events 33 type StreamerClient struct { 34 apiClient events.APIClient 35 handlers []handler.Handler 36 listener *events.EventListener 37 manager wm.Manager 38 newListener events.NewListenerFunc 39 newManager wm.NewManagerFunc 40 onStreamConnection func() 41 sequence events.SequenceProvider 42 topicSelfLink string 43 watchCfg *wm.Config 44 watchOpts []wm.Option 45 cacheManager agentcache.Manager 46 logger log.FieldLogger 47 environmentURL string 48 wt *management.WatchTopic 49 harvester harvester.Harvest 50 onEventSyncError func() 51 mutex sync.RWMutex 52 isInitialized bool 53 } 54 55 // NewStreamerClient creates a StreamerClient 56 func NewStreamerClient( 57 apiClient events.APIClient, 58 cfg config.CentralConfig, 59 getToken auth.TokenGetter, 60 handlers []handler.Handler, 61 options ...StreamerOpt, 62 ) (*StreamerClient, error) { 63 logger := log.NewFieldLogger(). 64 WithPackage("sdk.agent.stream"). 65 WithComponent("Client") 66 67 tenant := cfg.GetTenantID() 68 host, port := getWatchServiceHostPort(cfg) 69 70 watchCfg := &wm.Config{ 71 Host: host, 72 Port: uint32(port), 73 TenantID: tenant, 74 TokenGetter: getToken.GetToken, 75 } 76 77 s := &StreamerClient{ 78 handlers: handlers, 79 apiClient: apiClient, 80 watchCfg: watchCfg, 81 newManager: wm.New, 82 newListener: events.NewEventListener, 83 logger: logger, 84 environmentURL: cfg.GetEnvironmentURL(), 85 } 86 87 for _, opt := range options { 88 opt(s) 89 } 90 91 s.watchOpts = []wm.Option{ 92 wm.WithLogger(logrus.NewEntry(log.Get())), 93 wm.WithHarvester(s.harvester, s.sequence), 94 wm.WithProxy(cfg.GetProxyURL()), 95 wm.WithEventSyncError(s.onEventSyncError), 96 } 97 98 if cfg.IsGRPCInsecure() { 99 s.watchOpts = append(s.watchOpts, wm.WithTLSConfig(nil)) 100 } else { 101 s.watchOpts = append(s.watchOpts, wm.WithTLSConfig(cfg.GetTLSConfig().BuildTLSConfig())) 102 } 103 104 if cfg.GetSingleURL() != "" { 105 singleEntryURL, err := url.Parse(cfg.GetSingleURL()) 106 if err == nil { 107 singleEntryAddr := util.ParseAddr(singleEntryURL) 108 s.watchOpts = append(s.watchOpts, wm.WithSingleEntryAddr(singleEntryAddr)) 109 } 110 } 111 112 return s, nil 113 } 114 115 func getWatchServiceHostPort(cfg config.CentralConfig) (string, int) { 116 u, _ := url.Parse(cfg.GetURL()) 117 host := cfg.GetGRPCHost() 118 port := cfg.GetGRPCPort() 119 if host == "" { 120 host = u.Host 121 } 122 123 if port == 0 { 124 if u.Port() == "" { 125 port, _ = net.LookupPort("tcp", u.Scheme) 126 } else { 127 port, _ = strconv.Atoi(u.Port()) 128 } 129 } 130 131 return host, port 132 } 133 134 // Start creates and starts everything needed for a stream connection to central. 135 func (s *StreamerClient) Start() error { 136 eventCh, eventErrorCh := make(chan *proto.Event), make(chan error) 137 138 s.mutex.Lock() 139 140 s.listener = s.newListener( 141 eventCh, 142 s.apiClient, 143 s.sequence, 144 s.handlers..., 145 ) 146 defer s.listener.Stop() 147 148 manager, err := s.newManager(s.watchCfg, s.watchOpts...) 149 if err != nil { 150 return err 151 } 152 153 s.manager = manager 154 s.isInitialized = false 155 156 s.mutex.Unlock() 157 158 listenCh := s.listener.Listen() 159 160 _, err = s.manager.RegisterWatch(s.topicSelfLink, eventCh, eventErrorCh) 161 if s.onStreamConnection != nil { 162 s.onStreamConnection() 163 } 164 165 s.mutex.Lock() 166 s.isInitialized = true 167 s.mutex.Unlock() 168 169 if err != nil { 170 return err 171 } 172 173 select { 174 case err := <-listenCh: 175 return err 176 case err := <-eventErrorCh: 177 return err 178 } 179 } 180 181 // Status returns the health status 182 func (s *StreamerClient) Status() error { 183 s.mutex.RLock() 184 defer s.mutex.RUnlock() 185 if !s.isInitialized { 186 return nil 187 } 188 189 if s.manager == nil || s.listener == nil { 190 return fmt.Errorf("stream client is not ready") 191 } 192 if ok := s.manager.Status(); !ok { 193 return errors.ErrGrpcConnection 194 } 195 196 return nil 197 } 198 199 // Stop stops the StreamerClient 200 func (s *StreamerClient) Stop() { 201 s.manager.CloseConn() 202 s.listener.Stop() 203 } 204 205 // Healthcheck - health check for stream client 206 func (s *StreamerClient) Healthcheck(_ string) *hc.Status { 207 if err := s.Status(); err != nil { 208 return &hc.Status{ 209 Result: hc.FAIL, 210 Details: err.Error(), 211 } 212 } 213 return &hc.Status{ 214 Result: hc.OK, 215 } 216 }