version 0.2.1, better browser open, site size limit, save number of peers to sites.json to faster warmup, silent wsgihandler error, siteSetLimit API comment, grant ADMIN permissions to wrapper, display site changetime from includes too, loading screen warning support
This commit is contained in:
parent
882577968a
commit
fa7164a0f0
14 changed files with 243 additions and 48 deletions
|
@ -15,7 +15,7 @@ Decentralized websites using Bitcoin crypto and BitTorrent network
|
||||||
- After starting `zeronet.py` you will be able to visit zeronet sites using http://127.0.0.1:43110/{zeronet_address} (eg. http://127.0.0.1:43110/1EU1tbG9oC1A8jz2ouVwGZyQ5asrNsE4Vr).
|
- After starting `zeronet.py` you will be able to visit zeronet sites using http://127.0.0.1:43110/{zeronet_address} (eg. http://127.0.0.1:43110/1EU1tbG9oC1A8jz2ouVwGZyQ5asrNsE4Vr).
|
||||||
- When you visit a new zeronet site, it's trying to find peers using BitTorrent network and download the site files (html, css, js...) from them.
|
- When you visit a new zeronet site, it's trying to find peers using BitTorrent network and download the site files (html, css, js...) from them.
|
||||||
- Each visited sites become also served by You.
|
- Each visited sites become also served by You.
|
||||||
- Every site containing a `site.json` which holds all other files sha1 hash and a sign generated using site's private key.
|
- Every site containing a `site.json` which holds all other files sha512 hash and a sign generated using site's private key.
|
||||||
- If the site owner (who has the private key for the site address) modifies the site, then he/she signs the new `content.json` and publish it to the peers. After the peers have verified the `content.json` integrity (using the sign), they download the modified files and publish the new content to other peers.
|
- If the site owner (who has the private key for the site address) modifies the site, then he/she signs the new `content.json` and publish it to the peers. After the peers have verified the `content.json` integrity (using the sign), they download the modified files and publish the new content to other peers.
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ import ConfigParser
|
||||||
|
|
||||||
class Config(object):
|
class Config(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.version = "0.2.0"
|
self.version = "0.2.1"
|
||||||
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
|
||||||
|
@ -60,7 +60,9 @@ class Config(object):
|
||||||
parser.add_argument('--ui_ip', help='Web interface bind address', default="127.0.0.1", metavar='ip')
|
parser.add_argument('--ui_ip', help='Web interface bind address', default="127.0.0.1", metavar='ip')
|
||||||
parser.add_argument('--ui_port', help='Web interface bind port', default=43110, type=int, metavar='port')
|
parser.add_argument('--ui_port', help='Web interface bind port', default=43110, type=int, metavar='port')
|
||||||
parser.add_argument('--ui_restrict', help='Restrict web access', default=False, metavar='ip')
|
parser.add_argument('--ui_restrict', help='Restrict web access', default=False, metavar='ip')
|
||||||
|
parser.add_argument('--open_browser', help='Open homepage in web browser automatically', nargs='?', const="default_browser", metavar='browser_name')
|
||||||
parser.add_argument('--homepage', help='Web interface Homepage', default='1EU1tbG9oC1A8jz2ouVwGZyQ5asrNsE4Vr', metavar='address')
|
parser.add_argument('--homepage', help='Web interface Homepage', default='1EU1tbG9oC1A8jz2ouVwGZyQ5asrNsE4Vr', metavar='address')
|
||||||
|
parser.add_argument('--size_limit', help='Default site size limit in MB', default=10, metavar='size_limit')
|
||||||
|
|
||||||
parser.add_argument('--fileserver_ip', help='FileServer bind address', default="*", metavar='ip')
|
parser.add_argument('--fileserver_ip', help='FileServer bind address', default="*", metavar='ip')
|
||||||
parser.add_argument('--fileserver_port',help='FileServer bind port', default=15441, type=int, metavar='port')
|
parser.add_argument('--fileserver_port',help='FileServer bind port', default=15441, type=int, metavar='port')
|
||||||
|
|
|
@ -9,6 +9,7 @@ class ContentManager:
|
||||||
self.log = self.site.log
|
self.log = self.site.log
|
||||||
self.contents = {} # Known content.json (without files and includes)
|
self.contents = {} # Known content.json (without files and includes)
|
||||||
self.loadContent(add_bad_files = False)
|
self.loadContent(add_bad_files = False)
|
||||||
|
self.site.settings["size"] = self.getTotalSize()
|
||||||
|
|
||||||
|
|
||||||
# Load content.json to self.content
|
# Load content.json to self.content
|
||||||
|
@ -68,9 +69,24 @@ class ContentManager:
|
||||||
for inner_path in changed:
|
for inner_path in changed:
|
||||||
self.site.bad_files[inner_path] = True
|
self.site.bad_files[inner_path] = True
|
||||||
|
|
||||||
|
if new_content["modified"] > self.site.settings.get("modified", 0):
|
||||||
|
self.site.settings["modified"] = new_content["modified"]
|
||||||
|
|
||||||
return changed
|
return changed
|
||||||
|
|
||||||
|
|
||||||
|
# Get total size of site
|
||||||
|
# Return: 32819 (size of files in kb)
|
||||||
|
def getTotalSize(self, ignore=None):
|
||||||
|
total_size = 0
|
||||||
|
for inner_path, content in self.contents.iteritems():
|
||||||
|
if inner_path == ignore: continue
|
||||||
|
total_size += os.path.getsize(self.site.getPath(inner_path)) # Size of content.json
|
||||||
|
for file, info in content.get("files", {}).iteritems():
|
||||||
|
total_size += info["size"]
|
||||||
|
return total_size
|
||||||
|
|
||||||
|
|
||||||
# Find the file info line from self.contents
|
# Find the file info line from self.contents
|
||||||
# Return: { "sha512": "c29d73d30ee8c9c1b5600e8a84447a6de15a3c3db6869aca4a2a578c1721f518", "size": 41 , "content_inner_path": "content.json"}
|
# Return: { "sha512": "c29d73d30ee8c9c1b5600e8a84447a6de15a3c3db6869aca4a2a578c1721f518", "size": 41 , "content_inner_path": "content.json"}
|
||||||
def getFileInfo(self, inner_path):
|
def getFileInfo(self, inner_path):
|
||||||
|
@ -216,30 +232,50 @@ class ContentManager:
|
||||||
return 1 # Todo: Multisig
|
return 1 # Todo: Multisig
|
||||||
|
|
||||||
|
|
||||||
|
# Checks if the content.json content is valid
|
||||||
|
# Return: True or False
|
||||||
def validContent(self, inner_path, content):
|
def validContent(self, inner_path, content):
|
||||||
if inner_path == "content.json": return True # Always ok
|
content_size = len(json.dumps(content)) + sum([file["size"] for file in content["files"].values()]) # Size of new content
|
||||||
|
site_size = self.getTotalSize(ignore=inner_path)+content_size # Site size without old content
|
||||||
|
if site_size > self.site.settings.get("size", 0): self.site.settings["size"] = site_size # Save to settings if larger
|
||||||
|
|
||||||
|
site_size_limit = self.site.getSizeLimit()*1024*1024
|
||||||
|
|
||||||
|
# Check total site size limit
|
||||||
|
if site_size > site_size_limit:
|
||||||
|
self.log.error("%s: Site too large %s > %s, aborting task..." % (inner_path, site_size, site_size_limit))
|
||||||
|
task = self.site.worker_manager.findTask(inner_path)
|
||||||
|
if task: # Dont try to download from other peers
|
||||||
|
self.site.worker_manager.failTask(task)
|
||||||
|
return False
|
||||||
|
|
||||||
|
if inner_path == "content.json": return True # Root content.json is passed
|
||||||
|
|
||||||
|
# Load include details
|
||||||
include_info = self.getIncludeInfo(inner_path)
|
include_info = self.getIncludeInfo(inner_path)
|
||||||
if not include_info:
|
if not include_info:
|
||||||
self.log.error("%s: No include info" % inner_path)
|
self.log.error("%s: No include info" % inner_path)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if include_info.get("max_size"): # Size limit
|
# Check include size limit
|
||||||
total_size = len(json.dumps(content)) + sum([file["size"] for file in content["files"].values()])
|
if include_info.get("max_size"): # Include size limit
|
||||||
if total_size > include_info["max_size"]:
|
if content_size > include_info["max_size"]:
|
||||||
self.log.error("%s: Too large %s > %s" % (inner_path, total_size, include_info["max_size"]))
|
self.log.error("%s: Include too large %s > %s" % (inner_path, total_size, include_info["max_size"]))
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
# Check if content includes allowed
|
||||||
if include_info.get("includes_allowed") == False and content.get("includes"):
|
if include_info.get("includes_allowed") == False and content.get("includes"):
|
||||||
self.log.error("%s: Includes not allowed" % inner_path)
|
self.log.error("%s: Includes not allowed" % inner_path)
|
||||||
return False # Includes not allowed
|
return False # Includes not allowed
|
||||||
|
|
||||||
if include_info.get("files_allowed"): # Filename limit
|
# Filename limit
|
||||||
|
if include_info.get("files_allowed"):
|
||||||
for file_inner_path in content["files"].keys():
|
for file_inner_path in content["files"].keys():
|
||||||
if not re.match("^%s$" % include_info["files_allowed"], file_inner_path):
|
if not re.match("^%s$" % include_info["files_allowed"], file_inner_path):
|
||||||
self.log.error("%s: File not allowed: " % file_inner_path)
|
self.log.error("%s: File not allowed: " % file_inner_path)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
return True
|
return True # All good
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -292,7 +328,7 @@ class ContentManager:
|
||||||
self.log.error("Verify sign error: %s" % Debug.formatException(err))
|
self.log.error("Verify sign error: %s" % Debug.formatException(err))
|
||||||
return False
|
return False
|
||||||
|
|
||||||
else: # Check using sha1 hash
|
else: # Check using sha512 hash
|
||||||
file_info = self.getFileInfo(inner_path)
|
file_info = self.getFileInfo(inner_path)
|
||||||
if file_info:
|
if file_info:
|
||||||
if "sha512" in file_info:
|
if "sha512" in file_info:
|
||||||
|
|
|
@ -41,7 +41,9 @@ class FileRequest:
|
||||||
return False
|
return False
|
||||||
if site.settings["own"] and params["inner_path"].endswith("content.json"):
|
if site.settings["own"] and params["inner_path"].endswith("content.json"):
|
||||||
self.log.debug("Someone trying to push a file to own site %s, reload local %s first" % (site.address, params["inner_path"]))
|
self.log.debug("Someone trying to push a file to own site %s, reload local %s first" % (site.address, params["inner_path"]))
|
||||||
site.content_manager.loadContent(params["inner_path"])
|
changed = site.content_manager.loadContent(params["inner_path"], add_bad_files=False)
|
||||||
|
if changed: # Content.json changed locally
|
||||||
|
site.settings["size"] = site.content_manager.getTotalSize() # Update site size
|
||||||
buff = StringIO(params["body"])
|
buff = StringIO(params["body"])
|
||||||
valid = site.content_manager.verifyFile(params["inner_path"], buff)
|
valid = site.content_manager.verifyFile(params["inner_path"], buff)
|
||||||
if valid == True: # Valid and changed
|
if valid == True: # Valid and changed
|
||||||
|
|
|
@ -33,8 +33,8 @@ class Site:
|
||||||
self.notifications = [] # Pending notifications displayed once on page load [error|ok|info, message, timeout]
|
self.notifications = [] # Pending notifications displayed once on page load [error|ok|info, message, timeout]
|
||||||
self.page_requested = False # Page viewed in browser
|
self.page_requested = False # Page viewed in browser
|
||||||
|
|
||||||
self.content_manager = ContentManager(self) # Load contents
|
|
||||||
self.loadSettings() # Load settings from sites.json
|
self.loadSettings() # Load settings from sites.json
|
||||||
|
self.content_manager = ContentManager(self) # Load contents
|
||||||
|
|
||||||
if not self.settings.get("auth_key"): # To auth user in site (Obsolete, will be removed)
|
if not self.settings.get("auth_key"): # To auth user in site (Obsolete, will be removed)
|
||||||
self.settings["auth_key"] = ''.join(random.choice(string.ascii_uppercase + string.ascii_lowercase + string.digits) for _ in range(24))
|
self.settings["auth_key"] = ''.join(random.choice(string.ascii_uppercase + string.ascii_lowercase + string.digits) for _ in range(24))
|
||||||
|
@ -74,6 +74,22 @@ class Site:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
|
# Max site size in MB
|
||||||
|
def getSizeLimit(self):
|
||||||
|
return self.settings.get("size_limit", config.size_limit)
|
||||||
|
|
||||||
|
|
||||||
|
# Next size limit based on current size
|
||||||
|
def getNextSizeLimit(self):
|
||||||
|
size_limits = [10,20,50,100,200,500,1000,2000,5000,10000,20000,50000,100000]
|
||||||
|
size = self.settings.get("size", 0)
|
||||||
|
for size_limit in size_limits:
|
||||||
|
if size*1.2 < size_limit*1024*1024:
|
||||||
|
return size_limit
|
||||||
|
return 999999
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Sercurity check and return path of site's file
|
# Sercurity check and return path of site's file
|
||||||
def getPath(self, inner_path):
|
def getPath(self, inner_path):
|
||||||
inner_path = inner_path.replace("\\", "/") # Windows separator fix
|
inner_path = inner_path.replace("\\", "/") # Windows separator fix
|
||||||
|
@ -123,10 +139,14 @@ class Site:
|
||||||
|
|
||||||
# Download all files of the site
|
# Download all files of the site
|
||||||
@util.Noparallel(blocking=False)
|
@util.Noparallel(blocking=False)
|
||||||
def download(self):
|
def download(self, check_size=False):
|
||||||
self.log.debug("Start downloading...%s" % self.bad_files)
|
self.log.debug("Start downloading...%s" % self.bad_files)
|
||||||
self.announce()
|
self.announce()
|
||||||
self.last_downloads = []
|
self.last_downloads = []
|
||||||
|
if check_size: # Check the size first
|
||||||
|
valid = downloadContent(download_files=False)
|
||||||
|
if not valid: return False # Cant download content.jsons or size is not fits
|
||||||
|
|
||||||
found = self.downloadContent("content.json")
|
found = self.downloadContent("content.json")
|
||||||
|
|
||||||
return found
|
return found
|
||||||
|
@ -147,6 +167,8 @@ class Site:
|
||||||
if not self.settings["own"]: self.checkFiles(quick_check=True) # Quick check files based on file size
|
if not self.settings["own"]: self.checkFiles(quick_check=True) # Quick check files based on file size
|
||||||
if self.bad_files:
|
if self.bad_files:
|
||||||
self.download()
|
self.download()
|
||||||
|
|
||||||
|
self.settings["size"] = self.content_manager.getTotalSize() # Update site size
|
||||||
return changed
|
return changed
|
||||||
|
|
||||||
|
|
||||||
|
@ -266,6 +288,8 @@ class Site:
|
||||||
if added:
|
if added:
|
||||||
self.worker_manager.onPeers()
|
self.worker_manager.onPeers()
|
||||||
self.updateWebsocket(peers_added=added)
|
self.updateWebsocket(peers_added=added)
|
||||||
|
self.settings["peers"] = len(peers)
|
||||||
|
self.saveSettings()
|
||||||
self.log.debug("Found %s peers, new: %s" % (len(peers), added))
|
self.log.debug("Found %s peers, new: %s" % (len(peers), added))
|
||||||
else:
|
else:
|
||||||
pass # TODO: http tracker support
|
pass # TODO: http tracker support
|
||||||
|
|
|
@ -43,6 +43,7 @@ def isAddress(address):
|
||||||
# Return site and start download site files
|
# Return site and start download site files
|
||||||
def need(address, all_file=True):
|
def need(address, all_file=True):
|
||||||
from Site import Site
|
from Site import Site
|
||||||
|
new = False
|
||||||
if address not in sites: # Site not exits yet
|
if address not in sites: # Site not exits yet
|
||||||
if not isAddress(address): return False # Not address: %s % address
|
if not isAddress(address): return False # Not address: %s % address
|
||||||
logging.debug("Added new site: %s" % address)
|
logging.debug("Added new site: %s" % address)
|
||||||
|
@ -50,6 +51,7 @@ def need(address, all_file=True):
|
||||||
if not sites[address].settings["serving"]: # Maybe it was deleted before
|
if not sites[address].settings["serving"]: # Maybe it was deleted before
|
||||||
sites[address].settings["serving"] = True
|
sites[address].settings["serving"] = True
|
||||||
sites[address].saveSettings()
|
sites[address].saveSettings()
|
||||||
|
new = True
|
||||||
|
|
||||||
site = sites[address]
|
site = sites[address]
|
||||||
if all_file: site.download()
|
if all_file: site.download()
|
||||||
|
|
|
@ -21,7 +21,10 @@ class UiWSGIHandler(WSGIHandler):
|
||||||
self.ws_handler.run_application()
|
self.ws_handler.run_application()
|
||||||
else: # Standard HTTP request
|
else: # Standard HTTP request
|
||||||
#print self.application.__class__.__name__
|
#print self.application.__class__.__name__
|
||||||
return super(UiWSGIHandler, self).run_application()
|
try:
|
||||||
|
return super(UiWSGIHandler, self).run_application()
|
||||||
|
except Exception, err:
|
||||||
|
logging.debug("UiWSGIHandler error: %s" % err)
|
||||||
|
|
||||||
|
|
||||||
class UiServer:
|
class UiServer:
|
||||||
|
@ -77,5 +80,13 @@ class UiServer:
|
||||||
self.log.info("Web interface: http://%s:%s/" % (config.ui_ip, config.ui_port))
|
self.log.info("Web interface: http://%s:%s/" % (config.ui_ip, config.ui_port))
|
||||||
self.log.info("--------------------------------------")
|
self.log.info("--------------------------------------")
|
||||||
|
|
||||||
|
if config.open_browser:
|
||||||
|
logging.info("Opening browser: %s...", config.open_browser)
|
||||||
|
import webbrowser
|
||||||
|
if config.open_browser == "default_browser":
|
||||||
|
browser = webbrowser.get()
|
||||||
|
else:
|
||||||
|
browser = webbrowser.get(config.open_browser)
|
||||||
|
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()
|
WSGIServer((self.ip, self.port), handler, handler_class=UiWSGIHandler, log=self.log).serve_forever()
|
||||||
|
|
|
@ -84,6 +84,9 @@ class UiWebsocket:
|
||||||
cmd = req.get("cmd")
|
cmd = req.get("cmd")
|
||||||
params = req.get("params")
|
params = req.get("params")
|
||||||
permissions = self.site.settings["permissions"]
|
permissions = self.site.settings["permissions"]
|
||||||
|
if req["id"] >= 1000000: # Its a wrapper command, allow admin commands
|
||||||
|
permissions = permissions[:]
|
||||||
|
permissions.append("ADMIN")
|
||||||
|
|
||||||
if cmd == "response": # It's a response to a command
|
if cmd == "response": # It's a response to a command
|
||||||
return self.actionResponse(req["to"], req["result"])
|
return self.actionResponse(req["to"], req["result"])
|
||||||
|
@ -114,6 +117,8 @@ class UiWebsocket:
|
||||||
func = self.actionSiteDelete
|
func = self.actionSiteDelete
|
||||||
elif cmd == "siteList" and "ADMIN" in permissions:
|
elif cmd == "siteList" and "ADMIN" in permissions:
|
||||||
func = self.actionSiteList
|
func = self.actionSiteList
|
||||||
|
elif cmd == "siteSetLimit" and "ADMIN" in permissions:
|
||||||
|
func = self.actionSiteSetLimit
|
||||||
elif cmd == "channelJoinAllsite" and "ADMIN" in permissions:
|
elif cmd == "channelJoinAllsite" and "ADMIN" in permissions:
|
||||||
func = self.actionChannelJoinAllsite
|
func = self.actionChannelJoinAllsite
|
||||||
# Unknown command
|
# Unknown command
|
||||||
|
@ -155,16 +160,21 @@ class UiWebsocket:
|
||||||
if "sign" in content: del(content["sign"])
|
if "sign" in content: del(content["sign"])
|
||||||
if "signs" in content: del(content["signs"])
|
if "signs" in content: del(content["signs"])
|
||||||
|
|
||||||
|
settings = site.settings.copy()
|
||||||
|
del settings["wrapper_key"] # Dont expose wrapper key
|
||||||
|
|
||||||
ret = {
|
ret = {
|
||||||
"auth_key": self.site.settings["auth_key"], # Obsolete, will be removed
|
"auth_key": self.site.settings["auth_key"], # Obsolete, will be removed
|
||||||
"auth_key_sha512": hashlib.sha512(self.site.settings["auth_key"]).hexdigest()[0:64], # Obsolete, will be removed
|
"auth_key_sha512": hashlib.sha512(self.site.settings["auth_key"]).hexdigest()[0:64], # Obsolete, will be removed
|
||||||
"auth_address": self.user.getAuthAddress(site.address),
|
"auth_address": self.user.getAuthAddress(site.address),
|
||||||
"address": site.address,
|
"address": site.address,
|
||||||
"settings": site.settings,
|
"settings": settings,
|
||||||
"content_updated": site.content_updated,
|
"content_updated": site.content_updated,
|
||||||
"bad_files": len(site.bad_files),
|
"bad_files": len(site.bad_files),
|
||||||
|
"size_limit": site.getSizeLimit(),
|
||||||
|
"next_size_limit": site.getNextSizeLimit(),
|
||||||
"last_downloads": len(site.last_downloads),
|
"last_downloads": len(site.last_downloads),
|
||||||
"peers": len(site.peers),
|
"peers": site.settings["peers"],
|
||||||
"tasks": len([task["inner_path"] for task in site.worker_manager.tasks]),
|
"tasks": len([task["inner_path"] for task in site.worker_manager.tasks]),
|
||||||
"content": content
|
"content": content
|
||||||
}
|
}
|
||||||
|
@ -344,3 +354,10 @@ class UiWebsocket:
|
||||||
site.updateWebsocket()
|
site.updateWebsocket()
|
||||||
else:
|
else:
|
||||||
self.response(to, {"error": "Unknown site: %s" % address})
|
self.response(to, {"error": "Unknown site: %s" % address})
|
||||||
|
|
||||||
|
|
||||||
|
def actionSiteSetLimit(self, to, size_limit):
|
||||||
|
self.site.settings["size_limit"] = size_limit
|
||||||
|
self.site.saveSettings()
|
||||||
|
self.response(to, "Site size limit changed to %sMB" % size_limit)
|
||||||
|
self.site.download()
|
||||||
|
|
|
@ -34,7 +34,10 @@ class Loading
|
||||||
if not @screen_visible then return false
|
if not @screen_visible then return false
|
||||||
$(".loadingscreen .console .cursor").remove() # Remove previous cursor
|
$(".loadingscreen .console .cursor").remove() # Remove previous cursor
|
||||||
if type == "error" then text = "<span class='console-error'>#{text}</span>" else text = text+"<span class='cursor'> </span>"
|
if type == "error" then text = "<span class='console-error'>#{text}</span>" else text = text+"<span class='cursor'> </span>"
|
||||||
$(".loadingscreen .console").append("<div class='console-line'>#{text}</div>")
|
|
||||||
|
line = $("<div class='console-line'>#{text}</div>").appendTo(".loadingscreen .console")
|
||||||
|
if type == "warning" then line.addClass("console-warning")
|
||||||
|
return line
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -70,23 +70,28 @@ class Wrapper
|
||||||
else if cmd == "wrapperSetViewport" # Set the viewport
|
else if cmd == "wrapperSetViewport" # Set the viewport
|
||||||
@actionSetViewport(message)
|
@actionSetViewport(message)
|
||||||
else # Send to websocket
|
else # Send to websocket
|
||||||
@ws.send(message) # Pass message to websocket
|
if message.id < 1000000
|
||||||
|
@ws.send(message) # Pass message to websocket
|
||||||
|
else
|
||||||
|
@log "Invalid inner message id"
|
||||||
|
|
||||||
|
|
||||||
# - Actions -
|
# - Actions -
|
||||||
|
|
||||||
actionWrapperConfirm: (message) ->
|
actionWrapperConfirm: (message, cb=false) ->
|
||||||
message.params = @toHtmlSafe(message.params) # Escape html
|
message.params = @toHtmlSafe(message.params) # Escape html
|
||||||
if message.params[1] then caption = message.params[1] else caption = "ok"
|
if message.params[1] then caption = message.params[1] else caption = "ok"
|
||||||
|
@wrapperConfirm message.params[0], caption, =>
|
||||||
body = $("<span>"+message.params[0]+"</span>")
|
|
||||||
button = $("<a href='##{caption}' class='button button-#{caption}'>#{caption}</a>") # Add confirm button
|
|
||||||
button.on "click", => # Response on button click
|
|
||||||
@sendInner {"cmd": "response", "to": message.id, "result": "boom"} # Response to confirm
|
@sendInner {"cmd": "response", "to": message.id, "result": "boom"} # Response to confirm
|
||||||
return false
|
return false
|
||||||
|
|
||||||
|
|
||||||
|
wrapperConfirm: (message, caption, cb) ->
|
||||||
|
body = $("<span>"+message+"</span>")
|
||||||
|
button = $("<a href='##{caption}' class='button button-#{caption}'>#{caption}</a>") # Add confirm button
|
||||||
|
button.on "click", cb
|
||||||
body.append(button)
|
body.append(button)
|
||||||
|
@notifications.add("notification-#{caption}", "ask", body)
|
||||||
@notifications.add("notification-#{message.id}", "ask", body)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -151,7 +156,7 @@ class Wrapper
|
||||||
@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...")
|
||||||
), 500
|
), 1000
|
||||||
|
|
||||||
|
|
||||||
# Iframe loaded
|
# Iframe loaded
|
||||||
|
@ -163,7 +168,7 @@ class Wrapper
|
||||||
if window.location.hash then $("#inner-iframe")[0].src += window.location.hash # Hash tag
|
if window.location.hash then $("#inner-iframe")[0].src += window.location.hash # Hash tag
|
||||||
if @ws.ws.readyState == 1 and not @site_info # Ws opened
|
if @ws.ws.readyState == 1 and not @site_info # Ws opened
|
||||||
@reloadSiteInfo()
|
@reloadSiteInfo()
|
||||||
else if @site_info
|
else if @site_info and @site_info.content?.title?
|
||||||
window.document.title = @site_info.content.title+" - ZeroNet"
|
window.document.title = @site_info.content.title+" - ZeroNet"
|
||||||
@log "Setting title to", window.document.title
|
@log "Setting title to", window.document.title
|
||||||
|
|
||||||
|
@ -198,7 +203,18 @@ class Wrapper
|
||||||
# File failed downloading
|
# File failed downloading
|
||||||
else if site_info.event[0] == "file_failed"
|
else if site_info.event[0] == "file_failed"
|
||||||
@site_error = site_info.event[1]
|
@site_error = site_info.event[1]
|
||||||
@loading.printLine("#{site_info.event[1]} download failed", "error")
|
if site_info.settings.size > site_info.size_limit*1024*1024 # Site size too large and not displaying it yet
|
||||||
|
if $(".console .button-setlimit").length == 0 # Not displaying it yet
|
||||||
|
line = @loading.printLine("Site size: <b>#{parseInt(site_info.settings.size/1024/1024)}MB</b> is larger than default allowed #{parseInt(site_info.size_limit)}MB", "warning")
|
||||||
|
button = $("<a href='#Set+limit' class='button button-setlimit'>Open site and set size limit to #{site_info.next_size_limit}MB</a>")
|
||||||
|
button.on "click", (=> return @setSizeLimit(site_info.next_size_limit) )
|
||||||
|
line.after(button)
|
||||||
|
setTimeout (=>
|
||||||
|
@loading.printLine('Ready.')
|
||||||
|
), 100
|
||||||
|
|
||||||
|
else
|
||||||
|
@loading.printLine("#{site_info.event[1]} download failed", "error")
|
||||||
# New peers found
|
# New peers found
|
||||||
else if site_info.event[0] == "peers_added"
|
else if site_info.event[0] == "peers_added"
|
||||||
@loading.printLine("Peers found: #{site_info.peers}")
|
@loading.printLine("Peers found: #{site_info.peers}")
|
||||||
|
@ -209,6 +225,13 @@ class Wrapper
|
||||||
else
|
else
|
||||||
@site_error = "No peers found"
|
@site_error = "No peers found"
|
||||||
@loading.printLine "No peers found"
|
@loading.printLine "No peers found"
|
||||||
|
|
||||||
|
if not @site_info and $("#inner-iframe").attr("src").indexOf("?") == -1 # First site info and mainpage
|
||||||
|
if site_info.size_limit < site_info.next_size_limit # Need upgrade soon
|
||||||
|
@wrapperConfirm "Running out of size limit (#{(site_info.settings.size/1024/1024).toFixed(1)}MB/#{site_info.size_limit}MB)", "Set limit to #{site_info.next_size_limit}MB", =>
|
||||||
|
@ws.cmd "siteSetLimit", [site_info.next_size_limit], (res) =>
|
||||||
|
@notifications.add("size_limit", "done", res, 5000)
|
||||||
|
return false
|
||||||
@site_info = site_info
|
@site_info = site_info
|
||||||
|
|
||||||
|
|
||||||
|
@ -221,6 +244,14 @@ class Wrapper
|
||||||
return values
|
return values
|
||||||
|
|
||||||
|
|
||||||
|
setSizeLimit: (size_limit, reload=true) =>
|
||||||
|
@ws.cmd "siteSetLimit", [size_limit], (res) =>
|
||||||
|
@loading.printLine res
|
||||||
|
if reload
|
||||||
|
$("iframe").attr "src", $("iframe").attr("src") # Reload iframe
|
||||||
|
return false
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
log: (args...) ->
|
log: (args...) ->
|
||||||
console.log "[Wrapper]", args...
|
console.log "[Wrapper]", args...
|
||||||
|
|
|
@ -14,6 +14,7 @@ a { color: black }
|
||||||
.button-Delete { background-color: #e74c3c; border-bottom-color: #c0392b; color: white }
|
.button-Delete { background-color: #e74c3c; border-bottom-color: #c0392b; color: white }
|
||||||
.button-Delete:hover { background-color: #FF5442; border-bottom-color: #8E2B21 }
|
.button-Delete:hover { background-color: #FF5442; border-bottom-color: #8E2B21 }
|
||||||
|
|
||||||
|
|
||||||
/* Fixbutton */
|
/* Fixbutton */
|
||||||
|
|
||||||
.fixbutton {
|
.fixbutton {
|
||||||
|
@ -76,6 +77,9 @@ a { color: black }
|
||||||
display: inline-block; width: 9px; height: 19px; vertical-align: -4px;
|
display: inline-block; width: 9px; height: 19px; vertical-align: -4px;
|
||||||
}
|
}
|
||||||
.console .console-error { color: #e74c3c; font-weight: bold; animation: pulse 2s infinite linear }
|
.console .console-error { color: #e74c3c; font-weight: bold; animation: pulse 2s infinite linear }
|
||||||
|
.console .console-warning { color: #8e44ad; }
|
||||||
|
.console .button { margin: 20px; display: inline-block; text-transform: none; padding: 10px 20px }
|
||||||
|
|
||||||
|
|
||||||
/* Flipper loading anim */
|
/* Flipper loading anim */
|
||||||
.flipper-container { width: 40px; height: 40px; position: absolute; top: 0%; left: 50%; transform: translate3d(-50%, -50%, 0); perspective: 1200; opacity: 0 }
|
.flipper-container { width: 40px; height: 40px; position: absolute; top: 0%; left: 50%; transform: translate3d(-50%, -50%, 0); perspective: 1200; opacity: 0 }
|
||||||
|
|
|
@ -19,6 +19,7 @@ a { color: black }
|
||||||
.button-Delete { background-color: #e74c3c; border-bottom-color: #c0392b; color: white }
|
.button-Delete { background-color: #e74c3c; border-bottom-color: #c0392b; color: white }
|
||||||
.button-Delete:hover { background-color: #FF5442; border-bottom-color: #8E2B21 }
|
.button-Delete:hover { background-color: #FF5442; border-bottom-color: #8E2B21 }
|
||||||
|
|
||||||
|
|
||||||
/* Fixbutton */
|
/* Fixbutton */
|
||||||
|
|
||||||
.fixbutton {
|
.fixbutton {
|
||||||
|
@ -81,6 +82,9 @@ a { color: black }
|
||||||
display: inline-block; width: 9px; height: 19px; vertical-align: -4px;
|
display: inline-block; width: 9px; height: 19px; vertical-align: -4px;
|
||||||
}
|
}
|
||||||
.console .console-error { color: #e74c3c; font-weight: bold; -webkit-animation: pulse 2s infinite linear ; -moz-animation: pulse 2s infinite linear ; -o-animation: pulse 2s infinite linear ; -ms-animation: pulse 2s infinite linear ; animation: pulse 2s infinite linear }
|
.console .console-error { color: #e74c3c; font-weight: bold; -webkit-animation: pulse 2s infinite linear ; -moz-animation: pulse 2s infinite linear ; -o-animation: pulse 2s infinite linear ; -ms-animation: pulse 2s infinite linear ; animation: pulse 2s infinite linear }
|
||||||
|
.console .console-warning { color: #8e44ad; }
|
||||||
|
.console .button { margin: 20px; display: inline-block; text-transform: none; padding: 10px 20px }
|
||||||
|
|
||||||
|
|
||||||
/* Flipper loading anim */
|
/* Flipper loading anim */
|
||||||
.flipper-container { width: 40px; height: 40px; position: absolute; top: 0%; left: 50%; -webkit-transform: translate3d(-50%, -50%, 0); -moz-transform: translate3d(-50%, -50%, 0); -o-transform: translate3d(-50%, -50%, 0); -ms-transform: translate3d(-50%, -50%, 0); transform: translate3d(-50%, -50%, 0) ; -webkit-perspective: 1200; -moz-perspective: 1200; -o-perspective: 1200; -ms-perspective: 1200; perspective: 1200 ; opacity: 0 }
|
.flipper-container { width: 40px; height: 40px; position: absolute; top: 0%; left: 50%; -webkit-transform: translate3d(-50%, -50%, 0); -moz-transform: translate3d(-50%, -50%, 0); -o-transform: translate3d(-50%, -50%, 0); -ms-transform: translate3d(-50%, -50%, 0); transform: translate3d(-50%, -50%, 0) ; -webkit-perspective: 1200; -moz-perspective: 1200; -o-perspective: 1200; -ms-perspective: 1200; perspective: 1200 ; opacity: 0 }
|
||||||
|
|
|
@ -502,6 +502,7 @@ jQuery.extend( jQuery.easing,
|
||||||
};
|
};
|
||||||
|
|
||||||
Loading.prototype.printLine = function(text, type) {
|
Loading.prototype.printLine = function(text, type) {
|
||||||
|
var line;
|
||||||
if (type == null) {
|
if (type == null) {
|
||||||
type = "normal";
|
type = "normal";
|
||||||
}
|
}
|
||||||
|
@ -514,7 +515,11 @@ jQuery.extend( jQuery.easing,
|
||||||
} else {
|
} else {
|
||||||
text = text + "<span class='cursor'> </span>";
|
text = text + "<span class='cursor'> </span>";
|
||||||
}
|
}
|
||||||
return $(".loadingscreen .console").append("<div class='console-line'>" + text + "</div>");
|
line = $("<div class='console-line'>" + text + "</div>").appendTo(".loadingscreen .console");
|
||||||
|
if (type === "warning") {
|
||||||
|
line.addClass("console-warning");
|
||||||
|
}
|
||||||
|
return line;
|
||||||
};
|
};
|
||||||
|
|
||||||
return Loading;
|
return Loading;
|
||||||
|
@ -720,6 +725,7 @@ jQuery.extend( jQuery.easing,
|
||||||
|
|
||||||
Wrapper = (function() {
|
Wrapper = (function() {
|
||||||
function Wrapper(ws_url) {
|
function Wrapper(ws_url) {
|
||||||
|
this.setSizeLimit = __bind(this.setSizeLimit, this);
|
||||||
this.onLoad = __bind(this.onLoad, this);
|
this.onLoad = __bind(this.onLoad, this);
|
||||||
this.onCloseWebsocket = __bind(this.onCloseWebsocket, this);
|
this.onCloseWebsocket = __bind(this.onCloseWebsocket, this);
|
||||||
this.onOpenWebsocket = __bind(this.onOpenWebsocket, this);
|
this.onOpenWebsocket = __bind(this.onOpenWebsocket, this);
|
||||||
|
@ -802,21 +808,26 @@ jQuery.extend( jQuery.easing,
|
||||||
} else if (cmd === "wrapperSetViewport") {
|
} else if (cmd === "wrapperSetViewport") {
|
||||||
return this.actionSetViewport(message);
|
return this.actionSetViewport(message);
|
||||||
} else {
|
} else {
|
||||||
return this.ws.send(message);
|
if (message.id < 1000000) {
|
||||||
|
return this.ws.send(message);
|
||||||
|
} else {
|
||||||
|
return this.log("Invalid inner message id");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Wrapper.prototype.actionWrapperConfirm = function(message) {
|
Wrapper.prototype.actionWrapperConfirm = function(message, cb) {
|
||||||
var body, button, caption;
|
var caption;
|
||||||
|
if (cb == null) {
|
||||||
|
cb = false;
|
||||||
|
}
|
||||||
message.params = this.toHtmlSafe(message.params);
|
message.params = this.toHtmlSafe(message.params);
|
||||||
if (message.params[1]) {
|
if (message.params[1]) {
|
||||||
caption = message.params[1];
|
caption = message.params[1];
|
||||||
} else {
|
} else {
|
||||||
caption = "ok";
|
caption = "ok";
|
||||||
}
|
}
|
||||||
body = $("<span>" + message.params[0] + "</span>");
|
return this.wrapperConfirm(message.params[0], caption, (function(_this) {
|
||||||
button = $("<a href='#" + caption + "' class='button button-" + caption + "'>" + caption + "</a>");
|
|
||||||
button.on("click", (function(_this) {
|
|
||||||
return function() {
|
return function() {
|
||||||
_this.sendInner({
|
_this.sendInner({
|
||||||
"cmd": "response",
|
"cmd": "response",
|
||||||
|
@ -826,8 +837,15 @@ jQuery.extend( jQuery.easing,
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
})(this));
|
})(this));
|
||||||
|
};
|
||||||
|
|
||||||
|
Wrapper.prototype.wrapperConfirm = function(message, caption, cb) {
|
||||||
|
var body, button;
|
||||||
|
body = $("<span>" + message + "</span>");
|
||||||
|
button = $("<a href='#" + caption + "' class='button button-" + caption + "'>" + caption + "</a>");
|
||||||
|
button.on("click", cb);
|
||||||
body.append(button);
|
body.append(button);
|
||||||
return this.notifications.add("notification-" + message.id, "ask", body);
|
return this.notifications.add("notification-" + caption, "ask", body);
|
||||||
};
|
};
|
||||||
|
|
||||||
Wrapper.prototype.actionWrapperPrompt = function(message) {
|
Wrapper.prototype.actionWrapperPrompt = function(message) {
|
||||||
|
@ -913,10 +931,11 @@ jQuery.extend( jQuery.easing,
|
||||||
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...");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
})(this)), 500);
|
})(this)), 1000);
|
||||||
};
|
};
|
||||||
|
|
||||||
Wrapper.prototype.onLoad = function(e) {
|
Wrapper.prototype.onLoad = function(e) {
|
||||||
|
var _ref;
|
||||||
this.log("onLoad");
|
this.log("onLoad");
|
||||||
this.inner_loaded = true;
|
this.inner_loaded = true;
|
||||||
if (!this.inner_ready) {
|
if (!this.inner_ready) {
|
||||||
|
@ -932,7 +951,7 @@ jQuery.extend( jQuery.easing,
|
||||||
}
|
}
|
||||||
if (this.ws.ws.readyState === 1 && !this.site_info) {
|
if (this.ws.ws.readyState === 1 && !this.site_info) {
|
||||||
return this.reloadSiteInfo();
|
return this.reloadSiteInfo();
|
||||||
} else if (this.site_info) {
|
} else if (this.site_info && (((_ref = this.site_info.content) != null ? _ref.title : void 0) != null)) {
|
||||||
window.document.title = this.site_info.content.title + " - ZeroNet";
|
window.document.title = this.site_info.content.title + " - ZeroNet";
|
||||||
return this.log("Setting title to", window.document.title);
|
return this.log("Setting title to", window.document.title);
|
||||||
}
|
}
|
||||||
|
@ -953,6 +972,7 @@ jQuery.extend( jQuery.easing,
|
||||||
};
|
};
|
||||||
|
|
||||||
Wrapper.prototype.setSiteInfo = function(site_info) {
|
Wrapper.prototype.setSiteInfo = function(site_info) {
|
||||||
|
var button, line;
|
||||||
if (site_info.event != null) {
|
if (site_info.event != null) {
|
||||||
if (site_info.event[0] === "file_added" && site_info.bad_files) {
|
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");
|
||||||
|
@ -969,7 +989,25 @@ jQuery.extend( jQuery.easing,
|
||||||
}
|
}
|
||||||
} else if (site_info.event[0] === "file_failed") {
|
} else if (site_info.event[0] === "file_failed") {
|
||||||
this.site_error = site_info.event[1];
|
this.site_error = site_info.event[1];
|
||||||
this.loading.printLine(site_info.event[1] + " download failed", "error");
|
if (site_info.settings.size > site_info.size_limit * 1024 * 1024) {
|
||||||
|
if ($(".console .button-setlimit").length === 0) {
|
||||||
|
line = this.loading.printLine("Site size: <b>" + (parseInt(site_info.settings.size / 1024 / 1024)) + "MB</b> is larger than default allowed " + (parseInt(site_info.size_limit)) + "MB", "warning");
|
||||||
|
button = $("<a href='#Set+limit' class='button button-setlimit'>Open site and set size limit to " + site_info.next_size_limit + "MB</a>");
|
||||||
|
button.on("click", ((function(_this) {
|
||||||
|
return function() {
|
||||||
|
return _this.setSizeLimit(site_info.next_size_limit);
|
||||||
|
};
|
||||||
|
})(this)));
|
||||||
|
line.after(button);
|
||||||
|
setTimeout(((function(_this) {
|
||||||
|
return function() {
|
||||||
|
return _this.loading.printLine('Ready.');
|
||||||
|
};
|
||||||
|
})(this)), 100);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.loading.printLine(site_info.event[1] + " download failed", "error");
|
||||||
|
}
|
||||||
} else if (site_info.event[0] === "peers_added") {
|
} else if (site_info.event[0] === "peers_added") {
|
||||||
this.loading.printLine("Peers found: " + site_info.peers);
|
this.loading.printLine("Peers found: " + site_info.peers);
|
||||||
}
|
}
|
||||||
|
@ -982,6 +1020,18 @@ jQuery.extend( jQuery.easing,
|
||||||
this.loading.printLine("No peers found");
|
this.loading.printLine("No peers found");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!this.site_info && $("#inner-iframe").attr("src").indexOf("?") === -1) {
|
||||||
|
if (site_info.size_limit < site_info.next_size_limit) {
|
||||||
|
this.wrapperConfirm("Running out of size limit (" + ((site_info.settings.size / 1024 / 1024).toFixed(1)) + "MB/" + site_info.size_limit + "MB)", "Set limit to " + site_info.next_size_limit + "MB", (function(_this) {
|
||||||
|
return function() {
|
||||||
|
_this.ws.cmd("siteSetLimit", [site_info.next_size_limit], function(res) {
|
||||||
|
return _this.notifications.add("size_limit", "done", res, 5000);
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
})(this));
|
||||||
|
}
|
||||||
|
}
|
||||||
return this.site_info = site_info;
|
return this.site_info = site_info;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -999,6 +1049,21 @@ jQuery.extend( jQuery.easing,
|
||||||
return values;
|
return values;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Wrapper.prototype.setSizeLimit = function(size_limit, reload) {
|
||||||
|
if (reload == null) {
|
||||||
|
reload = true;
|
||||||
|
}
|
||||||
|
this.ws.cmd("siteSetLimit", [size_limit], (function(_this) {
|
||||||
|
return function(res) {
|
||||||
|
_this.loading.printLine(res);
|
||||||
|
if (reload) {
|
||||||
|
return $("iframe").attr("src", $("iframe").attr("src"));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})(this));
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
Wrapper.prototype.log = function() {
|
Wrapper.prototype.log = function() {
|
||||||
var args;
|
var args;
|
||||||
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
|
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
|
||||||
|
|
12
start.py
12
start.py
|
@ -1,16 +1,10 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
from multiprocessing import Process
|
|
||||||
import sys
|
import sys
|
||||||
import webbrowser
|
|
||||||
import zeronet
|
import zeronet
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
browser_name = sys.argv.pop() if len(sys.argv) >= 2 else None
|
sys.argv += ["--open_browser", "default_browser"]
|
||||||
server = Process(target=zeronet.main)
|
zeronet.main()
|
||||||
server.start()
|
|
||||||
browser = webbrowser.get(browser_name)
|
|
||||||
url = browser.open("http://127.0.0.1:43110", new=2)
|
|
||||||
server.join()
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
main()
|
main()
|
||||||
|
|
Loading…
Reference in a new issue