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:
parent
44d961aefa
commit
5b5c8acdcb
10 changed files with 75 additions and 23 deletions
|
@ -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?
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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")
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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"))
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue