// Applies the context to a ParamterizedController func (dc *DevContext) ApplyContext(controller web.Controller, response http.ResponseWriter, request *http.Request, chain []web.ChainableContext) { dc.SetParams(web.RetrieveAllParams(request)) dc.SetResponsePair(response, request) dc.isInit = true v, ok := controller.(ParameterizedController) if ok { if err := v.SetContext(dc); err != nil { fmt.Printf("Error setting paramter context: %s \n", err.Error()) } } else { fmt.Printf("Tried to wrap a controller that is not request parameter aware \n") } }
// Handles announce from a client. // Some TODOs: // * Bail out early if secret/hash or request is obviously malformed. (Not from a well-behaved torrent client.) // * Cache users and their secrets. (Presumably if they have started one torrent they will start many more.) // * Intelligent peer-list generation. // * Set `Content-Length` ? func announceHandle(w http.ResponseWriter, r *http.Request, s *Server) { w.Header().Set("Content-Type", "text/plain") params := libWeb.RetrieveAllParams(r) responseMap := make(map[string]interface{}) hexHash := hex.EncodeToString([]byte(params.All["info_hash"])) torrent, ok := s.torrentExists(hexHash) user := &models.User{} if err := user.SelectSecret(params.All["secret"]); err != nil { w.Write(failureResponses[RESP_USER_NOT_FOUND]) return } if !libTorrent.CheckHmac(params.All["secret"], params.All["hash"]) { w.Write(failureResponses[RESP_USER_NOT_FOUND]) return } // TODO: tracker request log. if !ok { w.Write(failureResponses[RESP_TORRENT_NOT_FOUND]) return } responseMap["interval"] = lib.TRACKER_ANNOUNCE_INTERVAL // intentionally short for debugging purposes. responseMap["min interval"] = 10 seeding, leeching := torrent.EnumeratePeers() responseMap["complete"] = seeding responseMap["incomplete"] = leeching responseMap["peers"], responseMap["peers6"] = torrent.GetPeerList(0) //naive peer ranker. io.Copy(w, encodeResponseMap(responseMap)) // Defer writes outside of response // (Just in case we block on DB access or have to contend for the peer list's mutex) go func() { if params.All["event"] == "stopped" { // TODO: remove peer method torrent.WritePeers(func(peerMap map[string]*libTorrent.Peer) { delete(peerMap, params.All["peer_id"]) }) } else { torrent.AddPeer( params.All["peer_id"], r.RemoteAddr, params.All["port"], params.All["secret"], ) torrent.UpdateStatsFor(params.All["peer_id"], "0", "0", params.All["left"]) } // Send stats over event bridge. stats := libBridge.TorrentStatMessage{} stats.InfoHash = torrent.InfoHash stats.Seeding, stats.Leeching = torrent.EnumeratePeers() message := &libBridge.Message{} message.Type = libBridge.TORRENT_STAT_TUPLE message.Payload = stats // TODO: Reaper needs to send this event // when a peer is removed. s.eventBridge.Publish("tracker", message) }() }