github.com/ethersphere/bee/v2@v2.2.0/pkg/accesscontrol/kvs/kvs.go (about) 1 // Copyright 2024 The Swarm Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Package kvs provides functionalities needed 6 // for storing key-value pairs on Swarm. 7 // 8 //nolint:ireturn 9 package kvs 10 11 import ( 12 "context" 13 "encoding/hex" 14 "errors" 15 "fmt" 16 17 "github.com/ethersphere/bee/v2/pkg/file" 18 "github.com/ethersphere/bee/v2/pkg/manifest" 19 "github.com/ethersphere/bee/v2/pkg/swarm" 20 ) 21 22 var ( 23 // ErrNothingToSave indicates that no new key-value pair was added to the store. 24 ErrNothingToSave = errors.New("nothing to save") 25 // ErrNotFound is returned when an Entry is not found in the storage. 26 ErrNotFound = errors.New("kvs entry not found") 27 ) 28 29 // KeyValueStore represents a key-value store. 30 type KeyValueStore interface { 31 // Get retrieves the value associated with the given key. 32 Get(ctx context.Context, key []byte) ([]byte, error) 33 // Put stores the given key-value pair in the store. 34 Put(ctx context.Context, key, value []byte) error 35 // Save saves key-value pair to the underlying storage and returns the reference. 36 Save(ctx context.Context) (swarm.Address, error) 37 } 38 39 type keyValueStore struct { 40 manifest manifest.Interface 41 putCnt int 42 } 43 44 var _ KeyValueStore = (*keyValueStore)(nil) 45 46 // Get retrieves the value associated with the given key. 47 func (s *keyValueStore) Get(ctx context.Context, key []byte) ([]byte, error) { 48 entry, err := s.manifest.Lookup(ctx, hex.EncodeToString(key)) 49 if err != nil { 50 switch { 51 case errors.Is(err, manifest.ErrNotFound): 52 return nil, ErrNotFound 53 default: 54 return nil, fmt.Errorf("failed to get value from manifest %w", err) 55 } 56 } 57 ref := entry.Reference() 58 return ref.Bytes(), nil 59 } 60 61 // Put stores the given key-value pair in the store. 62 func (s *keyValueStore) Put(ctx context.Context, key []byte, value []byte) error { 63 err := s.manifest.Add(ctx, hex.EncodeToString(key), manifest.NewEntry(swarm.NewAddress(value), map[string]string{})) 64 if err != nil { 65 return fmt.Errorf("failed to put value to manifest %w", err) 66 } 67 s.putCnt++ 68 return nil 69 } 70 71 // Save saves key-value pair to the underlying storage and returns the reference. 72 func (s *keyValueStore) Save(ctx context.Context) (swarm.Address, error) { 73 if s.putCnt == 0 { 74 return swarm.ZeroAddress, ErrNothingToSave 75 } 76 ref, err := s.manifest.Store(ctx) 77 if err != nil { 78 return swarm.ZeroAddress, fmt.Errorf("failed to store manifest %w", err) 79 } 80 s.putCnt = 0 81 return ref, nil 82 } 83 84 // New creates a new key-value store with a simple manifest. 85 func New(ls file.LoadSaver) (KeyValueStore, error) { 86 m, err := manifest.NewSimpleManifest(ls) 87 if err != nil { 88 return nil, fmt.Errorf("failed to create simple manifest: %w", err) 89 } 90 91 return &keyValueStore{ 92 manifest: m, 93 }, nil 94 } 95 96 // NewReference loads a key-value store with a simple manifest. 97 func NewReference(ls file.LoadSaver, ref swarm.Address) (KeyValueStore, error) { 98 m, err := manifest.NewSimpleManifestReference(ref, ls) 99 if err != nil { 100 return nil, fmt.Errorf("failed to create simple manifest reference: %w", err) 101 } 102 103 return &keyValueStore{ 104 manifest: m, 105 }, nil 106 }