Initial refactor to store more in the Announce
This commit is contained in:
parent
bfd8e110ea
commit
24b4437edd
2 changed files with 113 additions and 85 deletions
|
@ -54,40 +54,20 @@ func (tkr *Tracker) HandleAnnounce(ann *models.Announce, w Writer) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
var createdv4, createdv6, snatchedv4, snatchedv6 bool
|
ann.BuildPeer(user, torrent)
|
||||||
peer, peerv4, peerv6 := models.NewPeer(ann, user, torrent)
|
|
||||||
|
|
||||||
if peerv4 != nil {
|
created, err := updateSwarm(conn, ann)
|
||||||
createdv4, err = updateSwarm(conn, ann, peerv4, torrent)
|
if err != nil {
|
||||||
if err != nil {
|
return err
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if peerv6 != nil {
|
|
||||||
createdv6, err = updateSwarm(conn, ann, peerv6, torrent)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if peerv4 != nil {
|
snatched, err := handleEvent(conn, ann)
|
||||||
snatchedv4, err = handleEvent(conn, ann, peerv4, user, torrent)
|
if err != nil {
|
||||||
if err != nil {
|
return err
|
||||||
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 {
|
if tkr.cfg.PrivateEnabled {
|
||||||
delta := models.NewAnnounceDelta(ann, peer, user, torrent, created, snatched)
|
delta := models.NewAnnounceDelta(ann, created, snatched)
|
||||||
err = tkr.backend.RecordAnnounce(delta)
|
err = tkr.backend.RecordAnnounce(delta)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -99,12 +79,28 @@ func (tkr *Tracker) HandleAnnounce(ann *models.Announce, w Writer) error {
|
||||||
stats.RecordEvent(stats.DeletedTorrent)
|
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.
|
// 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) {
|
func updateSwarm(c Conn, ann *models.Announce) (created bool, err error) {
|
||||||
c.TouchTorrent(t.Infohash)
|
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 {
|
switch {
|
||||||
case t.InSeederPool(p):
|
case t.InSeederPool(p):
|
||||||
|
@ -145,13 +141,50 @@ func updateSwarm(c Conn, ann *models.Announce, p *models.Peer, t *models.Torrent
|
||||||
}
|
}
|
||||||
created = true
|
created = true
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// handleEvent checks to see whether an announce has an event and if it does,
|
// handleEvent checks to see whether an announce has an event and if it does,
|
||||||
// properly handles that event.
|
// 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 {
|
switch {
|
||||||
case ann.Event == "stopped" || ann.Event == "paused":
|
case ann.Event == "stopped" || ann.Event == "paused":
|
||||||
// updateSwarm checks if the peer is active on the torrent,
|
// 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":
|
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) {
|
if t.InLeecherPool(p) {
|
||||||
err = leecherFinished(c, t, p)
|
err = leecherFinished(c, t, p)
|
||||||
} else {
|
} else {
|
||||||
|
@ -227,9 +246,9 @@ func leecherFinished(c Conn, t *models.Torrent, p *models.Peer) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func newAnnounceResponse(ann *models.Announce, announcer *models.Peer, t *models.Torrent) *models.AnnounceResponse {
|
func newAnnounceResponse(ann *models.Announce) *models.AnnounceResponse {
|
||||||
seedCount := len(t.Seeders)
|
seedCount := len(ann.Torrent.Seeders)
|
||||||
leechCount := len(t.Leechers)
|
leechCount := len(ann.Torrent.Leechers)
|
||||||
|
|
||||||
res := &models.AnnounceResponse{
|
res := &models.AnnounceResponse{
|
||||||
Complete: seedCount,
|
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" {
|
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
|
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
|
// getPeers returns lists IPv4 and IPv6 peers on a given torrent sized according
|
||||||
// to the wanted parameter.
|
// 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{}
|
ipv4s, ipv6s = models.PeerList{}, models.PeerList{}
|
||||||
|
|
||||||
if ann.Left == 0 {
|
if ann.Left == 0 {
|
||||||
// If they're seeding, give them only leechers.
|
// 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.
|
// If they're leeching, prioritize giving them seeders.
|
||||||
ipv4s, ipv6s = appendPeers(ipv4s, ipv6s, ann, announcer, t.Seeders, wanted)
|
ipv4s, ipv6s = appendPeers(ipv4s, ipv6s, ann, ann.Torrent.Seeders, ann.NumWant)
|
||||||
return appendPeers(ipv4s, ipv6s, ann, announcer, t.Leechers, wanted-len(ipv4s)-len(ipv6s))
|
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.
|
// 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 {
|
if ann.Config.PreferredSubnet {
|
||||||
return appendSubnetPeers(ipv4s, ipv6s, ann, announcer, peers, wanted)
|
return appendSubnetPeers(ipv4s, ipv6s, ann, peers, wanted)
|
||||||
}
|
}
|
||||||
|
|
||||||
count := 0
|
count := 0
|
||||||
|
@ -272,7 +291,7 @@ func appendPeers(ipv4s, ipv6s models.PeerList, ann *models.Announce, announcer *
|
||||||
for _, peer := range peers {
|
for _, peer := range peers {
|
||||||
if count >= wanted {
|
if count >= wanted {
|
||||||
break
|
break
|
||||||
} else if peersEquivalent(&peer, announcer) {
|
} else if peersEquivalent(&peer, ann.Peer) {
|
||||||
continue
|
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
|
// appendSubnetPeers is an alternative version of appendPeers used when the
|
||||||
// config variable PreferredSubnet is enabled.
|
// 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 subnetIPv4 net.IPNet
|
||||||
var subnetIPv6 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)
|
inSubnet4 := peer.HasIPv4() && subnetIPv4.Contains(peer.IP)
|
||||||
inSubnet6 := peer.HasIPv6() && subnetIPv6.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
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -73,11 +73,14 @@ type PeerMap map[PeerKey]Peer
|
||||||
// for the announce parameter, it panics. When provided nil for the user or
|
// 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}
|
// torrent parameter, it returns a Peer{UserID: 0} or Peer{TorrentID: 0}
|
||||||
// respectively.
|
// 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 {
|
if a == nil {
|
||||||
panic("models: announce cannot equal nil")
|
panic("models: announce cannot equal nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
a.User = u
|
||||||
|
a.Torrent = t
|
||||||
|
|
||||||
var userID uint64
|
var userID uint64
|
||||||
if u != nil {
|
if u != nil {
|
||||||
userID = u.ID
|
userID = u.ID
|
||||||
|
@ -88,7 +91,7 @@ func NewPeer(a *Announce, u *User, t *Torrent) (peer *Peer, v4 *Peer, v6 *Peer)
|
||||||
torrentID = t.ID
|
torrentID = t.ID
|
||||||
}
|
}
|
||||||
|
|
||||||
peer = &Peer{
|
a.Peer = &Peer{
|
||||||
ID: a.PeerID,
|
ID: a.PeerID,
|
||||||
UserID: userID,
|
UserID: userID,
|
||||||
TorrentID: torrentID,
|
TorrentID: torrentID,
|
||||||
|
@ -99,17 +102,17 @@ func NewPeer(a *Announce, u *User, t *Torrent) (peer *Peer, v4 *Peer, v6 *Peer)
|
||||||
LastAnnounce: time.Now().Unix(),
|
LastAnnounce: time.Now().Unix(),
|
||||||
}
|
}
|
||||||
|
|
||||||
if a.IPv4 != nil && a.IPv6 != nil {
|
if a.HasIPv4() && a.HasIPv6() {
|
||||||
v4 = peer
|
a.PeerV4 = a.Peer
|
||||||
v4.IP = a.IPv4
|
a.PeerV4.IP = a.IPv4
|
||||||
v6 = &*peer
|
a.PeerV6 = &*a.Peer
|
||||||
v6.IP = a.IPv6
|
a.PeerV6.IP = a.IPv6
|
||||||
} else if a.IPv4 != nil {
|
} else if a.HasIPv4() {
|
||||||
v4 = peer
|
a.PeerV4 = a.Peer
|
||||||
v4.IP = a.IPv4
|
a.PeerV4.IP = a.IPv4
|
||||||
} else if a.IPv6 != nil {
|
} else if a.HasIPv6() {
|
||||||
v6 = peer
|
a.PeerV6 = a.Peer
|
||||||
v6.IP = a.IPv6
|
a.PeerV6.IP = a.IPv6
|
||||||
} else {
|
} else {
|
||||||
panic("models: announce must have an IP")
|
panic("models: announce must have an IP")
|
||||||
}
|
}
|
||||||
|
@ -166,7 +169,7 @@ type User struct {
|
||||||
|
|
||||||
UpMultiplier float64 `json:"up_multiplier"`
|
UpMultiplier float64 `json:"up_multiplier"`
|
||||||
DownMultiplier float64 `json:"down_multiplier"`
|
DownMultiplier float64 `json:"down_multiplier"`
|
||||||
Snatches uint64 `json:"snatches"`
|
Snatches uint64 `json:"snatches"` // TODO deleteme
|
||||||
}
|
}
|
||||||
|
|
||||||
// Announce is an Announce by a Peer.
|
// Announce is an Announce by a Peer.
|
||||||
|
@ -185,11 +188,17 @@ type Announce struct {
|
||||||
PeerID string `json:"peer_id"`
|
PeerID string `json:"peer_id"`
|
||||||
Port uint64 `json:"port"`
|
Port uint64 `json:"port"`
|
||||||
Uploaded uint64 `json:"uploaded"`
|
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
|
// ClientID returns the part of a PeerID that identifies a Peer's client
|
||||||
// software.
|
// software.
|
||||||
func (a Announce) ClientID() (clientID string) {
|
func (a *Announce) ClientID() (clientID string) {
|
||||||
length := len(a.PeerID)
|
length := len(a.PeerID)
|
||||||
if length >= 6 {
|
if length >= 6 {
|
||||||
if a.PeerID[0] == '-' {
|
if a.PeerID[0] == '-' {
|
||||||
|
@ -204,11 +213,11 @@ func (a Announce) ClientID() (clientID string) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a Announce) HasIPv4() bool {
|
func (a *Announce) HasIPv4() bool {
|
||||||
return a.IPv4 != nil
|
return a.IPv4 != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a Announce) HasIPv6() bool {
|
func (a *Announce) HasIPv6() bool {
|
||||||
return a.IPv6 != nil
|
return a.IPv6 != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -242,14 +251,14 @@ type AnnounceResponse struct {
|
||||||
|
|
||||||
// NewAnnounceDelta calculates a Peer's download and upload deltas between
|
// NewAnnounceDelta calculates a Peer's download and upload deltas between
|
||||||
// Announces and generates an AnnounceDelta.
|
// 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 (
|
var (
|
||||||
rawDeltaUp = p.Uploaded - a.Uploaded
|
rawDeltaUp = a.Peer.Uploaded - a.Uploaded
|
||||||
rawDeltaDown uint64
|
rawDeltaDown uint64
|
||||||
)
|
)
|
||||||
|
|
||||||
if !a.Config.FreeleechEnabled {
|
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.
|
// 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{
|
return &AnnounceDelta{
|
||||||
Peer: p,
|
Peer: a.Peer,
|
||||||
Torrent: t,
|
Torrent: a.Torrent,
|
||||||
User: u,
|
User: a.User,
|
||||||
|
|
||||||
Created: created,
|
Created: created,
|
||||||
Snatched: snatched,
|
Snatched: snatched,
|
||||||
|
|
||||||
Uploaded: uint64(float64(rawDeltaUp) * u.UpMultiplier * t.UpMultiplier),
|
Uploaded: uint64(float64(rawDeltaUp) * a.User.UpMultiplier * a.Torrent.UpMultiplier),
|
||||||
Downloaded: uint64(float64(rawDeltaDown) * u.DownMultiplier * t.DownMultiplier),
|
Downloaded: uint64(float64(rawDeltaDown) * a.User.DownMultiplier * a.Torrent.DownMultiplier),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue