-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathtorrent.go
99 lines (87 loc) · 2.03 KB
/
torrent.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
package metadata
import (
"encoding/hex"
"errors"
"github.com/IncSW/go-bencode"
)
// ErrInvalidMetadata ...
var ErrInvalidMetadata = errors.New("invalid metadata")
// Torrent ...
type Torrent struct {
raw interface{}
Announce string
Info TorrentInfo
}
// Bytes torrent file bytes.
func (torrent *Torrent) Bytes() []byte {
b, err := bencode.Marshal(torrent.raw)
if err != nil {
panic(err)
}
return b
}
// TorrentInfo ...
type TorrentInfo struct {
Files []TorrentSubFile
Length int64
Name string
PieceLength int64
Pieces string
}
// TorrentSubFile ...
type TorrentSubFile struct {
Length int64
Path string
}
// NewTorrentFrom ...
func NewTorrentFromMetadata(b []byte, torrent *Torrent) error {
metadata, err := bencode.Unmarshal(b)
if err != nil {
return err
}
torrent.raw = map[string]interface{}{
"info": metadata,
}
m, ok := torrent.raw.(map[string]interface{})
if !ok {
return ErrInvalidMetadata
}
if announce, ok := m["announce"].([]byte); ok {
torrent.Announce = string(announce)
}
if info, ok := m["info"].(map[string]interface{}); ok {
tinfo := TorrentInfo{}
// name of root file or folder
if name, ok := info["name"].([]byte); ok {
tinfo.Name = string(name)
}
// size of per piece
if pieceLength, ok := info["piece length"].(int64); ok {
tinfo.PieceLength = pieceLength
}
// piece's SHA-1 hash
if pieces, ok := info["pieces"].([]byte); ok {
tinfo.Pieces = hex.EncodeToString(pieces)
}
// sub files
if files, ok := info["files"].([]interface{}); ok {
fileNum := len(files)
tfiles := make([]TorrentSubFile, 0, fileNum)
for i := 0; i < fileNum; i++ {
if file, ok := files[i].(map[string]interface{}); ok {
tfile := TorrentSubFile{}
if length, ok := file["length"].(int64); ok {
tfile.Length = length
}
if path, ok := file["path"].([]interface{}); ok {
tfile.Path = string(path[0].([]byte))
tfiles = append(tfiles, tfile)
}
}
}
tinfo.Files = tfiles
}
torrent.Info = tinfo
}
return nil
}