new documents with examples, raise exception on connection error, close connection if no handshake for 60 sec, log unhandled exceptions, calc object size using guppy, typo fix

This commit is contained in:
HelloZeroNet 2015-03-11 01:12:53 +01:00
parent 44d961aefa
commit 5b5c8acdcb
10 changed files with 75 additions and 23 deletions

View File

@ -89,7 +89,7 @@ $ zeronet.py
Congratulations, you're finished! Now anyone can access your site using Congratulations, you're finished! Now anyone can access your site using
`http://localhost:43110/13DNDkMUExRf9Xa9ogwPKqp7zyHFEqbhC2` `http://localhost:43110/13DNDkMUExRf9Xa9ogwPKqp7zyHFEqbhC2`
Next steps: [ZeroNet Developer Documentation](https://github.com/HelloZeroNet/ZeroNet/wiki/ZeroNet-Developer-Documentation) Next steps: [ZeroNet Developer Documentation](http://zeronet.readthedocs.org/en/latest/site_development/debug_mode/)
## How can I modify a ZeroNet site? ## How can I modify a ZeroNet site?

View File

@ -264,6 +264,8 @@ class Connection:
def close(self): def close(self):
if self.closed: return False # Already closed if self.closed: return False # Already closed
self.closed = True self.closed = True
self.event_connected.set(False)
if config.debug_socket: self.log.debug("Closing connection, waiting_requests: %s, buff: %s..." % (len(self.waiting_requests), self.incomplete_buff_recv)) if config.debug_socket: self.log.debug("Closing connection, waiting_requests: %s, buff: %s..." % (len(self.waiting_requests), self.incomplete_buff_recv))
for request in self.waiting_requests.values(): # Mark pending requests failed for request in self.waiting_requests.values(): # Mark pending requests failed
request.set(False) request.set(False)

View File

@ -62,17 +62,22 @@ class ConnectionServer:
def getConnection(self, ip=None, port=None, peer_id=None): def getConnection(self, ip=None, port=None, peer_id=None):
if peer_id and peer_id in self.peer_ids: # Find connection by peer id if peer_id and peer_id in self.peer_ids: # Find connection by peer id
connection = self.peer_ids.get(peer_id) connection = self.peer_ids.get(peer_id)
if not connection.connected: connection.event_connected.get() # Wait for connection if not connection.connected:
succ = connection.event_connected.get() # Wait for connection
if not succ: raise Exception("Connection event return error")
return connection return connection
if ip in self.ips: # Find connection by ip if ip in self.ips: # Find connection by ip
connection = self.ips[ip] connection = self.ips[ip]
if not connection.connected: connection.event_connected.get() # Wait for connection if not connection.connected:
succ = connection.event_connected.get() # Wait for connection
if not succ: raise Exception("Connection event return error")
return connection return connection
# Recover from connection pool # Recover from connection pool
for connection in self.connections: for connection in self.connections:
if connection.ip == ip: if connection.ip == ip:
if not connection.connected: connection.event_connected.get() # Wait for connection if not connection.connected:
succ = connection.event_connected.get() # Wait for connection
if not succ: raise Exception("Connection event return error")
return connection return connection
# No connection found # No connection found
@ -80,7 +85,9 @@ class ConnectionServer:
connection = Connection(self, ip, port) connection = Connection(self, ip, port)
self.ips[ip] = connection self.ips[ip] = connection
self.connections.append(connection) self.connections.append(connection)
connection.connect() succ = connection.connect()
if not succ:
raise Exception("Connection event return error")
except Exception, err: except Exception, err:
self.log.debug("%s Connect error: %s" % (ip, Debug.formatException(err))) self.log.debug("%s Connect error: %s" % (ip, Debug.formatException(err)))
connection.close() connection.close()
@ -103,26 +110,32 @@ class ConnectionServer:
while self.running: while self.running:
time.sleep(60) # Sleep 1 min time.sleep(60) # Sleep 1 min
for connection in self.connections[:]: # Make a copy for connection in self.connections[:]: # Make a copy
if connection.protocol == "zeromq": continue # No stat on ZeroMQ sockets idle = time.time() - max(connection.last_recv_time, connection.start_time, connection.last_message_time)
idle = time.time() - max(connection.last_recv_time, connection.start_time)
if idle > 60*60: # Wake up after 1h if idle > 60*60: # Wake up after 1h
connection.log.debug("[Cleanup] After wakeup: %s" % connection.read_bytes(1024))
connection.close() connection.close()
elif idle > 20*60 and connection.last_send_time < time.time()-10: # Idle more than 20 min and we not send request in last 10 sec elif idle > 20*60 and connection.last_send_time < time.time()-10: # Idle more than 20 min and we not send request in last 10 sec
if connection.protocol == "?": connection.close() # Got no handshake response, close it if connection.protocol == "zeromq":
if idle > 50*60 and not connection.ping(): # Only ping every 50 sec
connection.close()
else: else:
if not connection.ping(): # send ping request if not connection.ping(): # send ping request
connection.close() connection.close()
elif idle > 10 and connection.incomplete_buff_recv > 0: # Incompelte data with more than 10 sec idle elif idle > 10 and connection.incomplete_buff_recv > 0: # Incompelte data with more than 10 sec idle
connection.log.debug("[Cleanup] Connection buff stalled, content: %s" % connection.u.read_bytes(1024)) connection.log.debug("[Cleanup] Connection buff stalled, content: %s" % connection.read_bytes(1024))
connection.close() connection.close()
elif idle > 10 and connection.waiting_requests and time.time() - connection.last_send_time > 10: # Sent command and no response in 10 sec elif idle > 10 and connection.waiting_requests and time.time() - connection.last_send_time > 10: # Sent command and no response in 10 sec
connection.log.debug("[Cleanup] Command %s timeout: %s" % (connection.last_cmd, time.time() - connection.last_send_time)) connection.log.debug("[Cleanup] Command %s timeout: %s" % (connection.last_cmd, time.time() - connection.last_send_time))
connection.close() connection.close()
elif idle > 60 and connection.protocol == "?": # No connection after 1 min
connection.log.debug("[Cleanup] Connect timeout: %s" % idle)
connection.close()
def zmqServer(self): def zmqServer(self):

View File

@ -1,4 +1,4 @@
import gevent, sys import gevent, sys, logging
from Config import config from Config import config
last_error = None last_error = None
@ -13,6 +13,7 @@ def handleError(*args):
silent = False silent = False
if args[0].__name__ != "Notify": last_error = args if args[0].__name__ != "Notify": last_error = args
if not silent and args[0].__name__ != "Notify": if not silent and args[0].__name__ != "Notify":
logging.exception("Unhandled exception")
sys.__excepthook__(*args) sys.__excepthook__(*args)

View File

@ -58,7 +58,7 @@ def merge(merged_path):
parts.append(out) parts.append(out)
else: else:
error = out error = out
logging.error("%s Compile error %s:" % (file_path, error)) logging.error("%s Compile error: %s" % (file_path, error))
parts.append("alert('%s compile error: %s');" % (file_path, re.escape(error).replace("\n", "\\n").replace(r"\\n", r"\n") ) ) parts.append("alert('%s compile error: %s');" % (file_path, re.escape(error).replace("\n", "\\n").replace(r"\\n", r"\n") ) )
else: # Not changed use the old_part else: # Not changed use the old_part
parts.append(old_parts[file_path]) parts.append(old_parts[file_path])
@ -78,4 +78,4 @@ if __name__ == "__main__":
logging.getLogger().setLevel(logging.DEBUG) logging.getLogger().setLevel(logging.DEBUG)
os.chdir("..") os.chdir("..")
config.coffeescript_compiler = r'type "%s" | tools\coffee-node\bin\node.exe tools\coffee-node\bin\coffee --no-header -s -p' config.coffeescript_compiler = r'type "%s" | tools\coffee-node\bin\node.exe tools\coffee-node\bin\coffee --no-header -s -p'
merge("data/1TaLk3zM7ZRskJvrh3ZNCDVGXvkJusPKQ/js/all.js") merge("data/12Hw8rTgzrNo4DSh2AkqwPRqDyTticwJyH/js/all.js")

View File

@ -40,8 +40,7 @@ class Peer:
try: try:
self.connection = self.connection_server.getConnection(self.ip, self.port) self.connection = self.connection_server.getConnection(self.ip, self.port)
except Exception, err: except Exception, err:
self.log.debug("Getting connection error: %s" % Debug.formatException(err)) self.log.debug("Getting connection error: %s (connection_error: %s, hash_failed: %s)" % (Debug.formatException(err), self.connection_error, self.hash_failed))
self.onConnectionError()
def __str__(self): def __str__(self):
return "Peer %-12s" % self.ip return "Peer %-12s" % self.ip
@ -58,7 +57,9 @@ class Peer:
def request(self, cmd, params = {}): def request(self, cmd, params = {}):
if not self.connection or self.connection.closed: if not self.connection or self.connection.closed:
self.connect() self.connect()
if not self.connection: return None # Connection failed if not self.connection:
self.onConnectionError()
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 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 # if not self.ping(): return None

View File

@ -51,6 +51,15 @@ class Site:
self.addEventListeners() self.addEventListeners()
def __str__(self):
return "Site %s" % self.address_short
def __repr__(self):
return "<%s>" % self.__str__()
# Load site settings from data/sites.json # Load site settings from data/sites.json
def loadSettings(self): def loadSettings(self):
sites_settings = json.load(open("data/sites.json")) sites_settings = json.load(open("data/sites.json"))

View File

@ -291,11 +291,29 @@ class UiRequest:
back.append("<td>%s</td>" % formatted) back.append("<td>%s</td>" % formatted)
return "<tr>%s</tr>" % "".join(back) return "<tr>%s</tr>" % "".join(back)
def getObjSize(self, obj, hpy = None):
if hpy:
return float(hpy.iso(obj).domisize)/1024
else:
return 0
def actionStats(self): def actionStats(self):
import gc, sys import gc, sys
hpy = None
if self.get.get("size") == "1": # Calc obj size
try:
import guppy
hpy = guppy.hpy()
except:
pass
self.sendHeader() self.sendHeader()
s = time.time() s = time.time()
main = sys.modules["src.main"] main = sys.modules["src.main"]
# Style
yield """ yield """
<style> <style>
* { font-family: monospace } * { font-family: monospace }
@ -313,7 +331,7 @@ class UiRequest:
yield "CPU: usr %.2fs sys %.2fs | " % process.cpu_times() yield "CPU: usr %.2fs sys %.2fs | " % process.cpu_times()
yield "Open files: %s | " % len(process.open_files()) yield "Open files: %s | " % len(process.open_files())
yield "Sockets: %s" % len(process.connections()) yield "Sockets: %s" % len(process.connections())
yield "<br>" yield " | Calc size <a href='?size=1'>on</a> <a href='?size=0'>off</a><br>"
except Exception, err: except Exception, err:
pass pass
@ -344,33 +362,40 @@ class UiRequest:
objs = [obj for obj in gc.get_objects() if isinstance(obj, greenlet)] objs = [obj for obj in gc.get_objects() if isinstance(obj, greenlet)]
yield "<br>Greenlets (%s):<br>" % len(objs) yield "<br>Greenlets (%s):<br>" % len(objs)
for obj in objs: for obj in objs:
yield " - %sbyte: %s<br>" % (sys.getsizeof(obj), cgi.escape(repr(obj))) yield " - %.3fkb: %s<br>" % (self.getObjSize(obj, hpy), cgi.escape(repr(obj)))
from Worker import Worker from Worker import Worker
objs = [obj for obj in gc.get_objects() if isinstance(obj, Worker)] objs = [obj for obj in gc.get_objects() if isinstance(obj, Worker)]
yield "<br>Workers (%s):<br>" % len(objs) yield "<br>Workers (%s):<br>" % len(objs)
for obj in objs: for obj in objs:
yield " - %sbyte: %s<br>" % (sys.getsizeof(obj), cgi.escape(repr(obj))) yield " - %.3fkb: %s<br>" % (self.getObjSize(obj, hpy), cgi.escape(repr(obj)))
from Connection import Connection from Connection import Connection
objs = [obj for obj in gc.get_objects() if isinstance(obj, Connection)] objs = [obj for obj in gc.get_objects() if isinstance(obj, Connection)]
yield "<br>Connections (%s):<br>" % len(objs) yield "<br>Connections (%s):<br>" % len(objs)
for obj in objs: for obj in objs:
yield " - %sbyte: %s<br>" % (sys.getsizeof(obj), cgi.escape(repr(obj))) yield " - %.3fkb: %s<br>" % (self.getObjSize(obj, hpy), cgi.escape(repr(obj)))
from Site import Site
objs = [obj for obj in gc.get_objects() if isinstance(obj, Site)]
yield "<br>Sites (%s):<br>" % len(objs)
for obj in objs:
yield " - %.3fkb: %s<br>" % (self.getObjSize(obj, hpy), cgi.escape(repr(obj)))
objs = [obj for obj in gc.get_objects() if isinstance(obj, self.server.log.__class__)] objs = [obj for obj in gc.get_objects() if isinstance(obj, self.server.log.__class__)]
yield "<br>Loggers (%s):<br>" % len(objs) yield "<br>Loggers (%s):<br>" % len(objs)
for obj in objs: for obj in objs:
yield " - %sbyte: %s<br>" % (sys.getsizeof(obj), cgi.escape(repr(obj.name))) yield " - %.3fkb: %s<br>" % (self.getObjSize(obj, hpy), cgi.escape(repr(obj.name)))
objs = [obj for obj in gc.get_objects() if isinstance(obj, UiRequest)] objs = [obj for obj in gc.get_objects() if isinstance(obj, UiRequest)]
yield "<br>UiRequest (%s):<br>" % len(objs) yield "<br>UiRequest (%s):<br>" % len(objs)
for obj in objs: for obj in objs:
yield " - %sbyte: %s<br>" % (sys.getsizeof(obj), cgi.escape(repr(obj))) yield " - %.3fkb: %s<br>" % (self.getObjSize(obj, hpy), cgi.escape(repr(obj)))
yield "Done in %.3f" % (time.time()-s) yield "Done in %.3f" % (time.time()-s)

View File

@ -172,6 +172,7 @@ class UiWebsocket:
settings = site.settings.copy() settings = site.settings.copy()
del settings["wrapper_key"] # Dont expose wrapper key del settings["wrapper_key"] # Dont expose wrapper key
del settings["auth_key"] # Dont send auth key twice
ret = { ret = {
"auth_key": self.site.settings["auth_key"], # Obsolete, will be removed "auth_key": self.site.settings["auth_key"], # Obsolete, will be removed

View File

@ -178,7 +178,7 @@ def open_port(port=15441, desc="UpnpPunch"):
local_ips = [_get_local_ip()] local_ips = [_get_local_ip()]
try: try:
local_ips += socket.gethostbyname_ex('')[2] # Get ip by '' hostrname not supported on all platform local_ips += socket.gethostbyname_ex('')[2] # Get ip by '' hostname not supported on all platform
except: except:
pass pass