50 sec send timeout, force activate keepalive, reworked websocket api to make it unified and allow named and unnamed parameters, reload on content.json fileWrite

This commit is contained in:
HelloZeroNet 2015-01-27 22:37:13 +01:00
parent ac211229a7
commit 655c104130
6 changed files with 78 additions and 60 deletions

View File

@ -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
...

View File

@ -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))

View File

@ -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))

View File

@ -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

View File

@ -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)
@

View File

@ -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);
}