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  }