Rev932, Skip news event from future, Disable siteSetOwned and setAutodownloadoptional when multiuser plugin enabled, Fix sidebar double click handlers, Log peer sent commands, Send modification to less peer if have enought peers, Close peers if more than 10 per site
This commit is contained in:
parent
5b821c46e5
commit
3f6f273fb1
7 changed files with 78 additions and 28 deletions
|
@ -1,5 +1,5 @@
|
||||||
from Plugin import PluginManager
|
from Plugin import PluginManager
|
||||||
import re
|
import re, time
|
||||||
|
|
||||||
@PluginManager.registerTo("UiWebsocket")
|
@PluginManager.registerTo("UiWebsocket")
|
||||||
class UiWebsocketPlugin(object):
|
class UiWebsocketPlugin(object):
|
||||||
|
@ -35,6 +35,8 @@ class UiWebsocketPlugin(object):
|
||||||
continue
|
continue
|
||||||
for row in res:
|
for row in res:
|
||||||
row = dict(row)
|
row = dict(row)
|
||||||
|
if row["date_added"] > time.time() + 60:
|
||||||
|
continue # Feed item is in the future, skip it
|
||||||
row["site"] = address
|
row["site"] = address
|
||||||
row["feed_name"] = name
|
row["feed_name"] = name
|
||||||
rows.append(row)
|
rows.append(row)
|
||||||
|
|
|
@ -492,12 +492,22 @@ class UiWebsocketPlugin(object):
|
||||||
|
|
||||||
def actionSiteSetOwned(self, to, owned):
|
def actionSiteSetOwned(self, to, owned):
|
||||||
permissions = self.getPermissions(to)
|
permissions = self.getPermissions(to)
|
||||||
|
|
||||||
|
if "Multiuser" in PluginManager.plugin_manager.plugin_names:
|
||||||
|
self.cmd("notification", ["info", "This function is disabled on this proxy"])
|
||||||
|
return False
|
||||||
|
|
||||||
if "ADMIN" not in permissions:
|
if "ADMIN" not in permissions:
|
||||||
return self.response(to, "You don't have permission to run this command")
|
return self.response(to, "You don't have permission to run this command")
|
||||||
self.site.settings["own"] = bool(owned)
|
self.site.settings["own"] = bool(owned)
|
||||||
|
|
||||||
def actionSiteSetAutodownloadoptional(self, to, owned):
|
def actionSiteSetAutodownloadoptional(self, to, owned):
|
||||||
permissions = self.getPermissions(to)
|
permissions = self.getPermissions(to)
|
||||||
|
|
||||||
|
if "Multiuser" in PluginManager.plugin_manager.plugin_names:
|
||||||
|
self.cmd("notification", ["info", "This function is disabled on this proxy"])
|
||||||
|
return False
|
||||||
|
|
||||||
if "ADMIN" not in permissions:
|
if "ADMIN" not in permissions:
|
||||||
return self.response(to, "You don't have permission to run this command")
|
return self.response(to, "You don't have permission to run this command")
|
||||||
self.site.settings["autodownloadoptional"] = bool(owned)
|
self.site.settings["autodownloadoptional"] = bool(owned)
|
||||||
|
|
|
@ -225,31 +225,31 @@ class Sidebar extends Class
|
||||||
), 300
|
), 300
|
||||||
|
|
||||||
# Site limit button
|
# Site limit button
|
||||||
@tag.find("#button-sitelimit").on "click", =>
|
@tag.find("#button-sitelimit").off("click").on "click", =>
|
||||||
wrapper.ws.cmd "siteSetLimit", $("#input-sitelimit").val(), =>
|
wrapper.ws.cmd "siteSetLimit", $("#input-sitelimit").val(), =>
|
||||||
wrapper.notifications.add "done-sitelimit", "done", "Site storage limit modified!", 5000
|
wrapper.notifications.add "done-sitelimit", "done", "Site storage limit modified!", 5000
|
||||||
@updateHtmlTag()
|
@updateHtmlTag()
|
||||||
return false
|
return false
|
||||||
|
|
||||||
# Owned checkbox
|
# Owned checkbox
|
||||||
@tag.find("#checkbox-owned").on "click", =>
|
@tag.find("#checkbox-owned").off("click").on "click", =>
|
||||||
wrapper.ws.cmd "siteSetOwned", [@tag.find("#checkbox-owned").is(":checked")]
|
wrapper.ws.cmd "siteSetOwned", [@tag.find("#checkbox-owned").is(":checked")]
|
||||||
|
|
||||||
# Owned checkbox
|
# Owned checkbox
|
||||||
@tag.find("#checkbox-autodownloadoptional").on "click", =>
|
@tag.find("#checkbox-autodownloadoptional").off("click").on "click", =>
|
||||||
wrapper.ws.cmd "siteSetAutodownloadoptional", [@tag.find("#checkbox-autodownloadoptional").is(":checked")]
|
wrapper.ws.cmd "siteSetAutodownloadoptional", [@tag.find("#checkbox-autodownloadoptional").is(":checked")]
|
||||||
|
|
||||||
# Change identity button
|
# Change identity button
|
||||||
@tag.find("#button-identity").on "click", =>
|
@tag.find("#button-identity").off("click").on "click", =>
|
||||||
wrapper.ws.cmd "certSelect"
|
wrapper.ws.cmd "certSelect"
|
||||||
return false
|
return false
|
||||||
|
|
||||||
# Owned checkbox
|
# Owned checkbox
|
||||||
@tag.find("#checkbox-owned").on "click", =>
|
@tag.find("#checkbox-owned").off("click").on "click", =>
|
||||||
wrapper.ws.cmd "siteSetOwned", [@tag.find("#checkbox-owned").is(":checked")]
|
wrapper.ws.cmd "siteSetOwned", [@tag.find("#checkbox-owned").is(":checked")]
|
||||||
|
|
||||||
# Save settings
|
# Save settings
|
||||||
@tag.find("#button-settings").on "click", =>
|
@tag.find("#button-settings").off("click").on "click", =>
|
||||||
wrapper.ws.cmd "fileGet", "content.json", (res) =>
|
wrapper.ws.cmd "fileGet", "content.json", (res) =>
|
||||||
data = JSON.parse(res)
|
data = JSON.parse(res)
|
||||||
data["title"] = $("#settings-title").val()
|
data["title"] = $("#settings-title").val()
|
||||||
|
@ -264,7 +264,7 @@ class Sidebar extends Class
|
||||||
return false
|
return false
|
||||||
|
|
||||||
# Sign content.json
|
# Sign content.json
|
||||||
@tag.find("#button-sign").on "click", =>
|
@tag.find("#button-sign").off("click").on "click", =>
|
||||||
inner_path = @tag.find("#select-contents").val()
|
inner_path = @tag.find("#select-contents").val()
|
||||||
|
|
||||||
if wrapper.site_info.privatekey
|
if wrapper.site_info.privatekey
|
||||||
|
@ -282,7 +282,7 @@ class Sidebar extends Class
|
||||||
return false
|
return false
|
||||||
|
|
||||||
# Publish content.json
|
# Publish content.json
|
||||||
@tag.find("#button-publish").on "click", =>
|
@tag.find("#button-publish").off("click").on "click", =>
|
||||||
inner_path = @tag.find("#select-contents").val()
|
inner_path = @tag.find("#select-contents").val()
|
||||||
@tag.find("#button-publish").addClass "loading"
|
@tag.find("#button-publish").addClass "loading"
|
||||||
wrapper.ws.cmd "sitePublish", {"inner_path": inner_path, "sign": false}, =>
|
wrapper.ws.cmd "sitePublish", {"inner_path": inner_path, "sign": false}, =>
|
||||||
|
|
|
@ -404,7 +404,7 @@ window.initScrollable = function () {
|
||||||
}), 300);
|
}), 300);
|
||||||
};
|
};
|
||||||
})(this));
|
})(this));
|
||||||
this.tag.find("#button-sitelimit").on("click", (function(_this) {
|
this.tag.find("#button-sitelimit").off("click").on("click", (function(_this) {
|
||||||
return function() {
|
return function() {
|
||||||
wrapper.ws.cmd("siteSetLimit", $("#input-sitelimit").val(), function() {
|
wrapper.ws.cmd("siteSetLimit", $("#input-sitelimit").val(), function() {
|
||||||
wrapper.notifications.add("done-sitelimit", "done", "Site storage limit modified!", 5000);
|
wrapper.notifications.add("done-sitelimit", "done", "Site storage limit modified!", 5000);
|
||||||
|
@ -413,28 +413,28 @@ window.initScrollable = function () {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
})(this));
|
})(this));
|
||||||
this.tag.find("#checkbox-owned").on("click", (function(_this) {
|
this.tag.find("#checkbox-owned").off("click").on("click", (function(_this) {
|
||||||
return function() {
|
return function() {
|
||||||
return wrapper.ws.cmd("siteSetOwned", [_this.tag.find("#checkbox-owned").is(":checked")]);
|
return wrapper.ws.cmd("siteSetOwned", [_this.tag.find("#checkbox-owned").is(":checked")]);
|
||||||
};
|
};
|
||||||
})(this));
|
})(this));
|
||||||
this.tag.find("#checkbox-autodownloadoptional").on("click", (function(_this) {
|
this.tag.find("#checkbox-autodownloadoptional").off("click").on("click", (function(_this) {
|
||||||
return function() {
|
return function() {
|
||||||
return wrapper.ws.cmd("siteSetAutodownloadoptional", [_this.tag.find("#checkbox-autodownloadoptional").is(":checked")]);
|
return wrapper.ws.cmd("siteSetAutodownloadoptional", [_this.tag.find("#checkbox-autodownloadoptional").is(":checked")]);
|
||||||
};
|
};
|
||||||
})(this));
|
})(this));
|
||||||
this.tag.find("#button-identity").on("click", (function(_this) {
|
this.tag.find("#button-identity").off("click").on("click", (function(_this) {
|
||||||
return function() {
|
return function() {
|
||||||
wrapper.ws.cmd("certSelect");
|
wrapper.ws.cmd("certSelect");
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
})(this));
|
})(this));
|
||||||
this.tag.find("#checkbox-owned").on("click", (function(_this) {
|
this.tag.find("#checkbox-owned").off("click").on("click", (function(_this) {
|
||||||
return function() {
|
return function() {
|
||||||
return wrapper.ws.cmd("siteSetOwned", [_this.tag.find("#checkbox-owned").is(":checked")]);
|
return wrapper.ws.cmd("siteSetOwned", [_this.tag.find("#checkbox-owned").is(":checked")]);
|
||||||
};
|
};
|
||||||
})(this));
|
})(this));
|
||||||
this.tag.find("#button-settings").on("click", (function(_this) {
|
this.tag.find("#button-settings").off("click").on("click", (function(_this) {
|
||||||
return function() {
|
return function() {
|
||||||
wrapper.ws.cmd("fileGet", "content.json", function(res) {
|
wrapper.ws.cmd("fileGet", "content.json", function(res) {
|
||||||
var data, json_raw;
|
var data, json_raw;
|
||||||
|
@ -454,7 +454,7 @@ window.initScrollable = function () {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
})(this));
|
})(this));
|
||||||
this.tag.find("#button-sign").on("click", (function(_this) {
|
this.tag.find("#button-sign").off("click").on("click", (function(_this) {
|
||||||
return function() {
|
return function() {
|
||||||
var inner_path;
|
var inner_path;
|
||||||
inner_path = _this.tag.find("#select-contents").val();
|
inner_path = _this.tag.find("#select-contents").val();
|
||||||
|
@ -474,7 +474,7 @@ window.initScrollable = function () {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
})(this));
|
})(this));
|
||||||
this.tag.find("#button-publish").on("click", (function(_this) {
|
this.tag.find("#button-publish").off("click").on("click", (function(_this) {
|
||||||
return function() {
|
return function() {
|
||||||
var inner_path;
|
var inner_path;
|
||||||
inner_path = _this.tag.find("#select-contents").val();
|
inner_path = _this.tag.find("#select-contents").val();
|
||||||
|
|
|
@ -8,7 +8,7 @@ class Config(object):
|
||||||
|
|
||||||
def __init__(self, argv):
|
def __init__(self, argv):
|
||||||
self.version = "0.3.6"
|
self.version = "0.3.6"
|
||||||
self.rev = 915
|
self.rev = 932
|
||||||
self.argv = argv
|
self.argv = argv
|
||||||
self.action = None
|
self.action = None
|
||||||
self.config_file = "zeronet.conf"
|
self.config_file = "zeronet.conf"
|
||||||
|
@ -133,6 +133,7 @@ class Config(object):
|
||||||
self.parser.add_argument('--homepage', help='Web interface Homepage', default='1HeLLo4uzjaLetFx6NH3PMwFP3qbRbTf3D',
|
self.parser.add_argument('--homepage', help='Web interface Homepage', default='1HeLLo4uzjaLetFx6NH3PMwFP3qbRbTf3D',
|
||||||
metavar='address')
|
metavar='address')
|
||||||
self.parser.add_argument('--size_limit', help='Default site size limit in MB', default=10, metavar='size')
|
self.parser.add_argument('--size_limit', help='Default site size limit in MB', default=10, metavar='size')
|
||||||
|
self.parser.add_argument('--connected_limit', help='Max connected peer per site', default=15, metavar='connected_limit')
|
||||||
|
|
||||||
self.parser.add_argument('--fileserver_ip', help='FileServer bind address', default="*", metavar='ip')
|
self.parser.add_argument('--fileserver_ip', help='FileServer bind address', default="*", metavar='ip')
|
||||||
self.parser.add_argument('--fileserver_port', help='FileServer bind port', default=15441, type=int, metavar='port')
|
self.parser.add_argument('--fileserver_port', help='FileServer bind port', default=15441, type=int, metavar='port')
|
||||||
|
|
|
@ -107,6 +107,9 @@ class Peer(object):
|
||||||
self.onConnectionError()
|
self.onConnectionError()
|
||||||
return None # Connection failed
|
return None # Connection failed
|
||||||
|
|
||||||
|
if config.debug:
|
||||||
|
self.log("Send request: %s %s" % (params.get("site", ""), cmd))
|
||||||
|
|
||||||
for retry in range(1, 4): # Retry 3 times
|
for retry in range(1, 4): # Retry 3 times
|
||||||
try:
|
try:
|
||||||
res = self.connection.request(cmd, params, stream_to)
|
res = self.connection.request(cmd, params, stream_to)
|
||||||
|
|
|
@ -345,7 +345,7 @@ class Site(object):
|
||||||
|
|
||||||
if result and "ok" in result:
|
if result and "ok" in result:
|
||||||
published.append(peer)
|
published.append(peer)
|
||||||
self.log.info("[OK] %s: %s" % (peer.key, result["ok"]))
|
self.log.info("[OK] %s: %s %s/%s" % (peer.key, result["ok"], len(published), limit))
|
||||||
else:
|
else:
|
||||||
if result == {"exception": "Timeout"}:
|
if result == {"exception": "Timeout"}:
|
||||||
peer.onConnectionError()
|
peer.onConnectionError()
|
||||||
|
@ -353,21 +353,29 @@ class Site(object):
|
||||||
|
|
||||||
# Update content.json on peers
|
# Update content.json on peers
|
||||||
@util.Noparallel()
|
@util.Noparallel()
|
||||||
def publish(self, limit=5, inner_path="content.json"):
|
def publish(self, limit="default", inner_path="content.json"):
|
||||||
published = [] # Successfully published (Peer)
|
published = [] # Successfully published (Peer)
|
||||||
publishers = [] # Publisher threads
|
publishers = [] # Publisher threads
|
||||||
|
|
||||||
if not self.peers:
|
if not self.peers:
|
||||||
self.announce()
|
self.announce()
|
||||||
|
|
||||||
|
threads = 5
|
||||||
|
if limit == "default":
|
||||||
|
if len(self.peers) > 50:
|
||||||
|
limit = 3
|
||||||
|
threads = 3
|
||||||
|
else:
|
||||||
|
limit = 5
|
||||||
|
|
||||||
connected_peers = self.getConnectedPeers()
|
connected_peers = self.getConnectedPeers()
|
||||||
if len(connected_peers) > limit * 2: # Publish to already connected peers if possible
|
if len(connected_peers) > limit * 2: # Publish to already connected peers if possible
|
||||||
peers = connected_peers
|
peers = connected_peers
|
||||||
else:
|
else:
|
||||||
peers = self.peers.values()
|
peers = self.peers.values()
|
||||||
|
|
||||||
self.log.info("Publishing to %s/%s peers (connected: %s)..." % (
|
self.log.info("Publishing %s to %s/%s peers (connected: %s)..." % (
|
||||||
min(len(self.peers), limit), len(self.peers), len(connected_peers)
|
inner_path, limit, len(self.peers), len(connected_peers)
|
||||||
))
|
))
|
||||||
|
|
||||||
if not peers:
|
if not peers:
|
||||||
|
@ -375,7 +383,7 @@ class Site(object):
|
||||||
|
|
||||||
random.shuffle(peers)
|
random.shuffle(peers)
|
||||||
event_done = gevent.event.AsyncResult()
|
event_done = gevent.event.AsyncResult()
|
||||||
for i in range(min(len(self.peers), limit, 5)): # Max 5 thread
|
for i in range(min(len(self.peers), limit, threads)):
|
||||||
publisher = gevent.spawn(self.publisher, inner_path, peers, published, limit, event_done)
|
publisher = gevent.spawn(self.publisher, inner_path, peers, published, limit, event_done)
|
||||||
publishers.append(publisher)
|
publishers.append(publisher)
|
||||||
|
|
||||||
|
@ -392,12 +400,12 @@ class Site(object):
|
||||||
] # Every connected passive peer that we not published to
|
] # Every connected passive peer that we not published to
|
||||||
|
|
||||||
self.log.info(
|
self.log.info(
|
||||||
"Successfuly published to %s peers, publishing to %s more passive peers" %
|
"Successfuly %s published to %s peers, publishing to %s more passive peers" % (
|
||||||
(len(published), len(passive_peers))
|
inner_path, len(published), len(passive_peers)
|
||||||
)
|
))
|
||||||
|
|
||||||
for peer in passive_peers:
|
for peer in passive_peers:
|
||||||
gevent.spawn(self.publisher, inner_path, passive_peers, published, limit=10)
|
gevent.spawn(self.publisher, inner_path, passive_peers, published, limit=limit+3)
|
||||||
|
|
||||||
# Send my hashfield to every connected peer if changed
|
# Send my hashfield to every connected peer if changed
|
||||||
gevent.spawn(self.sendMyHashfield, 100)
|
gevent.spawn(self.sendMyHashfield, 100)
|
||||||
|
@ -765,11 +773,13 @@ class Site(object):
|
||||||
def getConnectedPeers(self):
|
def getConnectedPeers(self):
|
||||||
return [peer for peer in self.peers.values() if peer.connection and peer.connection.connected]
|
return [peer for peer in self.peers.values() if peer.connection and peer.connection.connected]
|
||||||
|
|
||||||
# Cleanup probably dead peers
|
# Cleanup probably dead peers and close connection if too much
|
||||||
def cleanupPeers(self):
|
def cleanupPeers(self):
|
||||||
peers = self.peers.values()
|
peers = self.peers.values()
|
||||||
if len(peers) < 20:
|
if len(peers) < 20:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
# Cleanup old peers
|
||||||
removed = 0
|
removed = 0
|
||||||
|
|
||||||
for peer in peers:
|
for peer in peers:
|
||||||
|
@ -786,6 +796,30 @@ class Site(object):
|
||||||
if removed:
|
if removed:
|
||||||
self.log.debug("Cleanup peers result: Removed %s, left: %s" % (removed, len(self.peers)))
|
self.log.debug("Cleanup peers result: Removed %s, left: %s" % (removed, len(self.peers)))
|
||||||
|
|
||||||
|
# Close peers if too much
|
||||||
|
closed = 0
|
||||||
|
connected_peers = self.getConnectedPeers()
|
||||||
|
need_to_close = len(connected_peers) - config.connected_limit
|
||||||
|
# First try to remove active peers
|
||||||
|
if need_to_close > 0:
|
||||||
|
for peer in connected_peers:
|
||||||
|
if not peer.key.endswith(":0"): # Connectable peer
|
||||||
|
peer.remove()
|
||||||
|
closed += 1
|
||||||
|
if closed >= need_to_close:
|
||||||
|
break
|
||||||
|
|
||||||
|
# Also remove passive peers if still more than we need
|
||||||
|
if closed < need_to_close:
|
||||||
|
for peer in connected_peers:
|
||||||
|
peer.remove()
|
||||||
|
closed += 1
|
||||||
|
if closed >= need_to_close:
|
||||||
|
break
|
||||||
|
|
||||||
|
if need_to_close > 0:
|
||||||
|
self.log.debug("Connected: %s, Need to close: %s, Closed: %s" % (len(connected_peers), need_to_close, closed))
|
||||||
|
|
||||||
# Send hashfield to peers
|
# Send hashfield to peers
|
||||||
def sendMyHashfield(self, limit=3):
|
def sendMyHashfield(self, limit=3):
|
||||||
if not self.content_manager.hashfield: # No optional files
|
if not self.content_manager.hashfield: # No optional files
|
||||||
|
|
Loading…
Reference in a new issue