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  }