github.com/micro/go-micro/v2@v2.9.1/util/ring/buffer.go (about) 1 // Package ring provides a simple ring buffer for storing local data 2 package ring 3 4 import ( 5 "sync" 6 "time" 7 8 "github.com/google/uuid" 9 ) 10 11 // Buffer is ring buffer 12 type Buffer struct { 13 size int 14 15 sync.RWMutex 16 vals []*Entry 17 streams map[string]*Stream 18 } 19 20 // Entry is ring buffer data entry 21 type Entry struct { 22 Value interface{} 23 Timestamp time.Time 24 } 25 26 // Stream is used to stream the buffer 27 type Stream struct { 28 // Id of the stream 29 Id string 30 // Buffered entries 31 Entries chan *Entry 32 // Stop channel 33 Stop chan bool 34 } 35 36 // Put adds a new value to ring buffer 37 func (b *Buffer) Put(v interface{}) { 38 b.Lock() 39 defer b.Unlock() 40 41 // append to values 42 entry := &Entry{ 43 Value: v, 44 Timestamp: time.Now(), 45 } 46 b.vals = append(b.vals, entry) 47 48 // trim if bigger than size required 49 if len(b.vals) > b.size { 50 b.vals = b.vals[1:] 51 } 52 53 // send to every stream 54 for _, stream := range b.streams { 55 select { 56 case <-stream.Stop: 57 delete(b.streams, stream.Id) 58 close(stream.Entries) 59 case stream.Entries <- entry: 60 } 61 } 62 } 63 64 // Get returns the last n entries 65 func (b *Buffer) Get(n int) []*Entry { 66 b.RLock() 67 defer b.RUnlock() 68 69 // reset any invalid values 70 if n > len(b.vals) || n < 0 { 71 n = len(b.vals) 72 } 73 74 // create a delta 75 delta := len(b.vals) - n 76 77 // return the delta set 78 return b.vals[delta:] 79 } 80 81 // Return the entries since a specific time 82 func (b *Buffer) Since(t time.Time) []*Entry { 83 b.RLock() 84 defer b.RUnlock() 85 86 // return all the values 87 if t.IsZero() { 88 return b.vals 89 } 90 91 // if its in the future return nothing 92 if time.Since(t).Seconds() < 0.0 { 93 return nil 94 } 95 96 for i, v := range b.vals { 97 // find the starting point 98 d := v.Timestamp.Sub(t) 99 100 // return the values 101 if d.Seconds() > 0.0 { 102 return b.vals[i:] 103 } 104 } 105 106 return nil 107 } 108 109 // Stream logs from the buffer 110 // Close the channel when you want to stop 111 func (b *Buffer) Stream() (<-chan *Entry, chan bool) { 112 b.Lock() 113 defer b.Unlock() 114 115 entries := make(chan *Entry, 128) 116 id := uuid.New().String() 117 stop := make(chan bool) 118 119 b.streams[id] = &Stream{ 120 Id: id, 121 Entries: entries, 122 Stop: stop, 123 } 124 125 return entries, stop 126 } 127 128 // Size returns the size of the ring buffer 129 func (b *Buffer) Size() int { 130 return b.size 131 } 132 133 // New returns a new buffer of the given size 134 func New(i int) *Buffer { 135 return &Buffer{ 136 size: i, 137 streams: make(map[string]*Stream), 138 } 139 }