Skip to content
Snippets Groups Projects
Select Git revision
  • 62f4ec17fc1c92ce6a88629b4526defb1265a0af
  • release default protected
  • master protected
  • hotfix/GrpcParameters
  • XX-4441
  • tls-websockets
  • hotfix/allow-web-creds
  • hotfix/nilCert
  • XX-3566_const_time_token_compare
  • AceVentura/AccountBackup
  • dev
  • waitingRoundsRewrite
  • fullRateLimit
  • XX-3564/TlsCipherSuite
  • XX-3563/DisableTlsCheck
  • notls
  • url-repo-rename
  • perftuning
  • Anne/CI2
  • AddedGossipLogging
  • hotfix/connectionReduction
  • v0.0.6
  • v0.0.4
  • v0.0.5
  • v0.0.3
  • v0.0.2
  • v0.0.1
27 results

grpcConn.go

Blame
  • sentFileTransfers.go 7.80 KiB
    ////////////////////////////////////////////////////////////////////////////////
    // Copyright © 2020 xx network SEZC                                           //
    //                                                                            //
    // Use of this source code is governed by a license that can be found in the  //
    // LICENSE file                                                               //
    ////////////////////////////////////////////////////////////////////////////////
    
    package fileTransfer
    
    import (
    	"bytes"
    	"github.com/pkg/errors"
    	"gitlab.com/elixxir/client/interfaces"
    	"gitlab.com/elixxir/client/storage/versioned"
    	ftCrypto "gitlab.com/elixxir/crypto/fileTransfer"
    	"gitlab.com/xx_network/crypto/csprng"
    	"gitlab.com/xx_network/primitives/id"
    	"gitlab.com/xx_network/primitives/netTime"
    	"sync"
    	"time"
    )
    
    // Storage keys and versions.
    const (
    	sentFileTransfersPrefix  = "SentFileTransfersStore"
    	sentFileTransfersKey     = "SentFileTransfers"
    	sentFileTransfersVersion = 0
    )
    
    // Error messages.
    const (
    	saveSentTransfersListErr = "failed to save list of sent items in transfer map to storage: %+v"
    	loadSentTransfersListErr = "failed to load list of sent items in transfer map from storage: %+v"
    	loadSentTransfersErr     = "failed to load sent transfers from storage: %+v"
    
    	newSentTransferErr    = "failed to create new sent transfer: %+v"
    	getSentTransferErr    = "sent file transfer not found"
    	deleteSentTransferErr = "failed to delete sent transfer with ID %s from store: %+v"
    )
    
    // SentFileTransfers contains information for tracking sent file transfers.
    type SentFileTransfers struct {
    	transfers map[ftCrypto.TransferID]*SentTransfer
    	mux       sync.Mutex
    	kv        *versioned.KV
    }
    
    // NewSentFileTransfers creates a new SentFileTransfers with an empty map.
    func NewSentFileTransfers(kv *versioned.KV) (*SentFileTransfers, error) {
    	sft := &SentFileTransfers{
    		transfers: make(map[ftCrypto.TransferID]*SentTransfer),
    		kv:        kv.Prefix(sentFileTransfersPrefix),
    	}
    
    	return sft, sft.saveTransfersList()
    }
    
    // AddTransfer creates a new empty SentTransfer and adds it to the transfers
    // map.
    func (sft *SentFileTransfers) AddTransfer(recipient *id.ID,
    	key ftCrypto.TransferKey, parts [][]byte, numFps uint16,
    	progressCB interfaces.SentProgressCallback, period time.Duration,
    	rng csprng.Source) (ftCrypto.TransferID, error) {
    
    	sft.mux.Lock()
    	defer sft.mux.Unlock()
    
    	// Generate new transfer ID
    	tid, err := ftCrypto.NewTransferID(rng)
    	if err != nil {
    		return tid, errors.Errorf(addTransferNewIdErr, err)
    	}
    
    	// Generate a new SentTransfer and add it to the map
    	sft.transfers[tid], err = NewSentTransfer(
    		recipient, tid, key, parts, numFps, progressCB, period, sft.kv)
    	if err != nil {
    		return tid, errors.Errorf(newSentTransferErr, err)
    	}
    
    	// Update list of transfers in storage
    	err = sft.saveTransfersList()
    	if err != nil {
    		return tid, errors.Errorf(saveSentTransfersListErr, err)
    	}
    
    	return tid, nil
    }
    
    // GetTransfer returns the SentTransfer with the given transfer ID. An error is
    // returned if no corresponding transfer is found.
    func (sft *SentFileTransfers) GetTransfer(tid ftCrypto.TransferID) (
    	*SentTransfer, error) {
    	sft.mux.Lock()
    	defer sft.mux.Unlock()
    
    	rt, exists := sft.transfers[tid]
    	if !exists {
    		return nil, errors.New(getSentTransferErr)
    	}
    
    	return rt, nil
    }
    
    // DeleteTransfer removes the SentTransfer with the associated transfer ID
    // from memory and storage.
    func (sft *SentFileTransfers) DeleteTransfer(tid ftCrypto.TransferID) error {
    	sft.mux.Lock()
    	defer sft.mux.Unlock()
    
    	// Return an error if the transfer does not exist
    	_, exists := sft.transfers[tid]
    	if !exists {
    		return errors.New(getSentTransferErr)
    	}
    
    	// Delete all data the transfer saved to storage
    	err := sft.transfers[tid].delete()
    	if err != nil {
    		return errors.Errorf(deleteSentTransferErr, tid, err)
    	}
    
    	// Delete the transfer from memory
    	delete(sft.transfers, tid)
    
    	// Update the transfers list for the removed transfer
    	err = sft.saveTransfersList()
    	if err != nil {
    		return errors.Errorf(saveSentTransfersListErr, err)
    	}
    
    	return nil
    }
    
    ////////////////////////////////////////////////////////////////////////////////
    // Storage Functions                                                          //
    ////////////////////////////////////////////////////////////////////////////////
    
    // LoadSentFileTransfers loads all SentFileTransfers from storage.
    func LoadSentFileTransfers(kv *versioned.KV) (*SentFileTransfers, error) {
    	sft := &SentFileTransfers{
    		transfers: make(map[ftCrypto.TransferID]*SentTransfer),
    		kv:        kv.Prefix(sentFileTransfersPrefix),
    	}
    
    	// Get the list of transfer IDs corresponding to each sent transfer from
    	// storage
    	transfersList, err := sft.loadTransfersList()
    	if err != nil {
    		return nil, errors.Errorf(loadSentTransfersListErr, err)
    	}
    
    	// Load each transfer in the list from storage into the map
    	err = sft.loadTransfers(transfersList)
    	if err != nil {
    		return nil, errors.Errorf(loadSentTransfersErr, err)
    	}
    
    	return sft, nil
    }
    
    // NewOrLoadSentFileTransfers loads all SentFileTransfers from storage, if they
    // exist. Otherwise, a new SentFileTransfers is returned.
    func NewOrLoadSentFileTransfers(kv *versioned.KV) (*SentFileTransfers, error) {
    	sft := &SentFileTransfers{
    		transfers: make(map[ftCrypto.TransferID]*SentTransfer),
    		kv:        kv.Prefix(sentFileTransfersPrefix),
    	}
    
    	// If the transfer list cannot be loaded from storage, then create a new
    	// SentFileTransfers
    	vo, err := sft.kv.Get(sentFileTransfersKey, sentFileTransfersVersion)
    	if err != nil {
    		return NewSentFileTransfers(kv)
    	}
    
    	// Unmarshal data into list of saved transfer IDs
    	transfersList := unmarshalTransfersList(vo.Data)
    
    	// Load each transfer in the list from storage into the map
    	err = sft.loadTransfers(transfersList)
    	if err != nil {
    		return nil, errors.Errorf(loadSentTransfersErr, err)
    	}
    
    	return sft, nil
    }
    
    // saveTransfersList saves a list of items in the transfers map to storage.
    func (sft *SentFileTransfers) saveTransfersList() error {
    	// Create new versioned object with a list of items in the transfers map
    	obj := &versioned.Object{
    		Version:   sentFileTransfersVersion,
    		Timestamp: netTime.Now(),
    		Data:      sft.marshalTransfersList(),
    	}
    
    	// Save list of items in the transfers map to storage
    	return sft.kv.Set(sentFileTransfersKey, sentFileTransfersVersion, obj)
    }
    
    // loadTransfersList gets the list of transfer IDs corresponding to each saved
    // sent transfer from storage.
    func (sft *SentFileTransfers) loadTransfersList() ([]ftCrypto.TransferID, error) {
    	// Get transfers list from storage
    	vo, err := sft.kv.Get(sentFileTransfersKey, sentFileTransfersVersion)
    	if err != nil {
    		return nil, err
    	}
    
    	// Unmarshal data into list of saved transfer IDs
    	return unmarshalTransfersList(vo.Data), nil
    }
    
    // loadTransfers loads each SentTransfer from the list and adds them to the map.
    func (sft *SentFileTransfers) loadTransfers(list []ftCrypto.TransferID) error {
    	var err error
    
    	// Load each sentTransfer from storage into the map
    	for _, tid := range list {
    		sft.transfers[tid], err = loadSentTransfer(tid, sft.kv)
    		if err != nil {
    			return err
    		}
    	}
    
    	return nil
    }
    
    // marshalTransfersList creates a list of all transfer IDs in the transfers map
    // and serialises it.
    func (sft *SentFileTransfers) marshalTransfersList() []byte {
    	buff := bytes.NewBuffer(nil)
    	buff.Grow(ftCrypto.TransferIdLength * len(sft.transfers))
    
    	for tid := range sft.transfers {
    		buff.Write(tid.Bytes())
    	}
    
    	return buff.Bytes()
    }
    
    // unmarshalTransfersList deserializes a byte slice into a list of transfer IDs.
    func unmarshalTransfersList(b []byte) []ftCrypto.TransferID {
    	buff := bytes.NewBuffer(b)
    	list := make([]ftCrypto.TransferID, 0, buff.Len()/ftCrypto.TransferIdLength)
    
    	const size = ftCrypto.TransferIdLength
    	for n := buff.Next(size); len(n) == size; n = buff.Next(size) {
    		list = append(list, ftCrypto.UnmarshalTransferID(n))
    	}
    
    	return list
    }