diff --git a/tracker/http.go b/tracker/http.go index f85c96a8..e6bda240 100644 --- a/tracker/http.go +++ b/tracker/http.go @@ -15,14 +15,16 @@ import ( ) func init() { - RegisterClientScheme("http", NewClient) + registerClientScheme("http", newHTTPClient) } type httpClient struct { url url.URL } -func NewClient(url *url.URL) Client { +func (httpClient) Close() error { return nil } + +func newHTTPClient(url *url.URL) client { return &httpClient{ url: *url, } diff --git a/tracker/tracker.go b/tracker/tracker.go index c54aae0f..dd21c0be 100644 --- a/tracker/tracker.go +++ b/tracker/tracker.go @@ -46,27 +46,28 @@ const ( Stopped // The local peer is leaving the swarm. ) -type Client interface { +type client interface { // Returns ErrNotConnected if Connect needs to be called. Announce(*AnnounceRequest) (AnnounceResponse, error) Connect() error String() string URL() string + Close() error } var ( ErrNotConnected = errors.New("not connected") 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 } // 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) if err != nil { return @@ -79,3 +80,17 @@ func New(rawurl string) (cl Client, err error) { cl = newFunc(url_s) 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) + +} diff --git a/tracker/tracker_test.go b/tracker/tracker_test.go index 01e306a6..d095af5a 100644 --- a/tracker/tracker_test.go +++ b/tracker/tracker_test.go @@ -6,7 +6,7 @@ import ( func TestUnsupportedTrackerScheme(t *testing.T) { t.Parallel() - _, err := New("lol://tracker.openbittorrent.com:80/announce") + _, err := Announce("lol://tracker.openbittorrent.com:80/announce", nil) if err != ErrBadScheme { t.Fatal(err) } diff --git a/tracker/udp.go b/tracker/udp.go index 36f7cc7e..2f91c501 100644 --- a/tracker/udp.go +++ b/tracker/udp.go @@ -61,10 +61,10 @@ type AnnounceResponseHeader struct { } func init() { - RegisterClientScheme("udp", newClient) + registerClientScheme("udp", newUDPClient) } -func newClient(url *url.URL) Client { +func newUDPClient(url *url.URL) client { return &udpClient{ url: *url, } @@ -93,6 +93,13 @@ type udpClient struct { url url.URL } +func (me *udpClient) Close() error { + if me.socket != nil { + return me.socket.Close() + } + return nil +} + func (c *udpClient) URL() string { return c.url.String() } diff --git a/tracker/udp_test.go b/tracker/udp_test.go index e7dc0a82..c9328f7e 100644 --- a/tracker/udp_test.go +++ b/tracker/udp_test.go @@ -9,10 +9,10 @@ import ( "io/ioutil" "net" "net/url" - "strings" "sync" "testing" + _ "github.com/anacrolix/envpprof" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -102,13 +102,9 @@ func TestAnnounceLocalhost(t *testing.T) { srv.pc, err = net.ListenPacket("udp", ":0") require.NoError(t, err) defer srv.pc.Close() - tr, err := New(fmt.Sprintf("udp://%s/announce", srv.pc.LocalAddr().String())) - require.NoError(t, err) go func() { require.NoError(t, srv.serveOne()) }() - err = tr.Connect() - require.NoError(t, err) req := AnnounceRequest{ NumWant: -1, Event: Started, @@ -118,7 +114,7 @@ func TestAnnounceLocalhost(t *testing.T) { go func() { 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) assert.EqualValues(t, 1, ar.Seeders) assert.EqualValues(t, 2, len(ar.Peers)) @@ -126,27 +122,25 @@ func TestAnnounceLocalhost(t *testing.T) { func TestUDPTracker(t *testing.T) { t.Parallel() - tr, err := New("udp://tracker.openbittorrent.com:80/announce") - require.NoError(t, err) if testing.Short() { t.SkipNow() } - if err := tr.Connect(); err != nil { - if strings.Contains(err.Error(), "no such host") { - t.Skip(err) - } - if strings.Contains(err.Error(), "i/o timeout") { - t.Skip(err) - } - t.Fatal(err) - } + // if err := tr.Connect(); err != nil { + // if strings.Contains(err.Error(), "no such host") { + // t.Skip(err) + // } + // if strings.Contains(err.Error(), "i/o timeout") { + // t.Skip(err) + // } + // t.Fatal(err) + // } req := AnnounceRequest{ NumWant: -1, // Event: Started, } 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}) - ar, err := tr.Announce(&req) + ar, err := Announce("udp://tracker.openbittorrent.com:80/announce", &req) if ne, ok := err.(net.Error); ok { if ne.Timeout() { t.Skip(err) @@ -183,15 +177,7 @@ func TestAnnounceRandomInfoHashThirdParty(t *testing.T) { wg.Add(1) go func(url string) { defer wg.Done() - tr, err := New(url) - if err != nil { - t.Fatal(err) - } - if err := tr.Connect(); err != nil { - t.Log(err) - return - } - resp, err := tr.Announce(&req) + resp, err := Announce(url, &req) if err != nil { t.Logf("error announcing to %s: %s", url, err) return @@ -226,19 +212,16 @@ func TestURLPathOption(t *testing.T) { panic(err) } defer conn.Close() - cl := newClient(&url.URL{ - Host: conn.LocalAddr().String(), - Path: "/announce", - }) go func() { - err = cl.Connect() + _, err := Announce((&url.URL{ + Scheme: "udp", + Host: conn.LocalAddr().String(), + Path: "/announce", + }).String(), &AnnounceRequest{}) if err != nil { - t.Fatal(err) - } - _, err = cl.Announce(&AnnounceRequest{}) - if err != nil { - t.Fatal(err) + defer conn.Close() } + require.NoError(t, err) }() var b [512]byte _, addr, _ := conn.ReadFrom(b[:])