diff --git a/README.md b/README.md index c5ac0b2f..b059795c 100644 --- a/README.md +++ b/README.md @@ -38,12 +38,12 @@ Linux (Debian): - `pip install pyzmq` (if it drops a compile error then run `apt-get install python-dev` and try again) - `pip install gevent` - `pip install msgpack-python` - - start using `python zeronet.py` + - start using `python start.py` Linux (Without root access): - `wget https://bootstrap.pypa.io/get-pip.py` - `python get-pip.py --user pyzmq gevent msgpack-python` - - start using `python zeronet.py` + - start using `python start.py` ## Current limitations @@ -54,7 +54,7 @@ Linux (Without root access): ## How can I create a ZeroNet site? -Shut down zeronet.py if you are running it already +Shut down zeronet if you are running it already ``` $ zeronet.py siteCreate ... diff --git a/src/File/FileServer.py b/src/File/FileServer.py index 4a5e4f86..4f2c2b6c 100644 --- a/src/File/FileServer.py +++ b/src/File/FileServer.py @@ -158,6 +158,7 @@ class FileServer: socket = self.context.socket(zmq.REP) self.socket = socket self.socket.setsockopt(zmq.RCVTIMEO, 5000) # Wait for data receive + self.socket.setsockopt(zmq.SNDTIMEO, 50000) # Wait for data send self.log.info("Binding to tcp://%s:%s" % (self.ip, self.port)) try: self.socket.bind('tcp://%s:%s' % (self.ip, self.port)) diff --git a/src/Peer/Peer.py b/src/Peer/Peer.py index 47d3d8aa..d6e04e2c 100644 --- a/src/Peer/Peer.py +++ b/src/Peer/Peer.py @@ -33,12 +33,13 @@ class Peer: if self.socket: self.socket.close() self.socket = context.socket(zmq.REQ) + self.socket.setsockopt(zmq.RCVTIMEO, 50000) # Wait for data arrive self.socket.setsockopt(zmq.SNDTIMEO, 5000) # Wait for data send self.socket.setsockopt(zmq.LINGER, 500) # Wait for socket close - #self.socket.setsockopt(zmq.TCP_KEEPALIVE, 1) # Enable keepalive - #self.socket.setsockopt(zmq.TCP_KEEPALIVE_IDLE, 4*60) # Send after 4 minute idle - #self.socket.setsockopt(zmq.TCP_KEEPALIVE_INTVL, 15) # Wait 15 sec to response - #self.socket.setsockopt(zmq.TCP_KEEPALIVE_CNT, 4) # 4 Probes + self.socket.setsockopt(zmq.TCP_KEEPALIVE, 1) # Enable keepalive + self.socket.setsockopt(zmq.TCP_KEEPALIVE_IDLE, 4*60) # Send after 4 minute idle + self.socket.setsockopt(zmq.TCP_KEEPALIVE_INTVL, 15) # Wait 15 sec to response + self.socket.setsockopt(zmq.TCP_KEEPALIVE_CNT, 4) # 4 Probes self.socket.connect('tcp://%s:%s' % (self.ip, self.port)) diff --git a/src/Ui/UiWebsocket.py b/src/Ui/UiWebsocket.py index f8b40a72..28880dcb 100644 --- a/src/Ui/UiWebsocket.py +++ b/src/Ui/UiWebsocket.py @@ -77,48 +77,60 @@ class UiWebsocket: # Handle incoming messages def handleRequest(self, data): req = json.loads(data) - cmd = req.get("cmd", None) + + cmd = req.get("cmd") + params = req.get("params") permissions = self.site.settings["permissions"] - if cmd == "response": - self.actionResponse(req) + + if cmd == "response": # It's a response to a command + return self.actionResponse(req["to"], req["result"]) elif cmd == "ping": - self.actionPing(req["id"]) + func = self.actionPing elif cmd == "channelJoin": - self.actionChannelJoin(req["id"], req["params"]) + func = self.actionChannelJoin elif cmd == "siteInfo": - self.actionSiteInfo(req["id"], req["params"]) + func = self.actionSiteInfo elif cmd == "serverInfo": - self.actionServerInfo(req["id"], req["params"]) + func = self.actionServerInfo elif cmd == "siteUpdate": - self.actionSiteUpdate(req["id"], req["params"]) + func = self.actionSiteUpdate elif cmd == "sitePublish": - self.actionSitePublish(req["id"], req["params"]) + func = self.actionSitePublish elif cmd == "fileWrite": - self.actionFileWrite(req["id"], req["params"]) + func = self.actionFileWrite # Admin commands elif cmd == "sitePause" and "ADMIN" in permissions: - self.actionSitePause(req["id"], req["params"]) + func = self.actionSitePause elif cmd == "siteResume" and "ADMIN" in permissions: - self.actionSiteResume(req["id"], req["params"]) + func = self.actionSiteResume elif cmd == "siteDelete" and "ADMIN" in permissions: - self.actionSiteDelete(req["id"], req["params"]) + func = self.actionSiteDelete elif cmd == "siteList" and "ADMIN" in permissions: - self.actionSiteList(req["id"], req["params"]) + func = self.actionSiteList elif cmd == "channelJoinAllsite" and "ADMIN" in permissions: - self.actionChannelJoinAllsite(req["id"], req["params"]) + func = self.actionChannelJoinAllsite # Unknown command else: self.response(req["id"], "Unknown command: %s" % cmd) + return + + # Support calling as named, unnamed paramters and raw first argument too + if type(params) is dict: + func(req["id"], **params) + elif type(params) is list: + func(req["id"], *params) + else: + func(req["id"], params) # - Actions - # Do callback on response {"cmd": "response", "to": message_id, "result": result} - def actionResponse(self, req): - if req["to"] in self.waiting_cb: - self.waiting_cb(req["result"]) # Call callback function + def actionResponse(self, to, result): + if to in self.waiting_cb: + self.waiting_cb(result) # Call callback function else: - self.log.error("Websocket callback not found: %s" % req) + self.log.error("Websocket callback not found: %s, %s" % (to, result)) # Send a simple pong answer @@ -151,19 +163,19 @@ class UiWebsocket: # Send site details - def actionSiteInfo(self, to, params): + def actionSiteInfo(self, to): ret = self.formatSiteInfo(self.site) self.response(to, ret) # Join to an event channel - def actionChannelJoin(self, to, params): - if params["channel"] not in self.channels: - self.channels.append(params["channel"]) + def actionChannelJoin(self, to, channel): + if channel not in self.channels: + self.channels.append(channel) # Server variables - def actionServerInfo(self, to, params): + def actionServerInfo(self, to): ret = { "ip_external": bool(config.ip_external), "platform": sys.platform, @@ -177,13 +189,13 @@ class UiWebsocket: self.response(to, ret) - def actionSitePublish(self, to, params): + def actionSitePublish(self, to, privatekey): site = self.site if not site.settings["own"]: return self.response(to, "Forbidden, you can only modify your own sites") # Signing site.loadContent(True) # Reload content.json, ignore errors to make it up-to-date - signed = site.signContent(params[0]) # Sign using private key sent by user + signed = site.signContent(privatekey) # Sign using private key sent by user if signed: self.cmd("notification", ["done", "Private key correct, site signed!", 5000]) # Display message for 5 sec else: @@ -217,15 +229,18 @@ class UiWebsocket: # Write a file to disk - def actionFileWrite(self, to, params): + def actionFileWrite(self, to, inner_path, content_base64): if not self.site.settings["own"]: return self.response(to, "Forbidden, you can only modify your own sites") try: import base64 - content = base64.b64decode(params[1]) - open(self.site.getPath(params[0]), "wb").write(content) + content = base64.b64decode(content_base64) + open(self.site.getPath(inner_path), "wb").write(content) except Exception, err: return self.response(to, "Write error: %s" % err) + if inner_path == "content.json": + self.site.loadContent(True) + return self.response(to, "ok") @@ -234,7 +249,7 @@ class UiWebsocket: # - Admin actions - # List all site info - def actionSiteList(self, to, params): + def actionSiteList(self, to): ret = [] SiteManager.load() # Reload sites for site in self.server.sites.values(): @@ -244,9 +259,9 @@ class UiWebsocket: # Join to an event channel on all sites - def actionChannelJoinAllsite(self, to, params): - if params["channel"] not in self.channels: # Add channel to channels - self.channels.append(params["channel"]) + def actionChannelJoinAllsite(self, to, channel): + if channel not in self.channels: # Add channel to channels + self.channels.append(channel) for site in self.server.sites.values(): # Add websocket to every channel if self not in site.websockets: @@ -254,8 +269,7 @@ class UiWebsocket: # Update site content.json - def actionSiteUpdate(self, to, params): - address = params.get("address") + def actionSiteUpdate(self, to, address): site = self.server.sites.get(address) if site and (site.address == self.site.address or "ADMIN" in self.site.settings["permissions"]): gevent.spawn(site.update) @@ -264,8 +278,7 @@ class UiWebsocket: # Pause site serving - def actionSitePause(self, to, params): - address = params.get("address") + def actionSitePause(self, to, address): site = self.server.sites.get(address) if site: site.settings["serving"] = False @@ -277,8 +290,7 @@ class UiWebsocket: # Resume site serving - def actionSiteResume(self, to, params): - address = params.get("address") + def actionSiteResume(self, to, address): site = self.server.sites.get(address) if site: site.settings["serving"] = True @@ -290,8 +302,7 @@ class UiWebsocket: self.response(to, {"error": "Unknown site: %s" % address}) - def actionSiteDelete(self, to, params): - address = params.get("address") + def actionSiteDelete(self, to, address): site = self.server.sites.get(address) if site: site.settings["serving"] = False diff --git a/src/Ui/media/Wrapper.coffee b/src/Ui/media/Wrapper.coffee index 9c7b916b..7c559445 100644 --- a/src/Ui/media/Wrapper.coffee +++ b/src/Ui/media/Wrapper.coffee @@ -23,7 +23,8 @@ class Wrapper @site_error = null # Latest failed file download window.onload = @onLoad # On iframe loaded - $(window).on "hashchange", -> # On hash change + $(window).on "hashchange", => # On hash change + @log "Hashchange", window.location.hash src = $("#inner-iframe").attr("src").replace(/#.*/, "")+window.location.hash $("#inner-iframe").attr("src", src) @ diff --git a/src/Ui/media/all.js b/src/Ui/media/all.js index c4358dc3..c621dca2 100644 --- a/src/Ui/media/all.js +++ b/src/Ui/media/all.js @@ -535,8 +535,8 @@ jQuery.extend( jQuery.easing, __slice = [].slice; Notifications = (function() { - function Notifications(elem) { - this.elem = elem; + function Notifications(_at_elem) { + this.elem = _at_elem; this; } @@ -684,7 +684,8 @@ jQuery.extend( jQuery.easing, }); /*$(".fixbutton-bg").on "click", -> - return false */ + return false + */ $(".fixbutton-bg").on("mousedown", function() { return $(".fixbutton-burger").stop().animate({ "scale": 0.7, @@ -743,11 +744,14 @@ jQuery.extend( jQuery.easing, this.wrapperWsInited = false; this.site_error = null; window.onload = this.onLoad; - $(window).on("hashchange", function() { - var src; - src = $("#inner-iframe").attr("src").replace(/#.*/, "") + window.location.hash; - return $("#inner-iframe").attr("src", src); - }); + $(window).on("hashchange", (function(_this) { + return function() { + var src; + _this.log("Hashchange", window.location.hash); + src = $("#inner-iframe").attr("src").replace(/#.*/, "") + window.location.hash; + return $("#inner-iframe").attr("src", src); + }; + })(this)); this; } @@ -939,9 +943,9 @@ jQuery.extend( jQuery.easing, Wrapper.prototype.setSiteInfo = function(site_info) { if (site_info.event != null) { if (site_info.event[0] === "file_added" && site_info.bad_files) { - this.loading.printLine("" + site_info.bad_files + " files needs to be downloaded"); + this.loading.printLine(site_info.bad_files + " files needs to be downloaded"); } else if (site_info.event[0] === "file_done") { - this.loading.printLine("" + site_info.event[1] + " downloaded"); + this.loading.printLine(site_info.event[1] + " downloaded"); if (site_info.event[1] === window.inner_path) { this.loading.hideScreen(); if (!this.site_info) { @@ -953,7 +957,7 @@ jQuery.extend( jQuery.easing, } } else if (site_info.event[0] === "file_failed") { this.site_error = site_info.event[1]; - this.loading.printLine("" + site_info.event[1] + " download failed", "error"); + this.loading.printLine(site_info.event[1] + " download failed", "error"); } else if (site_info.event[0] === "peers_added") { this.loading.printLine("Peers found: " + site_info.peers); }