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  }