github.com/bhojpur/cache@v0.0.4/pkg/file/types/file.go (about)

     1  package types
     2  
     3  // Copyright (c) 2018 Bhojpur Consulting Private Limited, India. All rights reserved.
     4  
     5  // Permission is hereby granted, free of charge, to any person obtaining a copy
     6  // of this software and associated documentation files (the "Software"), to deal
     7  // in the Software without restriction, including without limitation the rights
     8  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     9  // copies of the Software, and to permit persons to whom the Software is
    10  // furnished to do so, subject to the following conditions:
    11  
    12  // The above copyright notice and this permission notice shall be included in
    13  // all copies or substantial portions of the Software.
    14  
    15  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    16  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    17  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    18  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    19  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    20  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    21  // THE SOFTWARE.
    22  
    23  import (
    24  	"encoding/json"
    25  	"errors"
    26  	"os"
    27  
    28  	"github.com/bhojpur/cache/pkg/file/crypto"
    29  	"github.com/bhojpur/cache/pkg/file/models"
    30  )
    31  
    32  var (
    33  	// ErrNilFilename is returned when the fileame to construct a new file is nil.
    34  	ErrNilFilename = errors.New("filename to construct file must not be nil")
    35  
    36  	// ErrNilShardCount is returned when the shard counnt to cosntruct a new file is nil.
    37  	ErrNilShardCount = errors.New("shard count to cosntruct file must not be nil")
    38  
    39  	// ErrNilFileSize is returned when the file size to construct a new file is nil.
    40  	ErrNilFileSize = errors.New("file size to construct file must not be nil")
    41  )
    42  
    43  // File contains the (important) metadata of a file stored in a database.
    44  type File struct {
    45  	Filename   string      `json:"filename"`    // The file's filename
    46  	ShardCount int         `json:"shard_count"` // The number of shards hosting the file
    47  	Size       uint32      `json:"size"`        // Total size of the file
    48  	ShardDB    *shardDB    `json:"shard_db"`    // Pointer to this file's shardDb
    49  	Hash       crypto.Hash `json:"hash"`        // The hash of the file
    50  }
    51  
    52  // NewFile constructs a new file from a file in memory.
    53  func NewFile(filename string) (*File, error) {
    54  	// Check that the filename is not nil
    55  	if filename == "" {
    56  		return nil, ErrNilFilename
    57  	}
    58  
    59  	// Open the file
    60  	f, err := os.Open(filename)
    61  	if err != nil {
    62  		return nil, err
    63  	}
    64  	defer f.Close()
    65  
    66  	// Get the file length and bytes
    67  	fileStat, err := f.Stat()
    68  	if err != nil {
    69  		return nil, err
    70  	}
    71  	size := uint32(fileStat.Size())
    72  	if size == 0 {
    73  		return nil, ErrNilFileSize
    74  	}
    75  
    76  	// Read from the file
    77  	bytes := make([]byte, size)
    78  	_, err = f.Read(bytes)
    79  	if err != nil {
    80  		return nil, err
    81  	}
    82  
    83  	shardCount := models.ShardCount
    84  
    85  	// Create a new file pointer
    86  	file := &File{
    87  		Filename:   filename,   // The filename
    88  		ShardCount: shardCount, // The total amount of shards hostinng the file
    89  		Size:       size,       // The total size of the file
    90  		ShardDB:    nil,        // nil for now
    91  	}
    92  
    93  	// Compute the hash of the file
    94  	(*file).Hash = crypto.Sha3(file.Bytes())
    95  	return file, nil
    96  }
    97  
    98  // FileFromBytes constructs a *File from a []byte.
    99  func FileFromBytes(b []byte) (*File, error) {
   100  	if b == nil {
   101  		return nil, errors.New("cannot construct file from nil []byte")
   102  	}
   103  	buffer := &File{}                // Init buffer
   104  	err := json.Unmarshal(b, buffer) // Unmarshal json
   105  	return buffer, err
   106  }
   107  
   108  /* ----- BEGIN HELPER FUNCTIONS ----- */
   109  
   110  // Bytes converts the database header to bytes.
   111  func (file *File) Bytes() []byte {
   112  	json, _ := json.MarshalIndent(*file, "", "  ")
   113  	return json
   114  }
   115  
   116  // String converts the database to a string.
   117  func (file *File) String() string {
   118  	json, _ := json.MarshalIndent(*file, "", "  ")
   119  	return string(json)
   120  }
   121  
   122  /* ----- END HELPER FUNCTIONS ----- */