// Announce announces using HTTP format func (h HTTPTracker) Announce(query url.Values, file data.FileRecord) []byte { // Generate response struct announce := AnnounceResponse{ Interval: common.Static.Config.Interval, MinInterval: common.Static.Config.Interval / 2, } // Get seeders count on file var err error announce.Complete, err = file.Seeders() if err != nil { log.Println(err.Error()) } // Get leechers count on file announce.Incomplete, err = file.Leechers() if err != nil { log.Println(err.Error()) } // Check for numwant parameter, return up to that number of peers // Default is 50 per protocol numwant := 50 if query.Get("numwant") != "" { // Verify numwant is an integer num, err := strconv.Atoi(query.Get("numwant")) if err == nil { numwant = num } } // Marshal struct into bencode buf := bytes.NewBuffer(make([]byte, 0)) if err := bencode.Marshal(buf, announce); err != nil { log.Println(err.Error()) return h.Error(ErrAnnounceFailure.Error()) } // Generate compact peer list of length numwant // Note: because we are HTTP, we can mark second parameter as 'true' to get a // more accurate peer list compactPeers, err := file.CompactPeerList(numwant, true) if err != nil { log.Println(err.Error()) return h.Error(ErrPeerListFailure.Error()) } // Because the bencode marshaler does not handle compact, binary peer list conversion, // we handle it manually here. // Get initial buffer, chop off 3 bytes: "0:e", append the actual list length with new colon out := buf.Bytes() out = append(out[0:len(out)-3], []byte(strconv.Itoa(len(compactPeers))+":")...) // Append peers list, terminate with an "e" return append(append(out, compactPeers...), byte('e')) }
// Announce announces using UDP format func (u UDPTracker) Announce(query url.Values, file data.FileRecord) []byte { // Create UDP announce response announce := udp.AnnounceResponse{ Action: 1, TransID: u.TransID, Interval: uint32(common.Static.Config.Interval), } // Calculate file seeders and leechers seeders, err := file.Seeders() if err != nil { log.Println(err.Error()) } announce.Seeders = uint32(seeders) leechers, err := file.Leechers() if err != nil { log.Println(err.Error()) } announce.Leechers = uint32(leechers) // Convert to UDP byte buffer announceBuf, err := announce.MarshalBinary() if err != nil { log.Println(err.Error()) return u.Error(ErrAnnounceFailure.Error()) } // Numwant numwant, err := strconv.Atoi(query.Get("numwant")) if err != nil { numwant = 50 } // Retrieve compact peer list // Note: because we are UDP, we send the second parameter 'false' to get // a "best guess" peer list, due to anonymous announces peers, err := file.CompactPeerList(numwant, false) if err != nil { log.Println(err.Error()) return u.Error(ErrPeerListFailure.Error()) } // Add compact peer list res := bytes.NewBuffer(announceBuf) err = binary.Write(res, binary.BigEndian, peers) if err != nil { log.Println(err.Error()) return u.Error(ErrPeerListFailure.Error()) } return res.Bytes() }