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 }