go-bt/torrent/file.go
2014-08-14 15:19:42 -04:00

115 lines
3.1 KiB
Go

package torrent
import (
//"github.com/vbatts/go-bt/bencode"
"crypto/sha1"
)
/*
map[string]interface {}{"announce":"http://torrent.fedoraproject.org:6969/announce", "creation date":1387244350, "info":map[string]interface {}{"files":[]interface {}{map[string]interface {}{"length":1125, "path":[]interface {}{"Fedora-20-x86_64-CHECKSUM"}}, map[string]interface {}{"length":4603248640, "path":[]interface {}{"Fedora-20-x86_64-DVD.iso"}}}, "name":"Fedora-20-x86_64-DVD", "piece length":262144, "pieces":"m\x
*/
type File struct {
// URL of a main tracker
Announce string `bencode:"announce"`
// Epoch of the creation of this torrent
CreationDate int64 `bencode:"creation date"`
// Dictionary about this torrent, including files to be tracked
Info TorrentFileInfo `bencode:"info"`
}
type TorrentFileInfo struct {
// suggested file/directory name where the file(s) are to be saved
Name string `bencode:"name"`
// hash list of joined SHA1 sums (160-bit length)
Pieces string `bencode:"pieces"`
// number of bytes per piece
PieceLength int64 `bencode:"piece length"`
// size of the file in bytes (only if this torrent is for a single file)
Length int64 `bencode:"length"`
// list of information about the files
Files []FileInfo `bencode:"files"`
}
func (tfi TorrentFileInfo) PiecesList() []string {
pieces := []string{}
for i := 0; i < (len(tfi.Pieces) / sha1.Size); i++ {
pieces = append(pieces, tfi.Pieces[i*sha1.Size:(i+1)*sha1.Size])
}
return pieces
}
type FileInfo struct {
// size of file in bytes
Length int64 `bencode:"length"`
// list of strings corresponding to subdirectory names, the last of which is the actual file name
Path []string `bencode:"path"`
}
type torrentError struct {
Msg string
}
func (te torrentError) Error() string {
return te.Msg
}
var (
ErrNotProperDataInterface = torrentError{"data does not look like map[string]interface{}"}
)
func DecocdeTorrentData(data interface{}) (*File, error) {
m, ok := data.(map[string]interface{})
if !ok {
return nil, ErrNotProperDataInterface
}
announce := m["announce"].(string)
creationDate := m["creation date"].(int64)
info := m["info"].(map[string]interface{})
pieceLength := info["piece length"].(int64)
pieces := info["pieces"].(string)
infoName := info["name"].(string)
isSingleFileTorrent := true
infoFiles, ok := info["files"].([]interface{})
if ok {
isSingleFileTorrent = false
}
infoLength := int64(0)
if isSingleFileTorrent {
infoLength = info["length"].(int64)
}
files := []FileInfo{}
if !isSingleFileTorrent {
for _, fileInterface := range infoFiles {
fileInfo := fileInterface.(map[string]interface{})
paths := []string{}
for _, path := range fileInfo["path"].([]interface{}) {
paths = append(paths, path.(string))
}
files = append(files, FileInfo{
Length: fileInfo["length"].(int64),
Path: paths,
})
}
}
return &File{
Announce: announce,
CreationDate: creationDate,
Info: TorrentFileInfo{
Name: infoName,
Length: infoLength,
Pieces: pieces,
PieceLength: pieceLength,
Files: files,
},
}, nil
}