]> Sergey Matveev's repositories - btrtrc.git/commitdiff
Start using the webtorrent package
authorMatt Joiner <anacrolix@gmail.com>
Mon, 6 Apr 2020 06:45:47 +0000 (16:45 +1000)
committerMatt Joiner <anacrolix@gmail.com>
Mon, 6 Apr 2020 06:45:47 +0000 (16:45 +1000)
torrent.go
webtorrent/client.go
webtorrent/main.go [deleted file]
webtorrent/transport.go
wstracker.go

index 81ff8970c5fef7a936a023fa9af502e490ef3238..ca8b06f55817b49bdbf9d48447a65a3acfc48835 100644 (file)
@@ -29,6 +29,7 @@ import (
        pp "github.com/anacrolix/torrent/peer_protocol"
        "github.com/anacrolix/torrent/storage"
        "github.com/anacrolix/torrent/tracker"
+       "github.com/anacrolix/torrent/webtorrent"
 )
 
 // Maintains state of torrent within a Client. Many methods should not be called before the info is
@@ -1287,7 +1288,13 @@ func (t *Torrent) startScrapingTracker(_url string) {
        sl := func() torrentTrackerAnnouncer {
                switch u.Scheme {
                case "ws", "wss":
-                       return websocketTracker{*u}
+                       wst := websocketTracker{*u, webtorrent.NewClient(t.cl.peerID, t.infoHash)}
+                       go func() {
+                               err := wst.Client.Run(t.announceRequest(tracker.Started))
+                               if err != nil {
+                                       t.logger.Printf("error running websocket tracker announcer: %v", err)
+                               }
+                       }()
                }
                if u.Scheme == "udp4" && (t.cl.config.DisableIPv4Peers || t.cl.config.DisableIPv4) {
                        return nil
index 28d6962a735dcd7d76a812b57e771ecf80c6b272..9b49e15df865bdbecfff8552a8df8868c036aaf7 100644 (file)
@@ -1,13 +1,14 @@
-package main
+package webtorrent
 
 import (
        "encoding/json"
        "fmt"
        "io"
-       "log"
        "sync"
 
-       "github.com/anacrolix/torrent/metainfo"
+       "github.com/anacrolix/log"
+
+       "github.com/anacrolix/torrent/tracker"
        "github.com/anacrolix/torrent/webtorrent/buffer"
        "github.com/gorilla/websocket"
        "github.com/pion/datachannel"
@@ -20,18 +21,11 @@ const (
 
 // Client represents the webtorrent client
 type Client struct {
-       peerID       string
-       peerIDBinary string
-
-       infoHash       string
+       lock           sync.Mutex
+       peerIDBinary   string
        infoHashBinary string
-       totalLength    int
-
-       offeredPeers map[string]Peer // OfferID to Peer
-
-       tracker *websocket.Conn
-
-       lock *sync.Mutex
+       offeredPeers   map[string]Peer // OfferID to Peer
+       tracker        *websocket.Conn
 }
 
 // Peer represents a remote peer
@@ -40,46 +34,23 @@ type Peer struct {
        transport *Transport
 }
 
-func NewClient() (*Client, error) {
-       c := &Client{
-               offeredPeers: make(map[string]Peer),
-               lock:         &sync.Mutex{},
+func binaryToJsonString(b []byte) string {
+       var seq []rune
+       for _, v := range b {
+               seq = append(seq, rune(v))
        }
-
-       randPeerID, err := buffer.RandomBytes(9)
-       if err != nil {
-               return nil, fmt.Errorf("failed to generate bytes: %v", err)
-       }
-       peerIDBuffer := buffer.From("-WW0007-" + randPeerID.ToStringBase64())
-       c.peerID = peerIDBuffer.ToStringHex()
-       c.peerIDBinary = peerIDBuffer.ToStringLatin1()
-
-       return c, nil
+       return string(seq)
 }
 
-func (c *Client) LoadFile(p string) error {
-       meta, err := metainfo.LoadFromFile(p)
-       if err != nil {
-               return fmt.Errorf("failed to load meta info: %v\n", err)
+func NewClient(peerId, infoHash [20]byte) *Client {
+       return &Client{
+               offeredPeers:   make(map[string]Peer),
+               peerIDBinary:   binaryToJsonString(peerId[:]),
+               infoHashBinary: binaryToJsonString(infoHash[:]),
        }
-
-       info, err := meta.UnmarshalInfo()
-       if err != nil {
-               return fmt.Errorf("failed to unmarshal info: %v\n", err)
-       }
-       c.totalLength = int(info.TotalLength())
-
-       c.infoHash = meta.HashInfoBytes().String()
-       b, err := buffer.FromHex(c.infoHash)
-       if err != nil {
-               return fmt.Errorf("failed to create buffer: %v\n", err)
-       }
-       c.infoHashBinary = b.ToStringLatin1()
-
-       return nil
 }
 
-func (c *Client) Run() error {
+func (c *Client) Run(ar tracker.AnnounceRequest) error {
        t, _, err := websocket.DefaultDialer.Dial(trackerURL, nil)
        if err != nil {
                return fmt.Errorf("failed to dial tracker: %v", err)
@@ -87,21 +58,21 @@ func (c *Client) Run() error {
        defer t.Close()
        c.tracker = t
 
-       go c.announce()
+       go c.announce(ar)
        c.trackerReadLoop()
 
        return nil
 }
 
-func (c *Client) announce() {
+func (c *Client) announce(request tracker.AnnounceRequest) error {
        transpot, offer, err := NewTransport()
        if err != nil {
-               log.Fatalf("failed to create transport: %v\n", err)
+               return fmt.Errorf("failed to create transport: %w", err)
        }
 
        randOfferID, err := buffer.RandomBytes(20)
        if err != nil {
-               log.Fatalf("failed to generate bytes: %v\n", err)
+               return fmt.Errorf("failed to generate bytes: %w", err)
        }
        // OfferID := randOfferID.ToStringHex()
        offerIDBinary := randOfferID.ToStringLatin1()
@@ -114,33 +85,33 @@ func (c *Client) announce() {
                Numwant:    1, // If higher we need to create equal amount of offers
                Uploaded:   0,
                Downloaded: 0,
-               Left:       int(c.totalLength),
+               Left:       request.Left,
                Event:      "started",
                Action:     "announce",
                InfoHash:   c.infoHashBinary,
                PeerID:     c.peerIDBinary,
-               Offers: []Offer{
-                       {
-                               OfferID: offerIDBinary,
-                               Offer:   offer,
-                       }},
+               Offers: []Offer{{
+                       OfferID: offerIDBinary,
+                       Offer:   offer,
+               }},
        }
 
        data, err := json.Marshal(req)
        if err != nil {
-               log.Fatal("failed to marshal request:", err)
+               return fmt.Errorf("failed to marshal request: %w", err)
        }
        c.lock.Lock()
        tracker := c.tracker
        err = tracker.WriteMessage(websocket.TextMessage, data)
        if err != nil {
-               log.Fatal("write AnnounceRequest:", err)
+               return fmt.Errorf("write AnnounceRequest: %w", err)
                c.lock.Unlock()
        }
        c.lock.Unlock()
+       return nil
 }
 
-func (c *Client) trackerReadLoop() {
+func (c *Client) trackerReadLoop() error {
 
        c.lock.Lock()
        tracker := c.tracker
@@ -148,9 +119,9 @@ func (c *Client) trackerReadLoop() {
        for {
                _, message, err := tracker.ReadMessage()
                if err != nil {
-                       log.Fatalf("read error: %v", err)
+                       return fmt.Errorf("read error: %w", err)
                }
-               log.Printf("recv: %s", message)
+               log.Printf("recv: %q", message)
 
                var ar AnnounceResponse
                if err := json.Unmarshal(message, &ar); err != nil {
@@ -158,14 +129,14 @@ func (c *Client) trackerReadLoop() {
                        continue
                }
                if ar.InfoHash != c.infoHashBinary {
-                       log.Printf("announce response for different hash: %s", ar.InfoHash)
+                       log.Printf("announce response for different hash: expected %q got %q", c.infoHashBinary, ar.InfoHash)
                        continue
                }
                switch {
                case ar.Offer != nil:
                        t, answer, err := NewTransportFromOffer(*ar.Offer, c.handleDataChannel)
                        if err != nil {
-                               log.Fatal("write AnnounceResponse:", err)
+                               return fmt.Errorf("write AnnounceResponse: %w", err)
                        }
 
                        req := AnnounceResponse{
@@ -178,13 +149,13 @@ func (c *Client) trackerReadLoop() {
                        }
                        data, err := json.Marshal(req)
                        if err != nil {
-                               log.Fatal("failed to marshal request:", err)
+                               return fmt.Errorf("failed to marshal request: %w", err)
                        }
 
                        c.lock.Lock()
                        err = tracker.WriteMessage(websocket.TextMessage, data)
                        if err != nil {
-                               log.Fatal("write AnnounceResponse:", err)
+                               return fmt.Errorf("write AnnounceResponse: %w", err)
                                c.lock.Unlock()
                        }
                        c.lock.Unlock()
@@ -196,12 +167,13 @@ func (c *Client) trackerReadLoop() {
                        peer, ok := c.offeredPeers[ar.OfferID]
                        c.lock.Unlock()
                        if !ok {
-                               fmt.Printf("could not find peer for offer %s", ar.OfferID)
+                               log.Printf("could not find peer for offer %q", ar.OfferID)
                                continue
                        }
+                       log.Printf("offer %q got answer %q", ar.OfferID, ar.Answer)
                        err = peer.transport.SetAnswer(*ar.Answer, c.handleDataChannel)
                        if err != nil {
-                               log.Fatalf("failed to sent answer: %v", err)
+                               return fmt.Errorf("failed to sent answer: %v", err)
                        }
                }
        }
@@ -217,7 +189,7 @@ func (c *Client) dcReadLoop(d io.Reader) {
                buffer := make([]byte, 1024)
                n, err := d.Read(buffer)
                if err != nil {
-                       log.Fatal("Datachannel closed; Exit the readloop:", err)
+                       log.Printf("Datachannel closed; Exit the readloop: %v", err)
                }
 
                fmt.Printf("Message from DataChannel: %s\n", string(buffer[:n]))
@@ -228,7 +200,7 @@ type AnnounceRequest struct {
        Numwant    int     `json:"numwant"`
        Uploaded   int     `json:"uploaded"`
        Downloaded int     `json:"downloaded"`
-       Left       int     `json:"left"`
+       Left       int64   `json:"left"`
        Event      string  `json:"event"`
        Action     string  `json:"action"`
        InfoHash   string  `json:"info_hash"`
diff --git a/webtorrent/main.go b/webtorrent/main.go
deleted file mode 100644 (file)
index f434f05..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-package main
-
-import (
-       "log"
-)
-
-func main() {
-       wt, err := NewClient()
-       if err != nil {
-               log.Fatalf("failed to create client: %v", err)
-       }
-       err = wt.LoadFile("./sintel.torrent")
-       if err != nil {
-               log.Fatalf("failed to load file: %v", err)
-       }
-       err = wt.Run()
-       if err != nil {
-               log.Fatalf("failed to run: %v", err)
-       }
-}
index 374df116cc03adac5e52d517d90b126a3d354046..e613b26e4340e2e11644bd61b29f8df119717fec 100644 (file)
@@ -1,4 +1,4 @@
-package main
+package webtorrent
 
 import (
        "fmt"
index 7b26b43e1039bce724f9009c0708abd0d765ed0a..4001b73e0b630e6a1ffe2230d45505df9433788f 100644 (file)
@@ -3,10 +3,13 @@ package torrent
 import (
        "fmt"
        "net/url"
+
+       "github.com/anacrolix/torrent/webtorrent"
 )
 
 type websocketTracker struct {
        url url.URL
+       *webtorrent.Client
 }
 
 func (me websocketTracker) statusLine() string {