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 }