2
0
mirror of synced 2025-02-24 14:48:27 +00:00

tracker: Shoehorn old client implementations into new tracker Announce interface

This commit is contained in:
Matt Joiner 2016-02-07 18:06:13 +11:00
parent 4587f61074
commit f04af72757
5 changed files with 53 additions and 46 deletions

View File

@ -15,14 +15,16 @@ import (
) )
func init() { func init() {
RegisterClientScheme("http", NewClient) registerClientScheme("http", newHTTPClient)
} }
type httpClient struct { type httpClient struct {
url url.URL url url.URL
} }
func NewClient(url *url.URL) Client { func (httpClient) Close() error { return nil }
func newHTTPClient(url *url.URL) client {
return &httpClient{ return &httpClient{
url: *url, url: *url,
} }

View File

@ -46,27 +46,28 @@ const (
Stopped // The local peer is leaving the swarm. Stopped // The local peer is leaving the swarm.
) )
type Client interface { type client interface {
// Returns ErrNotConnected if Connect needs to be called. // Returns ErrNotConnected if Connect needs to be called.
Announce(*AnnounceRequest) (AnnounceResponse, error) Announce(*AnnounceRequest) (AnnounceResponse, error)
Connect() error Connect() error
String() string String() string
URL() string URL() string
Close() error
} }
var ( var (
ErrNotConnected = errors.New("not connected") ErrNotConnected = errors.New("not connected")
ErrBadScheme = errors.New("unknown scheme") ErrBadScheme = errors.New("unknown scheme")
schemes = make(map[string]func(*url.URL) Client) schemes = make(map[string]func(*url.URL) client)
) )
func RegisterClientScheme(scheme string, newFunc func(*url.URL) Client) { func registerClientScheme(scheme string, newFunc func(*url.URL) client) {
schemes[scheme] = newFunc schemes[scheme] = newFunc
} }
// Returns ErrBadScheme if the tracker scheme isn't recognised. // Returns ErrBadScheme if the tracker scheme isn't recognised.
func New(rawurl string) (cl Client, err error) { func new(rawurl string) (cl client, err error) {
url_s, err := url.Parse(rawurl) url_s, err := url.Parse(rawurl)
if err != nil { if err != nil {
return return
@ -79,3 +80,17 @@ func New(rawurl string) (cl Client, err error) {
cl = newFunc(url_s) cl = newFunc(url_s)
return return
} }
func Announce(urlStr string, req *AnnounceRequest) (res AnnounceResponse, err error) {
cl, err := new(urlStr)
if err != nil {
return
}
defer cl.Close()
err = cl.Connect()
if err != nil {
return
}
return cl.Announce(req)
}

View File

@ -6,7 +6,7 @@ import (
func TestUnsupportedTrackerScheme(t *testing.T) { func TestUnsupportedTrackerScheme(t *testing.T) {
t.Parallel() t.Parallel()
_, err := New("lol://tracker.openbittorrent.com:80/announce") _, err := Announce("lol://tracker.openbittorrent.com:80/announce", nil)
if err != ErrBadScheme { if err != ErrBadScheme {
t.Fatal(err) t.Fatal(err)
} }

View File

@ -61,10 +61,10 @@ type AnnounceResponseHeader struct {
} }
func init() { func init() {
RegisterClientScheme("udp", newClient) registerClientScheme("udp", newUDPClient)
} }
func newClient(url *url.URL) Client { func newUDPClient(url *url.URL) client {
return &udpClient{ return &udpClient{
url: *url, url: *url,
} }
@ -93,6 +93,13 @@ type udpClient struct {
url url.URL url url.URL
} }
func (me *udpClient) Close() error {
if me.socket != nil {
return me.socket.Close()
}
return nil
}
func (c *udpClient) URL() string { func (c *udpClient) URL() string {
return c.url.String() return c.url.String()
} }

View File

@ -9,10 +9,10 @@ import (
"io/ioutil" "io/ioutil"
"net" "net"
"net/url" "net/url"
"strings"
"sync" "sync"
"testing" "testing"
_ "github.com/anacrolix/envpprof"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
@ -102,13 +102,9 @@ func TestAnnounceLocalhost(t *testing.T) {
srv.pc, err = net.ListenPacket("udp", ":0") srv.pc, err = net.ListenPacket("udp", ":0")
require.NoError(t, err) require.NoError(t, err)
defer srv.pc.Close() defer srv.pc.Close()
tr, err := New(fmt.Sprintf("udp://%s/announce", srv.pc.LocalAddr().String()))
require.NoError(t, err)
go func() { go func() {
require.NoError(t, srv.serveOne()) require.NoError(t, srv.serveOne())
}() }()
err = tr.Connect()
require.NoError(t, err)
req := AnnounceRequest{ req := AnnounceRequest{
NumWant: -1, NumWant: -1,
Event: Started, Event: Started,
@ -118,7 +114,7 @@ func TestAnnounceLocalhost(t *testing.T) {
go func() { go func() {
require.NoError(t, srv.serveOne()) require.NoError(t, srv.serveOne())
}() }()
ar, err := tr.Announce(&req) ar, err := Announce(fmt.Sprintf("udp://%s/announce", srv.pc.LocalAddr().String()), &req)
require.NoError(t, err) require.NoError(t, err)
assert.EqualValues(t, 1, ar.Seeders) assert.EqualValues(t, 1, ar.Seeders)
assert.EqualValues(t, 2, len(ar.Peers)) assert.EqualValues(t, 2, len(ar.Peers))
@ -126,27 +122,25 @@ func TestAnnounceLocalhost(t *testing.T) {
func TestUDPTracker(t *testing.T) { func TestUDPTracker(t *testing.T) {
t.Parallel() t.Parallel()
tr, err := New("udp://tracker.openbittorrent.com:80/announce")
require.NoError(t, err)
if testing.Short() { if testing.Short() {
t.SkipNow() t.SkipNow()
} }
if err := tr.Connect(); err != nil { // if err := tr.Connect(); err != nil {
if strings.Contains(err.Error(), "no such host") { // if strings.Contains(err.Error(), "no such host") {
t.Skip(err) // t.Skip(err)
} // }
if strings.Contains(err.Error(), "i/o timeout") { // if strings.Contains(err.Error(), "i/o timeout") {
t.Skip(err) // t.Skip(err)
} // }
t.Fatal(err) // t.Fatal(err)
} // }
req := AnnounceRequest{ req := AnnounceRequest{
NumWant: -1, NumWant: -1,
// Event: Started, // Event: Started,
} }
rand.Read(req.PeerId[:]) rand.Read(req.PeerId[:])
copy(req.InfoHash[:], []uint8{0xa3, 0x56, 0x41, 0x43, 0x74, 0x23, 0xe6, 0x26, 0xd9, 0x38, 0x25, 0x4a, 0x6b, 0x80, 0x49, 0x10, 0xa6, 0x67, 0xa, 0xc1}) copy(req.InfoHash[:], []uint8{0xa3, 0x56, 0x41, 0x43, 0x74, 0x23, 0xe6, 0x26, 0xd9, 0x38, 0x25, 0x4a, 0x6b, 0x80, 0x49, 0x10, 0xa6, 0x67, 0xa, 0xc1})
ar, err := tr.Announce(&req) ar, err := Announce("udp://tracker.openbittorrent.com:80/announce", &req)
if ne, ok := err.(net.Error); ok { if ne, ok := err.(net.Error); ok {
if ne.Timeout() { if ne.Timeout() {
t.Skip(err) t.Skip(err)
@ -183,15 +177,7 @@ func TestAnnounceRandomInfoHashThirdParty(t *testing.T) {
wg.Add(1) wg.Add(1)
go func(url string) { go func(url string) {
defer wg.Done() defer wg.Done()
tr, err := New(url) resp, err := Announce(url, &req)
if err != nil {
t.Fatal(err)
}
if err := tr.Connect(); err != nil {
t.Log(err)
return
}
resp, err := tr.Announce(&req)
if err != nil { if err != nil {
t.Logf("error announcing to %s: %s", url, err) t.Logf("error announcing to %s: %s", url, err)
return return
@ -226,19 +212,16 @@ func TestURLPathOption(t *testing.T) {
panic(err) panic(err)
} }
defer conn.Close() defer conn.Close()
cl := newClient(&url.URL{ go func() {
_, err := Announce((&url.URL{
Scheme: "udp",
Host: conn.LocalAddr().String(), Host: conn.LocalAddr().String(),
Path: "/announce", Path: "/announce",
}) }).String(), &AnnounceRequest{})
go func() {
err = cl.Connect()
if err != nil { if err != nil {
t.Fatal(err) defer conn.Close()
}
_, err = cl.Announce(&AnnounceRequest{})
if err != nil {
t.Fatal(err)
} }
require.NoError(t, err)
}() }()
var b [512]byte var b [512]byte
_, addr, _ := conn.ReadFrom(b[:]) _, addr, _ := conn.ReadFrom(b[:])