github.com/simpleiot/simpleiot@v0.18.3/client/edge.go (about)

     1  package client
     2  
     3  import (
     4  	"log"
     5  	"net"
     6  	"time"
     7  
     8  	"github.com/nats-io/nats.go"
     9  )
    10  
    11  // EdgeOptions describes options for connecting edge devices
    12  type EdgeOptions struct {
    13  	URI          string
    14  	AuthToken    string
    15  	NoEcho       bool
    16  	Connected    func()
    17  	Disconnected func()
    18  	Reconnected  func()
    19  	Closed       func()
    20  }
    21  
    22  // EdgeConnect is a function that attempts connections for edge devices with appropriate
    23  // timeouts, backups, etc. Currently set to disconnect if we don't have a connection after 6m,
    24  // and then exp backup to try to connect every 6m after that.
    25  func EdgeConnect(eo EdgeOptions) (*nats.Conn, error) {
    26  	authEnabled := "no"
    27  	if eo.AuthToken != "" {
    28  		authEnabled = "yes"
    29  	}
    30  
    31  	natsErrHandler := func(_ *nats.Conn, sub *nats.Subscription, natsErr error) {
    32  		log.Printf("error: %v\n", natsErr)
    33  		switch natsErr {
    34  		case nats.ErrSlowConsumer:
    35  			pendingMsgs, _, err := sub.Pending()
    36  			if err != nil {
    37  				log.Printf("couldn't get pending messages: %v", err)
    38  				return
    39  			}
    40  			log.Printf("Falling behind with %d pending messages on subject %q.\n",
    41  				pendingMsgs, sub.Subject)
    42  			// Log error, notify operations...
    43  		default:
    44  			log.Println("Nats client error:", natsErr)
    45  		}
    46  		// check for other errors
    47  	}
    48  
    49  	siotOptions := func(o *nats.Options) error {
    50  		_ = nats.Timeout(30 * time.Second)(o)
    51  		_ = nats.DrainTimeout(30 * time.Second)(o)
    52  		_ = nats.PingInterval(2 * time.Minute)(o)
    53  		_ = nats.MaxPingsOutstanding(3)(o)
    54  		_ = nats.RetryOnFailedConnect(true)(o)
    55  		_ = nats.ReconnectBufSize(128 * 1024)(o)
    56  		_ = nats.ReconnectWait(10 * time.Second)(o)
    57  		_ = nats.MaxReconnects(-1)(o)
    58  		_ = nats.SetCustomDialer(&net.Dialer{
    59  			KeepAlive: -1,
    60  		})(o)
    61  
    62  		_ = nats.CustomReconnectDelay(func(attempts int) time.Duration {
    63  			delay := ExpBackoff(attempts, 6*time.Minute)
    64  			log.Printf("NATS reconnect attempts: %v, delay: %v", attempts, delay)
    65  			return delay
    66  		})(o)
    67  
    68  		_ = nats.Token(eo.AuthToken)(o)
    69  
    70  		if eo.NoEcho {
    71  			o.NoEcho = true
    72  		}
    73  
    74  		_ = nats.ErrorHandler(natsErrHandler)(o)
    75  
    76  		_ = nats.ConnectHandler(func(_ *nats.Conn) {
    77  			if eo.Connected != nil {
    78  				eo.Connected()
    79  			}
    80  		})(o)
    81  
    82  		_ = nats.ErrorHandler(func(_ *nats.Conn, sub *nats.Subscription,
    83  			err error) {
    84  			if sub != nil {
    85  				log.Printf("NATS Error, sub: %v, err: %v\n", sub.Subject, err)
    86  			} else {
    87  				log.Printf("NATS Error, err: %v\n", err)
    88  			}
    89  		})(o)
    90  
    91  		_ = nats.ReconnectHandler(func(_ *nats.Conn) {
    92  			if eo.Reconnected != nil {
    93  				eo.Reconnected()
    94  			}
    95  		})(o)
    96  
    97  		_ = nats.DisconnectHandler(func(_ *nats.Conn) {
    98  			if eo.Disconnected != nil {
    99  				eo.Disconnected()
   100  			}
   101  		})(o)
   102  
   103  		_ = nats.ClosedHandler(func(_ *nats.Conn) {
   104  			if eo.Closed != nil {
   105  				eo.Closed()
   106  			}
   107  		})(o)
   108  
   109  		return nil
   110  	}
   111  
   112  	uri, err := sanitizeURI(eo.URI)
   113  	if err != nil {
   114  		log.Printf("Error sanitizing URI %v: %v", eo.URI, err)
   115  		return nil, err
   116  	}
   117  
   118  	log.Printf("NATS edge connect to: %v, auth enabled: %v", uri, authEnabled)
   119  	nc, err := nats.Connect(uri, siotOptions)
   120  
   121  	if err != nil {
   122  		return nil, err
   123  	}
   124  
   125  	log.Println("NATS: TLS required:", nc.TLSRequired())
   126  
   127  	return nc, nil
   128  }