github.com/ethersphere/bee/v2@v2.2.0/pkg/manifest/simple/manifest.go (about)

     1  // Copyright 2020 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 simple
     6  
     7  import (
     8  	"encoding"
     9  	"encoding/json"
    10  	"errors"
    11  	"fmt"
    12  	"strings"
    13  	"sync"
    14  )
    15  
    16  // Error used when lookup path does not match
    17  var (
    18  	ErrNotFound  = errors.New("not found")
    19  	ErrEmptyPath = errors.New("empty path")
    20  )
    21  
    22  // Manifest is a representation of a manifest.
    23  type Manifest interface {
    24  	// Add adds a manifest entry to the specified path.
    25  	Add(string, string, map[string]string) error
    26  	// Remove removes a manifest entry on the specified path.
    27  	Remove(string) error
    28  	// Lookup returns a manifest node entry if one is found in the specified path.
    29  	Lookup(string) (Entry, error)
    30  	// HasPrefix tests whether the specified prefix path exists.
    31  	HasPrefix(string) bool
    32  	// Length returns an implementation-specific count of elements in the manifest.
    33  	// For Manifest, this means the number of all the existing entries.
    34  	Length() int
    35  
    36  	// WalkEntry walks all entries, calling walkFn for each entry in the map.
    37  	// All errors that arise visiting entries are filtered by walkFn.
    38  	WalkEntry(string, WalkEntryFunc) error
    39  
    40  	encoding.BinaryMarshaler
    41  	encoding.BinaryUnmarshaler
    42  }
    43  
    44  // manifest is a JSON representation of a manifest.
    45  // It stores manifest entries in a map based on string keys.
    46  type manifest struct {
    47  	Entries map[string]*entry `json:"entries,omitempty"`
    48  
    49  	mu sync.RWMutex // mutex for accessing the entries map
    50  }
    51  
    52  // NewManifest creates a new Manifest struct and returns a pointer to it.
    53  func NewManifest() Manifest {
    54  	return &manifest{
    55  		Entries: make(map[string]*entry),
    56  	}
    57  }
    58  
    59  func notFound(path string) error {
    60  	return fmt.Errorf("entry on '%s': %w", path, ErrNotFound)
    61  }
    62  
    63  func (m *manifest) Add(path, entry string, metadata map[string]string) error {
    64  	if path == "" {
    65  		return ErrEmptyPath
    66  	}
    67  
    68  	m.mu.Lock()
    69  	defer m.mu.Unlock()
    70  
    71  	m.Entries[path] = newEntry(entry, metadata)
    72  
    73  	return nil
    74  }
    75  
    76  func (m *manifest) Remove(path string) error {
    77  	if path == "" {
    78  		return ErrEmptyPath
    79  	}
    80  
    81  	m.mu.Lock()
    82  	defer m.mu.Unlock()
    83  
    84  	delete(m.Entries, path)
    85  
    86  	return nil
    87  }
    88  
    89  func (m *manifest) Lookup(path string) (Entry, error) {
    90  	m.mu.RLock()
    91  	defer m.mu.RUnlock()
    92  
    93  	entry, ok := m.Entries[path]
    94  	if !ok {
    95  		return nil, notFound(path)
    96  	}
    97  
    98  	// return a copy to prevent external modification
    99  	return newEntry(entry.Reference(), entry.Metadata()), nil
   100  }
   101  
   102  func (m *manifest) HasPrefix(path string) bool {
   103  	m.mu.RLock()
   104  	defer m.mu.RUnlock()
   105  
   106  	for k := range m.Entries {
   107  		if strings.HasPrefix(k, path) {
   108  			return true
   109  		}
   110  	}
   111  
   112  	return false
   113  }
   114  
   115  func (m *manifest) Length() int {
   116  	m.mu.RLock()
   117  	defer m.mu.RUnlock()
   118  
   119  	return len(m.Entries)
   120  }
   121  
   122  // MarshalBinary implements encoding.BinaryMarshaler.
   123  func (m *manifest) MarshalBinary() ([]byte, error) {
   124  	m.mu.RLock()
   125  	defer m.mu.RUnlock()
   126  
   127  	return json.Marshal(m)
   128  }
   129  
   130  // UnmarshalBinary implements encoding.BinaryUnmarshaler.
   131  func (m *manifest) UnmarshalBinary(b []byte) error {
   132  	m.mu.Lock()
   133  	defer m.mu.Unlock()
   134  
   135  	return json.Unmarshal(b, m)
   136  }