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:
parent
ac211229a7
commit
655c104130
6 changed files with 78 additions and 60 deletions
|
@ -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
|
||||
...
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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))
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
@
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue