Sexy system trac icon instead of ugly console, Total received/sent stat, List all site peer, Dont sent passive peers over pex, Dont store passive peers on trackers, Dont monkey patch thread at all, Allow main command plugins
This commit is contained in:
parent
804fed2659
commit
30281c8fb5
14 changed files with 1170 additions and 207 deletions
|
@ -162,6 +162,7 @@ class Connection:
|
|||
self.last_recv_time = time.time()
|
||||
self.incomplete_buff_recv += 1
|
||||
self.bytes_recv += len(buff)
|
||||
self.server.bytes_recv += len(buff)
|
||||
if not self.unpacker:
|
||||
self.unpacker = msgpack.Unpacker()
|
||||
self.unpacker.feed(buff)
|
||||
|
@ -198,13 +199,19 @@ class Connection:
|
|||
if config.debug_socket: self.log("Got handshake response: %s, ping: %s" % (message, ping))
|
||||
self.last_ping_delay = ping
|
||||
self.handshake = message
|
||||
self.port = message["fileserver_port"] # Set peer fileserver port
|
||||
if self.handshake.get("port_opened", None) == False: # Not connectable
|
||||
self.port = 0
|
||||
else:
|
||||
self.port = message["fileserver_port"] # Set peer fileserver port
|
||||
else:
|
||||
self.log("Unknown response: %s" % message)
|
||||
elif message.get("cmd"): # Handhsake request
|
||||
if message["cmd"] == "handshake":
|
||||
self.handshake = message["params"]
|
||||
self.port = self.handshake["fileserver_port"] # Set peer fileserver port
|
||||
if self.handshake.get("port_opened", None) == False: # Not connectable
|
||||
self.port = 0
|
||||
else:
|
||||
self.port = self.handshake["fileserver_port"] # Set peer fileserver port
|
||||
if config.debug_socket: self.log("Handshake request: %s" % message)
|
||||
data = self.handshakeInfo()
|
||||
data["cmd"] = "response"
|
||||
|
@ -242,6 +249,7 @@ class Connection:
|
|||
else: # Normal connection
|
||||
data = msgpack.packb(message)
|
||||
self.bytes_sent += len(data)
|
||||
self.server.bytes_sent += len(data)
|
||||
self.sock.sendall(data)
|
||||
self.last_sent_time = time.time()
|
||||
return True
|
||||
|
|
|
@ -22,6 +22,9 @@ class ConnectionServer:
|
|||
self.running = True
|
||||
self.thread_checker = gevent.spawn(self.checkConnections)
|
||||
|
||||
self.bytes_recv = 0
|
||||
self.bytes_sent = 0
|
||||
|
||||
self.zmq_running = False
|
||||
self.zmq_last_connection = None # Last incoming message client
|
||||
|
||||
|
@ -82,6 +85,8 @@ class ConnectionServer:
|
|||
return connection
|
||||
|
||||
# No connection found
|
||||
if port == 0:
|
||||
raise Exception("This peer is not connectable")
|
||||
try:
|
||||
connection = Connection(self, ip, port)
|
||||
self.ips[ip] = connection
|
||||
|
|
|
@ -131,10 +131,10 @@ class FileRequest:
|
|||
address = self.unpackAddress(peer)
|
||||
got_peer_keys.append("%s:%s" % address)
|
||||
if (site.addPeer(*address)): added += 1
|
||||
# Send back peers that is not in the sent list
|
||||
# Send back peers that is not in the sent list and connectable (not port 0)
|
||||
peers = site.peers.values()
|
||||
random.shuffle(peers)
|
||||
packed_peers = [peer.packAddress() for peer in peers if peer.key not in got_peer_keys][0:params["need"]]
|
||||
packed_peers = [peer.packAddress() for peer in peers if not peer.key.endswith(":0") and peer.key not in got_peer_keys][0:params["need"]]
|
||||
if added:
|
||||
self.log.debug("Added %s peers to %s using pex, sending back %s" % (added, site, len(packed_peers)))
|
||||
self.response({"peers": packed_peers})
|
||||
|
|
|
@ -150,7 +150,7 @@ class Peer:
|
|||
if not site: site = self.site # If no site definied request peers for this site
|
||||
peers = self.site.peers.values()
|
||||
random.shuffle(peers)
|
||||
packed_peers = [peer.packAddress() for peer in peers][0:need_num]
|
||||
packed_peers = [peer.packAddress() for peer in peers if not peer.key.endswith(":0")][0:need_num]
|
||||
response = self.request("pex", {"site": site.address, "peers": packed_peers, "need": need_num})
|
||||
if not response or "error" in response:
|
||||
return False
|
||||
|
|
|
@ -319,11 +319,10 @@ class Site:
|
|||
address_hash = hashlib.sha1(self.address).hexdigest()
|
||||
my_peer_id = sys.modules["main"].file_server.peer_id
|
||||
|
||||
# Later, if we have peer exchange
|
||||
"""if sys.modules["main"].file_server.port_opened:
|
||||
if sys.modules["main"].file_server.port_opened:
|
||||
fileserver_port = config.fileserver_port
|
||||
else: # Port not opened, report port 0
|
||||
fileserver_port = 0"""
|
||||
fileserver_port = 0
|
||||
|
||||
fileserver_port = config.fileserver_port
|
||||
s = time.time()
|
||||
|
|
|
@ -112,9 +112,11 @@ class UiServer:
|
|||
|
||||
|
||||
def stop(self):
|
||||
self.log.debug("Stopping...")
|
||||
# Close WS sockets
|
||||
for client in self.server.clients.values():
|
||||
client.ws.close()
|
||||
if "clients" in dir(self.server):
|
||||
for client in self.server.clients.values():
|
||||
client.ws.close()
|
||||
# Close http sockets
|
||||
sock_closed = 0
|
||||
for sock in self.server.sockets.values():
|
||||
|
|
384
src/main.py
384
src/main.py
|
@ -35,11 +35,10 @@ logging.getLogger('').name = "-" # Remove root prefix
|
|||
from Debug import DebugHook
|
||||
if config.debug:
|
||||
console_log.setLevel(logging.DEBUG) # Display everything to console
|
||||
from gevent import monkey; monkey.patch_all(thread=False) # thread=False because of pyfilesystem
|
||||
else:
|
||||
console_log.setLevel(logging.INFO) # Display only important info to console
|
||||
from gevent import monkey; monkey.patch_all() # Make time, thread, socket gevent compatible
|
||||
|
||||
from gevent import monkey; monkey.patch_all(thread=False) # Make time, socket gevent compatible
|
||||
import gevent
|
||||
import time
|
||||
|
||||
|
@ -64,195 +63,196 @@ PluginManager.plugin_manager.loadPlugins()
|
|||
|
||||
# -- Actions --
|
||||
|
||||
@PluginManager.acceptPlugins
|
||||
class Actions:
|
||||
# Default action: Start serving UiServer and FileServer
|
||||
def main(self):
|
||||
logging.info("Version: %s, Python %s, Gevent: %s" % (config.version, sys.version, gevent.__version__))
|
||||
global ui_server, file_server
|
||||
from File import FileServer
|
||||
from Ui import UiServer
|
||||
logging.info("Creating UiServer....")
|
||||
ui_server = UiServer()
|
||||
|
||||
logging.info("Creating FileServer....")
|
||||
file_server = FileServer()
|
||||
|
||||
logging.info("Starting servers....")
|
||||
gevent.joinall([gevent.spawn(ui_server.start), gevent.spawn(file_server.start)])
|
||||
|
||||
|
||||
# Site commands
|
||||
|
||||
def siteCreate(self):
|
||||
logging.info("Generating new privatekey...")
|
||||
from Crypt import CryptBitcoin
|
||||
privatekey = CryptBitcoin.newPrivatekey()
|
||||
logging.info("----------------------------------------------------------------------")
|
||||
logging.info("Site private key: %s" % privatekey)
|
||||
logging.info(" !!! ^ Save it now, required to modify the site ^ !!!")
|
||||
address = CryptBitcoin.privatekeyToAddress(privatekey)
|
||||
logging.info("Site address: %s" % address)
|
||||
logging.info("----------------------------------------------------------------------")
|
||||
|
||||
while True:
|
||||
if raw_input("? Have you secured your private key? (yes, no) > ").lower() == "yes": break
|
||||
else: logging.info("Please, secure it now, you going to need it to modify your site!")
|
||||
|
||||
logging.info("Creating directory structure...")
|
||||
from Site import Site
|
||||
os.mkdir("data/%s" % address)
|
||||
open("data/%s/index.html" % address, "w").write("Hello %s!" % address)
|
||||
|
||||
logging.info("Creating content.json...")
|
||||
site = Site(address)
|
||||
site.content_manager.sign(privatekey=privatekey)
|
||||
site.settings["own"] = True
|
||||
site.saveSettings()
|
||||
|
||||
logging.info("Site created!")
|
||||
|
||||
|
||||
def siteSign(self, address, privatekey=None, inner_path="content.json"):
|
||||
from Site import Site
|
||||
logging.info("Signing site: %s..." % address)
|
||||
site = Site(address, allow_create = False)
|
||||
|
||||
if not privatekey: # If no privatekey in args then ask it now
|
||||
import getpass
|
||||
privatekey = getpass.getpass("Private key (input hidden):")
|
||||
site.content_manager.sign(inner_path=inner_path, privatekey=privatekey, update_changed_files=True)
|
||||
|
||||
|
||||
def siteVerify(self, address):
|
||||
from Site import Site
|
||||
logging.info("Verifing site: %s..." % address)
|
||||
site = Site(address)
|
||||
|
||||
for content_inner_path in site.content_manager.contents:
|
||||
logging.info("Verifing %s signature..." % content_inner_path)
|
||||
if site.content_manager.verifyFile(content_inner_path, site.storage.open(content_inner_path, "rb"), ignore_same=False) == True:
|
||||
logging.info("[OK] %s signed by address %s!" % (content_inner_path, address))
|
||||
else:
|
||||
logging.error("[ERROR] %s not signed by address %s!" % (content_inner_path, address))
|
||||
|
||||
logging.info("Verifying site files...")
|
||||
bad_files = site.storage.verifyFiles()
|
||||
if not bad_files:
|
||||
logging.info("[OK] All file sha512sum matches!")
|
||||
else:
|
||||
logging.error("[ERROR] Error during verifying site files!")
|
||||
|
||||
|
||||
def dbRebuild(self, address):
|
||||
from Site import Site
|
||||
logging.info("Rebuilding site sql cache: %s..." % address)
|
||||
site = Site(address)
|
||||
s = time.time()
|
||||
site.storage.rebuildDb()
|
||||
logging.info("Done in %.3fs" % (time.time()-s))
|
||||
|
||||
|
||||
def dbQuery(self, address, query):
|
||||
from Site import Site
|
||||
import json
|
||||
site = Site(address)
|
||||
result = []
|
||||
for row in site.storage.query(query):
|
||||
result.append(dict(row))
|
||||
print json.dumps(result, indent=4)
|
||||
|
||||
|
||||
def siteAnnounce(self, address):
|
||||
from Site.Site import Site
|
||||
logging.info("Announcing site %s to tracker..." % address)
|
||||
site = Site(address)
|
||||
|
||||
s = time.time()
|
||||
site.announce()
|
||||
print "Response time: %.3fs" % (time.time()-s)
|
||||
print site.peers
|
||||
|
||||
|
||||
def siteNeedFile(self, address, inner_path):
|
||||
from Site import Site
|
||||
site = Site(address)
|
||||
site.announce()
|
||||
print site.needFile(inner_path, update=True)
|
||||
|
||||
|
||||
def sitePublish(self, address, peer_ip=None, peer_port=15441, inner_path="content.json"):
|
||||
global file_server
|
||||
from Site import Site
|
||||
from File import FileServer # We need fileserver to handle incoming file requests
|
||||
|
||||
logging.info("Creating FileServer....")
|
||||
file_server = FileServer()
|
||||
file_server_thread = gevent.spawn(file_server.start, check_sites=False) # Dont check every site integrity
|
||||
file_server.openport()
|
||||
if file_server.port_opened == False:
|
||||
logging.info("Port not opened, passive publishing not supported yet :(")
|
||||
return
|
||||
site = file_server.sites[address]
|
||||
site.settings["serving"] = True # Serving the site even if its disabled
|
||||
if peer_ip: # Announce ip specificed
|
||||
site.addPeer(peer_ip, peer_port)
|
||||
else: # Just ask the tracker
|
||||
logging.info("Gathering peers from tracker")
|
||||
site.announce() # Gather peers
|
||||
site.publish(20, inner_path) # Push to 20 peers
|
||||
time.sleep(3)
|
||||
logging.info("Serving files...")
|
||||
gevent.joinall([file_server_thread])
|
||||
logging.info("Done.")
|
||||
|
||||
|
||||
|
||||
# Crypto commands
|
||||
|
||||
def cryptoPrivatekeyToAddress(self, privatekey=None):
|
||||
from Crypt import CryptBitcoin
|
||||
if not privatekey: # If no privatekey in args then ask it now
|
||||
import getpass
|
||||
privatekey = getpass.getpass("Private key (input hidden):")
|
||||
|
||||
print CryptBitcoin.privatekeyToAddress(privatekey)
|
||||
|
||||
|
||||
# Peer
|
||||
|
||||
def peerPing(self, peer_ip, peer_port):
|
||||
logging.info("Opening a simple connection server")
|
||||
global file_server
|
||||
from Connection import ConnectionServer
|
||||
file_server = ConnectionServer("127.0.0.1", 1234)
|
||||
|
||||
from Peer import Peer
|
||||
logging.info("Pinging 5 times peer: %s:%s..." % (peer_ip, int(peer_port)))
|
||||
peer = Peer(peer_ip, peer_port)
|
||||
for i in range(5):
|
||||
s = time.time()
|
||||
print peer.ping(),
|
||||
print "Response time: %.3fs" % (time.time()-s)
|
||||
time.sleep(1)
|
||||
|
||||
|
||||
def peerGetFile(self, peer_ip, peer_port, site, filename):
|
||||
logging.info("Opening a simple connection server")
|
||||
global file_server
|
||||
from Connection import ConnectionServer
|
||||
file_server = ConnectionServer()
|
||||
|
||||
from Peer import Peer
|
||||
logging.info("Getting %s/%s from peer: %s:%s..." % (site, filename, peer_ip, peer_port))
|
||||
peer = Peer(peer_ip, peer_port)
|
||||
s = time.time()
|
||||
print peer.getFile(site, filename).read()
|
||||
print "Response time: %.3fs" % (time.time()-s)
|
||||
|
||||
actions = Actions()
|
||||
# Starts here when running zeronet.py
|
||||
def start():
|
||||
action_func = globals()[config.action] # Function reference
|
||||
action_kwargs = config.getActionArguments() # non-config arguments when calling zeronet.py
|
||||
|
||||
action_func(**action_kwargs)
|
||||
|
||||
|
||||
# Start serving UiServer and PeerServer
|
||||
def main():
|
||||
logging.info("Version: %s, Python %s, Gevent: %s" % (config.version, sys.version, gevent.__version__))
|
||||
global ui_server, file_server
|
||||
from File import FileServer
|
||||
from Ui import UiServer
|
||||
logging.info("Creating UiServer....")
|
||||
ui_server = UiServer()
|
||||
|
||||
logging.info("Creating FileServer....")
|
||||
file_server = FileServer()
|
||||
|
||||
logging.info("Starting servers....")
|
||||
gevent.joinall([gevent.spawn(ui_server.start), gevent.spawn(file_server.start)])
|
||||
|
||||
|
||||
# Site commands
|
||||
|
||||
def siteCreate():
|
||||
logging.info("Generating new privatekey...")
|
||||
from Crypt import CryptBitcoin
|
||||
privatekey = CryptBitcoin.newPrivatekey()
|
||||
logging.info("----------------------------------------------------------------------")
|
||||
logging.info("Site private key: %s" % privatekey)
|
||||
logging.info(" !!! ^ Save it now, required to modify the site ^ !!!")
|
||||
address = CryptBitcoin.privatekeyToAddress(privatekey)
|
||||
logging.info("Site address: %s" % address)
|
||||
logging.info("----------------------------------------------------------------------")
|
||||
|
||||
while True:
|
||||
if raw_input("? Have you secured your private key? (yes, no) > ").lower() == "yes": break
|
||||
else: logging.info("Please, secure it now, you going to need it to modify your site!")
|
||||
|
||||
logging.info("Creating directory structure...")
|
||||
from Site import Site
|
||||
os.mkdir("data/%s" % address)
|
||||
open("data/%s/index.html" % address, "w").write("Hello %s!" % address)
|
||||
|
||||
logging.info("Creating content.json...")
|
||||
site = Site(address)
|
||||
site.content_manager.sign(privatekey=privatekey)
|
||||
site.settings["own"] = True
|
||||
site.saveSettings()
|
||||
|
||||
logging.info("Site created!")
|
||||
|
||||
|
||||
def siteSign(address, privatekey=None, inner_path="content.json"):
|
||||
from Site import Site
|
||||
logging.info("Signing site: %s..." % address)
|
||||
site = Site(address, allow_create = False)
|
||||
|
||||
if not privatekey: # If no privatekey in args then ask it now
|
||||
import getpass
|
||||
privatekey = getpass.getpass("Private key (input hidden):")
|
||||
site.content_manager.sign(inner_path=inner_path, privatekey=privatekey, update_changed_files=True)
|
||||
|
||||
|
||||
def siteVerify(address):
|
||||
from Site import Site
|
||||
logging.info("Verifing site: %s..." % address)
|
||||
site = Site(address)
|
||||
|
||||
for content_inner_path in site.content_manager.contents:
|
||||
logging.info("Verifing %s signature..." % content_inner_path)
|
||||
if site.content_manager.verifyFile(content_inner_path, site.storage.open(content_inner_path, "rb"), ignore_same=False) == True:
|
||||
logging.info("[OK] %s signed by address %s!" % (content_inner_path, address))
|
||||
else:
|
||||
logging.error("[ERROR] %s not signed by address %s!" % (content_inner_path, address))
|
||||
|
||||
logging.info("Verifying site files...")
|
||||
bad_files = site.storage.verifyFiles()
|
||||
if not bad_files:
|
||||
logging.info("[OK] All file sha512sum matches!")
|
||||
else:
|
||||
logging.error("[ERROR] Error during verifying site files!")
|
||||
|
||||
|
||||
def dbRebuild(address):
|
||||
from Site import Site
|
||||
logging.info("Rebuilding site sql cache: %s..." % address)
|
||||
site = Site(address)
|
||||
s = time.time()
|
||||
site.storage.rebuildDb()
|
||||
logging.info("Done in %.3fs" % (time.time()-s))
|
||||
|
||||
|
||||
def dbQuery(address, query):
|
||||
from Site import Site
|
||||
import json
|
||||
site = Site(address)
|
||||
result = []
|
||||
for row in site.storage.query(query):
|
||||
result.append(dict(row))
|
||||
print json.dumps(result, indent=4)
|
||||
|
||||
|
||||
def siteAnnounce(address):
|
||||
from Site.Site import Site
|
||||
logging.info("Announcing site %s to tracker..." % address)
|
||||
site = Site(address)
|
||||
|
||||
s = time.time()
|
||||
site.announce()
|
||||
print "Response time: %.3fs" % (time.time()-s)
|
||||
print site.peers
|
||||
|
||||
|
||||
def siteNeedFile(address, inner_path):
|
||||
from Site import Site
|
||||
site = Site(address)
|
||||
site.announce()
|
||||
print site.needFile(inner_path, update=True)
|
||||
|
||||
|
||||
def sitePublish(address, peer_ip=None, peer_port=15441, inner_path="content.json"):
|
||||
global file_server
|
||||
from Site import Site
|
||||
from File import FileServer # We need fileserver to handle incoming file requests
|
||||
|
||||
logging.info("Creating FileServer....")
|
||||
file_server = FileServer()
|
||||
file_server_thread = gevent.spawn(file_server.start, check_sites=False) # Dont check every site integrity
|
||||
file_server.openport()
|
||||
if file_server.port_opened == False:
|
||||
logging.info("Port not opened, passive publishing not supported yet :(")
|
||||
return
|
||||
site = file_server.sites[address]
|
||||
site.settings["serving"] = True # Serving the site even if its disabled
|
||||
if peer_ip: # Announce ip specificed
|
||||
site.addPeer(peer_ip, peer_port)
|
||||
else: # Just ask the tracker
|
||||
logging.info("Gathering peers from tracker")
|
||||
site.announce() # Gather peers
|
||||
site.publish(20, inner_path) # Push to 20 peers
|
||||
time.sleep(3)
|
||||
logging.info("Serving files...")
|
||||
gevent.joinall([file_server_thread])
|
||||
logging.info("Done.")
|
||||
|
||||
|
||||
|
||||
# Crypto commands
|
||||
|
||||
def cryptoPrivatekeyToAddress(privatekey=None):
|
||||
from Crypt import CryptBitcoin
|
||||
if not privatekey: # If no privatekey in args then ask it now
|
||||
import getpass
|
||||
privatekey = getpass.getpass("Private key (input hidden):")
|
||||
|
||||
print CryptBitcoin.privatekeyToAddress(privatekey)
|
||||
|
||||
|
||||
# Peer
|
||||
|
||||
def peerPing(peer_ip, peer_port):
|
||||
logging.info("Opening a simple connection server")
|
||||
global file_server
|
||||
from Connection import ConnectionServer
|
||||
file_server = ConnectionServer("127.0.0.1", 1234)
|
||||
|
||||
from Peer import Peer
|
||||
logging.info("Pinging 5 times peer: %s:%s..." % (peer_ip, int(peer_port)))
|
||||
peer = Peer(peer_ip, peer_port)
|
||||
for i in range(5):
|
||||
s = time.time()
|
||||
print peer.ping(),
|
||||
print "Response time: %.3fs" % (time.time()-s)
|
||||
time.sleep(1)
|
||||
|
||||
|
||||
def peerGetFile(peer_ip, peer_port, site, filename):
|
||||
logging.info("Opening a simple connection server")
|
||||
global file_server
|
||||
from Connection import ConnectionServer
|
||||
file_server = ConnectionServer()
|
||||
|
||||
from Peer import Peer
|
||||
logging.info("Getting %s/%s from peer: %s:%s..." % (site, filename, peer_ip, peer_port))
|
||||
peer = Peer(peer_ip, peer_port)
|
||||
s = time.time()
|
||||
print peer.getFile(site, filename).read()
|
||||
print "Response time: %.3fs" % (time.time()-s)
|
||||
|
||||
# Call function
|
||||
func = getattr(actions, config.action, None)
|
||||
action_kwargs = config.getActionArguments()
|
||||
func(**action_kwargs)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue