import time import html import os import json import sys import itertools from Plugin import PluginManager from Config import config from util import helper from Debug import Debug from Db import Db @PluginManager.registerTo("UiRequest") class UiRequestPlugin(object): def formatTableRow(self, row, class_name=""): back = [] for format, val in row: if val is None: formatted = "n/a" elif format == "since": if val: formatted = "%.0f" % (time.time() - val) else: formatted = "n/a" else: formatted = format % val back.append("%s" % formatted) return "%s" % (class_name, "".join(back)) def getObjSize(self, obj, hpy=None): if hpy: return float(hpy.iso(obj).domisize) / 1024 else: return 0 def renderHead(self): import main from Crypt import CryptConnection # Memory yield "rev%s | " % config.rev yield "%s | " % main.file_server.ip_external_list yield "Port: %s | " % main.file_server.port yield "Network: %s | " % main.file_server.supported_ip_types yield "Opened: %s | " % main.file_server.port_opened yield "Crypt: %s, TLSv1.3: %s | " % (CryptConnection.manager.crypt_supported, CryptConnection.ssl.HAS_TLSv1_3) yield "In: %.2fMB, Out: %.2fMB | " % ( float(main.file_server.bytes_recv) / 1024 / 1024, float(main.file_server.bytes_sent) / 1024 / 1024 ) yield "Peerid: %s | " % main.file_server.peer_id yield "Time: %.2fs | " % main.file_server.getTimecorrection() yield "Blocks: %s" % Debug.num_block try: import psutil process = psutil.Process(os.getpid()) mem = process.get_memory_info()[0] / float(2 ** 20) yield "Mem: %.2fMB | " % mem yield "Threads: %s | " % len(process.threads()) yield "CPU: usr %.2fs sys %.2fs | " % process.cpu_times() yield "Files: %s | " % len(process.open_files()) yield "Sockets: %s | " % len(process.connections()) yield "Calc size on off" except Exception: pass yield "
" def renderConnectionsTable(self): import main # Connections yield "Connections (%s, total made: %s, in: %s, out: %s):
" % ( len(main.file_server.connections), main.file_server.last_connection_id, main.file_server.num_incoming, main.file_server.num_outgoing ) yield "" yield "" yield "" for connection in main.file_server.connections: if "cipher" in dir(connection.sock): cipher = connection.sock.cipher()[0] tls_version = connection.sock.version() else: cipher = connection.crypt tls_version = "" if "time" in connection.handshake and connection.last_ping_delay: time_correction = connection.handshake["time"] - connection.handshake_time - connection.last_ping_delay else: time_correction = 0.0 yield self.formatTableRow([ ("%3d", connection.id), ("%s", connection.type), ("%s:%s", (connection.ip, connection.port)), ("%s", connection.handshake.get("port_opened")), ("%s", (cipher, tls_version, connection.crypt)), ("%6.3f", connection.last_ping_delay), ("%s", connection.incomplete_buff_recv), ("%s", connection.bad_actions), ("since", max(connection.last_send_time, connection.last_recv_time)), ("since", connection.start_time), ("%.3f", max(-1, connection.last_sent_time - connection.last_send_time)), ("%.3f", connection.cpu_time), ("%.0fk", connection.bytes_sent / 1024), ("%.0fk", connection.bytes_recv / 1024), ("%s", (connection.last_cmd_recv, connection.last_cmd_sent)), ("%s", list(connection.waiting_requests.keys())), ("%s r%s", (connection.handshake.get("version"), connection.handshake.get("rev", "?"))), ("%.2fs", time_correction), ("%s", connection.sites) ]) yield "
id type ip open crypt pingbuff bad idle open delay cpu out in last sentwait version time sites
" def renderTrackers(self): # Trackers yield "

Trackers:
" yield "" from Site import SiteAnnouncer # importing at the top of the file breaks plugins for tracker_address, tracker_stat in sorted(SiteAnnouncer.global_stats.items()): yield self.formatTableRow([ ("%s", tracker_address), ("%s", tracker_stat["num_request"]), ("%s", tracker_stat["num_error"]), ("%.0f min ago", min(999, (time.time() - tracker_stat["time_request"]) / 60)) ]) yield "
address request successive errors last_request
" if "AnnounceShare" in PluginManager.plugin_manager.plugin_names: yield "

Shared trackers:
" yield "" from AnnounceShare import AnnounceSharePlugin for tracker_address, tracker_stat in sorted(AnnounceSharePlugin.tracker_storage.getTrackers().items()): yield self.formatTableRow([ ("%s", tracker_address), ("%.0f min ago", min(999, (time.time() - tracker_stat["time_added"]) / 60)), ("%.0f min ago", min(999, (time.time() - tracker_stat.get("time_found", 0)) / 60)), ("%.3fs", tracker_stat["latency"]), ("%s", tracker_stat["num_error"]), ("%.0f min ago", min(999, (time.time() - tracker_stat["time_success"]) / 60)), ]) yield "
address added found latency successive errors last_success
" def renderTor(self): import main yield "

Tor hidden services (status: %s):
" % main.file_server.tor_manager.status for site_address, onion in list(main.file_server.tor_manager.site_onions.items()): yield "- %-34s: %s
" % (site_address, onion) def renderDbStats(self): yield "

Db:
" for db in Db.opened_dbs: tables = [row["name"] for row in db.execute("SELECT name FROM sqlite_master WHERE type = 'table'").fetchall()] table_rows = {} for table in tables: table_rows[table] = db.execute("SELECT COUNT(*) AS c FROM %s" % table).fetchone()["c"] db_size = os.path.getsize(db.db_path) / 1024.0 / 1024.0 yield "- %.3fs: %s %.3fMB, table rows: %s
" % ( time.time() - db.last_query_time, db.db_path, db_size, json.dumps(table_rows, sort_keys=True) ) def renderSites(self): yield "

Sites:" yield "" yield "" for site in list(self.server.sites.values()): yield self.formatTableRow([ ( """%s""", (site.address, site.address) ), ("%s", [peer.connection.id for peer in list(site.peers.values()) if peer.connection and peer.connection.connected]), ("%s/%s/%s", ( len([peer for peer in list(site.peers.values()) if peer.connection and peer.connection.connected]), len(site.getConnectablePeers(100)), len(site.peers) )), ("%s (loaded: %s)", ( len(site.content_manager.contents), len([key for key, val in dict(site.content_manager.contents).items() if val]) )), ("%.0fk", site.settings.get("bytes_sent", 0) / 1024), ("%.0fk", site.settings.get("bytes_recv", 0) / 1024), ], "serving-%s" % site.settings["serving"]) yield "" yield "
address connected peers content.json out in
" def renderBigfiles(self): yield "

Big files:
" for site in list(self.server.sites.values()): if not site.settings.get("has_bigfile"): continue bigfiles = {} yield """%s
""" % (site.address, site.address) for peer in list(site.peers.values()): if not peer.time_piecefields_updated: continue for sha512, piecefield in peer.piecefields.items(): if sha512 not in bigfiles: bigfiles[sha512] = [] bigfiles[sha512].append(peer) yield "" def renderRequests(self): import main yield "
" yield "

Sent commands:
" yield "" for stat_key, stat in sorted(main.file_server.stat_sent.items(), key=lambda i: i[1]["bytes"], reverse=True): yield "" % (stat_key, stat["num"], stat["bytes"] / 1024) yield "
%sx %s =%.0fkB
" yield "
" yield "
" yield "

Received commands:
" yield "" for stat_key, stat in sorted(main.file_server.stat_recv.items(), key=lambda i: i[1]["bytes"], reverse=True): yield "" % (stat_key, stat["num"], stat["bytes"] / 1024) yield "
%sx %s =%.0fkB
" yield "
" yield "
" def renderMemory(self): import gc from Ui import UiRequest hpy = None if self.get.get("size") == "1": # Calc obj size try: import guppy hpy = guppy.hpy() except Exception: pass self.sendHeader() # Object types obj_count = {} for obj in gc.get_objects(): obj_type = str(type(obj)) if obj_type not in obj_count: obj_count[obj_type] = [0, 0] obj_count[obj_type][0] += 1 # Count obj_count[obj_type][1] += float(sys.getsizeof(obj)) / 1024 # Size yield "

Objects in memory (types: %s, total: %s, %.2fkb):
" % ( len(obj_count), sum([stat[0] for stat in list(obj_count.values())]), sum([stat[1] for stat in list(obj_count.values())]) ) for obj, stat in sorted(list(obj_count.items()), key=lambda x: x[1][0], reverse=True): # Sorted by count yield " - %.1fkb = %s x %s
" % (stat[1], stat[0], obj, html.escape(obj)) # Classes class_count = {} for obj in gc.get_objects(): obj_type = str(type(obj)) if obj_type != "": continue class_name = obj.__class__.__name__ if class_name not in class_count: class_count[class_name] = [0, 0] class_count[class_name][0] += 1 # Count class_count[class_name][1] += float(sys.getsizeof(obj)) / 1024 # Size yield "

Classes in memory (types: %s, total: %s, %.2fkb):
" % ( len(class_count), sum([stat[0] for stat in list(class_count.values())]), sum([stat[1] for stat in list(class_count.values())]) ) for obj, stat in sorted(list(class_count.items()), key=lambda x: x[1][0], reverse=True): # Sorted by count yield " - %.1fkb = %s x %s
" % (stat[1], stat[0], obj, html.escape(obj)) from greenlet import greenlet objs = [obj for obj in gc.get_objects() if isinstance(obj, greenlet)] yield "
Greenlets (%s):
" % len(objs) for obj in objs: yield " - %.1fkb: %s
" % (self.getObjSize(obj, hpy), html.escape(repr(obj))) from Worker import Worker objs = [obj for obj in gc.get_objects() if isinstance(obj, Worker)] yield "
Workers (%s):
" % len(objs) for obj in objs: yield " - %.1fkb: %s
" % (self.getObjSize(obj, hpy), html.escape(repr(obj))) from Connection import Connection objs = [obj for obj in gc.get_objects() if isinstance(obj, Connection)] yield "
Connections (%s):
" % len(objs) for obj in objs: yield " - %.1fkb: %s
" % (self.getObjSize(obj, hpy), html.escape(repr(obj))) from socket import socket objs = [obj for obj in gc.get_objects() if isinstance(obj, socket)] yield "
Sockets (%s):
" % len(objs) for obj in objs: yield " - %.1fkb: %s
" % (self.getObjSize(obj, hpy), html.escape(repr(obj))) from msgpack import Unpacker objs = [obj for obj in gc.get_objects() if isinstance(obj, Unpacker)] yield "
Msgpack unpacker (%s):
" % len(objs) for obj in objs: yield " - %.1fkb: %s
" % (self.getObjSize(obj, hpy), html.escape(repr(obj))) from Site.Site import Site objs = [obj for obj in gc.get_objects() if isinstance(obj, Site)] yield "
Sites (%s):
" % len(objs) for obj in objs: yield " - %.1fkb: %s
" % (self.getObjSize(obj, hpy), html.escape(repr(obj))) objs = [obj for obj in gc.get_objects() if isinstance(obj, self.server.log.__class__)] yield "
Loggers (%s):
" % len(objs) for obj in objs: yield " - %.1fkb: %s
" % (self.getObjSize(obj, hpy), html.escape(repr(obj.name))) objs = [obj for obj in gc.get_objects() if isinstance(obj, UiRequest)] yield "
UiRequests (%s):
" % len(objs) for obj in objs: yield " - %.1fkb: %s
" % (self.getObjSize(obj, hpy), html.escape(repr(obj))) from Peer import Peer objs = [obj for obj in gc.get_objects() if isinstance(obj, Peer)] yield "
Peers (%s):
" % len(objs) for obj in objs: yield " - %.1fkb: %s
" % (self.getObjSize(obj, hpy), html.escape(repr(obj))) objs = [(key, val) for key, val in sys.modules.items() if val is not None] objs.sort() yield "
Modules (%s):
" % len(objs) for module_name, module in objs: yield " - %.3fkb: %s %s
" % (self.getObjSize(module, hpy), module_name, html.escape(repr(module))) # /Stats entry point @helper.encodeResponse def actionStats(self): import gc self.sendHeader() if "Multiuser" in PluginManager.plugin_manager.plugin_names and not config.multiuser_local: yield "This function is disabled on this proxy" return s = time.time() # Style yield """ """ renderers = [ self.renderHead(), self.renderConnectionsTable(), self.renderTrackers(), self.renderTor(), self.renderDbStats(), self.renderSites(), self.renderBigfiles(), self.renderRequests() ] for part in itertools.chain(*renderers): yield part if config.debug: for part in self.renderMemory(): yield part gc.collect() # Implicit grabage collection yield "Done in %.1f" % (time.time() - s) @helper.encodeResponse def actionDumpobj(self): import gc import sys self.sendHeader() if "Multiuser" in PluginManager.plugin_manager.plugin_names and not config.multiuser_local: yield "This function is disabled on this proxy" return # No more if not in debug mode if not config.debug: yield "Not in debug mode" return class_filter = self.get.get("class") yield """ """ objs = gc.get_objects() for obj in objs: obj_type = str(type(obj)) if obj_type != "" or obj.__class__.__name__ != class_filter: continue yield "%.1fkb %s... " % (float(sys.getsizeof(obj)) / 1024, html.escape(str(obj))) for attr in dir(obj): yield "- %s: %s
" % (attr, html.escape(str(getattr(obj, attr)))) yield "
" gc.collect() # Implicit grabage collection @helper.encodeResponse def actionListobj(self): import gc import sys self.sendHeader() if "Multiuser" in PluginManager.plugin_manager.plugin_names and not config.multiuser_local: yield "This function is disabled on this proxy" return # No more if not in debug mode if not config.debug: yield "Not in debug mode" return type_filter = self.get.get("type") yield """ """ yield "Listing all %s objects in memory...
" % html.escape(type_filter) ref_count = {} objs = gc.get_objects() for obj in objs: obj_type = str(type(obj)) if obj_type != type_filter: continue refs = [ ref for ref in gc.get_referrers(obj) if hasattr(ref, "__class__") and ref.__class__.__name__ not in ["list", "dict", "function", "type", "frame", "WeakSet", "tuple"] ] if not refs: continue try: yield "%.1fkb %s... " % ( float(sys.getsizeof(obj)) / 1024, html.escape(str(obj)), html.escape(str(obj)[0:100].ljust(100)) ) except Exception: continue for ref in refs: yield " [" if "object at" in str(ref) or len(str(ref)) > 100: yield str(ref.__class__.__name__) else: yield str(ref.__class__.__name__) + ":" + html.escape(str(ref)) yield "] " ref_type = ref.__class__.__name__ if ref_type not in ref_count: ref_count[ref_type] = [0, 0] ref_count[ref_type][0] += 1 # Count ref_count[ref_type][1] += float(sys.getsizeof(obj)) / 1024 # Size yield "
" yield "
Object referrer (total: %s, %.2fkb):
" % (len(ref_count), sum([stat[1] for stat in list(ref_count.values())])) for obj, stat in sorted(list(ref_count.items()), key=lambda x: x[1][0], reverse=True)[0:30]: # Sorted by count yield " - %.1fkb = %s x %s
" % (stat[1], stat[0], html.escape(str(obj))) gc.collect() # Implicit grabage collection @helper.encodeResponse def actionGcCollect(self): import gc self.sendHeader() yield str(gc.collect()) # /About entry point @helper.encodeResponse def actionEnv(self): import main self.sendHeader() yield """ """ if "Multiuser" in PluginManager.plugin_manager.plugin_names and not config.multiuser_local: yield "This function is disabled on this proxy" return yield from main.actions.testEnv(format="html") @PluginManager.registerTo("Actions") class ActionsPlugin: def formatTable(self, *rows, format="text"): if format == "html": return self.formatTableHtml(*rows) else: return self.formatTableText(*rows) def formatHead(self, title, format="text"): if format == "html": return "

%s

" % title else: return "\n* %s\n" % title def formatTableHtml(self, *rows): yield "" for row in rows: yield "" for col in row: yield "" % html.escape(str(col)) yield "" yield "
%s
" def formatTableText(self, *rows): for row in rows: yield " " for col in row: yield " " + str(col) yield "\n" def testEnv(self, format="text"): import gevent import msgpack import pkg_resources import importlib import coincurve import sqlite3 from Crypt import CryptBitcoin yield "\n" yield from self.formatTable( ["ZeroNet version:", "%s rev%s" % (config.version, config.rev)], ["Python:", "%s" % sys.version], ["Platform:", "%s" % sys.platform], ["Crypt verify lib:", "%s" % CryptBitcoin.lib_verify_best], ["OpenSSL:", "%s" % CryptBitcoin.sslcrypto.ecc.get_backend()], ["Libsecp256k1:", "%s" % type(coincurve._libsecp256k1.lib).__name__], ["SQLite:", "%s, API: %s" % (sqlite3.sqlite_version, sqlite3.version)], format=format ) yield self.formatHead("Libraries:") rows = [] for lib_name in ["gevent", "greenlet", "msgpack", "base58", "merkletools", "rsa", "socks", "pyasn1", "gevent_ws", "websocket", "maxminddb"]: try: module = importlib.import_module(lib_name) if "__version__" in dir(module): version = module.__version__ elif "version" in dir(module): version = module.version else: version = "unknown version" if type(version) is tuple: version = ".".join(map(str, version)) rows.append(["- %s:" % lib_name, version, "at " + module.__file__]) except Exception as err: rows.append(["! Error importing %s:", repr(err)]) """ try: yield " - %s
" % html.escape(repr(pkg_resources.get_distribution(lib_name))) except Exception as err: yield " ! %s
" % html.escape(repr(err)) """ yield from self.formatTable(*rows, format=format) yield self.formatHead("Library config:", format=format) yield from self.formatTable( ["- gevent:", gevent.config.loop.__module__], ["- msgpack unpacker:", msgpack.Unpacker.__module__], format=format )