...

Source file src/github.com/concurrency-8/parser/parser.go

Documentation: github.com/concurrency-8/parser

     1  package parser
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"io/ioutil"
     7  	"math"
     8  	"os"
     9  	"time"
    10  
    11  	"github.com/concurrency-8/args"
    12  	bencode "github.com/zeebo/bencode"
    13  )
    14  
    15  // BLOCK_LEN is length  of block
    16  var BLOCK_LEN = uint32(math.Pow(2, 14))
    17  
    18  //Parse parses from a stream and returns a pointer to a TorrentFile.
    19  func Parse(reader io.Reader) (TorrentFile, error) {
    20  	data, err := ioutil.ReadAll(reader)
    21  	//return an error if reading fails.
    22  	if err != nil {
    23  		return TorrentFile{}, err
    24  	}
    25  
    26  	metadata := &MetaData{}
    27  	err = bencode.DecodeBytes(data, metadata)
    28  	//return an error if decode fails.
    29  	if err != nil {
    30  		return TorrentFile{}, err
    31  	}
    32  
    33  	info := &InfoMetaData{}
    34  	err = bencode.DecodeBytes(metadata.Info, info)
    35  	//return an error if further decode fails.
    36  	if err != nil {
    37  		return TorrentFile{}, err
    38  	}
    39  	//This variable refers to the Total torrent size.
    40  	var Length uint64
    41  	files := make([]*File, 0)
    42  	// single file context
    43  	os.Mkdir(info.Name, os.ModePerm)
    44  	if info.Length > 0 {
    45  		var filePointer *os.File
    46  		if !args.ARGS.Resume {
    47  			filePointer, err = os.Create(info.Name + "/" + info.Name)
    48  		} else {
    49  			filePointer, err = os.OpenFile(info.Name+"/"+info.Name, os.O_APPEND|os.O_WRONLY, 0600)
    50  		}
    51  
    52  		if err != nil {
    53  			fmt.Println(err)
    54  			panic(err)
    55  		}
    56  		files = append(files, &File{
    57  			Path:        []string{info.Name},
    58  			Length:      info.Length,
    59  			FilePointer: filePointer,
    60  		})
    61  		Length = info.Length
    62  	} else {
    63  		//multiple files are present.
    64  		metadataFiles := make([]*FileMetaData, 0)
    65  		err = bencode.DecodeBytes(info.Files, &metadataFiles)
    66  		if err != nil {
    67  			return TorrentFile{}, err
    68  		}
    69  
    70  		for _, f := range metadataFiles {
    71  			var filePointer *os.File
    72  			if !args.ARGS.Resume {
    73  				filePointer, err = os.Create(info.Name + "/" + f.Path[0])
    74  			} else {
    75  				filePointer, err = os.OpenFile(info.Name+"/"+f.Path[0], os.O_APPEND|os.O_WRONLY, 0600)
    76  			}
    77  			if err != nil {
    78  				fmt.Println(err)
    79  				panic("Unable to create files ")
    80  			}
    81  			files = append(files, &File{
    82  				Path:        []string{info.Name + "/" + f.Path[0]},
    83  				Length:      f.Length,
    84  				FilePointer: filePointer,
    85  			})
    86  			Length += f.Length
    87  		}
    88  	}
    89  
    90  	//announces is the list of trackers.
    91  	announces := make([]string, 0)
    92  
    93  	if len(metadata.AnnounceList) > 0 {
    94  		for _, announceItem := range metadata.AnnounceList {
    95  			for _, announce := range announceItem {
    96  				announces = append(announces, announce)
    97  			}
    98  		}
    99  	} else {
   100  		announces = append(announces, metadata.Announce)
   101  	}
   102  
   103  	//return the object containing the metadata.
   104  	return TorrentFile{
   105  		Name:        info.Name,
   106  		Announce:    announces,
   107  		Comment:     metadata.Comment,
   108  		CreatedBy:   metadata.CreatedBy,
   109  		CreatedAt:   time.Unix(metadata.CreatedAt, 0),
   110  		InfoHash:    toSHA1(metadata.Info),
   111  		Length:      Length,
   112  		Files:       files,
   113  		PieceLength: info.PieceLength,
   114  		Piece:       info.Piece,
   115  	}, nil
   116  }
   117  
   118  //ParseFromFile parses a .torrent file.
   119  func ParseFromFile(path string) (TorrentFile, error) {
   120  	file, err := os.Open(path)
   121  	if err != nil {
   122  		return TorrentFile{}, err
   123  	}
   124  	//Close the file after returning automatically.
   125  	defer file.Close()
   126  
   127  	return Parse(file)
   128  }
   129  
   130  // PieceLen returns the length of ith piece of file
   131  func PieceLen(torrent TorrentFile, index uint32) (length uint32, err error) {
   132  	totalLength := torrent.Length
   133  	pieceLength := torrent.PieceLength
   134  	lastPieceLen := uint32(totalLength % uint64(pieceLength))
   135  	lastPieceIndex := uint32(len(torrent.Piece)/20 - 1)
   136  
   137  	if lastPieceLen == 0 {
   138  		lastPieceLen = pieceLength
   139  	}
   140  
   141  	if lastPieceIndex == index {
   142  		length = lastPieceLen
   143  	} else if lastPieceIndex > index {
   144  		length = pieceLength
   145  	} else {
   146  		err = fmt.Errorf("Piece Index out of range")
   147  	}
   148  	return
   149  }
   150  
   151  // BlocksPerPiece returns number of blocks in a ith piece
   152  func BlocksPerPiece(torrent TorrentFile, index uint32) (blocks uint32, err error) {
   153  	pieceLength, err := PieceLen(torrent, index)
   154  
   155  	if err != nil {
   156  		return
   157  	}
   158  	blocks = uint32(math.Ceil(float64(pieceLength) / float64(BLOCK_LEN)))
   159  	return
   160  }
   161  
   162  // BlockLen calculates length of ith block in jth piece
   163  func BlockLen(torrent TorrentFile, pieceIndex uint32, blockIndex uint32) (length uint32, err error) {
   164  	pieceLength, err := PieceLen(torrent, pieceIndex)
   165  
   166  	if err != nil {
   167  		return
   168  	}
   169  
   170  	lastBlockLength := pieceLength % BLOCK_LEN
   171  	lastBlockIndex := uint32(math.Ceil(float64(pieceLength)/float64(BLOCK_LEN))) - 1
   172  
   173  	if lastBlockLength == 0 {
   174  		lastBlockLength = BLOCK_LEN
   175  	}
   176  
   177  	if lastBlockIndex == blockIndex {
   178  		length = lastBlockLength
   179  	} else if lastBlockIndex > blockIndex {
   180  		length = BLOCK_LEN
   181  	} else {
   182  		err = fmt.Errorf("Block Index out of range")
   183  	}
   184  	return
   185  }
   186  

View as plain text