version 0.2.4, peerPing and peerGetFile commands, old content update bugfix, new network code and protocol, connection share between sites, connection reuse, dont retry bad file more than 3 times in 20 min, multi threaded include file download, shuffle peers before publish, simple internal stats page, dont retry on failed peers, more than 10 peers publish bugfix
This commit is contained in:
parent
531bf68ddd
commit
31d4609a3b
18 changed files with 790 additions and 130 deletions
|
@ -1,21 +1,20 @@
|
|||
import os, logging, gevent, time, msgpack
|
||||
import os, logging, gevent, time, msgpack, sys
|
||||
import zmq.green as zmq
|
||||
from cStringIO import StringIO
|
||||
from Config import config
|
||||
from Debug import Debug
|
||||
|
||||
context = zmq.Context()
|
||||
|
||||
# Communicate remote peers
|
||||
class Peer:
|
||||
def __init__(self, ip, port, site):
|
||||
def __init__(self, ip, port, site=None):
|
||||
self.ip = ip
|
||||
self.port = port
|
||||
self.site = site
|
||||
self.key = "%s:%s" % (ip, port)
|
||||
self.log = None
|
||||
self.connection_server = sys.modules["src.main"].file_server
|
||||
|
||||
self.socket = None
|
||||
self.connection = None
|
||||
self.last_found = None # Time of last found in the torrent tracker
|
||||
self.last_response = None # Time of last successfull response from peer
|
||||
self.last_ping = None # Last response time for ping
|
||||
|
@ -29,19 +28,22 @@ class Peer:
|
|||
|
||||
# Connect to host
|
||||
def connect(self):
|
||||
if self.connection: self.connection.close()
|
||||
self.connection = None
|
||||
if not self.log: self.log = logging.getLogger("Peer:%s:%s" % (self.ip, self.port))
|
||||
if self.socket: self.socket.close()
|
||||
|
||||
self.socket = context.socket(zmq.REQ)
|
||||
self.socket.setsockopt(zmq.RCVTIMEO, 50000) # Wait for data arrive
|
||||
self.socket.setsockopt(zmq.SNDTIMEO, 5000) # Wait for data send
|
||||
self.socket.setsockopt(zmq.LINGER, 500) # Wait for socket close
|
||||
# self.socket.setsockopt(zmq.TCP_KEEPALIVE, 1) # Enable keepalive
|
||||
# self.socket.setsockopt(zmq.TCP_KEEPALIVE_IDLE, 4*60) # Send after 4 minute idle
|
||||
# self.socket.setsockopt(zmq.TCP_KEEPALIVE_INTVL, 15) # Wait 15 sec to response
|
||||
# self.socket.setsockopt(zmq.TCP_KEEPALIVE_CNT, 4) # 4 Probes
|
||||
self.socket.connect('tcp://%s:%s' % (self.ip, self.port))
|
||||
self.log.debug("Connecting...")
|
||||
try:
|
||||
self.connection = self.connection_server.connect(self.ip, self.port)
|
||||
except Exception, err:
|
||||
self.log.debug("Connecting error: %s" % Debug.formatException(err))
|
||||
self.onConnectionError()
|
||||
|
||||
def __str__(self):
|
||||
return "Peer %-12s" % self.ip
|
||||
|
||||
def __repr__(self):
|
||||
return "<%s>" % self.__str__()
|
||||
|
||||
# Found a peer on tracker
|
||||
def found(self):
|
||||
|
@ -49,18 +51,20 @@ class Peer:
|
|||
|
||||
|
||||
# Send a command to peer
|
||||
def sendCmd(self, cmd, params = {}):
|
||||
if not self.socket: self.connect()
|
||||
def request(self, cmd, params = {}):
|
||||
if not self.connection or self.connection.closed:
|
||||
self.connect()
|
||||
if not self.connection: return None # Connection failed
|
||||
|
||||
if cmd != "ping" and self.last_response and time.time() - self.last_response > 20*60: # If last response if older than 20 minute, ping first to see if still alive
|
||||
if not self.ping(): return None
|
||||
|
||||
for retry in range(1,3): # Retry 3 times
|
||||
if config.debug_socket: self.log.debug("sendCmd: %s %s" % (cmd, params.get("inner_path")))
|
||||
#if config.debug_socket: self.log.debug("sendCmd: %s %s" % (cmd, params.get("inner_path")))
|
||||
try:
|
||||
self.socket.send(msgpack.packb({"cmd": cmd, "params": params}, use_bin_type=True))
|
||||
if config.debug_socket: self.log.debug("Sent command: %s" % cmd)
|
||||
response = msgpack.unpackb(self.socket.recv())
|
||||
if config.debug_socket: self.log.debug("Got response to: %s" % cmd)
|
||||
response = self.connection.request(cmd, params)
|
||||
if not response: raise Exception("Send error")
|
||||
#if config.debug_socket: self.log.debug("Got response to: %s" % cmd)
|
||||
if "error" in response:
|
||||
self.log.debug("%s error: %s" % (cmd, response["error"]))
|
||||
self.onConnectionError()
|
||||
|
@ -69,13 +73,14 @@ class Peer:
|
|||
self.last_response = time.time()
|
||||
return response
|
||||
except Exception, err:
|
||||
self.onConnectionError()
|
||||
self.log.debug("%s (connection_error: %s, hash_failed: %s, retry: %s)" % (Debug.formatException(err), self.connection_error, self.hash_failed, retry))
|
||||
time.sleep(1*retry)
|
||||
self.connect()
|
||||
if type(err).__name__ == "Notify" and err.message == "Worker stopped": # Greenlet kill by worker
|
||||
self.log.debug("Peer worker got killed, aborting cmd: %s" % cmd)
|
||||
if type(err).__name__ == "Notify": # Greenlet kill by worker
|
||||
self.log.debug("Peer worker got killed: %s, aborting cmd: %s" % (err.message, cmd))
|
||||
break
|
||||
else:
|
||||
self.onConnectionError()
|
||||
self.log.debug("%s (connection_error: %s, hash_failed: %s, retry: %s)" % (Debug.formatException(err), self.connection_error, self.hash_failed, retry))
|
||||
time.sleep(1*retry)
|
||||
self.connect()
|
||||
return None # Failed after 4 retry
|
||||
|
||||
|
||||
|
@ -85,7 +90,7 @@ class Peer:
|
|||
buff = StringIO()
|
||||
s = time.time()
|
||||
while 1: # Read in 512k parts
|
||||
back = self.sendCmd("getFile", {"site": site, "inner_path": inner_path, "location": location}) # Get file content from last location
|
||||
back = self.request("getFile", {"site": site, "inner_path": inner_path, "location": location}) # Get file content from last location
|
||||
if not back or "body" not in back: # Error
|
||||
return False
|
||||
|
||||
|
@ -106,7 +111,8 @@ class Peer:
|
|||
for retry in range(1,3): # Retry 3 times
|
||||
s = time.time()
|
||||
with gevent.Timeout(10.0, False): # 10 sec timeout, dont raise exception
|
||||
response = self.sendCmd("ping")
|
||||
response = self.request("ping")
|
||||
|
||||
if response and "body" in response and response["body"] == "Pong!":
|
||||
response_time = time.time()-s
|
||||
break # All fine, exit from for loop
|
||||
|
@ -126,7 +132,8 @@ class Peer:
|
|||
def remove(self):
|
||||
self.log.debug("Removing peer...Connection error: %s, Hash failed: %s" % (self.connection_error, self.hash_failed))
|
||||
if self.key in self.site.peers: del(self.site.peers[self.key])
|
||||
self.socket.close()
|
||||
if self.connection:
|
||||
self.connection.close()
|
||||
|
||||
|
||||
# - EVENTS -
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue