github.com/ethersphere/bee/v2@v2.2.0/pkg/manifest/mantaray.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 manifest
     6  
     7  import (
     8  	"context"
     9  	"errors"
    10  	"fmt"
    11  
    12  	"github.com/ethersphere/bee/v2/pkg/file"
    13  	"github.com/ethersphere/bee/v2/pkg/manifest/mantaray"
    14  	"github.com/ethersphere/bee/v2/pkg/swarm"
    15  )
    16  
    17  const (
    18  	// ManifestMantarayContentType represents content type used for noting that
    19  	// specific file should be processed as mantaray manifest.
    20  	ManifestMantarayContentType = "application/bzz-manifest-mantaray+octet-stream"
    21  )
    22  
    23  type mantarayManifest struct {
    24  	trie *mantaray.Node
    25  
    26  	ls file.LoadSaver
    27  }
    28  
    29  // NewMantarayManifest creates a new mantaray-based manifest.
    30  func NewMantarayManifest(
    31  	ls file.LoadSaver,
    32  	encrypted bool,
    33  ) (Interface, error) {
    34  	mm := &mantarayManifest{
    35  		trie: mantaray.New(),
    36  		ls:   ls,
    37  	}
    38  	// use empty obfuscation key if not encrypting
    39  	if !encrypted {
    40  		// NOTE: it will be copied to all trie nodes
    41  		mm.trie.SetObfuscationKey(mantaray.ZeroObfuscationKey)
    42  	}
    43  	return mm, nil
    44  }
    45  
    46  // NewMantarayManifestReference loads existing mantaray-based manifest.
    47  func NewMantarayManifestReference(
    48  	reference swarm.Address,
    49  	ls file.LoadSaver,
    50  ) (Interface, error) {
    51  	return &mantarayManifest{
    52  		trie: mantaray.NewNodeRef(reference.Bytes()),
    53  		ls:   ls,
    54  	}, nil
    55  }
    56  
    57  func (m *mantarayManifest) Root() *mantaray.Node {
    58  	return m.trie
    59  }
    60  
    61  func (m *mantarayManifest) Type() string {
    62  	return ManifestMantarayContentType
    63  }
    64  
    65  func (m *mantarayManifest) Add(ctx context.Context, path string, entry Entry) error {
    66  	p := []byte(path)
    67  	e := entry.Reference().Bytes()
    68  
    69  	return m.trie.Add(ctx, p, e, entry.Metadata(), m.ls)
    70  }
    71  
    72  func (m *mantarayManifest) Remove(ctx context.Context, path string) error {
    73  	p := []byte(path)
    74  
    75  	err := m.trie.Remove(ctx, p, m.ls)
    76  	if err != nil {
    77  		if errors.Is(err, mantaray.ErrNotFound) {
    78  			return ErrNotFound
    79  		}
    80  		return err
    81  	}
    82  
    83  	return nil
    84  }
    85  
    86  func (m *mantarayManifest) Lookup(ctx context.Context, path string) (Entry, error) {
    87  	p := []byte(path)
    88  
    89  	node, err := m.trie.LookupNode(ctx, p, m.ls)
    90  	if err != nil {
    91  		if errors.Is(err, mantaray.ErrNotFound) {
    92  			return nil, ErrNotFound
    93  		}
    94  		return nil, err
    95  	}
    96  
    97  	if !node.IsValueType() {
    98  		return nil, ErrNotFound
    99  	}
   100  
   101  	address := swarm.NewAddress(node.Entry())
   102  	entry := NewEntry(address, node.Metadata())
   103  
   104  	return entry, nil
   105  }
   106  
   107  func (m *mantarayManifest) HasPrefix(ctx context.Context, prefix string) (bool, error) {
   108  	p := []byte(prefix)
   109  
   110  	return m.trie.HasPrefix(ctx, p, m.ls)
   111  }
   112  
   113  func (m *mantarayManifest) Store(ctx context.Context, storeSizeFn ...StoreSizeFunc) (swarm.Address, error) {
   114  	var ls mantaray.LoadSaver
   115  	if len(storeSizeFn) > 0 {
   116  		ls = &mantarayLoadSaver{
   117  			ls:          m.ls,
   118  			storeSizeFn: storeSizeFn,
   119  		}
   120  	} else {
   121  		ls = m.ls
   122  	}
   123  
   124  	err := m.trie.Save(ctx, ls)
   125  	if err != nil {
   126  		return swarm.ZeroAddress, fmt.Errorf("manifest save error: %w", err)
   127  	}
   128  
   129  	address := swarm.NewAddress(m.trie.Reference())
   130  
   131  	return address, nil
   132  }
   133  
   134  func (m *mantarayManifest) IterateAddresses(ctx context.Context, fn swarm.AddressIterFunc) error {
   135  	reference := swarm.NewAddress(m.trie.Reference())
   136  
   137  	if swarm.ZeroAddress.Equal(reference) {
   138  		return ErrMissingReference
   139  	}
   140  
   141  	emptyAddr := swarm.NewAddress([]byte{31: 0})
   142  	walker := func(path []byte, node *mantaray.Node, err error) error {
   143  		if err != nil {
   144  			return err
   145  		}
   146  
   147  		if node != nil {
   148  			if node.Reference() != nil {
   149  				ref := swarm.NewAddress(node.Reference())
   150  
   151  				err = fn(ref)
   152  				if err != nil {
   153  					return err
   154  				}
   155  			}
   156  
   157  			if node.IsValueType() && len(node.Entry()) > 0 {
   158  				entry := swarm.NewAddress(node.Entry())
   159  				// The following comparison to the emptyAddr is
   160  				// a dirty hack which prevents the walker to
   161  				// fail when it encounters an empty address
   162  				// (e.g.: during the unpin traversal operation
   163  				// for manifest). This workaround should be
   164  				// removed after the manifest serialization bug
   165  				// is fixed.
   166  				if entry.Equal(emptyAddr) {
   167  					return nil
   168  				}
   169  				if err := fn(entry); err != nil {
   170  					return err
   171  				}
   172  			}
   173  		}
   174  
   175  		return nil
   176  	}
   177  
   178  	err := m.trie.WalkNode(ctx, []byte{}, m.ls, walker)
   179  	if err != nil {
   180  		return fmt.Errorf("manifest iterate addresses: %w", err)
   181  	}
   182  
   183  	return nil
   184  }
   185  
   186  type mantarayLoadSaver struct {
   187  	ls          file.LoadSaver
   188  	storeSizeFn []StoreSizeFunc
   189  }
   190  
   191  func (ls *mantarayLoadSaver) Load(ctx context.Context, ref []byte) ([]byte, error) {
   192  	return ls.ls.Load(ctx, ref)
   193  }
   194  
   195  func (ls *mantarayLoadSaver) Save(ctx context.Context, data []byte) ([]byte, error) {
   196  	dataLen := int64(len(data))
   197  	for i := range ls.storeSizeFn {
   198  		err := ls.storeSizeFn[i](dataLen)
   199  		if err != nil {
   200  			return nil, fmt.Errorf("manifest store size func: %w", err)
   201  		}
   202  	}
   203  
   204  	return ls.ls.Save(ctx, data)
   205  }