diff --git a/README.md b/README.md
index 67e96552..cbb412dc 100644
--- a/README.md
+++ b/README.md
@@ -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
diff --git a/plugins/Stats/StatsPlugin.py b/plugins/Stats/StatsPlugin.py
index 77f4a20b..d0270e53 100644
--- a/plugins/Stats/StatsPlugin.py
+++ b/plugins/Stats/StatsPlugin.py
@@ -104,7 +104,11 @@ class UiRequestPlugin(object):
yield self.formatTableRow([
("%s", (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 "
" % site.address
diff --git a/plugins/Trayicon/TrayiconPlugin.py b/plugins/Trayicon/TrayiconPlugin.py
index 5517fa96..9e35cb1f 100644
--- a/plugins/Trayicon/TrayiconPlugin.py
+++ b/plugins/Trayicon/TrayiconPlugin.py
@@ -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())
diff --git a/plugins/Trayicon/lib/notificationicon.py b/plugins/Trayicon/lib/notificationicon.py
index 19b26af5..f6a2b44d 100644
--- a/plugins/Trayicon/lib/notificationicon.py
+++ b/plugins/Trayicon/lib/notificationicon.py
@@ -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)
diff --git a/plugins/Trayicon/lib/winfolders.py b/plugins/Trayicon/lib/winfolders.py
index 0e390fad..d28efc1a 100644
--- a/plugins/Trayicon/lib/winfolders.py
+++ b/plugins/Trayicon/lib/winfolders.py
@@ -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())
\ No newline at end of file
diff --git a/plugins/Zeroname/updater/zeroname_updater.py b/plugins/Zeroname/updater/zeroname_updater.py
index e7fcda25..c1247305 100644
--- a/plugins/Zeroname/updater/zeroname_updater.py
+++ b/plugins/Zeroname/updater/zeroname_updater.py
@@ -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",
diff --git a/src/Site/Site.py b/src/Site/Site.py
index cbf652b2..a4d94a6a 100644
--- a/src/Site/Site.py
+++ b/src/Site/Site.py
@@ -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
diff --git a/src/Site/SiteStorage.py b/src/Site/SiteStorage.py
index 157e5648..fc69d919 100644
--- a/src/Site/SiteStorage.py
+++ b/src/Site/SiteStorage.py
@@ -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
|