github.com/ergo-services/ergo@v1.999.224/proto/dist/flusher.go (about)

     1  package dist
     2  
     3  import (
     4  	"bufio"
     5  	"io"
     6  	"sync"
     7  	"time"
     8  )
     9  
    10  var (
    11  	// KeepAlive packet is just 4 bytes with zero value
    12  	keepAlivePacket = []byte{0, 0, 0, 0}
    13  	keepAlivePeriod = 15 * time.Second
    14  )
    15  
    16  func newLinkFlusher(w io.Writer, latency time.Duration) *linkFlusher {
    17  	lf := &linkFlusher{
    18  		latency: latency,
    19  		writer:  bufio.NewWriter(w),
    20  		w:       w, // in case if we skip buffering
    21  	}
    22  
    23  	lf.timer = time.AfterFunc(keepAlivePeriod, func() {
    24  
    25  		lf.mutex.Lock()
    26  		defer lf.mutex.Unlock()
    27  
    28  		// if we have no pending data to send we should
    29  		// send a KeepAlive packet
    30  		if lf.pending == false {
    31  			lf.w.Write(keepAlivePacket)
    32  			lf.timer.Reset(keepAlivePeriod)
    33  			return
    34  		}
    35  
    36  		lf.writer.Flush()
    37  		lf.pending = false
    38  		lf.timer.Reset(keepAlivePeriod)
    39  	})
    40  
    41  	return lf
    42  }
    43  
    44  type linkFlusher struct {
    45  	mutex   sync.Mutex
    46  	latency time.Duration
    47  	writer  *bufio.Writer
    48  	w       io.Writer
    49  
    50  	timer   *time.Timer
    51  	pending bool
    52  }
    53  
    54  func (lf *linkFlusher) Write(b []byte) (int, error) {
    55  	lf.mutex.Lock()
    56  	defer lf.mutex.Unlock()
    57  
    58  	l := len(b)
    59  	lenB := l
    60  
    61  	// long data write directly to the socket.
    62  	if l > 64000 {
    63  		for {
    64  			n, e := lf.w.Write(b[lenB-l:])
    65  			if e != nil {
    66  				return n, e
    67  			}
    68  			// check if something left
    69  			l -= n
    70  			if l > 0 {
    71  				continue
    72  			}
    73  			return lenB, nil
    74  		}
    75  	}
    76  
    77  	// write data to the buffer
    78  	for {
    79  		n, e := lf.writer.Write(b)
    80  		if e != nil {
    81  			return n, e
    82  		}
    83  		// check if something left
    84  		l -= n
    85  		if l > 0 {
    86  			continue
    87  		}
    88  		break
    89  	}
    90  
    91  	if lf.pending {
    92  		return lenB, nil
    93  	}
    94  
    95  	lf.pending = true
    96  	lf.timer.Reset(lf.latency)
    97  
    98  	return lenB, nil
    99  }
   100  
   101  func (lf *linkFlusher) Stop() {
   102  	if lf.timer != nil {
   103  		lf.timer.Stop()
   104  	}
   105  }