sdk: setup KVStore.

This commit is contained in:
fiatjaf
2025-01-14 23:11:37 -03:00
parent e89b817f7d
commit faa4fabffe
7 changed files with 342 additions and 18 deletions

View File

@@ -0,0 +1,59 @@
package badger
import (
"github.com/dgraph-io/badger/v4"
"github.com/nbd-wtf/go-nostr/sdk/kvstore"
)
var _ kvstore.KVStore = (*Store)(nil)
type Store struct {
db *badger.DB
}
func NewStore(path string) (*Store, error) {
opts := badger.DefaultOptions(path)
db, err := badger.Open(opts)
if err != nil {
return nil, err
}
return &Store{db: db}, nil
}
func (s *Store) Get(key []byte) ([]byte, error) {
var valCopy []byte
err := s.db.View(func(txn *badger.Txn) error {
item, err := txn.Get(key)
if err == badger.ErrKeyNotFound {
return nil
}
if err != nil {
return err
}
return item.Value(func(val []byte) error {
valCopy = make([]byte, len(val))
copy(valCopy, val)
return nil
})
})
if err != nil {
return nil, err
}
return valCopy, nil
}
func (s *Store) Set(key []byte, value []byte) error {
return s.db.Update(func(txn *badger.Txn) error {
return txn.Set(key, value)
})
}
func (s *Store) Delete(key []byte) error {
return s.db.Update(func(txn *badger.Txn) error {
return txn.Delete(key)
})
}
func (s *Store) Close() error {
return s.db.Close()
}

16
sdk/kvstore/interface.go Normal file
View File

@@ -0,0 +1,16 @@
package kvstore
// KVStore is a simple key-value store interface
type KVStore interface {
// Get retrieves a value for a given key. Returns nil if not found.
Get(key []byte) ([]byte, error)
// Set stores a value for a given key
Set(key []byte, value []byte) error
// Delete removes a key and its value
Delete(key []byte) error
// Close releases any resources held by the store
Close() error
}

92
sdk/kvstore/lmdb/store.go Normal file
View File

@@ -0,0 +1,92 @@
package lmdb
import (
"os"
"github.com/PowerDNS/lmdb-go/lmdb"
"github.com/nbd-wtf/go-nostr/sdk/kvstore"
)
var _ kvstore.KVStore = (*Store)(nil)
type Store struct {
env *lmdb.Env
dbi lmdb.DBI
}
func NewStore(path string) (*Store, error) {
// create directory if it doesn't exist
if err := os.MkdirAll(path, 0755); err != nil {
return nil, err
}
// initialize environment
env, err := lmdb.NewEnv()
if err != nil {
return nil, err
}
// set max DBs and map size
env.SetMaxDBs(1)
env.SetMapSize(1 << 30) // 1GB
// open the environment
if err := env.Open(path, lmdb.NoTLS|lmdb.WriteMap, 0644); err != nil {
return nil, err
}
store := &Store{env: env}
// open the database
if err := env.Update(func(txn *lmdb.Txn) error {
dbi, err := txn.OpenDBI("store", lmdb.Create)
if err != nil {
return err
}
store.dbi = dbi
return nil
}); err != nil {
env.Close()
return nil, err
}
return store, nil
}
func (s *Store) Get(key []byte) ([]byte, error) {
var value []byte
err := s.env.View(func(txn *lmdb.Txn) error {
v, err := txn.Get(s.dbi, key)
if lmdb.IsNotFound(err) {
return nil
}
if err != nil {
return err
}
// make a copy since v is only valid during the transaction
value = make([]byte, len(v))
copy(value, v)
return nil
})
if err != nil {
return nil, err
}
return value, nil
}
func (s *Store) Set(key []byte, value []byte) error {
return s.env.Update(func(txn *lmdb.Txn) error {
return txn.Put(s.dbi, key, value, 0)
})
}
func (s *Store) Delete(key []byte) error {
return s.env.Update(func(txn *lmdb.Txn) error {
return txn.Del(s.dbi, key, nil)
})
}
func (s *Store) Close() error {
s.env.Close()
return nil
}

View File

@@ -0,0 +1,58 @@
package memory
import (
"sync"
"github.com/nbd-wtf/go-nostr/sdk/kvstore"
)
var _ kvstore.KVStore = (*Store)(nil)
type Store struct {
sync.RWMutex
data map[string][]byte
}
func NewStore() *Store {
return &Store{
data: make(map[string][]byte),
}
}
func (s *Store) Get(key []byte) ([]byte, error) {
s.RLock()
defer s.RUnlock()
if val, ok := s.data[string(key)]; ok {
// Return a copy to prevent modification of stored data
cp := make([]byte, len(val))
copy(cp, val)
return cp, nil
}
return nil, nil
}
func (s *Store) Set(key []byte, value []byte) error {
s.Lock()
defer s.Unlock()
// Store a copy to prevent modification of stored data
cp := make([]byte, len(value))
copy(cp, value)
s.data[string(key)] = cp
return nil
}
func (s *Store) Delete(key []byte) error {
s.Lock()
defer s.Unlock()
delete(s.data, string(key))
return nil
}
func (s *Store) Close() error {
s.Lock()
defer s.Unlock()
s.data = nil
return nil
}