From 24b4437eddf79b7bb9d2e1305b906e7f49d683f5 Mon Sep 17 00:00:00 2001 From: Justin Li Date: Fri, 1 Aug 2014 13:24:24 -0400 Subject: [PATCH] Initial refactor to store more in the Announce --- tracker/announce.go | 139 ++++++++++++++++++++++----------------- tracker/models/models.go | 59 ++++++++++------- 2 files changed, 113 insertions(+), 85 deletions(-) diff --git a/tracker/announce.go b/tracker/announce.go index 18e7a51..3ef1936 100644 --- a/tracker/announce.go +++ b/tracker/announce.go @@ -54,40 +54,20 @@ func (tkr *Tracker) HandleAnnounce(ann *models.Announce, w Writer) error { return err } - var createdv4, createdv6, snatchedv4, snatchedv6 bool - peer, peerv4, peerv6 := models.NewPeer(ann, user, torrent) + ann.BuildPeer(user, torrent) - if peerv4 != nil { - createdv4, err = updateSwarm(conn, ann, peerv4, torrent) - if err != nil { - return err - } - } - if peerv6 != nil { - createdv6, err = updateSwarm(conn, ann, peerv6, torrent) - if err != nil { - return err - } + created, err := updateSwarm(conn, ann) + if err != nil { + return err } - if peerv4 != nil { - snatchedv4, err = handleEvent(conn, ann, peerv4, user, torrent) - if err != nil { - return err - } + snatched, err := handleEvent(conn, ann) + if err != nil { + return err } - if peerv6 != nil { - snatchedv6, err = handleEvent(conn, ann, peerv6, user, torrent) - if err != nil { - return err - } - } - - created := createdv4 || createdv6 - snatched := snatchedv4 || snatchedv6 if tkr.cfg.PrivateEnabled { - delta := models.NewAnnounceDelta(ann, peer, user, torrent, created, snatched) + delta := models.NewAnnounceDelta(ann, created, snatched) err = tkr.backend.RecordAnnounce(delta) if err != nil { return err @@ -99,12 +79,28 @@ func (tkr *Tracker) HandleAnnounce(ann *models.Announce, w Writer) error { stats.RecordEvent(stats.DeletedTorrent) } - return w.WriteAnnounce(newAnnounceResponse(ann, peer, torrent)) + return w.WriteAnnounce(newAnnounceResponse(ann)) } // updateSwarm handles the changes to a torrent's swarm given an announce. -func updateSwarm(c Conn, ann *models.Announce, p *models.Peer, t *models.Torrent) (created bool, err error) { - c.TouchTorrent(t.Infohash) +func updateSwarm(c Conn, ann *models.Announce) (created bool, err error) { + var createdv4, createdv6 bool + c.TouchTorrent(ann.Torrent.Infohash) + + if ann.HasIPv4() { + createdv4, err = updatePeer(c, ann, ann.PeerV4) + if err != nil { + return + } + } + if ann.HasIPv6() { + createdv6, err = updatePeer(c, ann, ann.PeerV6) + } + return createdv4 || createdv6, err +} + +func updatePeer(c Conn, ann *models.Announce, peer *models.Peer) (created bool, err error) { + p, t := ann.Peer, ann.Torrent switch { case t.InSeederPool(p): @@ -145,13 +141,50 @@ func updateSwarm(c Conn, ann *models.Announce, p *models.Peer, t *models.Torrent } created = true } - return } // handleEvent checks to see whether an announce has an event and if it does, // properly handles that event. -func handleEvent(c Conn, ann *models.Announce, p *models.Peer, u *models.User, t *models.Torrent) (snatched bool, err error) { +func handleEvent(c Conn, ann *models.Announce) (snatched bool, err error) { + var snatchedv4, snatchedv6 bool + + if ann.HasIPv4() { + snatchedv4, err = handlePeerEvent(c, ann, ann.PeerV4) + if err != nil { + return + } + } + if ann.HasIPv6() { + snatchedv6, err = handlePeerEvent(c, ann, ann.PeerV6) + if err != nil { + return + } + } + + snatched = snatchedv4 || snatchedv6 + + if snatched { + err = c.IncrementTorrentSnatches(ann.Torrent.Infohash) + if err != nil { + return + } + ann.Torrent.Snatches++ + } + + if snatched && ann.Config.PrivateEnabled { + err = c.IncrementUserSnatches(ann.User.Passkey) + if err != nil { + return + } + ann.User.Snatches++ + } + return +} + +func handlePeerEvent(c Conn, ann *models.Announce, p *models.Peer) (snatched bool, err error) { + p, t := ann.Peer, ann.Torrent + switch { case ann.Event == "stopped" || ann.Event == "paused": // updateSwarm checks if the peer is active on the torrent, @@ -174,20 +207,6 @@ func handleEvent(c Conn, ann *models.Announce, p *models.Peer, u *models.User, t } case ann.Event == "completed": - err = c.IncrementTorrentSnatches(t.Infohash) - if err != nil { - return - } - t.Snatches++ - - if ann.Config.PrivateEnabled { - err = c.IncrementUserSnatches(u.Passkey) - if err != nil { - return - } - u.Snatches++ - } - if t.InLeecherPool(p) { err = leecherFinished(c, t, p) } else { @@ -227,9 +246,9 @@ func leecherFinished(c Conn, t *models.Torrent, p *models.Peer) error { return nil } -func newAnnounceResponse(ann *models.Announce, announcer *models.Peer, t *models.Torrent) *models.AnnounceResponse { - seedCount := len(t.Seeders) - leechCount := len(t.Leechers) +func newAnnounceResponse(ann *models.Announce) *models.AnnounceResponse { + seedCount := len(ann.Torrent.Seeders) + leechCount := len(ann.Torrent.Leechers) res := &models.AnnounceResponse{ Complete: seedCount, @@ -240,7 +259,7 @@ func newAnnounceResponse(ann *models.Announce, announcer *models.Peer, t *models } if ann.NumWant > 0 && ann.Event != "stopped" && ann.Event != "paused" { - res.IPv4Peers, res.IPv6Peers = getPeers(ann, announcer, t, ann.NumWant) + res.IPv4Peers, res.IPv6Peers = getPeers(ann) } return res @@ -248,23 +267,23 @@ func newAnnounceResponse(ann *models.Announce, announcer *models.Peer, t *models // getPeers returns lists IPv4 and IPv6 peers on a given torrent sized according // to the wanted parameter. -func getPeers(ann *models.Announce, announcer *models.Peer, t *models.Torrent, wanted int) (ipv4s, ipv6s models.PeerList) { +func getPeers(ann *models.Announce) (ipv4s, ipv6s models.PeerList) { ipv4s, ipv6s = models.PeerList{}, models.PeerList{} if ann.Left == 0 { // If they're seeding, give them only leechers. - return appendPeers(ipv4s, ipv6s, ann, announcer, t.Leechers, wanted) + return appendPeers(ipv4s, ipv6s, ann, ann.Torrent.Leechers, ann.NumWant) } // If they're leeching, prioritize giving them seeders. - ipv4s, ipv6s = appendPeers(ipv4s, ipv6s, ann, announcer, t.Seeders, wanted) - return appendPeers(ipv4s, ipv6s, ann, announcer, t.Leechers, wanted-len(ipv4s)-len(ipv6s)) + ipv4s, ipv6s = appendPeers(ipv4s, ipv6s, ann, ann.Torrent.Seeders, ann.NumWant) + return appendPeers(ipv4s, ipv6s, ann, ann.Torrent.Leechers, ann.NumWant-len(ipv4s)-len(ipv6s)) } // appendPeers implements the logic of adding peers to the IPv4 or IPv6 lists. -func appendPeers(ipv4s, ipv6s models.PeerList, ann *models.Announce, announcer *models.Peer, peers models.PeerMap, wanted int) (models.PeerList, models.PeerList) { +func appendPeers(ipv4s, ipv6s models.PeerList, ann *models.Announce, peers models.PeerMap, wanted int) (models.PeerList, models.PeerList) { if ann.Config.PreferredSubnet { - return appendSubnetPeers(ipv4s, ipv6s, ann, announcer, peers, wanted) + return appendSubnetPeers(ipv4s, ipv6s, ann, peers, wanted) } count := 0 @@ -272,7 +291,7 @@ func appendPeers(ipv4s, ipv6s models.PeerList, ann *models.Announce, announcer * for _, peer := range peers { if count >= wanted { break - } else if peersEquivalent(&peer, announcer) { + } else if peersEquivalent(&peer, ann.Peer) { continue } @@ -290,7 +309,7 @@ func appendPeers(ipv4s, ipv6s models.PeerList, ann *models.Announce, announcer * // appendSubnetPeers is an alternative version of appendPeers used when the // config variable PreferredSubnet is enabled. -func appendSubnetPeers(ipv4s, ipv6s models.PeerList, ann *models.Announce, announcer *models.Peer, peers models.PeerMap, wanted int) (models.PeerList, models.PeerList) { +func appendSubnetPeers(ipv4s, ipv6s models.PeerList, ann *models.Announce, peers models.PeerMap, wanted int) (models.PeerList, models.PeerList) { var subnetIPv4 net.IPNet var subnetIPv6 net.IPNet @@ -314,7 +333,7 @@ func appendSubnetPeers(ipv4s, ipv6s models.PeerList, ann *models.Announce, annou inSubnet4 := peer.HasIPv4() && subnetIPv4.Contains(peer.IP) inSubnet6 := peer.HasIPv6() && subnetIPv6.Contains(peer.IP) - if peersEquivalent(&peer, announcer) || checkInSubnet != (inSubnet4 || inSubnet6) { + if peersEquivalent(&peer, ann.Peer) || checkInSubnet != (inSubnet4 || inSubnet6) { continue } diff --git a/tracker/models/models.go b/tracker/models/models.go index 92ecfcf..ae2e93a 100644 --- a/tracker/models/models.go +++ b/tracker/models/models.go @@ -73,11 +73,14 @@ type PeerMap map[PeerKey]Peer // for the announce parameter, it panics. When provided nil for the user or // torrent parameter, it returns a Peer{UserID: 0} or Peer{TorrentID: 0} // respectively. -func NewPeer(a *Announce, u *User, t *Torrent) (peer *Peer, v4 *Peer, v6 *Peer) { +func (a *Announce) BuildPeer(u *User, t *Torrent) { if a == nil { panic("models: announce cannot equal nil") } + a.User = u + a.Torrent = t + var userID uint64 if u != nil { userID = u.ID @@ -88,7 +91,7 @@ func NewPeer(a *Announce, u *User, t *Torrent) (peer *Peer, v4 *Peer, v6 *Peer) torrentID = t.ID } - peer = &Peer{ + a.Peer = &Peer{ ID: a.PeerID, UserID: userID, TorrentID: torrentID, @@ -99,17 +102,17 @@ func NewPeer(a *Announce, u *User, t *Torrent) (peer *Peer, v4 *Peer, v6 *Peer) LastAnnounce: time.Now().Unix(), } - if a.IPv4 != nil && a.IPv6 != nil { - v4 = peer - v4.IP = a.IPv4 - v6 = &*peer - v6.IP = a.IPv6 - } else if a.IPv4 != nil { - v4 = peer - v4.IP = a.IPv4 - } else if a.IPv6 != nil { - v6 = peer - v6.IP = a.IPv6 + if a.HasIPv4() && a.HasIPv6() { + a.PeerV4 = a.Peer + a.PeerV4.IP = a.IPv4 + a.PeerV6 = &*a.Peer + a.PeerV6.IP = a.IPv6 + } else if a.HasIPv4() { + a.PeerV4 = a.Peer + a.PeerV4.IP = a.IPv4 + } else if a.HasIPv6() { + a.PeerV6 = a.Peer + a.PeerV6.IP = a.IPv6 } else { panic("models: announce must have an IP") } @@ -166,7 +169,7 @@ type User struct { UpMultiplier float64 `json:"up_multiplier"` DownMultiplier float64 `json:"down_multiplier"` - Snatches uint64 `json:"snatches"` + Snatches uint64 `json:"snatches"` // TODO deleteme } // Announce is an Announce by a Peer. @@ -185,11 +188,17 @@ type Announce struct { PeerID string `json:"peer_id"` Port uint64 `json:"port"` Uploaded uint64 `json:"uploaded"` + + Torrent *Torrent `json:"-"` + User *User `json:"-"` + Peer *Peer `json:"-"` + PeerV4 *Peer `json:"-"` + PeerV6 *Peer `json:"-"` } // ClientID returns the part of a PeerID that identifies a Peer's client // software. -func (a Announce) ClientID() (clientID string) { +func (a *Announce) ClientID() (clientID string) { length := len(a.PeerID) if length >= 6 { if a.PeerID[0] == '-' { @@ -204,11 +213,11 @@ func (a Announce) ClientID() (clientID string) { return } -func (a Announce) HasIPv4() bool { +func (a *Announce) HasIPv4() bool { return a.IPv4 != nil } -func (a Announce) HasIPv6() bool { +func (a *Announce) HasIPv6() bool { return a.IPv6 != nil } @@ -242,14 +251,14 @@ type AnnounceResponse struct { // NewAnnounceDelta calculates a Peer's download and upload deltas between // Announces and generates an AnnounceDelta. -func NewAnnounceDelta(a *Announce, p *Peer, u *User, t *Torrent, created, snatched bool) *AnnounceDelta { +func NewAnnounceDelta(a *Announce, created, snatched bool) *AnnounceDelta { var ( - rawDeltaUp = p.Uploaded - a.Uploaded + rawDeltaUp = a.Peer.Uploaded - a.Uploaded rawDeltaDown uint64 ) if !a.Config.FreeleechEnabled { - rawDeltaDown = p.Downloaded - a.Downloaded + rawDeltaDown = a.Peer.Downloaded - a.Downloaded } // Restarting a torrent may cause a delta to be negative. @@ -262,15 +271,15 @@ func NewAnnounceDelta(a *Announce, p *Peer, u *User, t *Torrent, created, snatch } return &AnnounceDelta{ - Peer: p, - Torrent: t, - User: u, + Peer: a.Peer, + Torrent: a.Torrent, + User: a.User, Created: created, Snatched: snatched, - Uploaded: uint64(float64(rawDeltaUp) * u.UpMultiplier * t.UpMultiplier), - Downloaded: uint64(float64(rawDeltaDown) * u.DownMultiplier * t.DownMultiplier), + Uploaded: uint64(float64(rawDeltaUp) * a.User.UpMultiplier * a.Torrent.UpMultiplier), + Downloaded: uint64(float64(rawDeltaDown) * a.User.DownMultiplier * a.Torrent.DownMultiplier), } }