github.com/0chain/gosdk@v1.17.11/zboxcore/fileref/fileref.go (about)

     1  package fileref
     2  
     3  import (
     4  	"fmt"
     5  	"hash/fnv"
     6  	"math"
     7  	"strconv"
     8  	"strings"
     9  
    10  	"github.com/0chain/gosdk/core/common"
    11  	"github.com/0chain/gosdk/core/encryption"
    12  	lru "github.com/hashicorp/golang-lru/v2"
    13  )
    14  
    15  // File read/write chunk size
    16  const CHUNK_SIZE = 64 * 1024
    17  
    18  const (
    19  	// FILE represents a file for fileref
    20  	FILE = "f"
    21  
    22  	// DIRECTORY represents a directory for fileref
    23  	DIRECTORY = "d"
    24  	REGULAR   = "regular"
    25  )
    26  
    27  var fileCache, _ = lru.New[string, FileRef](100)
    28  
    29  type Collaborator struct {
    30  	RefID     int64  `json:"ref_id"`
    31  	ClientID  string `json:"client_id"`
    32  	CreatedAt string `json:"created_at"`
    33  }
    34  
    35  type FileRef struct {
    36  	Ref            `mapstructure:",squash"`
    37  	CustomMeta     string `json:"custom_meta" mapstructure:"custom_meta"`
    38  	ValidationRoot string `json:"validation_root" mapstructure:"validation_root"`
    39  	// ValidationRootSignature is signature signed by client for hash_of(ActualFileHashSignature + ValidationRoot)
    40  	ValidationRootSignature string `json:"validation_root_signature" mapstructure:"validation_root_signature"`
    41  	FixedMerkleRoot         string `json:"fixed_merkle_root" mapstructure:"fixed_merkle_root"`
    42  	ThumbnailSize           int64  `json:"thumbnail_size" mapstructure:"thumbnail_size"`
    43  	ThumbnailHash           string `json:"thumbnail_hash" mapstructure:"thumbnail_hash"`
    44  	ActualFileSize          int64  `json:"actual_file_size" mapstructure:"actual_file_size"`
    45  	ActualFileHash          string `json:"actual_file_hash" mapstructure:"actual_file_hash"`
    46  	// ActualFileHashSignature is signature signed by client for ActualFileHash
    47  	ActualFileHashSignature string         `json:"actual_file_hash_signature" mapstructure:"actual_file_hash_signature"`
    48  	ActualThumbnailSize     int64          `json:"actual_thumbnail_size" mapstructure:"actual_thumbnail_size"`
    49  	ActualThumbnailHash     string         `json:"actual_thumbnail_hash" mapstructure:"actual_thumbnail_hash"`
    50  	MimeType                string         `json:"mimetype" mapstructure:"mimetype"`
    51  	EncryptedKey            string         `json:"encrypted_key" mapstructure:"encrypted_key"`
    52  	EncryptedKeyPoint       string         `json:"encrypted_key_point" mapstructure:"encrypted_key_point"`
    53  	Collaborators           []Collaborator `json:"collaborators" mapstructure:"collaborators"`
    54  }
    55  
    56  func (fRef *FileRef) MetaID() string {
    57  
    58  	hash := fnv.New64a()
    59  	hash.Write([]byte(fRef.Path))
    60  
    61  	return strconv.FormatUint(hash.Sum64(), 36)
    62  }
    63  
    64  type RefEntity interface {
    65  	GetNumBlocks() int64
    66  	GetSize() int64
    67  	GetFileMetaHash() string
    68  	GetHash() string
    69  	CalculateHash() string
    70  	GetType() string
    71  	GetPathHash() string
    72  	GetLookupHash() string
    73  	GetPath() string
    74  	GetName() string
    75  	GetFileID() string
    76  	GetCreatedAt() common.Timestamp
    77  	GetUpdatedAt() common.Timestamp
    78  }
    79  
    80  type Ref struct {
    81  	Type                string `json:"type" mapstructure:"type"`
    82  	AllocationID        string `json:"allocation_id" mapstructure:"allocation_id"`
    83  	Name                string `json:"name" mapstructure:"name"`
    84  	Path                string `json:"path" mapstructure:"path"`
    85  	Size                int64  `json:"size" mapstructure:"size"`
    86  	ActualSize          int64  `json:"actual_file_size" mapstructure:"actual_file_size"`
    87  	Hash                string `json:"hash" mapstructure:"hash"`
    88  	ChunkSize           int64  `json:"chunk_size" mapstructure:"chunk_size"`
    89  	NumBlocks           int64  `json:"num_of_blocks" mapstructure:"num_of_blocks"`
    90  	PathHash            string `json:"path_hash" mapstructure:"path_hash"`
    91  	LookupHash          string `json:"lookup_hash" mapstructure:"lookup_hash"`
    92  	FileID              string `json:"file_id" mapstructure:"file_id"`
    93  	FileMetaHash        string `json:"file_meta_hash" mapstructure:"file_meta_hash"`
    94  	ThumbnailHash       string `json:"thumbnail_hash" mapstructure:"thumbnail_hash"`
    95  	ThumbnailSize       int64  `json:"thumbnail_size" mapstructure:"thumbnail_size"`
    96  	ActualThumbnailHash string `json:"actual_thumbnail_hash" mapstructure:"actual_thumbnail_hash"`
    97  	ActualThumbnailSize int64  `json:"actual_thumbnail_size" mapstructure:"actual_thumbnail_size"`
    98  	HashToBeComputed    bool
    99  	ChildrenLoaded      bool
   100  	Children            []RefEntity      `json:"-" mapstructure:"-"`
   101  	CreatedAt           common.Timestamp `json:"created_at" mapstructure:"created_at"`
   102  	UpdatedAt           common.Timestamp `json:"updated_at" mapstructure:"updated_at"`
   103  }
   104  
   105  // GetReferenceLookup returns the lookup hash for a given allocationID and path
   106  //   - allocationID: allocation ID
   107  //   - path: path of the file
   108  func GetReferenceLookup(allocationID string, path string) string {
   109  	return encryption.Hash(allocationID + ":" + path)
   110  }
   111  
   112  func GetCacheKey(lookuphash, blobberID string) string {
   113  	return encryption.FastHash(lookuphash + ":" + blobberID)
   114  }
   115  
   116  func StoreFileRef(key string, fr FileRef) {
   117  	fileCache.Add(key, fr)
   118  }
   119  
   120  func GetFileRef(key string) (FileRef, bool) {
   121  	if fr, ok := fileCache.Get(key); ok {
   122  		return fr, true
   123  	}
   124  	return FileRef{}, false
   125  }
   126  
   127  func DeleteFileRef(key string) {
   128  	fileCache.Remove(key)
   129  }
   130  
   131  func (r *Ref) CalculateHash() string {
   132  	if len(r.Children) == 0 && !r.ChildrenLoaded && !r.HashToBeComputed {
   133  		return r.Hash
   134  	}
   135  
   136  	childHashes := make([]string, len(r.Children))
   137  	childFileMetaHashes := make([]string, len(r.Children))
   138  	childPaths := make([]string, len(r.Children))
   139  	var refNumBlocks int64
   140  	var size int64
   141  
   142  	for index, childRef := range r.Children {
   143  		childRef.CalculateHash()
   144  		childFileMetaHashes[index] = childRef.GetFileMetaHash()
   145  		childHashes[index] = childRef.GetHash()
   146  		childPaths[index] = childRef.GetPath()
   147  		refNumBlocks += childRef.GetNumBlocks()
   148  		size += childRef.GetSize()
   149  	}
   150  
   151  	r.FileMetaHash = encryption.Hash(r.GetPath() + strings.Join(childFileMetaHashes, ":"))
   152  	r.Hash = encryption.Hash(r.GetHashData() + strings.Join(childHashes, ":"))
   153  
   154  	r.PathHash = encryption.Hash(strings.Join(childPaths, ":"))
   155  	r.NumBlocks = refNumBlocks
   156  	r.Size = size
   157  
   158  	return r.Hash
   159  }
   160  
   161  func (r *Ref) GetFileMetaHash() string {
   162  	return r.FileMetaHash
   163  }
   164  
   165  func (r *Ref) GetHash() string {
   166  	return r.Hash
   167  }
   168  
   169  func (r *Ref) GetHashData() string {
   170  	return fmt.Sprintf("%s:%s:%s", r.AllocationID, r.Path, r.FileID)
   171  }
   172  
   173  func (r *Ref) GetType() string {
   174  	return r.Type
   175  }
   176  
   177  func (r *Ref) GetNumBlocks() int64 {
   178  	return r.NumBlocks
   179  }
   180  
   181  func (r *Ref) GetSize() int64 {
   182  	return r.Size
   183  }
   184  
   185  func (r *Ref) GetPathHash() string {
   186  	return r.PathHash
   187  }
   188  
   189  func (r *Ref) GetLookupHash() string {
   190  	return r.LookupHash
   191  }
   192  
   193  func (r *Ref) GetPath() string {
   194  	return r.Path
   195  }
   196  
   197  func (r *Ref) GetName() string {
   198  	return r.Name
   199  }
   200  
   201  func (r *Ref) GetFileID() string {
   202  	return r.FileID
   203  }
   204  
   205  func (r *Ref) GetCreatedAt() common.Timestamp {
   206  	return r.CreatedAt
   207  }
   208  
   209  func (r *Ref) GetUpdatedAt() common.Timestamp {
   210  	return r.UpdatedAt
   211  }
   212  
   213  func (r *Ref) AddChild(child RefEntity) {
   214  	if r.Children == nil {
   215  		r.Children = make([]RefEntity, 0)
   216  	}
   217  	var index int
   218  	var ltFound bool // less than found
   219  	// Add child in sorted fashion
   220  	for i, ref := range r.Children {
   221  		if strings.Compare(child.GetPath(), ref.GetPath()) == -1 {
   222  			index = i
   223  			ltFound = true
   224  			break
   225  		}
   226  	}
   227  	if ltFound {
   228  		r.Children = append(r.Children[:index+1], r.Children[index:]...)
   229  		r.Children[index] = child
   230  	} else {
   231  		r.Children = append(r.Children, child)
   232  	}
   233  	r.ChildrenLoaded = true
   234  }
   235  
   236  func (r *Ref) RemoveChild(idx int) {
   237  	if idx < 0 {
   238  		return
   239  	}
   240  	r.Children = append(r.Children[:idx], r.Children[idx+1:]...)
   241  }
   242  
   243  func (fr *FileRef) GetFileMetaHash() string {
   244  	return fr.FileMetaHash
   245  }
   246  func (fr *FileRef) GetFileMetaHashData() string {
   247  	return fmt.Sprintf(
   248  		"%s:%d:%d:%s",
   249  		fr.Path, fr.Size,
   250  		fr.ActualFileSize, fr.ActualFileHash)
   251  }
   252  
   253  func (fr *FileRef) GetHashData() string {
   254  	return fmt.Sprintf(
   255  		"%s:%s:%s:%s:%d:%s:%s:%d:%s:%d:%s",
   256  		fr.AllocationID,
   257  		fr.Type, // don't need to add it as well
   258  		fr.Name, // don't see any utility as fr.Path below has name in it
   259  		fr.Path,
   260  		fr.Size,
   261  		fr.ValidationRoot,
   262  		fr.FixedMerkleRoot,
   263  		fr.ActualFileSize,
   264  		fr.ActualFileHash,
   265  		fr.ChunkSize,
   266  		fr.FileID,
   267  	)
   268  }
   269  
   270  func (fr *FileRef) GetHash() string {
   271  	return fr.Hash
   272  }
   273  
   274  func (fr *FileRef) CalculateHash() string {
   275  	fr.Hash = encryption.Hash(fr.GetHashData())
   276  	fr.FileMetaHash = encryption.Hash(fr.GetFileMetaHashData())
   277  	fr.NumBlocks = int64(math.Ceil(float64(fr.Size*1.0) / CHUNK_SIZE))
   278  	return fr.Hash
   279  }
   280  
   281  func (fr *FileRef) GetType() string {
   282  	return fr.Type
   283  }
   284  
   285  func (fr *FileRef) GetNumBlocks() int64 {
   286  	return fr.NumBlocks
   287  }
   288  
   289  func (fr *FileRef) GetSize() int64 {
   290  	return fr.Size
   291  }
   292  
   293  func (fr *FileRef) GetPathHash() string {
   294  	return fr.PathHash
   295  }
   296  
   297  func (fr *FileRef) GetLookupHash() string {
   298  	return fr.LookupHash
   299  }
   300  
   301  func (fr *FileRef) GetPath() string {
   302  	return fr.Path
   303  }
   304  
   305  func (fr *FileRef) GetName() string {
   306  	return fr.Name
   307  }
   308  
   309  func (fr *FileRef) GetFileID() string {
   310  	return fr.FileID
   311  }
   312  
   313  func (fr *FileRef) GetCreatedAt() common.Timestamp {
   314  	return fr.CreatedAt
   315  }
   316  
   317  func (fr *FileRef) GetUpdatedAt() common.Timestamp {
   318  	return fr.UpdatedAt
   319  }