github.com/tickoalcantara12/micro/v3@v3.0.0-20221007104245-9d75b9bcbab9/util/ring/buffer.go (about) 1 // Licensed under the Apache License, Version 2.0 (the "License"); 2 // you may not use this file except in compliance with the License. 3 // You may obtain a copy of the License at 4 // 5 // https://www.apache.org/licenses/LICENSE-2.0 6 // 7 // Unless required by applicable law or agreed to in writing, software 8 // distributed under the License is distributed on an "AS IS" BASIS, 9 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 // See the License for the specific language governing permissions and 11 // limitations under the License. 12 // 13 // Original source: github.com/micro/go-micro/v3/util/ring/buffer.go 14 15 // Package ring provides a simple ring buffer for storing local data 16 package ring 17 18 import ( 19 "sync" 20 "time" 21 22 "github.com/google/uuid" 23 ) 24 25 // Buffer is ring buffer 26 type Buffer struct { 27 size int 28 29 sync.RWMutex 30 vals []*Entry 31 streams map[string]*Stream 32 } 33 34 // Entry is ring buffer data entry 35 type Entry struct { 36 Value interface{} 37 Timestamp time.Time 38 } 39 40 // Stream is used to stream the buffer 41 type Stream struct { 42 // Id of the stream 43 Id string 44 // Buffered entries 45 Entries chan *Entry 46 // Stop channel 47 Stop chan bool 48 } 49 50 // Put adds a new value to ring buffer 51 func (b *Buffer) Put(v interface{}) { 52 b.Lock() 53 defer b.Unlock() 54 55 // append to values 56 entry := &Entry{ 57 Value: v, 58 Timestamp: time.Now(), 59 } 60 b.vals = append(b.vals, entry) 61 62 // trim if bigger than size required 63 if len(b.vals) > b.size { 64 b.vals = b.vals[1:] 65 } 66 67 // send to every stream 68 for _, stream := range b.streams { 69 select { 70 case <-stream.Stop: 71 delete(b.streams, stream.Id) 72 close(stream.Entries) 73 case stream.Entries <- entry: 74 } 75 } 76 } 77 78 // Get returns the last n entries 79 func (b *Buffer) Get(n int) []*Entry { 80 b.RLock() 81 defer b.RUnlock() 82 83 // reset any invalid values 84 if n > len(b.vals) || n < 0 { 85 n = len(b.vals) 86 } 87 88 // create a delta 89 delta := len(b.vals) - n 90 91 // return the delta set 92 return b.vals[delta:] 93 } 94 95 // Return the entries since a specific time 96 func (b *Buffer) Since(t time.Time) []*Entry { 97 b.RLock() 98 defer b.RUnlock() 99 100 // return all the values 101 if t.IsZero() { 102 return b.vals 103 } 104 105 // if its in the future return nothing 106 if time.Since(t).Seconds() < 0.0 { 107 return nil 108 } 109 110 for i, v := range b.vals { 111 // find the starting point 112 d := v.Timestamp.Sub(t) 113 114 // return the values 115 if d.Seconds() > 0.0 { 116 return b.vals[i:] 117 } 118 } 119 120 return nil 121 } 122 123 // Stream logs from the buffer 124 // Close the channel when you want to stop 125 func (b *Buffer) Stream() (<-chan *Entry, chan bool) { 126 b.Lock() 127 defer b.Unlock() 128 129 entries := make(chan *Entry, 128) 130 id := uuid.New().String() 131 stop := make(chan bool) 132 133 b.streams[id] = &Stream{ 134 Id: id, 135 Entries: entries, 136 Stop: stop, 137 } 138 139 return entries, stop 140 } 141 142 // Size returns the size of the ring buffer 143 func (b *Buffer) Size() int { 144 return b.size 145 } 146 147 // New returns a new buffer of the given size 148 func New(i int) *Buffer { 149 return &Buffer{ 150 size: i, 151 streams: make(map[string]*Stream), 152 } 153 }