mirror of
https://github.com/nbd-wtf/go-nostr.git
synced 2025-08-28 06:41:53 +02:00
sdk: setup KVStore.
This commit is contained in:
59
sdk/kvstore/badger/store.go
Normal file
59
sdk/kvstore/badger/store.go
Normal 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
16
sdk/kvstore/interface.go
Normal 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
92
sdk/kvstore/lmdb/store.go
Normal 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
|
||||
}
|
58
sdk/kvstore/memory/store.go
Normal file
58
sdk/kvstore/memory/store.go
Normal 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
|
||||
}
|
Reference in New Issue
Block a user