mirror of
https://github.com/GopeedLab/gopeed.git
synced 2026-11-06 16:40:32 +00:00
Refactor
This commit is contained in:
1 parent
075852b847
commit
adb7d89018
19 files changed
+415
-258
No files matched your search
+2
-2
@@ -2,8 +2,8 @@ package bt
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"gopeed/down/bt/metainfo"
|
||||
"gopeed/down/bt/torrent"
|
||||
"github.com/monkeyWie/gopeed/down/bt/metainfo"
|
||||
"github.com/monkeyWie/gopeed/down/bt/torrent"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
|
||||
@@ -39,8 +39,8 @@ type File struct {
|
||||
}
|
||||
|
||||
type ExtraInfo struct {
|
||||
InfoHash [20]byte
|
||||
FileSize uint64
|
||||
InfoHash [20]byte
|
||||
TotalSize uint64
|
||||
}
|
||||
|
||||
func ParseFromFile(path string) (*MetaInfo, error) {
|
||||
@@ -75,10 +75,22 @@ func ParseFromFile(path string) (*MetaInfo, error) {
|
||||
}
|
||||
}
|
||||
}
|
||||
metaInfo.FileSize = getTotalSize(&metaInfo)
|
||||
metaInfo.TotalSize = getTotalSize(&metaInfo)
|
||||
return &metaInfo, nil
|
||||
}
|
||||
|
||||
// 获取某个分片的大小
|
||||
func (metaInfo *MetaInfo) GetPieceSize(index int) uint64 {
|
||||
// 是否为最后一个分片
|
||||
if index == len(metaInfo.Info.Pieces)-1 {
|
||||
size := metaInfo.TotalSize % metaInfo.Info.PieceLength
|
||||
if size > 0 {
|
||||
return size
|
||||
}
|
||||
}
|
||||
return metaInfo.Info.PieceLength
|
||||
}
|
||||
|
||||
func getTotalSize(metaInfo *MetaInfo) uint64 {
|
||||
if metaInfo.Info != nil {
|
||||
if len(metaInfo.Info.Files) > 0 {
|
||||
|
||||
@@ -1,31 +1,52 @@
|
||||
package peer
|
||||
package message
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
)
|
||||
|
||||
type MessageID int
|
||||
// message ID
|
||||
type ID byte
|
||||
|
||||
const (
|
||||
Keepalive MessageID = -1
|
||||
Choke MessageID = 0
|
||||
Unchoke MessageID = 1
|
||||
Interested MessageID = 2
|
||||
NotInterested MessageID = 3
|
||||
Have MessageID = 4
|
||||
Bitfield MessageID = 5
|
||||
Request MessageID = 6
|
||||
Piece MessageID = 7
|
||||
Cancel MessageID = 8
|
||||
IdChoke ID = 0
|
||||
IdUnchoke ID = 1
|
||||
IdInterested ID = 2
|
||||
IdNotinterested ID = 3
|
||||
IdHave ID = 4
|
||||
IdBitfield ID = 5
|
||||
IdRequest ID = 6
|
||||
IdPiece ID = 7
|
||||
IdCancel ID = 8
|
||||
)
|
||||
|
||||
type Message struct {
|
||||
/*type Message struct {
|
||||
Length uint32
|
||||
ID MessageID
|
||||
Payload []byte
|
||||
}*/
|
||||
type Message struct {
|
||||
Length uint32
|
||||
ID ID
|
||||
}
|
||||
|
||||
func NewMessage(id MessageID, payload []byte) *Message {
|
||||
func (msg Message) Encode() []byte {
|
||||
buf := make([]byte, 5)
|
||||
binary.BigEndian.PutUint32(buf, msg.Length)
|
||||
buf[4] = byte(msg.ID)
|
||||
return buf
|
||||
}
|
||||
|
||||
func (msg Message) Decode(buf []byte) {
|
||||
msg.Length = binary.BigEndian.Uint32(buf)
|
||||
msg.ID = ID(buf[4])
|
||||
}
|
||||
|
||||
type Serialize interface {
|
||||
Encode() []byte
|
||||
Decode(buf []byte) Serialize
|
||||
}
|
||||
|
||||
/*func NewMessage(id MessageID, payload []byte) *Message {
|
||||
message := &Message{ID: id, Payload: payload}
|
||||
if id == Keepalive {
|
||||
message.Length = 0
|
||||
@@ -57,7 +78,7 @@ func (msg *Message) Decode(buf []byte) {
|
||||
msg.Payload = buf[5:]
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
// Message protocol
|
||||
// Length prefix| message ID | Payload
|
||||
@@ -73,39 +94,3 @@ func SplitMessage(data []byte, atEOF bool) (advance int, token []byte, err error
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type MsgBitfield []byte
|
||||
|
||||
// 某个分片是否下载完成
|
||||
func (mb MsgBitfield) IsComplete(i int) bool {
|
||||
bts := []byte(mb)
|
||||
index := i / 8
|
||||
if index >= len(bts) {
|
||||
return false
|
||||
}
|
||||
return bts[index]&(1<<uint(7-i%8)) > 0
|
||||
}
|
||||
|
||||
// 给定一组分片下载状态,计算出当前peer能提供下载的分片下标
|
||||
func (mb MsgBitfield) Have(pieces []bool) []int {
|
||||
arr := make([]int, 0)
|
||||
bts := []byte(mb)
|
||||
length := len(pieces) / 8
|
||||
if len(pieces)%8 != 0 {
|
||||
length++
|
||||
}
|
||||
|
||||
for i := 0; i < length; i++ {
|
||||
for j := 0; j < 8; j++ {
|
||||
index := i*8 + j
|
||||
// 如果此分片在本地还未下载,检查peer是否能提供该分片下载
|
||||
if index < len(pieces) &&
|
||||
!pieces[index] &&
|
||||
i < len(bts) &&
|
||||
uint(bts[i])&(1<<uint(7-j)) > 0 {
|
||||
arr = append(arr, index)
|
||||
}
|
||||
}
|
||||
}
|
||||
return arr
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package message
|
||||
|
||||
// bitfield: <len=0001+X><id=5><bitfield>
|
||||
type Bitfield struct {
|
||||
Message
|
||||
payload []byte
|
||||
}
|
||||
|
||||
func NewBitfield(payload []byte) *Bitfield {
|
||||
return &Bitfield{
|
||||
Message: Message{
|
||||
Length: uint32(len(payload) + 1),
|
||||
ID: IdBitfield,
|
||||
},
|
||||
payload: payload,
|
||||
}
|
||||
}
|
||||
|
||||
func (b *Bitfield) Encode() []byte {
|
||||
return append(b.Message.Encode(), b.payload...)
|
||||
}
|
||||
|
||||
func (b *Bitfield) Decode(buf []byte) Serialize {
|
||||
b.Message.Decode(buf)
|
||||
copy(b.payload, buf[5:])
|
||||
return b
|
||||
}
|
||||
|
||||
// 某个分片是否下载完成
|
||||
func (b *Bitfield) IsComplete(i int) bool {
|
||||
index := i / 8
|
||||
if index >= len(b.payload) {
|
||||
return false
|
||||
}
|
||||
return b.payload[index]&(1<<(7-i%8)) > 0
|
||||
}
|
||||
|
||||
// 给定一组分片下载状态,计算出当前peer能提供下载的分片下标
|
||||
func (b *Bitfield) Have(pieces []bool) []int {
|
||||
arr := make([]int, 0)
|
||||
length := len(pieces) / 8
|
||||
if len(pieces)%8 != 0 {
|
||||
length++
|
||||
}
|
||||
|
||||
for i := 0; i < length; i++ {
|
||||
for j := 0; j < 8; j++ {
|
||||
index := i*8 + j
|
||||
// 如果此分片在本地还未下载,检查peer是否能提供该分片下载
|
||||
if index < len(pieces) &&
|
||||
!pieces[index] &&
|
||||
i < len(b.payload) &&
|
||||
b.payload[i]&(1<<(7-j)) > 0 {
|
||||
arr = append(arr, index)
|
||||
}
|
||||
}
|
||||
}
|
||||
return arr
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package message
|
||||
|
||||
// choke: <len=0001><id=0>
|
||||
type Choke struct {
|
||||
Message
|
||||
}
|
||||
|
||||
func NewChoke() *Choke {
|
||||
return &Choke{
|
||||
Message{
|
||||
Length: 1,
|
||||
ID: IdChoke,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Choke) Encode() []byte {
|
||||
return c.Message.Encode()
|
||||
}
|
||||
|
||||
func (c *Choke) Decode(buf []byte) Serialize {
|
||||
c.Message.Decode(buf)
|
||||
return c
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package message
|
||||
|
||||
// choke: <len=0001><id=0>
|
||||
type Interested struct {
|
||||
Message
|
||||
}
|
||||
|
||||
func NewInterested() *Interested {
|
||||
return &Interested{
|
||||
Message{
|
||||
Length: 1,
|
||||
ID: IdInterested,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Interested) Encode() []byte {
|
||||
return c.Message.Encode()
|
||||
}
|
||||
|
||||
func (c *Interested) Decode(buf []byte) Serialize {
|
||||
c.Message.Decode(buf)
|
||||
return c
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package message
|
||||
|
||||
// keep-alive: <len=0000>
|
||||
type Keepalive struct{}
|
||||
|
||||
func (k *Keepalive) Encode() []byte {
|
||||
return []byte{0, 0, 0, 0}
|
||||
}
|
||||
|
||||
func (k *Keepalive) Decode(buf []byte) Serialize {
|
||||
return &Keepalive{}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package message
|
||||
|
||||
// choke: <len=0001><id=0>
|
||||
type NotInterested struct {
|
||||
Message
|
||||
}
|
||||
|
||||
func NewNotInterested() *NotInterested {
|
||||
return &NotInterested{
|
||||
Message{
|
||||
Length: 1,
|
||||
ID: IdNotinterested,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (ni *NotInterested) Encode() []byte {
|
||||
return ni.Message.Encode()
|
||||
}
|
||||
|
||||
func (ni *NotInterested) Decode(buf []byte) Serialize {
|
||||
ni.Message.Decode(buf)
|
||||
return ni
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package message
|
||||
|
||||
import "io"
|
||||
|
||||
// piece: <len=0009+X><id=7><index><begin><block>
|
||||
type Piece struct {
|
||||
Message
|
||||
Index uint32
|
||||
Begin uint32
|
||||
Block io.Reader
|
||||
}
|
||||
|
||||
func newPiece(index uint32, begin uint32, reader io.Reader, length uint32) *Piece {
|
||||
return &Piece{
|
||||
Message: Message{
|
||||
Length: 9 + length,
|
||||
ID: IdPiece,
|
||||
},
|
||||
Index: index,
|
||||
Begin: begin,
|
||||
Block: io.LimitReader(reader, int64(length)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package message
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
)
|
||||
|
||||
// request: <len=0013><id=6><index><begin><length>
|
||||
type Request struct {
|
||||
Message
|
||||
Index uint32
|
||||
Begin uint32
|
||||
Length uint32
|
||||
}
|
||||
|
||||
func NewRequest(index uint32, begin uint32, length uint32) *Request {
|
||||
return &Request{
|
||||
Message: Message{
|
||||
Length: 13,
|
||||
ID: IdRequest,
|
||||
},
|
||||
Index: index,
|
||||
Begin: begin,
|
||||
Length: length,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Request) Encode() []byte {
|
||||
buf := make([]byte, 12)
|
||||
binary.BigEndian.PutUint32(buf[:4], r.Index)
|
||||
binary.BigEndian.PutUint32(buf[4:8], r.Begin)
|
||||
binary.BigEndian.PutUint32(buf[8:], r.Length)
|
||||
return append(r.Message.Encode(), buf...)
|
||||
}
|
||||
|
||||
func (r *Request) Decode(buf []byte) Serialize {
|
||||
r.Message.Decode(buf)
|
||||
r.Length = binary.BigEndian.Uint32(buf[5:9])
|
||||
r.Begin = binary.BigEndian.Uint32(buf[9:13])
|
||||
r.Index = binary.BigEndian.Uint32(buf[13:17])
|
||||
return r
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package message
|
||||
|
||||
// unchoke: <len=0001><id=1>
|
||||
type Unchoke struct {
|
||||
Message
|
||||
}
|
||||
|
||||
func NewUnchoke() *Unchoke {
|
||||
return &Unchoke{
|
||||
Message{
|
||||
Length: 1,
|
||||
ID: IdUnchoke,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (u *Unchoke) Encode() []byte {
|
||||
return u.Message.Encode()
|
||||
}
|
||||
|
||||
func (u *Unchoke) Decode(buf []byte) Serialize {
|
||||
u.Message.Decode(buf)
|
||||
return u
|
||||
}
|
||||
@@ -1,138 +0,0 @@
|
||||
package peer
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestMsgBitfield_IsComplete(t *testing.T) {
|
||||
type args struct {
|
||||
i int
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
mb MsgBitfield
|
||||
args args
|
||||
want bool
|
||||
}{
|
||||
{
|
||||
"case-0",
|
||||
MsgBitfield([]byte{convertByte("10000000")}),
|
||||
args{
|
||||
0,
|
||||
},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"case-1",
|
||||
MsgBitfield([]byte{convertByte("01000000")}),
|
||||
args{
|
||||
1,
|
||||
},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"case-2",
|
||||
MsgBitfield([]byte{convertByte("00000000")}),
|
||||
args{
|
||||
2,
|
||||
},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"case-10",
|
||||
MsgBitfield([]byte{convertByte("00000000"), convertByte("00100000")}),
|
||||
args{
|
||||
10,
|
||||
},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"case-11",
|
||||
MsgBitfield([]byte{convertByte("00000000"), convertByte("00100000")}),
|
||||
args{
|
||||
11,
|
||||
},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"case-20",
|
||||
MsgBitfield([]byte{convertByte("00000000"), convertByte("00100000")}),
|
||||
args{
|
||||
20,
|
||||
},
|
||||
false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := tt.mb.IsComplete(tt.args.i); got != tt.want {
|
||||
t.Errorf("MsgBitfield.get() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMsgBitfield_Have(t *testing.T) {
|
||||
type args struct {
|
||||
pieces []bool
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
mb MsgBitfield
|
||||
args args
|
||||
want []int
|
||||
}{
|
||||
{
|
||||
"case-1",
|
||||
MsgBitfield([]byte{convertByte("11111111"), convertByte("00000000")}),
|
||||
args{
|
||||
[]bool{false, false, false, false, false, false, false, false},
|
||||
},
|
||||
[]int{0, 1, 2, 3, 4, 5, 6, 7},
|
||||
},
|
||||
{
|
||||
"case-2",
|
||||
MsgBitfield([]byte{convertByte("01010101"), convertByte("01000000")}),
|
||||
args{
|
||||
[]bool{false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false},
|
||||
},
|
||||
[]int{1, 3, 5, 7, 9},
|
||||
},
|
||||
{
|
||||
"case-3",
|
||||
MsgBitfield([]byte{convertByte("11010101"), convertByte("01000000")}),
|
||||
args{
|
||||
[]bool{false, true, false},
|
||||
},
|
||||
[]int{0},
|
||||
},
|
||||
{
|
||||
"case-4",
|
||||
MsgBitfield([]byte{convertByte("11010101")}),
|
||||
args{
|
||||
[]bool{false, true, false, false, true, false, false, true, false},
|
||||
},
|
||||
[]int{0, 3, 5},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := tt.mb.Have(tt.args.pieces); !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("MsgBitfield.Have() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMsg(t *testing.T) {
|
||||
fmt.Println(Choke)
|
||||
fmt.Println(Bitfield)
|
||||
}
|
||||
|
||||
func convertByte(bit string) byte {
|
||||
i, _ := strconv.ParseUint(bit, 2, 8)
|
||||
return byte(i)
|
||||
}
|
||||
@@ -5,8 +5,10 @@ import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"github.com/cenkalti/mse"
|
||||
"gopeed/down/bt/peer"
|
||||
"github.com/monkeyWie/gopeed/down/bt/peer"
|
||||
"github.com/monkeyWie/gopeed/down/bt/peer/message"
|
||||
"io"
|
||||
"math"
|
||||
"net"
|
||||
)
|
||||
|
||||
@@ -23,7 +25,8 @@ type peerState struct {
|
||||
// peer is interested in this client
|
||||
peerInterested bool
|
||||
|
||||
bitfield peer.MsgBitfield
|
||||
writeMsgCh chan []byte
|
||||
bitfield *message.Bitfield
|
||||
}
|
||||
|
||||
// 使用MSE加密来避免运营商对bt流量的封锁,基本上现在市面上BT客户端都默认开启了,不用MSE的话很多Peer拒绝连接
|
||||
@@ -81,38 +84,50 @@ func (ps *peerState) handshake() (*peer.Handshake, error) {
|
||||
}
|
||||
|
||||
func (ps *peerState) download() error {
|
||||
// 异步写,防止读取阻塞
|
||||
ps.writeMsgCh = make(chan []byte, 64)
|
||||
go func() {
|
||||
for buf := range ps.writeMsgCh {
|
||||
_, err := ps.conn.Write(buf)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
ps.conn.Close()
|
||||
}
|
||||
}
|
||||
}()
|
||||
scanner := bufio.NewScanner(ps.conn)
|
||||
scanner.Split(peer.SplitMessage)
|
||||
scanner.Split(message.SplitMessage)
|
||||
for scanner.Scan() {
|
||||
buf := scanner.Bytes()
|
||||
message := &peer.Message{}
|
||||
message.Decode(buf)
|
||||
switch message.ID {
|
||||
case peer.Keepalive:
|
||||
break
|
||||
case peer.Choke:
|
||||
ps.peerChoking = true
|
||||
break
|
||||
case peer.Unchoke:
|
||||
ps.handleUnchoke()
|
||||
break
|
||||
case peer.Interested:
|
||||
ps.peerInterested = true
|
||||
break
|
||||
case peer.NotInterested:
|
||||
ps.peerInterested = false
|
||||
break
|
||||
case peer.Have:
|
||||
break
|
||||
case peer.Bitfield:
|
||||
ps.handleBitfield(message.Payload)
|
||||
break
|
||||
case peer.Request:
|
||||
break
|
||||
case peer.Piece:
|
||||
break
|
||||
case peer.Cancel:
|
||||
break
|
||||
length := binary.BigEndian.Uint32(buf[:4])
|
||||
if length == 0 {
|
||||
// keepalive
|
||||
} else {
|
||||
messageID := message.ID(buf[4])
|
||||
payload := buf[5:]
|
||||
switch messageID {
|
||||
case message.IdChoke:
|
||||
break
|
||||
case message.IdUnchoke:
|
||||
ps.handleUnchoke()
|
||||
break
|
||||
case message.IdInterested:
|
||||
break
|
||||
case message.IdNotinterested:
|
||||
break
|
||||
case message.IdHave:
|
||||
break
|
||||
case message.IdBitfield:
|
||||
ps.handleBitfield(payload)
|
||||
break
|
||||
case message.IdRequest:
|
||||
break
|
||||
case message.IdPiece:
|
||||
ps.handlePiece()
|
||||
break
|
||||
case message.IdCancel:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
@@ -124,16 +139,19 @@ func (ps *peerState) handleUnchoke() {
|
||||
if ps.amInterested {
|
||||
have := ps.getHavePieces(ps.bitfield)
|
||||
if len(have) > 0 {
|
||||
for i := range have {
|
||||
buf := make([]byte, 12)
|
||||
binary.BigEndian.PutUint32(buf[:4], uint32(have[i]))
|
||||
binary.BigEndian.PutUint32(buf[4:8], 0)
|
||||
binary.BigEndian.PutUint32(buf[8:], 2<<13)
|
||||
_, err := ps.conn.Write(peer.NewMessage(peer.Request, buf).Encode())
|
||||
if err != nil {
|
||||
ps.conn.Close()
|
||||
return
|
||||
// 获取分片的长度
|
||||
for _, index := range have {
|
||||
pieceLength := ps.torrent.MetaInfo.GetPieceSize(index)
|
||||
lastOffset := uint64(0)
|
||||
// 按块下载分片
|
||||
for lastOffset < pieceLength {
|
||||
blockLength := math.Min(2<<13, float64(pieceLength-lastOffset))
|
||||
ps.write(message.NewRequest(uint32(index), uint32(lastOffset), uint32(blockLength)).Encode())
|
||||
lastOffset += uint64(blockLength)
|
||||
fmt.Println("request piece")
|
||||
}
|
||||
// TODO 测试代码
|
||||
break
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -142,32 +160,50 @@ func (ps *peerState) handleUnchoke() {
|
||||
}
|
||||
|
||||
func (ps *peerState) handleBitfield(payload []byte) {
|
||||
ps.bitfield = payload
|
||||
ps.bitfield = message.NewBitfield(payload)
|
||||
have := ps.getHavePieces(ps.bitfield)
|
||||
if len(have) > 0 {
|
||||
// 表示对该peer感兴趣,并且不choked该peer
|
||||
_, err := ps.conn.Write(peer.NewMessage(peer.Interested, []byte{}).Encode())
|
||||
if err != nil {
|
||||
ps.conn.Close()
|
||||
return
|
||||
}
|
||||
ps.write(message.NewInterested().Encode())
|
||||
ps.amInterested = true
|
||||
_, err = ps.conn.Write(peer.NewMessage(peer.Unchoke, []byte{}).Encode())
|
||||
if err != nil {
|
||||
ps.conn.Close()
|
||||
return
|
||||
}
|
||||
|
||||
ps.write(message.NewUnchoke().Encode())
|
||||
ps.amChoking = false
|
||||
} else {
|
||||
ps.conn.Close()
|
||||
}
|
||||
}
|
||||
|
||||
// 处理分片下载响应
|
||||
func (ps *peerState) handlePiece() {
|
||||
fmt.Println("one piece")
|
||||
}
|
||||
|
||||
// 获取peer能提供需要下载的文件分片
|
||||
func (ps *peerState) getHavePieces(bitfield peer.MsgBitfield) []int {
|
||||
func (ps *peerState) getHavePieces(bitfield *message.Bitfield) []int {
|
||||
states := make([]bool, len(ps.torrent.PieceState))
|
||||
for i := range states {
|
||||
states[i] = ps.torrent.PieceState[i].complete
|
||||
}
|
||||
return bitfield.Have(states)
|
||||
}
|
||||
|
||||
// 异步写入数据
|
||||
func (ps *peerState) write(buf []byte) {
|
||||
ps.writeMsgCh <- buf
|
||||
}
|
||||
|
||||
// 获取要写入到的文件
|
||||
/*func (ps *peerState) getWriteFile(request *message.Request) string {
|
||||
info := ps.torrent.MetaInfo.Info
|
||||
// 单文件
|
||||
if len(info.Files) == 0 {
|
||||
return info.Name
|
||||
} else {
|
||||
request.Index * info.PieceLength + be
|
||||
for i := 0; i < len(info.Files); i++ {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
@@ -2,9 +2,9 @@ package torrent
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"gopeed/down/bt/metainfo"
|
||||
"gopeed/down/bt/peer"
|
||||
"gopeed/down/bt/tracker"
|
||||
"github.com/monkeyWie/gopeed/down/bt/metainfo"
|
||||
"github.com/monkeyWie/gopeed/down/bt/peer"
|
||||
"github.com/monkeyWie/gopeed/down/bt/tracker"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@@ -31,6 +31,8 @@ func Test_peerState_download(t *testing.T) {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println("handshake end")
|
||||
|
||||
// 开始下载
|
||||
err = ps.download()
|
||||
|
||||
@@ -77,3 +79,7 @@ func peerTest(torrent *Torrent, peer *peer.Peer, ch chan *peerState) {
|
||||
}
|
||||
ch <- ps
|
||||
}
|
||||
|
||||
func TestSome(t *testing.T) {
|
||||
fmt.Println(11)
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
package torrent
|
||||
|
||||
import (
|
||||
"gopeed/down/bt/metainfo"
|
||||
"github.com/monkeyWie/gopeed/down/bt/metainfo"
|
||||
)
|
||||
|
||||
type Torrent struct {
|
||||
|
||||
@@ -4,8 +4,8 @@ import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"gopeed/down/bt/metainfo"
|
||||
"gopeed/down/bt/peer"
|
||||
"github.com/monkeyWie/gopeed/down/bt/metainfo"
|
||||
"github.com/monkeyWie/gopeed/down/bt/peer"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math"
|
||||
@@ -208,7 +208,7 @@ func (tracker *Tracker) announce(conn *net.UDPConn, timeout int64, connectionId
|
||||
request.peerID = tracker.PeerID
|
||||
request.downloaded = 0
|
||||
request.uploaded = 0
|
||||
request.left = tracker.MetaInfo.FileSize - request.downloaded
|
||||
request.left = tracker.MetaInfo.TotalSize - request.downloaded
|
||||
request.event = 0
|
||||
request.ip = 0
|
||||
request.key = 0
|
||||
@@ -287,7 +287,7 @@ func (tracker *Tracker) httpTracker(url *url.URL) (peers []peer.Peer, err error)
|
||||
query.Add("port", "6882")
|
||||
query.Add("uploaded", "0")
|
||||
query.Add("downloaded", "0")
|
||||
query.Add("left", strconv.FormatInt(int64(metaInfo.FileSize), 10))
|
||||
query.Add("left", strconv.FormatInt(int64(metaInfo.TotalSize), 10))
|
||||
url.RawQuery = query.Encode()
|
||||
request, err := http.NewRequest("GET", url.String(), nil)
|
||||
if err != nil {
|
||||
|
||||
@@ -2,7 +2,7 @@ package tracker
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"gopeed/down/bt/metainfo"
|
||||
"github.com/monkeyWie/gopeed/down/bt/metainfo"
|
||||
"testing"
|
||||
)
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
module gopeed
|
||||
module github.com/monkeyWie/gopeed
|
||||
|
||||
go 1.12
|
||||
go 1.13
|
||||
|
||||
require (
|
||||
github.com/cenkalti/mse v0.0.0-20140930130441-6ef65f170972
|
||||
|
||||
@@ -2,7 +2,11 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"gopeed/down/http"
|
||||
"github.com/monkeyWie/gopeed/down/bt/metainfo"
|
||||
"github.com/monkeyWie/gopeed/down/bt/peer"
|
||||
"github.com/monkeyWie/gopeed/down/bt/torrent"
|
||||
"github.com/monkeyWie/gopeed/down/bt/tracker"
|
||||
"github.com/monkeyWie/gopeed/down/http"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -20,5 +24,26 @@ func main() {
|
||||
}
|
||||
got, _ := http.Resolve(request)
|
||||
fmt.Println(got)
|
||||
getUsablePeer()
|
||||
// webview.Open("Minimal webview example", "https://www.baidu.com", 800, 600, true)
|
||||
}
|
||||
|
||||
func buildTorrent() *torrent.Torrent {
|
||||
metaInfo, err := metainfo.ParseFromFile("../testdata/Game.of.Thrones.S08E05.720p.WEB.H264-MEMENTO.torrent")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
metaInfo.Announce = "udp://tracker.opentrackr.org:1337/announce"
|
||||
metaInfo.AnnounceList = [][]string{}
|
||||
return torrent.NewTorrent(peer.GenPeerID(), metaInfo)
|
||||
}
|
||||
|
||||
// 获取一个能连接上的peer
|
||||
func getUsablePeer() {
|
||||
torrent := buildTorrent()
|
||||
tracker := &tracker.Tracker{
|
||||
PeerID: torrent.PeerID,
|
||||
MetaInfo: torrent.MetaInfo,
|
||||
}
|
||||
tracker.Tracker()
|
||||
}
|
||||
Reference in new issue
Block a user