156 lines
4.5 KiB
Go
156 lines
4.5 KiB
Go
package listenkv
|
|
|
|
import (
|
|
"io"
|
|
|
|
"github.com/cosmos/cosmos-sdk/store/types"
|
|
)
|
|
|
|
var _ types.KVStore = &Store{}
|
|
|
|
// Store implements the KVStore interface with listening enabled.
|
|
// Operations are traced on each core KVStore call and written to any of the
|
|
// underlying listeners with the proper key and operation permissions
|
|
type Store struct {
|
|
parent types.KVStore
|
|
listeners []types.WriteListener
|
|
parentStoreKey types.StoreKey
|
|
}
|
|
|
|
// NewStore returns a reference to a new traceKVStore given a parent
|
|
// KVStore implementation and a buffered writer.
|
|
func NewStore(parent types.KVStore, parentStoreKey types.StoreKey, listeners []types.WriteListener) *Store {
|
|
return &Store{parent: parent, listeners: listeners, parentStoreKey: parentStoreKey}
|
|
}
|
|
|
|
// Get implements the KVStore interface. It traces a read operation and
|
|
// delegates a Get call to the parent KVStore.
|
|
func (s *Store) Get(key []byte) []byte {
|
|
value := s.parent.Get(key)
|
|
return value
|
|
}
|
|
|
|
// Set implements the KVStore interface. It traces a write operation and
|
|
// delegates the Set call to the parent KVStore.
|
|
func (s *Store) Set(key []byte, value []byte) {
|
|
types.AssertValidKey(key)
|
|
s.parent.Set(key, value)
|
|
s.onWrite(false, key, value)
|
|
}
|
|
|
|
// Delete implements the KVStore interface. It traces a write operation and
|
|
// delegates the Delete call to the parent KVStore.
|
|
func (s *Store) Delete(key []byte) {
|
|
s.parent.Delete(key)
|
|
s.onWrite(true, key, nil)
|
|
}
|
|
|
|
// Has implements the KVStore interface. It delegates the Has call to the
|
|
// parent KVStore.
|
|
func (s *Store) Has(key []byte) bool {
|
|
return s.parent.Has(key)
|
|
}
|
|
|
|
// Iterator implements the KVStore interface. It delegates the Iterator call
|
|
// the to the parent KVStore.
|
|
func (s *Store) Iterator(start, end []byte) types.Iterator {
|
|
return s.iterator(start, end, true)
|
|
}
|
|
|
|
// ReverseIterator implements the KVStore interface. It delegates the
|
|
// ReverseIterator call the to the parent KVStore.
|
|
func (s *Store) ReverseIterator(start, end []byte) types.Iterator {
|
|
return s.iterator(start, end, false)
|
|
}
|
|
|
|
// iterator facilitates iteration over a KVStore. It delegates the necessary
|
|
// calls to it's parent KVStore.
|
|
func (s *Store) iterator(start, end []byte, ascending bool) types.Iterator {
|
|
var parent types.Iterator
|
|
|
|
if ascending {
|
|
parent = s.parent.Iterator(start, end)
|
|
} else {
|
|
parent = s.parent.ReverseIterator(start, end)
|
|
}
|
|
|
|
return newTraceIterator(parent, s.listeners)
|
|
}
|
|
|
|
type listenIterator struct {
|
|
parent types.Iterator
|
|
listeners []types.WriteListener
|
|
}
|
|
|
|
func newTraceIterator(parent types.Iterator, listeners []types.WriteListener) types.Iterator {
|
|
return &listenIterator{parent: parent, listeners: listeners}
|
|
}
|
|
|
|
// Domain implements the Iterator interface.
|
|
func (li *listenIterator) Domain() (start []byte, end []byte) {
|
|
return li.parent.Domain()
|
|
}
|
|
|
|
// Valid implements the Iterator interface.
|
|
func (li *listenIterator) Valid() bool {
|
|
return li.parent.Valid()
|
|
}
|
|
|
|
// Next implements the Iterator interface.
|
|
func (li *listenIterator) Next() {
|
|
li.parent.Next()
|
|
}
|
|
|
|
// Key implements the Iterator interface.
|
|
func (li *listenIterator) Key() []byte {
|
|
key := li.parent.Key()
|
|
return key
|
|
}
|
|
|
|
// Value implements the Iterator interface.
|
|
func (li *listenIterator) Value() []byte {
|
|
value := li.parent.Value()
|
|
return value
|
|
}
|
|
|
|
// Close implements the Iterator interface.
|
|
func (li *listenIterator) Close() error {
|
|
return li.parent.Close()
|
|
}
|
|
|
|
// Error delegates the Error call to the parent iterator.
|
|
func (li *listenIterator) Error() error {
|
|
return li.parent.Error()
|
|
}
|
|
|
|
// GetStoreType implements the KVStore interface. It returns the underlying
|
|
// KVStore type.
|
|
func (s *Store) GetStoreType() types.StoreType {
|
|
return s.parent.GetStoreType()
|
|
}
|
|
|
|
// CacheWrap implements the KVStore interface. It panics as a Store
|
|
// cannot be cache wrapped.
|
|
func (s *Store) CacheWrap() types.CacheWrap {
|
|
panic("cannot CacheWrap a ListenKVStore")
|
|
}
|
|
|
|
// CacheWrapWithTrace implements the KVStore interface. It panics as a
|
|
// Store cannot be cache wrapped.
|
|
func (s *Store) CacheWrapWithTrace(_ io.Writer, _ types.TraceContext) types.CacheWrap {
|
|
panic("cannot CacheWrapWithTrace a ListenKVStore")
|
|
}
|
|
|
|
// CacheWrapWithListeners implements the KVStore interface. It panics as a
|
|
// Store cannot be cache wrapped.
|
|
func (s *Store) CacheWrapWithListeners(_ types.StoreKey, _ []types.WriteListener) types.CacheWrap {
|
|
panic("cannot CacheWrapWithListeners a ListenKVStore")
|
|
}
|
|
|
|
// onWrite writes a KVStore operation to all of the WriteListeners
|
|
func (s *Store) onWrite(delete bool, key, value []byte) {
|
|
for _, l := range s.listeners {
|
|
l.OnWrite(s.parentStoreKey, key, value, delete)
|
|
}
|
|
}
|