Move the BitTorrent related code from SiteAnnouncer.py (#2078)
* Move the BitTorrent related code from SiteAnnouncer.py to a separate plugin * AnnounceBitTorrentPlugin.py: add missing `from Debug import Debug`
This commit is contained in:
parent
6b5fa140b9
commit
a2cb1615b3
3 changed files with 152 additions and 124 deletions
150
plugins/AnnounceBitTorrent/AnnounceBitTorrentPlugin.py
Normal file
150
plugins/AnnounceBitTorrent/AnnounceBitTorrentPlugin.py
Normal file
|
@ -0,0 +1,150 @@
|
||||||
|
import time
|
||||||
|
import urllib.request
|
||||||
|
import struct
|
||||||
|
import socket
|
||||||
|
|
||||||
|
import bencode
|
||||||
|
from lib.subtl.subtl import UdpTrackerClient
|
||||||
|
import socks
|
||||||
|
import sockshandler
|
||||||
|
import gevent
|
||||||
|
|
||||||
|
from Plugin import PluginManager
|
||||||
|
from Config import config
|
||||||
|
from Debug import Debug
|
||||||
|
from util import helper
|
||||||
|
|
||||||
|
|
||||||
|
# We can only import plugin host clases after the plugins are loaded
|
||||||
|
@PluginManager.afterLoad
|
||||||
|
def importHostClasses():
|
||||||
|
global Peer, AnnounceError
|
||||||
|
from Peer import Peer
|
||||||
|
from Site.SiteAnnouncer import AnnounceError
|
||||||
|
|
||||||
|
|
||||||
|
@PluginManager.registerTo("SiteAnnouncer")
|
||||||
|
class SiteAnnouncerPlugin(object):
|
||||||
|
def getSupportedTrackers(self):
|
||||||
|
trackers = super(SiteAnnouncerPlugin, self).getSupportedTrackers()
|
||||||
|
if config.disable_udp or config.trackers_proxy != "disable":
|
||||||
|
trackers = [tracker for tracker in trackers if not tracker.startswith("udp://")]
|
||||||
|
|
||||||
|
return trackers
|
||||||
|
|
||||||
|
def getTrackerHandler(self, protocol):
|
||||||
|
if protocol == "udp":
|
||||||
|
handler = self.announceTrackerUdp
|
||||||
|
elif protocol == "http":
|
||||||
|
handler = self.announceTrackerHttp
|
||||||
|
elif protocol == "https":
|
||||||
|
handler = self.announceTrackerHttps
|
||||||
|
else:
|
||||||
|
handler = super(SiteAnnouncerPlugin, self).getTrackerHandler(protocol)
|
||||||
|
return handler
|
||||||
|
|
||||||
|
def announceTrackerUdp(self, tracker_address, mode="start", num_want=10):
|
||||||
|
s = time.time()
|
||||||
|
if config.disable_udp:
|
||||||
|
raise AnnounceError("Udp disabled by config")
|
||||||
|
if config.trackers_proxy != "disable":
|
||||||
|
raise AnnounceError("Udp trackers not available with proxies")
|
||||||
|
|
||||||
|
ip, port = tracker_address.split("/")[0].split(":")
|
||||||
|
tracker = UdpTrackerClient(ip, int(port))
|
||||||
|
if helper.getIpType(ip) in self.getOpenedServiceTypes():
|
||||||
|
tracker.peer_port = self.fileserver_port
|
||||||
|
else:
|
||||||
|
tracker.peer_port = 0
|
||||||
|
tracker.connect()
|
||||||
|
if not tracker.poll_once():
|
||||||
|
raise AnnounceError("Could not connect")
|
||||||
|
tracker.announce(info_hash=self.site.address_sha1, num_want=num_want, left=431102370)
|
||||||
|
back = tracker.poll_once()
|
||||||
|
if not back:
|
||||||
|
raise AnnounceError("No response after %.0fs" % (time.time() - s))
|
||||||
|
elif type(back) is dict and "response" in back:
|
||||||
|
peers = back["response"]["peers"]
|
||||||
|
else:
|
||||||
|
raise AnnounceError("Invalid response: %r" % back)
|
||||||
|
|
||||||
|
return peers
|
||||||
|
|
||||||
|
def httpRequest(self, url):
|
||||||
|
headers = {
|
||||||
|
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari/537.11',
|
||||||
|
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
|
||||||
|
'Accept-Charset': 'ISO-8859-1,utf-8;q=0.7,*;q=0.3',
|
||||||
|
'Accept-Encoding': 'none',
|
||||||
|
'Accept-Language': 'en-US,en;q=0.8',
|
||||||
|
'Connection': 'keep-alive'
|
||||||
|
}
|
||||||
|
|
||||||
|
req = urllib.request.Request(url, headers=headers)
|
||||||
|
|
||||||
|
if config.trackers_proxy == "tor":
|
||||||
|
tor_manager = self.site.connection_server.tor_manager
|
||||||
|
handler = sockshandler.SocksiPyHandler(socks.SOCKS5, tor_manager.proxy_ip, tor_manager.proxy_port)
|
||||||
|
opener = urllib.request.build_opener(handler)
|
||||||
|
return opener.open(req, timeout=50)
|
||||||
|
elif config.trackers_proxy == "disable":
|
||||||
|
return urllib.request.urlopen(req, timeout=25)
|
||||||
|
else:
|
||||||
|
proxy_ip, proxy_port = config.trackers_proxy.split(":")
|
||||||
|
handler = sockshandler.SocksiPyHandler(socks.SOCKS5, proxy_ip, int(proxy_port))
|
||||||
|
opener = urllib.request.build_opener(handler)
|
||||||
|
return opener.open(req, timeout=50)
|
||||||
|
|
||||||
|
def announceTrackerHttps(self, *args, **kwargs):
|
||||||
|
kwargs["protocol"] = "https"
|
||||||
|
return self.announceTrackerHttp(*args, **kwargs)
|
||||||
|
|
||||||
|
def announceTrackerHttp(self, tracker_address, mode="start", num_want=10, protocol="http"):
|
||||||
|
tracker_ip, tracker_port = tracker_address.rsplit(":", 1)
|
||||||
|
if helper.getIpType(tracker_ip) in self.getOpenedServiceTypes():
|
||||||
|
port = self.fileserver_port
|
||||||
|
else:
|
||||||
|
port = 1
|
||||||
|
params = {
|
||||||
|
'info_hash': self.site.address_sha1,
|
||||||
|
'peer_id': self.peer_id, 'port': port,
|
||||||
|
'uploaded': 0, 'downloaded': 0, 'left': 431102370, 'compact': 1, 'numwant': num_want,
|
||||||
|
'event': 'started'
|
||||||
|
}
|
||||||
|
|
||||||
|
url = protocol + "://" + tracker_address + "?" + urllib.parse.urlencode(params)
|
||||||
|
|
||||||
|
s = time.time()
|
||||||
|
response = None
|
||||||
|
# Load url
|
||||||
|
if config.tor == "always" or config.trackers_proxy != "disable":
|
||||||
|
timeout = 60
|
||||||
|
else:
|
||||||
|
timeout = 30
|
||||||
|
|
||||||
|
with gevent.Timeout(timeout, False): # Make sure of timeout
|
||||||
|
req = self.httpRequest(url)
|
||||||
|
response = req.read()
|
||||||
|
req.close()
|
||||||
|
req = None
|
||||||
|
|
||||||
|
if not response:
|
||||||
|
raise AnnounceError("No response after %.0fs" % (time.time() - s))
|
||||||
|
|
||||||
|
# Decode peers
|
||||||
|
try:
|
||||||
|
peer_data = bencode.decode(response)["peers"]
|
||||||
|
if type(peer_data) is not bytes:
|
||||||
|
peer_data = peer_data.encode()
|
||||||
|
response = None
|
||||||
|
peer_count = int(len(peer_data) / 6)
|
||||||
|
peers = []
|
||||||
|
for peer_offset in range(peer_count):
|
||||||
|
off = 6 * peer_offset
|
||||||
|
peer = peer_data[off:off + 6]
|
||||||
|
addr, port = struct.unpack('!LH', peer)
|
||||||
|
peers.append({"addr": socket.inet_ntoa(struct.pack('!L', addr)), "port": port})
|
||||||
|
except Exception as err:
|
||||||
|
raise AnnounceError("Invalid response: %r (%s)" % (response, Debug.formatException(err)))
|
||||||
|
|
||||||
|
return peers
|
1
plugins/AnnounceBitTorrent/__init__.py
Normal file
1
plugins/AnnounceBitTorrent/__init__.py
Normal file
|
@ -0,0 +1 @@
|
||||||
|
from . import AnnounceBitTorrentPlugin
|
|
@ -1,16 +1,9 @@
|
||||||
import random
|
import random
|
||||||
import time
|
import time
|
||||||
import hashlib
|
import hashlib
|
||||||
import urllib.request
|
|
||||||
import struct
|
|
||||||
import socket
|
|
||||||
import re
|
import re
|
||||||
import collections
|
import collections
|
||||||
|
|
||||||
import bencode
|
|
||||||
from lib.subtl.subtl import UdpTrackerClient
|
|
||||||
import socks
|
|
||||||
import sockshandler
|
|
||||||
import gevent
|
import gevent
|
||||||
|
|
||||||
from Plugin import PluginManager
|
from Plugin import PluginManager
|
||||||
|
@ -41,8 +34,6 @@ class SiteAnnouncer(object):
|
||||||
|
|
||||||
def getSupportedTrackers(self):
|
def getSupportedTrackers(self):
|
||||||
trackers = self.getTrackers()
|
trackers = self.getTrackers()
|
||||||
if config.disable_udp or config.trackers_proxy != "disable":
|
|
||||||
trackers = [tracker for tracker in trackers if not tracker.startswith("udp://")]
|
|
||||||
|
|
||||||
if not self.site.connection_server.tor_manager.enabled:
|
if not self.site.connection_server.tor_manager.enabled:
|
||||||
trackers = [tracker for tracker in trackers if ".onion" not in tracker]
|
trackers = [tracker for tracker in trackers if ".onion" not in tracker]
|
||||||
|
@ -157,15 +148,7 @@ class SiteAnnouncer(object):
|
||||||
self.updateWebsocket(pex="announced")
|
self.updateWebsocket(pex="announced")
|
||||||
|
|
||||||
def getTrackerHandler(self, protocol):
|
def getTrackerHandler(self, protocol):
|
||||||
if protocol == "udp":
|
return None
|
||||||
handler = self.announceTrackerUdp
|
|
||||||
elif protocol == "http":
|
|
||||||
handler = self.announceTrackerHttp
|
|
||||||
elif protocol == "https":
|
|
||||||
handler = self.announceTrackerHttps
|
|
||||||
else:
|
|
||||||
handler = None
|
|
||||||
return handler
|
|
||||||
|
|
||||||
def getAddressParts(self, tracker):
|
def getAddressParts(self, tracker):
|
||||||
if "://" not in tracker or not re.match("^[A-Za-z0-9:/\\.#-]+$", tracker):
|
if "://" not in tracker or not re.match("^[A-Za-z0-9:/\\.#-]+$", tracker):
|
||||||
|
@ -266,112 +249,6 @@ class SiteAnnouncer(object):
|
||||||
)
|
)
|
||||||
return time.time() - s
|
return time.time() - s
|
||||||
|
|
||||||
def announceTrackerUdp(self, tracker_address, mode="start", num_want=10):
|
|
||||||
s = time.time()
|
|
||||||
if config.disable_udp:
|
|
||||||
raise AnnounceError("Udp disabled by config")
|
|
||||||
if config.trackers_proxy != "disable":
|
|
||||||
raise AnnounceError("Udp trackers not available with proxies")
|
|
||||||
|
|
||||||
ip, port = tracker_address.split("/")[0].split(":")
|
|
||||||
tracker = UdpTrackerClient(ip, int(port))
|
|
||||||
if helper.getIpType(ip) in self.getOpenedServiceTypes():
|
|
||||||
tracker.peer_port = self.fileserver_port
|
|
||||||
else:
|
|
||||||
tracker.peer_port = 0
|
|
||||||
tracker.connect()
|
|
||||||
if not tracker.poll_once():
|
|
||||||
raise AnnounceError("Could not connect")
|
|
||||||
tracker.announce(info_hash=self.site.address_sha1, num_want=num_want, left=431102370)
|
|
||||||
back = tracker.poll_once()
|
|
||||||
if not back:
|
|
||||||
raise AnnounceError("No response after %.0fs" % (time.time() - s))
|
|
||||||
elif type(back) is dict and "response" in back:
|
|
||||||
peers = back["response"]["peers"]
|
|
||||||
else:
|
|
||||||
raise AnnounceError("Invalid response: %r" % back)
|
|
||||||
|
|
||||||
return peers
|
|
||||||
|
|
||||||
def httpRequest(self, url):
|
|
||||||
headers = {
|
|
||||||
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari/537.11',
|
|
||||||
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
|
|
||||||
'Accept-Charset': 'ISO-8859-1,utf-8;q=0.7,*;q=0.3',
|
|
||||||
'Accept-Encoding': 'none',
|
|
||||||
'Accept-Language': 'en-US,en;q=0.8',
|
|
||||||
'Connection': 'keep-alive'
|
|
||||||
}
|
|
||||||
|
|
||||||
req = urllib.request.Request(url, headers=headers)
|
|
||||||
|
|
||||||
if config.trackers_proxy == "tor":
|
|
||||||
tor_manager = self.site.connection_server.tor_manager
|
|
||||||
handler = sockshandler.SocksiPyHandler(socks.SOCKS5, tor_manager.proxy_ip, tor_manager.proxy_port)
|
|
||||||
opener = urllib.request.build_opener(handler)
|
|
||||||
return opener.open(req, timeout=50)
|
|
||||||
elif config.trackers_proxy == "disable":
|
|
||||||
return urllib.request.urlopen(req, timeout=25)
|
|
||||||
else:
|
|
||||||
proxy_ip, proxy_port = config.trackers_proxy.split(":")
|
|
||||||
handler = sockshandler.SocksiPyHandler(socks.SOCKS5, proxy_ip, int(proxy_port))
|
|
||||||
opener = urllib.request.build_opener(handler)
|
|
||||||
return opener.open(req, timeout=50)
|
|
||||||
|
|
||||||
def announceTrackerHttps(self, *args, **kwargs):
|
|
||||||
kwargs["protocol"] = "https"
|
|
||||||
return self.announceTrackerHttp(*args, **kwargs)
|
|
||||||
|
|
||||||
def announceTrackerHttp(self, tracker_address, mode="start", num_want=10, protocol="http"):
|
|
||||||
tracker_ip, tracker_port = tracker_address.rsplit(":", 1)
|
|
||||||
if helper.getIpType(tracker_ip) in self.getOpenedServiceTypes():
|
|
||||||
port = self.fileserver_port
|
|
||||||
else:
|
|
||||||
port = 1
|
|
||||||
params = {
|
|
||||||
'info_hash': self.site.address_sha1,
|
|
||||||
'peer_id': self.peer_id, 'port': port,
|
|
||||||
'uploaded': 0, 'downloaded': 0, 'left': 431102370, 'compact': 1, 'numwant': num_want,
|
|
||||||
'event': 'started'
|
|
||||||
}
|
|
||||||
|
|
||||||
url = protocol + "://" + tracker_address + "?" + urllib.parse.urlencode(params)
|
|
||||||
|
|
||||||
s = time.time()
|
|
||||||
response = None
|
|
||||||
# Load url
|
|
||||||
if config.tor == "always" or config.trackers_proxy != "disable":
|
|
||||||
timeout = 60
|
|
||||||
else:
|
|
||||||
timeout = 30
|
|
||||||
|
|
||||||
with gevent.Timeout(timeout, False): # Make sure of timeout
|
|
||||||
req = self.httpRequest(url)
|
|
||||||
response = req.read()
|
|
||||||
req.close()
|
|
||||||
req = None
|
|
||||||
|
|
||||||
if not response:
|
|
||||||
raise AnnounceError("No response after %.0fs" % (time.time() - s))
|
|
||||||
|
|
||||||
# Decode peers
|
|
||||||
try:
|
|
||||||
peer_data = bencode.decode(response)["peers"]
|
|
||||||
if type(peer_data) is not bytes:
|
|
||||||
peer_data = peer_data.encode()
|
|
||||||
response = None
|
|
||||||
peer_count = int(len(peer_data) / 6)
|
|
||||||
peers = []
|
|
||||||
for peer_offset in range(peer_count):
|
|
||||||
off = 6 * peer_offset
|
|
||||||
peer = peer_data[off:off + 6]
|
|
||||||
addr, port = struct.unpack('!LH', peer)
|
|
||||||
peers.append({"addr": socket.inet_ntoa(struct.pack('!L', addr)), "port": port})
|
|
||||||
except Exception as err:
|
|
||||||
raise AnnounceError("Invalid response: %r (%s)" % (response, Debug.formatException(err)))
|
|
||||||
|
|
||||||
return peers
|
|
||||||
|
|
||||||
@util.Noparallel(blocking=False)
|
@util.Noparallel(blocking=False)
|
||||||
def announcePex(self, query_num=2, need_num=5):
|
def announcePex(self, query_num=2, need_num=5):
|
||||||
peers = self.site.getConnectedPeers()
|
peers = self.site.getConnectedPeers()
|
||||||
|
|
Loading…
Reference in a new issue