Repository navigation
Expand file tree
/
Copy pathmeta.go
More file actions
133 lines (116 loc) · 3.11 KB
/
Copy pathmeta.go
File metadata and controls
133 lines (116 loc) · 3.11 KB
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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
package bittorrent
import (
"bytes"
"crypto/sha1"
"errors"
"io"
"net"
"github.com/zeebo/bencode"
)
type Metainfo struct {
Announce string
CreationDate uint64
Comment string
CreatedBy string
Encoding string
Info InfoDictionary
}
type metainfo struct {
Announce string `bencode:"announce"`
CreationDate uint64 `bencode:"creation date"`
Comment string `bencode:"comment"`
CreatedBy string `bencode:"created by"`
Encoding string `bencode:"encoding"`
Info bencode.RawMessage `bencode:"info"`
}
type InfoDictionary struct {
PieceLength int64 `bencode:"piece length"`
Pieces []byte `bencode:"pieces"`
Private bool `bencode:"private"`
Name string `bencode:"name"`
// Single file Mode
Length int64 `bencode:"length"`
// Multi File Mode
Files []InfoFile `bencode:"files"`
}
type InfoFile struct {
Length int64 `bencode:"length"`
Path []string `bencode:"path"`
}
type TrackerRequest struct {
InfoHash [20]byte
PeerID [20]byte
IP string
Port int
Uploaded int
Downloaded int
Left int
Event string
}
type TrackerResponse struct {
FailureReason string `bencode:"failure reason"`
Interval int `bencode:"interval"`
TrackerID string `bencode:"tracker id"`
Complete int `bencode:"complete"`
Incomplete int `bencode:"incomplete"`
Peers PeerInfos `bencode:"peers"`
}
type PeerInfos []PeerInfo
func (pi *PeerInfos) UnmarshalBencode(b []byte) error {
if b[0] == 'l' {
// list of dicts
return bencode.DecodeBytes(b, (*[]PeerInfo)(pi))
} else if b[0] >= '0' || b[0] <= '9' {
// compact encoding
var s string
if err := bencode.DecodeBytes(b, &s); err != nil {
return err
}
if len(s)%6 != 0 {
return errors.New("malformed compact peer list encoding")
}
for len(s) > 0 {
ip := net.IPv4(s[0], s[1], s[2], s[3])
port := int(s[4])<<8 | int(s[5])
*pi = append(*pi, PeerInfo{IP: ip.String(), Port: port})
s = s[6:]
}
} else {
return errors.New("unsupported peer list encoding")
}
return nil
}
type PeerInfo struct {
PeerID string `bencode:"peer id"`
IP string `bencode:"ip"`
Port int `bencode:"port"`
}
type ScrapeResponse struct {
Files map[string]ScrapeFile `bencode:"files"`
}
type ScrapeFile struct {
// Number of seeders
Complete int `bencode:"complete"`
// Number of times this torrent has been downloaded fully
Downloaded int `bencode:"downloaded"`
// Number of leechers
Incomplete int `bencode:"incomplete"`
// The torrent's name
Name string `bencode:"name"`
}
func ParseMetainfo(r io.Reader) (*Metainfo, [20]byte, error) {
var minfo metainfo
if err := bencode.NewDecoder(r).Decode(&minfo); err != nil {
return nil, [20]byte{}, err
}
hash := sha1.Sum([]byte(minfo.Info))
out := &Metainfo{
Announce: minfo.Announce,
CreationDate: minfo.CreationDate,
Comment: minfo.Comment,
CreatedBy: minfo.CreatedBy,
Encoding: minfo.Encoding,
}
err := bencode.NewDecoder(bytes.NewReader([]byte(minfo.Info))).Decode(&out.Info)
return out, hash, err
}