Skip to content

Commit

Permalink
feat(tracker): request peers
Browse files Browse the repository at this point in the history
  • Loading branch information
BrianLusina committed Jul 19, 2022
1 parent 7513323 commit f38bf5a
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 25 deletions.
33 changes: 33 additions & 0 deletions pkg/torrentfile/torrentfile.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
package torrentfile

import (
"net/http"
"net/url"
"strconv"
"time"

"github.com/brianlusina/tclient/pkg/peers"
"github.com/jackpal/bencode-go"
)

// Port to listen on
Expand All @@ -18,6 +23,11 @@ type TorrentFile struct {
Name string
}

type bencodeTrackerResp struct {
Interval int `bencode:"interval"`
Peers string `bencode:"peers"`
}

func (t *TorrentFile) buildTrackerUrl(peerId [20]byte, port uint16) (string, error) {
base, err := url.Parse(t.Announce)

Expand All @@ -38,3 +48,26 @@ func (t *TorrentFile) buildTrackerUrl(peerId [20]byte, port uint16) (string, err
base.RawQuery = params.Encode()
return base.String(), nil
}

func (t *TorrentFile) requestPeers(peerID [20]byte, port uint16) ([]peers.Peer, error) {
url, err := t.buildTrackerUrl(peerID, port)
if err != nil {
return nil, err
}

c := &http.Client{Timeout: 15 * time.Second}
resp, err := c.Get(url)
if err != nil {
return nil, err
}

defer resp.Body.Close()

trackerResp := bencodeTrackerResp{}
err = bencode.Unmarshal(resp.Body, &trackerResp)
if err != nil {
return nil, err
}

return peers.Unmarshal([]byte(trackerResp.Peers))
}
64 changes: 39 additions & 25 deletions pkg/torrentfile/torrentfile_test.go
Original file line number Diff line number Diff line change
@@ -1,39 +1,18 @@
package torrentfile

import (
"encoding/json"
"flag"
"io/ioutil"
"net"
"net/http"
"net/http/httptest"
"testing"

"github.com/brianlusina/tclient/pkg/peers"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

var update = flag.Bool("update", false, "update .golden.json files")

func TestOpen(t *testing.T) {
torrent, err := Open("testdata/archlinux-2019.12.01-x86_64.iso.torrent")
require.Nil(t, err)

goldenPath := "testdata/archlinux-2019.12.01-x86_64.iso.torrent.golden.json"

if *update {
serialized, err := json.MarshalIndent(torrent, "", " ")
require.Nil(t, err)
ioutil.WriteFile(goldenPath, serialized, 0644)
}

expected := TorrentFile{}
golden, err := ioutil.ReadFile(goldenPath)
require.Nil(t, err)

err = json.Unmarshal(golden, &expected)
require.Nil(t, err)

assert.Equal(t, expected, torrent)
}

func TestBuildTrackerUrl(t *testing.T) {
to := TorrentFile{
Announce: "http://bttracker.debian.org:6969/announce",
Expand All @@ -54,3 +33,38 @@ func TestBuildTrackerUrl(t *testing.T) {
assert.Nil(t, err)
assert.Equal(t, url, expected)
}

func TestRequestPeers(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
response := []byte(
"d" +
"8:interval" + "i900e" +
"5:peers" + "12:" +
string([]byte{
192, 0, 2, 123, 0x1A, 0xE1, // 0x1AE1 = 6881
127, 0, 0, 1, 0x1A, 0xE9, // 0x1AE9 = 6889
}) + "e")
w.Write(response)
}))
defer ts.Close()
tf := TorrentFile{
Announce: ts.URL,
InfoHash: [20]byte{216, 247, 57, 206, 195, 40, 149, 108, 204, 91, 191, 31, 134, 217, 253, 207, 219, 168, 206, 182},
PieceHashes: [][20]byte{
{49, 50, 51, 52, 53, 54, 55, 56, 57, 48, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106},
{97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 49, 50, 51, 52, 53, 54, 55, 56, 57, 48},
},
PieceLength: 262144,
Length: 351272960,
Name: "debian-10.2.0-amd64-netinst.iso",
}
peerID := [20]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}
const port uint16 = 6882
expected := []peers.Peer{
{IP: net.IP{192, 0, 2, 123}, Port: 6881},
{IP: net.IP{127, 0, 0, 1}, Port: 6889},
}
p, err := tf.requestPeers(peerID, port)
assert.Nil(t, err)
assert.Equal(t, expected, p)
}
32 changes: 32 additions & 0 deletions pkg/torrentfile/utils_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package torrentfile

import (
"encoding/json"
"io/ioutil"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestOpen(t *testing.T) {
torrent, err := Open("testdata/archlinux-2019.12.01-x86_64.iso.torrent")
require.Nil(t, err)

goldenPath := "testdata/archlinux-2019.12.01-x86_64.iso.torrent.golden.json"

if *update {
serialized, err := json.MarshalIndent(torrent, "", " ")
require.Nil(t, err)
ioutil.WriteFile(goldenPath, serialized, 0644)
}

expected := TorrentFile{}
golden, err := ioutil.ReadFile(goldenPath)
require.Nil(t, err)

err = json.Unmarshal(golden, &expected)
require.Nil(t, err)

assert.Equal(t, expected, torrent)
}

0 comments on commit f38bf5a

Please sign in to comment.