Version 0.2.3, One click updater from github, Clean FileServer and UiServer shutdown, Count UiServer http connections to clean close, serverUpdate WrapperAPI command, randomize peers before work start and publish, switched to upnpc-shared it has better virustotal reputation
This commit is contained in:
parent
68e3ee158c
commit
531bf68ddd
12 changed files with 157 additions and 36 deletions
|
@ -3,7 +3,7 @@ import ConfigParser
|
||||||
|
|
||||||
class Config(object):
|
class Config(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.version = "0.2.2"
|
self.version = "0.2.3"
|
||||||
self.parser = self.createArguments()
|
self.parser = self.createArguments()
|
||||||
argv = sys.argv[:] # Copy command line arguments
|
argv = sys.argv[:] # Copy command line arguments
|
||||||
argv = self.parseConfig(argv) # Add arguments from config file
|
argv = self.parseConfig(argv) # Add arguments from config file
|
||||||
|
@ -19,7 +19,7 @@ class Config(object):
|
||||||
def createArguments(self):
|
def createArguments(self):
|
||||||
# Platform specific
|
# Platform specific
|
||||||
if sys.platform.startswith("win"):
|
if sys.platform.startswith("win"):
|
||||||
upnpc = "tools\\upnpc\\upnpc-static.exe"
|
upnpc = "tools\\upnpc\\upnpc-shared.exe"
|
||||||
coffeescript = "type %s | tools\\coffee\\coffee.cmd"
|
coffeescript = "type %s | tools\\coffee\\coffee.cmd"
|
||||||
else:
|
else:
|
||||||
upnpc = None
|
upnpc = None
|
||||||
|
|
|
@ -18,6 +18,7 @@ class FileServer:
|
||||||
else:
|
else:
|
||||||
self.port_opened = None # Is file server opened on router
|
self.port_opened = None # Is file server opened on router
|
||||||
self.sites = SiteManager.list()
|
self.sites = SiteManager.list()
|
||||||
|
self.running = True
|
||||||
|
|
||||||
|
|
||||||
# Handle request to fileserver
|
# Handle request to fileserver
|
||||||
|
@ -168,17 +169,26 @@ class FileServer:
|
||||||
if check_sites: # Open port, Update sites, Check files integrity
|
if check_sites: # Open port, Update sites, Check files integrity
|
||||||
gevent.spawn(self.checkSites)
|
gevent.spawn(self.checkSites)
|
||||||
|
|
||||||
gevent.spawn(self.announceSites)
|
thread_announce_sites = gevent.spawn(self.announceSites)
|
||||||
gevent.spawn(self.wakeupWatcher)
|
thread_wakeup_watcher = gevent.spawn(self.wakeupWatcher)
|
||||||
|
|
||||||
while True:
|
while self.running:
|
||||||
try:
|
try:
|
||||||
ret = {}
|
ret = {}
|
||||||
req = msgpack.unpackb(socket.recv())
|
req = msgpack.unpackb(socket.recv())
|
||||||
self.handleRequest(req)
|
self.handleRequest(req)
|
||||||
except Exception, err:
|
except Exception, err:
|
||||||
self.log.error(err)
|
self.log.error(err)
|
||||||
self.socket.send(msgpack.packb({"error": "%s" % Debug.formatException(err)}, use_bin_type=True))
|
if self.running: self.socket.send(msgpack.packb({"error": "%s" % Debug.formatException(err)}, use_bin_type=True))
|
||||||
if config.debug: # Raise exception
|
if config.debug: # Raise exception
|
||||||
import sys
|
import sys
|
||||||
sys.excepthook(*sys.exc_info())
|
sys.modules["src.main"].DebugHook.handleError()
|
||||||
|
thread_wakeup_watcher.kill(exception=Debug.Notify("Stopping FileServer"))
|
||||||
|
thread_announce_sites.kill(exception=Debug.Notify("Stopping FileServer"))
|
||||||
|
self.log.debug("Stopped.")
|
||||||
|
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
self.running = False
|
||||||
|
self.socket.close()
|
||||||
|
|
||||||
|
|
|
@ -194,9 +194,6 @@ class Site:
|
||||||
self.log.info("[OK] %s: %s" % (peer.key, result["ok"]))
|
self.log.info("[OK] %s: %s" % (peer.key, result["ok"]))
|
||||||
else:
|
else:
|
||||||
self.log.info("[ERROR] %s: %s" % (peer.key, result))
|
self.log.info("[ERROR] %s: %s" % (peer.key, result))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Update content.json on peers
|
# Update content.json on peers
|
||||||
|
|
|
@ -11,20 +11,25 @@ from Debug import Debug
|
||||||
# Skip websocket handler if not necessary
|
# Skip websocket handler if not necessary
|
||||||
class UiWSGIHandler(WSGIHandler):
|
class UiWSGIHandler(WSGIHandler):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
|
self.server = args[2]
|
||||||
super(UiWSGIHandler, self).__init__(*args, **kwargs)
|
super(UiWSGIHandler, self).__init__(*args, **kwargs)
|
||||||
self.ws_handler = WebSocketHandler(*args, **kwargs)
|
self.args = args
|
||||||
|
self.kwargs = kwargs
|
||||||
|
|
||||||
|
|
||||||
def run_application(self):
|
def run_application(self):
|
||||||
|
self.server.sockets[self.client_address] = self.socket
|
||||||
if "HTTP_UPGRADE" in self.environ: # Websocket request
|
if "HTTP_UPGRADE" in self.environ: # Websocket request
|
||||||
self.ws_handler.__dict__ = self.__dict__ # Match class variables
|
ws_handler = WebSocketHandler(*self.args, **self.kwargs)
|
||||||
self.ws_handler.run_application()
|
ws_handler.__dict__ = self.__dict__ # Match class variables
|
||||||
|
ws_handler.run_application()
|
||||||
else: # Standard HTTP request
|
else: # Standard HTTP request
|
||||||
#print self.application.__class__.__name__
|
#print self.application.__class__.__name__
|
||||||
try:
|
try:
|
||||||
return super(UiWSGIHandler, self).run_application()
|
return super(UiWSGIHandler, self).run_application()
|
||||||
except Exception, err:
|
except Exception, err:
|
||||||
logging.debug("UiWSGIHandler error: %s" % err)
|
logging.debug("UiWSGIHandler error: %s" % err)
|
||||||
|
del self.server.sockets[self.client_address]
|
||||||
|
|
||||||
|
|
||||||
class UiServer:
|
class UiServer:
|
||||||
|
@ -89,4 +94,27 @@ class UiServer:
|
||||||
browser = webbrowser.get(config.open_browser)
|
browser = webbrowser.get(config.open_browser)
|
||||||
browser.open("http://%s:%s" % (config.ui_ip, config.ui_port), new=2)
|
browser.open("http://%s:%s" % (config.ui_ip, config.ui_port), new=2)
|
||||||
|
|
||||||
WSGIServer((self.ip, self.port), handler, handler_class=UiWSGIHandler, log=self.log).serve_forever()
|
self.server = WSGIServer((self.ip, self.port), handler, handler_class=UiWSGIHandler, log=self.log)
|
||||||
|
self.server.sockets = {}
|
||||||
|
self.server.serve_forever()
|
||||||
|
self.log.debug("Stopped.")
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
# Close WS sockets
|
||||||
|
for client in self.server.clients.values():
|
||||||
|
client.ws.close()
|
||||||
|
# Close http sockets
|
||||||
|
sock_closed = 0
|
||||||
|
for sock in self.server.sockets.values():
|
||||||
|
try:
|
||||||
|
sock._sock.close()
|
||||||
|
sock.close()
|
||||||
|
sock_closed += 1
|
||||||
|
except Exception, err:
|
||||||
|
pass
|
||||||
|
self.log.debug("Socket closed: %s" % sock_closed)
|
||||||
|
|
||||||
|
self.server.socket.close()
|
||||||
|
self.server.stop()
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
|
|
@ -121,6 +121,8 @@ class UiWebsocket:
|
||||||
func = self.actionSiteSetLimit
|
func = self.actionSiteSetLimit
|
||||||
elif cmd == "channelJoinAllsite" and "ADMIN" in permissions:
|
elif cmd == "channelJoinAllsite" and "ADMIN" in permissions:
|
||||||
func = self.actionChannelJoinAllsite
|
func = self.actionChannelJoinAllsite
|
||||||
|
elif cmd == "serverUpdate" and "ADMIN" in permissions:
|
||||||
|
func = self.actionServerUpdate
|
||||||
# Unknown command
|
# Unknown command
|
||||||
else:
|
else:
|
||||||
self.response(req["id"], "Unknown command: %s" % cmd)
|
self.response(req["id"], "Unknown command: %s" % cmd)
|
||||||
|
@ -361,3 +363,12 @@ class UiWebsocket:
|
||||||
self.site.saveSettings()
|
self.site.saveSettings()
|
||||||
self.response(to, "Site size limit changed to %sMB" % size_limit)
|
self.response(to, "Site size limit changed to %sMB" % size_limit)
|
||||||
self.site.download()
|
self.site.download()
|
||||||
|
|
||||||
|
|
||||||
|
def actionServerUpdate(self, to):
|
||||||
|
import sys
|
||||||
|
self.cmd("updating")
|
||||||
|
sys.modules["src.main"].update_after_shutdown = True
|
||||||
|
sys.modules["src.main"].file_server.stop()
|
||||||
|
sys.modules["src.main"].ui_server.stop()
|
||||||
|
|
||||||
|
|
|
@ -46,6 +46,9 @@ class Wrapper
|
||||||
@sendInner message # Pass to inner frame
|
@sendInner message # Pass to inner frame
|
||||||
if message.params.address == window.address # Current page
|
if message.params.address == window.address # Current page
|
||||||
@setSiteInfo message.params
|
@setSiteInfo message.params
|
||||||
|
else if cmd == "updating" # Close connection
|
||||||
|
@ws.ws.close()
|
||||||
|
@ws.onCloseWebsocket(null, 4000)
|
||||||
else
|
else
|
||||||
@sendInner message # Pass message to inner frame
|
@sendInner message # Pass message to inner frame
|
||||||
|
|
||||||
|
@ -166,7 +169,7 @@ class Wrapper
|
||||||
@wrapperWsInited = false
|
@wrapperWsInited = false
|
||||||
setTimeout (=> # Wait a bit, maybe its page closing
|
setTimeout (=> # Wait a bit, maybe its page closing
|
||||||
@sendInner {"cmd": "wrapperClosedWebsocket"} # Send to inner frame
|
@sendInner {"cmd": "wrapperClosedWebsocket"} # Send to inner frame
|
||||||
if e.code == 1000 # Server error please reload page
|
if e and e.code == 1000 and e.wasClean == false # Server error please reload page
|
||||||
@ws_error = @notifications.add("connection", "error", "UiServer Websocket error, please reload the page.")
|
@ws_error = @notifications.add("connection", "error", "UiServer Websocket error, please reload the page.")
|
||||||
else if not @ws_error
|
else if not @ws_error
|
||||||
@ws_error = @notifications.add("connection", "error", "Connection with <b>UiServer Websocket</b> was lost. Reconnecting...")
|
@ws_error = @notifications.add("connection", "error", "Connection with <b>UiServer Websocket</b> was lost. Reconnecting...")
|
||||||
|
|
|
@ -120,17 +120,20 @@
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
ZeroWebsocket.prototype.onCloseWebsocket = function(e) {
|
ZeroWebsocket.prototype.onCloseWebsocket = function(e, reconnect) {
|
||||||
|
if (reconnect == null) {
|
||||||
|
reconnect = 10000;
|
||||||
|
}
|
||||||
this.log("Closed", e);
|
this.log("Closed", e);
|
||||||
if (e.code === 1000) {
|
if (e && e.code === 1000 && e.wasClean === false) {
|
||||||
this.log("Server error, please reload the page");
|
this.log("Server error, please reload the page", e.wasClean);
|
||||||
} else {
|
} else {
|
||||||
setTimeout(((function(_this) {
|
setTimeout(((function(_this) {
|
||||||
return function() {
|
return function() {
|
||||||
_this.log("Reconnecting...");
|
_this.log("Reconnecting...");
|
||||||
return _this.connect();
|
return _this.connect();
|
||||||
};
|
};
|
||||||
})(this)), 10000);
|
})(this)), reconnect);
|
||||||
}
|
}
|
||||||
if (this.onClose != null) {
|
if (this.onClose != null) {
|
||||||
return this.onClose(e);
|
return this.onClose(e);
|
||||||
|
@ -780,6 +783,9 @@ jQuery.extend( jQuery.easing,
|
||||||
if (message.params.address === window.address) {
|
if (message.params.address === window.address) {
|
||||||
return this.setSiteInfo(message.params);
|
return this.setSiteInfo(message.params);
|
||||||
}
|
}
|
||||||
|
} else if (cmd === "updating") {
|
||||||
|
this.ws.ws.close();
|
||||||
|
return this.ws.onCloseWebsocket(null, 4000);
|
||||||
} else {
|
} else {
|
||||||
return this.sendInner(message);
|
return this.sendInner(message);
|
||||||
}
|
}
|
||||||
|
@ -947,7 +953,7 @@ jQuery.extend( jQuery.easing,
|
||||||
_this.sendInner({
|
_this.sendInner({
|
||||||
"cmd": "wrapperClosedWebsocket"
|
"cmd": "wrapperClosedWebsocket"
|
||||||
});
|
});
|
||||||
if (e.code === 1000) {
|
if (e && e.code === 1000 && e.wasClean === false) {
|
||||||
return _this.ws_error = _this.notifications.add("connection", "error", "UiServer Websocket error, please reload the page.");
|
return _this.ws_error = _this.notifications.add("connection", "error", "UiServer Websocket error, please reload the page.");
|
||||||
} else if (!_this.ws_error) {
|
} else if (!_this.ws_error) {
|
||||||
return _this.ws_error = _this.notifications.add("connection", "error", "Connection with <b>UiServer Websocket</b> was lost. Reconnecting...");
|
return _this.ws_error = _this.notifications.add("connection", "error", "Connection with <b>UiServer Websocket</b> was lost. Reconnecting...");
|
||||||
|
|
|
@ -66,15 +66,15 @@ class ZeroWebsocket
|
||||||
if @onError? then @onError(e)
|
if @onError? then @onError(e)
|
||||||
|
|
||||||
|
|
||||||
onCloseWebsocket: (e) =>
|
onCloseWebsocket: (e, reconnect=10000) =>
|
||||||
@log "Closed", e
|
@log "Closed", e
|
||||||
if e.code == 1000
|
if e and e.code == 1000 and e.wasClean == false
|
||||||
@log "Server error, please reload the page"
|
@log "Server error, please reload the page", e.wasClean
|
||||||
else # Connection error
|
else # Connection error
|
||||||
setTimeout (=>
|
setTimeout (=>
|
||||||
@log "Reconnecting..."
|
@log "Reconnecting..."
|
||||||
@connect()
|
@connect()
|
||||||
), 10000
|
), reconnect
|
||||||
if @onClose? then @onClose(e)
|
if @onClose? then @onClose(e)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
from Worker import Worker
|
from Worker import Worker
|
||||||
import gevent, time, logging
|
import gevent, time, logging, random
|
||||||
|
|
||||||
MAX_WORKERS = 10
|
MAX_WORKERS = 10
|
||||||
|
|
||||||
|
@ -87,10 +87,12 @@ class WorkerManager:
|
||||||
def startWorkers(self, peers=None):
|
def startWorkers(self, peers=None):
|
||||||
if len(self.workers) >= MAX_WORKERS and not peers: return False # Workers number already maxed
|
if len(self.workers) >= MAX_WORKERS and not peers: return False # Workers number already maxed
|
||||||
if not self.tasks: return False # No task for workers
|
if not self.tasks: return False # No task for workers
|
||||||
for key, peer in self.site.peers.iteritems(): # One worker for every peer
|
peers = self.site.peers.values()
|
||||||
|
random.shuffle(peers)
|
||||||
|
for peer in peers: # One worker for every peer
|
||||||
if peers and peer not in peers: continue # If peers definied and peer not valid
|
if peers and peer not in peers: continue # If peers definied and peer not valid
|
||||||
worker = self.addWorker(peer)
|
worker = self.addWorker(peer)
|
||||||
if worker: self.log.debug("Added worker: %s, workers: %s/%s" % (key, len(self.workers), MAX_WORKERS))
|
if worker: self.log.debug("Added worker: %s, workers: %s/%s" % (peer.key, len(self.workers), MAX_WORKERS))
|
||||||
|
|
||||||
|
|
||||||
# Stop all worker
|
# Stop all worker
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import os, sys
|
import os, sys
|
||||||
|
update_after_shutdown = False
|
||||||
sys.path.insert(0, os.path.dirname(__file__)) # Imports relative to main.py
|
sys.path.insert(0, os.path.dirname(__file__)) # Imports relative to main.py
|
||||||
|
|
||||||
# Create necessary files and dirs
|
# Create necessary files and dirs
|
||||||
|
@ -43,7 +44,6 @@ else:
|
||||||
import gevent
|
import gevent
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
|
||||||
logging.debug("Starting... %s" % config)
|
logging.debug("Starting... %s" % config)
|
||||||
|
|
||||||
# Starts here when running zeronet.py
|
# Starts here when running zeronet.py
|
||||||
|
@ -56,6 +56,7 @@ def start():
|
||||||
|
|
||||||
# Start serving UiServer and PeerServer
|
# Start serving UiServer and PeerServer
|
||||||
def main():
|
def main():
|
||||||
|
global ui_server, file_server
|
||||||
from File import FileServer
|
from File import FileServer
|
||||||
from Ui import UiServer
|
from Ui import UiServer
|
||||||
logging.info("Creating UiServer....")
|
logging.info("Creating UiServer....")
|
||||||
|
|
39
update.py
Normal file
39
update.py
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
from gevent import monkey; monkey.patch_all()
|
||||||
|
import urllib, zipfile, os, ssl, httplib, socket
|
||||||
|
import cStringIO as StringIO
|
||||||
|
|
||||||
|
def update():
|
||||||
|
# Gevent https bug workaround (https://github.com/gevent/gevent/issues/477)
|
||||||
|
reload(socket)
|
||||||
|
reload(httplib)
|
||||||
|
reload(ssl)
|
||||||
|
|
||||||
|
print "Downloading.",
|
||||||
|
file = urllib.urlopen("https://github.com/HelloZeroNet/ZeroNet/archive/master.zip")
|
||||||
|
data = StringIO.StringIO()
|
||||||
|
while True:
|
||||||
|
buff = file.read(1024*16)
|
||||||
|
if not buff: break
|
||||||
|
data.write(buff)
|
||||||
|
print ".",
|
||||||
|
|
||||||
|
print "Extracting...",
|
||||||
|
zip = zipfile.ZipFile(data)
|
||||||
|
for inner_path in zip.namelist():
|
||||||
|
print ".",
|
||||||
|
dest_path = inner_path.replace("ZeroNet-master/", "")
|
||||||
|
if not dest_path: continue
|
||||||
|
|
||||||
|
dest_dir = os.path.dirname(dest_path)
|
||||||
|
if dest_dir and not os.path.isdir(dest_dir):
|
||||||
|
os.makedirs(dest_dir)
|
||||||
|
|
||||||
|
if dest_dir != dest_path.strip("/"):
|
||||||
|
data = zip.read(inner_path)
|
||||||
|
open(dest_path, 'wb').write(data)
|
||||||
|
|
||||||
|
print "Done."
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
update()
|
40
zeronet.py
40
zeronet.py
|
@ -1,13 +1,37 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
try:
|
try:
|
||||||
from src import main
|
from src import main
|
||||||
main.start()
|
main.start()
|
||||||
except Exception, err: # Prevent closing
|
if main.update_after_shutdown: # Updater
|
||||||
import traceback
|
import update, sys, os, gc
|
||||||
traceback.print_exc()
|
# Update
|
||||||
raw_input("-- Error happened, press enter to close --")
|
update.update()
|
||||||
|
|
||||||
|
# Close log files
|
||||||
|
logger = sys.modules["src.main"].logging.getLogger()
|
||||||
|
|
||||||
|
for handler in logger.handlers[:]:
|
||||||
|
handler.flush()
|
||||||
|
handler.close()
|
||||||
|
logger.removeHandler(handler)
|
||||||
|
|
||||||
|
except Exception, err: # Prevent closing
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
raw_input("-- Error happened, press enter to close --")
|
||||||
|
|
||||||
|
if main.update_after_shutdown: # Updater
|
||||||
|
# Restart
|
||||||
|
gc.collect() # Garbage collect
|
||||||
|
print "Restarting..."
|
||||||
|
args = sys.argv[:]
|
||||||
|
args.insert(0, sys.executable)
|
||||||
|
if sys.platform == 'win32':
|
||||||
|
args = ['"%s"' % arg for arg in args]
|
||||||
|
os.execv(sys.executable, args)
|
||||||
|
print "Bye."
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
main()
|
main()
|
||||||
|
|
Loading…
Reference in a new issue