github.com/ethersphere/bee/v2@v2.2.0/pkg/file/loadsave/loadsave.go (about)

     1  // Copyright 2021 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 loadsave provides lightweight persistence abstraction
     6  // for manifest operations.
     7  package loadsave
     8  
     9  import (
    10  	"bytes"
    11  	"context"
    12  	"errors"
    13  
    14  	"github.com/ethersphere/bee/v2/pkg/file"
    15  	"github.com/ethersphere/bee/v2/pkg/file/joiner"
    16  	"github.com/ethersphere/bee/v2/pkg/file/pipeline"
    17  	"github.com/ethersphere/bee/v2/pkg/file/pipeline/builder"
    18  	storage "github.com/ethersphere/bee/v2/pkg/storage"
    19  	"github.com/ethersphere/bee/v2/pkg/swarm"
    20  )
    21  
    22  var errReadonlyLoadSave = errors.New("readonly manifest loadsaver")
    23  
    24  // loadSave is needed for manifest operations and provides
    25  // simple wrapping over load and save operations using file
    26  // package abstractions. use with caution since Loader will
    27  // load all of the subtrie of a given hash in memory.
    28  type loadSave struct {
    29  	getter     storage.Getter
    30  	putter     storage.Putter
    31  	pipelineFn func() pipeline.Interface
    32  }
    33  
    34  // New returns a new read-write load-saver.
    35  func New(getter storage.Getter, putter storage.Putter, pipelineFn func() pipeline.Interface) file.LoadSaver {
    36  	return &loadSave{
    37  		getter:     getter,
    38  		putter:     putter,
    39  		pipelineFn: pipelineFn,
    40  	}
    41  }
    42  
    43  // NewReadonly returns a new read-only load-saver
    44  // which will error on write.
    45  func NewReadonly(getter storage.Getter) file.LoadSaver {
    46  	return &loadSave{
    47  		getter: getter,
    48  	}
    49  }
    50  
    51  func (ls *loadSave) Load(ctx context.Context, ref []byte) ([]byte, error) {
    52  	j, _, err := joiner.New(ctx, ls.getter, ls.putter, swarm.NewAddress(ref))
    53  	if err != nil {
    54  		return nil, err
    55  	}
    56  
    57  	buf := bytes.NewBuffer(nil)
    58  	_, err = file.JoinReadAll(ctx, j, buf)
    59  	if err != nil {
    60  		return nil, err
    61  	}
    62  
    63  	return buf.Bytes(), nil
    64  }
    65  
    66  func (ls *loadSave) Save(ctx context.Context, data []byte) ([]byte, error) {
    67  	if ls.pipelineFn == nil {
    68  		return nil, errReadonlyLoadSave
    69  	}
    70  
    71  	pipe := ls.pipelineFn()
    72  	address, err := builder.FeedPipeline(ctx, pipe, bytes.NewReader(data))
    73  	if err != nil {
    74  		return swarm.ZeroAddress.Bytes(), err
    75  	}
    76  
    77  	return address.Bytes(), nil
    78  }