115 lines
3 KiB
Go
115 lines
3 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 "announce"
|
||
|
|
||
|
// Epoch of the creation of this torrent
|
||
|
CreationDate int64 "creation date"
|
||
|
|
||
|
// Dictionary about this torrent, including files to be tracked
|
||
|
Info TorrentFileInfo "info"
|
||
|
}
|
||
|
|
||
|
type TorrentFileInfo struct {
|
||
|
// suggested file/directory name where the file(s) are to be saved
|
||
|
Name string "name"
|
||
|
|
||
|
// hash list of joined SHA1 sums (160-bit length)
|
||
|
Pieces string "pieces"
|
||
|
|
||
|
// number of bytes per piece
|
||
|
PieceLength int64 "piece length"
|
||
|
|
||
|
// size of the file in bytes (only if this torrent is for a single file)
|
||
|
Length int64 "length"
|
||
|
|
||
|
// list of information about the files
|
||
|
Files []FileInfo "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 "length"
|
||
|
|
||
|
// list of strings corresponding to subdirectory names, the last of which is the actual file name
|
||
|
Path []string "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
|
||
|
}
|