Updated features in readme, Connectable peer stats, Start ZeroNet when Windows starts option, ZeroName updater invalid key fix, Add peer ping to timeout on publish, Make sure the passive peers get the updated files

This commit is contained in:
HelloZeroNet 2015-04-17 00:34:08 +02:00
parent b39b6904e7
commit f1a885b0ef
8 changed files with 79 additions and 17 deletions

View File

@ -31,15 +31,15 @@ Decentralized websites using Bitcoin crypto and the BitTorrent network
other peers.
## Features
* Easy, zero configuration setup
* Real-time updated sites
* Namecoin .bit domains support
* Easy to setup: unpack & run
* Password-less [BIP32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki)
based authorization: Your account is protected by same cryptography as your bitcoin wallet
* Namecoin .bit domains support
* SQL Database support: Allows easier site development and faster page load times
* Tor network support
* Automatic, uPnP port opening
* Plugin for multiuser (openproxy) support
* [ZeroFrame API](http://zeronet.readthedocs.org/en/latest/site_development/zeroframe_api_reference/) for dynamic sites
* One click ZeroNet client updater
## Screenshots

View File

@ -104,7 +104,11 @@ class UiRequestPlugin(object):
yield self.formatTableRow([
("<a href='#ShowPeers' onclick='document.getElementById(\"peers_%s\").style.display=\"initial\"; return false'>%s</a>", (site.address, site.address)),
("%s", [peer.connection.id for peer in site.peers.values() if peer.connection and peer.connection.connected]),
("%s/%s", ( len([peer for peer in site.peers.values() if peer.connection and peer.connection.connected]), len(site.peers) ) ),
("%s/%s/%s", (
len([peer for peer in site.peers.values() if peer.connection and peer.connection.connected]),
len(site.getConnectablePeers(100)),
len(site.peers)
) ),
("%s", len(site.content_manager.contents)),
])
yield "<tr><td id='peers_%s' style='display: none; white-space: pre'>" % site.address

View File

@ -32,6 +32,7 @@ class ActionsPlugin(object):
(self.titleConnections, False),
(self.titleTransfer, False),
(self.titleConsole, self.toggleConsole),
(self.titleAutorun, self.toggleAutorun),
"--",
("ZeroNet Twitter", lambda: self.opensite("https://twitter.com/HelloZeroNet") ),
("ZeroNet Reddit", lambda: self.opensite("http://www.reddit.com/r/zeronet/") ),
@ -51,6 +52,7 @@ class ActionsPlugin(object):
super(ActionsPlugin, self).main()
icon._die = True
def quit(self):
self.icon.die()
time.sleep(0.1)
@ -58,10 +60,12 @@ class ActionsPlugin(object):
self.main.file_server.stop()
#sys.exit()
def opensite(self, url):
import webbrowser
webbrowser.open(url, new=2)
def titleIp(self):
title = "!IP: %s" % config.ip_external
if self.main.file_server.port_opened:
@ -70,18 +74,22 @@ class ActionsPlugin(object):
title += " (passive)"
return title
def titleConnections(self):
title = "Connections: %s" % len(self.main.file_server.connections)
return title
def titleTransfer(self):
title = "Received: %.2f MB | Sent: %.2f MB" % (float(self.main.file_server.bytes_recv)/1024/1024, float(self.main.file_server.bytes_sent)/1024/1024)
return title
def titleConsole(self):
if self.console: return "+Show console window"
else: return "Show console window"
def toggleConsole(self):
if self.console:
notificationicon.hideConsole()
@ -89,3 +97,34 @@ class ActionsPlugin(object):
else:
notificationicon.showConsole()
self.console = True
def getAutorunPath(self):
return "%s\\zeronet.cmd" % winfolders.get(winfolders.STARTUP)
def formatAutorun(self):
args = sys.argv[:]
args.insert(0, sys.executable)
if sys.platform == 'win32':
args = ['"%s"' % arg for arg in args]
cmd = " ".join(args)
cmd = cmd.replace("start.py", "zeronet.py").replace('"--open_browser"', "").replace('"default_browser"', "") # Dont open browser on autorun
return "cd /D %s \n%s" % (os.getcwd(), cmd)
def isAutorunEnabled(self):
path = self.getAutorunPath()
return os.path.isfile(path) and open(path).read() == self.formatAutorun()
def titleAutorun(self):
if self.isAutorunEnabled(): return "+Start ZeroNet when Windows starts"
else: return "Start ZeroNet when Windows starts"
def toggleAutorun(self):
if self.isAutorunEnabled():
os.unlink(self.getAutorunPath())
else:
open(self.getAutorunPath(), "w").write(self.formatAutorun())

View File

@ -632,9 +632,8 @@ class NotificationIcon(object):
Shell_NotifyIcon(NIM_ADD, ctypes.pointer(iconinfo))
iconinfo.union.uVersion = NOTIFYICON_VERSION
self.iconinfo = ctypes.pointer(iconinfo)
Shell_NotifyIcon(NIM_SETVERSION, ctypes.pointer(iconinfo))
self.iconinfo = iconinfo
PostMessage(self._hwnd, WM_NULL, 0, 0)

View File

@ -46,3 +46,8 @@ def get(intFolder):
exit_code=_SHGetFolderPath(0, intFolder, 0, 0, auPathBuffer)
return auPathBuffer.value
if __name__ == "__main__":
import os
print get(STARTUP)
open(get(STARTUP)+"\\zeronet.cmd", "w").write("cd /D %s\r\nzeronet.py" % os.getcwd())

View File

@ -20,6 +20,9 @@ def processNameOp(domain, value):
if "zeronet" not in data:
print "No zeronet in ", data.keys()
return False
if type(data["zeronet"]) != type({}):
print "Bad type: ", data["zeronet"]
return False
if "slave" in sys.argv:
print "Waiting for master update arrive"
@ -96,7 +99,7 @@ print "Processing block from #%s to #%s..." % (config["lastprocessed"], last_blo
for block_id in range(config["lastprocessed"], last_block+1):
processBlock(block_id)
#processBlock(223911) # Testing
# processBlock(223911) # Testing
while 1:
print "Waiting for new block",

View File

@ -178,6 +178,7 @@ class Site:
for changed_file in changed:
self.bad_files[changed_file] = self.bad_files.get(changed_file, 0)+1
if not self.settings["own"]: self.storage.checkFiles(quick_check=True) # Quick check files based on file size
if self.bad_files:
self.download()
@ -187,12 +188,17 @@ class Site:
# Publish worker
def publisher(self, inner_path, peers, published, limit, event_done=None):
timeout = 5+int(self.storage.getSize(inner_path)/1024) # Timeout: 5sec + size in kb
file_size = self.storage.getSize(inner_path)
body = self.storage.read(inner_path)
while 1:
if not peers or len(published) >= limit:
if event_done: event_done.set(True)
break # All peers done, or published engouht
peer = peers.pop(0)
if peer.connection and peer.connection.last_ping_delay: # Peer connected
timeout = timeout = 5+int(file_size/1024)+peer.connection.last_ping_delay # Timeout: 5sec + size in kb + last_ping
else:
timeout = timeout = 5+int(file_size/1024) # Timeout: 5sec + size in kb
result = {"exception": "Timeout"}
for retry in range(2):
@ -201,7 +207,7 @@ class Site:
result = peer.request("update", {
"site": self.address,
"inner_path": inner_path,
"body": self.storage.open(inner_path).read(),
"body": body,
"peer": (config.ip_external, config.fileserver_port)
})
if result: break
@ -219,7 +225,7 @@ class Site:
# Update content.json on peers
def publish(self, limit=5, inner_path="content.json"):
self.log.info( "Publishing to %s/%s peers..." % (limit, len(self.peers)) )
published = [] # Successfuly published (Peer)
published = [] # Successfully published (Peer)
publishers = [] # Publisher threads
peers = self.peers.values()
@ -233,7 +239,12 @@ class Site:
if len(published) < min(len(self.peers), limit): time.sleep(0.2) # If less than we need sleep a bit
if len(published) == 0: gevent.joinall(publishers) # No successful publish, wait for all publisher
self.log.info("Successfuly published to %s peers" % len(published))
# Make sure the connected passive peers got the update
passive_peers = [peer for peer in peers if peer.connection and not peer.connection.closed and peer.key.endswith(":0") and peer not in published] # Every connected passive peer that we not published to
for peer in passive_peers:
gevent.spawn(self.publisher, inner_path, passive_peers, published, limit=10)
self.log.info("Successfuly published to %s peers, publishing to %s more passive peers" % (len(published), len(passive_peers)) )
return len(published)
@ -399,7 +410,7 @@ class Site:
self.announcePex()
# Need open connections
# Keep connections to get the updates (required for passive clients)
def needConnections(self):
need = min(len(self.peers)/2, 10) # Connect to half of total peers, but max 10
need = max(need, 5) # But minimum 5 peers

View File

@ -186,14 +186,14 @@ class SiteStorage:
self.site.content_manager.loadContent() # Reload content.json
for content_inner_path, content in self.site.content_manager.contents.items():
if not os.path.isfile(self.getPath(content_inner_path)): # Missing content.json file
self.log.error("[MISSING] %s" % content_inner_path)
self.log.debug("[MISSING] %s" % content_inner_path)
bad_files.append(content_inner_path)
for file_relative_path in content["files"].keys():
file_inner_path = self.site.content_manager.toDir(content_inner_path)+file_relative_path # Relative to content.json
file_inner_path = file_inner_path.strip("/") # Strip leading /
file_path = self.getPath(file_inner_path)
if not os.path.isfile(file_path):
self.log.error("[MISSING] %s" % file_inner_path)
self.log.debug("[MISSING] %s" % file_inner_path)
bad_files.append(file_inner_path)
continue
@ -203,7 +203,7 @@ class SiteStorage:
ok = self.site.content_manager.verifyFile(file_inner_path, open(file_path, "rb"))
if not ok:
self.log.debug("[CHNAGED] %s" % file_inner_path)
self.log.debug("[CHANGED] %s" % file_inner_path)
bad_files.append(file_inner_path)
self.log.debug("%s verified: %s files, quick_check: %s, bad files: %s" % (content_inner_path, len(content["files"]), quick_check, bad_files))
@ -212,11 +212,12 @@ class SiteStorage:
# Check and try to fix site files integrity
def checkFiles(self, quick_check=True):
self.log.debug("Checking files... Quick:%s" % quick_check)
s = time.time()
bad_files = self.verifyFiles(quick_check)
if bad_files:
for bad_file in bad_files:
self.site.bad_files[bad_file] = self.site.bad_files.get("bad_file", 0)+1
self.log.debug("Checked files in %.2fs... Quick:%s" % (time.time()-s, quick_check))
# Delete site's all file