From fa7164a0f065cc178e852345402741ab1d0c7a6a Mon Sep 17 00:00:00 2001 From: HelloZeroNet Date: Sat, 14 Feb 2015 14:05:00 +0100 Subject: [PATCH] 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 --- README.md | 2 +- src/Config.py | 4 +- src/Content/ContentManager.py | 52 +++++++++++++++++---- src/File/FileRequest.py | 4 +- src/Site/Site.py | 28 ++++++++++- src/Site/SiteManager.py | 2 + src/Ui/UiServer.py | 13 +++++- src/Ui/UiWebsocket.py | 21 ++++++++- src/Ui/media/Loading.coffee | 5 +- src/Ui/media/Wrapper.coffee | 53 ++++++++++++++++----- src/Ui/media/Wrapper.css | 4 ++ src/Ui/media/all.css | 4 ++ src/Ui/media/all.js | 87 ++++++++++++++++++++++++++++++----- start.py | 12 ++--- 14 files changed, 243 insertions(+), 48 deletions(-) diff --git a/README.md b/README.md index 2eba782e..b58fc90a 100644 --- a/README.md +++ b/README.md @@ -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). - 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. - - 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. diff --git a/src/Config.py b/src/Config.py index a5ca95c9..99ad9567 100644 --- a/src/Config.py +++ b/src/Config.py @@ -3,7 +3,7 @@ import ConfigParser class Config(object): def __init__(self): - self.version = "0.2.0" + self.version = "0.2.1" self.parser = self.createArguments() argv = sys.argv[:] # Copy command line arguments 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_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('--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('--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_port',help='FileServer bind port', default=15441, type=int, metavar='port') diff --git a/src/Content/ContentManager.py b/src/Content/ContentManager.py index 96e49671..2e69252d 100644 --- a/src/Content/ContentManager.py +++ b/src/Content/ContentManager.py @@ -9,6 +9,7 @@ class ContentManager: self.log = self.site.log self.contents = {} # Known content.json (without files and includes) self.loadContent(add_bad_files = False) + self.site.settings["size"] = self.getTotalSize() # Load content.json to self.content @@ -68,9 +69,24 @@ class ContentManager: for inner_path in changed: 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 + # 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 # Return: { "sha512": "c29d73d30ee8c9c1b5600e8a84447a6de15a3c3db6869aca4a2a578c1721f518", "size": 41 , "content_inner_path": "content.json"} def getFileInfo(self, inner_path): @@ -216,30 +232,50 @@ class ContentManager: return 1 # Todo: Multisig + # Checks if the content.json content is valid + # Return: True or False 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) if not include_info: self.log.error("%s: No include info" % inner_path) return False - if include_info.get("max_size"): # Size limit - total_size = len(json.dumps(content)) + sum([file["size"] for file in content["files"].values()]) - if total_size > include_info["max_size"]: - self.log.error("%s: Too large %s > %s" % (inner_path, total_size, include_info["max_size"])) + # Check include size limit + if include_info.get("max_size"): # Include size limit + if content_size > include_info["max_size"]: + self.log.error("%s: Include too large %s > %s" % (inner_path, total_size, include_info["max_size"])) return False + # Check if content includes allowed if include_info.get("includes_allowed") == False and content.get("includes"): self.log.error("%s: Includes not allowed" % inner_path) 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(): if not re.match("^%s$" % include_info["files_allowed"], file_inner_path): self.log.error("%s: File not allowed: " % file_inner_path) return False - return True + return True # All good @@ -292,7 +328,7 @@ class ContentManager: self.log.error("Verify sign error: %s" % Debug.formatException(err)) return False - else: # Check using sha1 hash + else: # Check using sha512 hash file_info = self.getFileInfo(inner_path) if file_info: if "sha512" in file_info: diff --git a/src/File/FileRequest.py b/src/File/FileRequest.py index 050ca240..02b134e1 100644 --- a/src/File/FileRequest.py +++ b/src/File/FileRequest.py @@ -41,7 +41,9 @@ class FileRequest: return False 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"])) - 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"]) valid = site.content_manager.verifyFile(params["inner_path"], buff) if valid == True: # Valid and changed diff --git a/src/Site/Site.py b/src/Site/Site.py index 56b5dce3..21cf7105 100644 --- a/src/Site/Site.py +++ b/src/Site/Site.py @@ -33,8 +33,8 @@ class Site: self.notifications = [] # Pending notifications displayed once on page load [error|ok|info, message, timeout] self.page_requested = False # Page viewed in browser - self.content_manager = ContentManager(self) # Load contents 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) 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 + # 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 def getPath(self, inner_path): inner_path = inner_path.replace("\\", "/") # Windows separator fix @@ -123,10 +139,14 @@ class Site: # Download all files of the site @util.Noparallel(blocking=False) - def download(self): + def download(self, check_size=False): self.log.debug("Start downloading...%s" % self.bad_files) self.announce() 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") 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 self.bad_files: self.download() + + self.settings["size"] = self.content_manager.getTotalSize() # Update site size return changed @@ -266,6 +288,8 @@ class Site: if added: self.worker_manager.onPeers() self.updateWebsocket(peers_added=added) + self.settings["peers"] = len(peers) + self.saveSettings() self.log.debug("Found %s peers, new: %s" % (len(peers), added)) else: pass # TODO: http tracker support diff --git a/src/Site/SiteManager.py b/src/Site/SiteManager.py index 4692cfce..87d1b0d3 100644 --- a/src/Site/SiteManager.py +++ b/src/Site/SiteManager.py @@ -43,6 +43,7 @@ def isAddress(address): # Return site and start download site files def need(address, all_file=True): from Site import Site + new = False if address not in sites: # Site not exits yet if not isAddress(address): return False # Not address: %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 sites[address].settings["serving"] = True sites[address].saveSettings() + new = True site = sites[address] if all_file: site.download() diff --git a/src/Ui/UiServer.py b/src/Ui/UiServer.py index e14a72bc..cc15d8e2 100644 --- a/src/Ui/UiServer.py +++ b/src/Ui/UiServer.py @@ -21,7 +21,10 @@ class UiWSGIHandler(WSGIHandler): self.ws_handler.run_application() else: # Standard HTTP request #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: @@ -77,5 +80,13 @@ class UiServer: self.log.info("Web interface: http://%s:%s/" % (config.ui_ip, config.ui_port)) 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() diff --git a/src/Ui/UiWebsocket.py b/src/Ui/UiWebsocket.py index c63a8978..6c556eab 100644 --- a/src/Ui/UiWebsocket.py +++ b/src/Ui/UiWebsocket.py @@ -84,6 +84,9 @@ class UiWebsocket: cmd = req.get("cmd") params = req.get("params") 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 return self.actionResponse(req["to"], req["result"]) @@ -114,6 +117,8 @@ class UiWebsocket: func = self.actionSiteDelete elif cmd == "siteList" and "ADMIN" in permissions: func = self.actionSiteList + elif cmd == "siteSetLimit" and "ADMIN" in permissions: + func = self.actionSiteSetLimit elif cmd == "channelJoinAllsite" and "ADMIN" in permissions: func = self.actionChannelJoinAllsite # Unknown command @@ -155,16 +160,21 @@ class UiWebsocket: if "sign" in content: del(content["sign"]) if "signs" in content: del(content["signs"]) + settings = site.settings.copy() + del settings["wrapper_key"] # Dont expose wrapper key + ret = { "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_address": self.user.getAuthAddress(site.address), "address": site.address, - "settings": site.settings, + "settings": settings, "content_updated": site.content_updated, "bad_files": len(site.bad_files), + "size_limit": site.getSizeLimit(), + "next_size_limit": site.getNextSizeLimit(), "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]), "content": content } @@ -344,3 +354,10 @@ class UiWebsocket: site.updateWebsocket() else: 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() diff --git a/src/Ui/media/Loading.coffee b/src/Ui/media/Loading.coffee index c42ed1df..2da7a39f 100644 --- a/src/Ui/media/Loading.coffee +++ b/src/Ui/media/Loading.coffee @@ -34,7 +34,10 @@ class Loading if not @screen_visible then return false $(".loadingscreen .console .cursor").remove() # Remove previous cursor if type == "error" then text = "#{text}" else text = text+" " - $(".loadingscreen .console").append("
#{text}
") + + line = $("
#{text}
").appendTo(".loadingscreen .console") + if type == "warning" then line.addClass("console-warning") + return line diff --git a/src/Ui/media/Wrapper.coffee b/src/Ui/media/Wrapper.coffee index 36167c09..7a5fa1da 100644 --- a/src/Ui/media/Wrapper.coffee +++ b/src/Ui/media/Wrapper.coffee @@ -70,23 +70,28 @@ class Wrapper else if cmd == "wrapperSetViewport" # Set the viewport @actionSetViewport(message) 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 - - actionWrapperConfirm: (message) -> + actionWrapperConfirm: (message, cb=false) -> message.params = @toHtmlSafe(message.params) # Escape html if message.params[1] then caption = message.params[1] else caption = "ok" - - body = $(""+message.params[0]+"") - button = $("#{caption}") # Add confirm button - button.on "click", => # Response on button click + @wrapperConfirm message.params[0], caption, => @sendInner {"cmd": "response", "to": message.id, "result": "boom"} # Response to confirm return false + + + wrapperConfirm: (message, caption, cb) -> + body = $(""+message+"") + button = $("#{caption}") # Add confirm button + button.on "click", cb body.append(button) - - @notifications.add("notification-#{message.id}", "ask", body) + @notifications.add("notification-#{caption}", "ask", body) @@ -151,7 +156,7 @@ class Wrapper @ws_error = @notifications.add("connection", "error", "UiServer Websocket error, please reload the page.") else if not @ws_error @ws_error = @notifications.add("connection", "error", "Connection with UiServer Websocket was lost. Reconnecting...") - ), 500 + ), 1000 # Iframe loaded @@ -163,7 +168,7 @@ class Wrapper 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 @reloadSiteInfo() - else if @site_info + else if @site_info and @site_info.content?.title? window.document.title = @site_info.content.title+" - ZeroNet" @log "Setting title to", window.document.title @@ -198,7 +203,18 @@ class Wrapper # File failed downloading else if site_info.event[0] == "file_failed" @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: #{parseInt(site_info.settings.size/1024/1024)}MB is larger than default allowed #{parseInt(site_info.size_limit)}MB", "warning") + button = $("Open site and set size limit to #{site_info.next_size_limit}MB") + 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 else if site_info.event[0] == "peers_added" @loading.printLine("Peers found: #{site_info.peers}") @@ -209,6 +225,13 @@ class Wrapper else @site_error = "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 @@ -221,6 +244,14 @@ class Wrapper 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...) -> console.log "[Wrapper]", args... diff --git a/src/Ui/media/Wrapper.css b/src/Ui/media/Wrapper.css index 6249c3dd..f6e0bf99 100644 --- a/src/Ui/media/Wrapper.css +++ b/src/Ui/media/Wrapper.css @@ -14,6 +14,7 @@ a { color: black } .button-Delete { background-color: #e74c3c; border-bottom-color: #c0392b; color: white } .button-Delete:hover { background-color: #FF5442; border-bottom-color: #8E2B21 } + /* Fixbutton */ .fixbutton { @@ -76,6 +77,9 @@ a { color: black } 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-warning { color: #8e44ad; } +.console .button { margin: 20px; display: inline-block; text-transform: none; padding: 10px 20px } + /* Flipper loading anim */ .flipper-container { width: 40px; height: 40px; position: absolute; top: 0%; left: 50%; transform: translate3d(-50%, -50%, 0); perspective: 1200; opacity: 0 } diff --git a/src/Ui/media/all.css b/src/Ui/media/all.css index c5b559cf..72f174e4 100644 --- a/src/Ui/media/all.css +++ b/src/Ui/media/all.css @@ -19,6 +19,7 @@ a { color: black } .button-Delete { background-color: #e74c3c; border-bottom-color: #c0392b; color: white } .button-Delete:hover { background-color: #FF5442; border-bottom-color: #8E2B21 } + /* Fixbutton */ .fixbutton { @@ -81,6 +82,9 @@ a { color: black } 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-warning { color: #8e44ad; } +.console .button { margin: 20px; display: inline-block; text-transform: none; padding: 10px 20px } + /* 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 } diff --git a/src/Ui/media/all.js b/src/Ui/media/all.js index 37721640..ce25fff7 100644 --- a/src/Ui/media/all.js +++ b/src/Ui/media/all.js @@ -502,6 +502,7 @@ jQuery.extend( jQuery.easing, }; Loading.prototype.printLine = function(text, type) { + var line; if (type == null) { type = "normal"; } @@ -514,7 +515,11 @@ jQuery.extend( jQuery.easing, } else { text = text + " "; } - return $(".loadingscreen .console").append("
" + text + "
"); + line = $("
" + text + "
").appendTo(".loadingscreen .console"); + if (type === "warning") { + line.addClass("console-warning"); + } + return line; }; return Loading; @@ -720,6 +725,7 @@ jQuery.extend( jQuery.easing, Wrapper = (function() { function Wrapper(ws_url) { + this.setSizeLimit = __bind(this.setSizeLimit, this); this.onLoad = __bind(this.onLoad, this); this.onCloseWebsocket = __bind(this.onCloseWebsocket, this); this.onOpenWebsocket = __bind(this.onOpenWebsocket, this); @@ -802,21 +808,26 @@ jQuery.extend( jQuery.easing, } else if (cmd === "wrapperSetViewport") { return this.actionSetViewport(message); } 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) { - var body, button, caption; + Wrapper.prototype.actionWrapperConfirm = function(message, cb) { + var caption; + if (cb == null) { + cb = false; + } message.params = this.toHtmlSafe(message.params); if (message.params[1]) { caption = message.params[1]; } else { caption = "ok"; } - body = $("" + message.params[0] + ""); - button = $("" + caption + ""); - button.on("click", (function(_this) { + return this.wrapperConfirm(message.params[0], caption, (function(_this) { return function() { _this.sendInner({ "cmd": "response", @@ -826,8 +837,15 @@ jQuery.extend( jQuery.easing, return false; }; })(this)); + }; + + Wrapper.prototype.wrapperConfirm = function(message, caption, cb) { + var body, button; + body = $("" + message + ""); + button = $("" + caption + ""); + button.on("click", cb); 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) { @@ -913,10 +931,11 @@ jQuery.extend( jQuery.easing, return _this.ws_error = _this.notifications.add("connection", "error", "Connection with UiServer Websocket was lost. Reconnecting..."); } }; - })(this)), 500); + })(this)), 1000); }; Wrapper.prototype.onLoad = function(e) { + var _ref; this.log("onLoad"); this.inner_loaded = true; if (!this.inner_ready) { @@ -932,7 +951,7 @@ jQuery.extend( jQuery.easing, } if (this.ws.ws.readyState === 1 && !this.site_info) { 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"; return this.log("Setting title to", window.document.title); } @@ -953,6 +972,7 @@ jQuery.extend( jQuery.easing, }; Wrapper.prototype.setSiteInfo = function(site_info) { + var button, line; 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"); @@ -969,7 +989,25 @@ 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"); + if (site_info.settings.size > site_info.size_limit * 1024 * 1024) { + if ($(".console .button-setlimit").length === 0) { + line = this.loading.printLine("Site size: " + (parseInt(site_info.settings.size / 1024 / 1024)) + "MB is larger than default allowed " + (parseInt(site_info.size_limit)) + "MB", "warning"); + button = $("Open site and set size limit to " + site_info.next_size_limit + "MB"); + 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") { this.loading.printLine("Peers found: " + site_info.peers); } @@ -982,6 +1020,18 @@ jQuery.extend( jQuery.easing, 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; }; @@ -999,6 +1049,21 @@ jQuery.extend( jQuery.easing, 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() { var args; args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; diff --git a/start.py b/start.py index 9ce5da06..29069a74 100644 --- a/start.py +++ b/start.py @@ -1,16 +1,10 @@ #!/usr/bin/env python -from multiprocessing import Process import sys -import webbrowser import zeronet def main(): - browser_name = sys.argv.pop() if len(sys.argv) >= 2 else None - server = Process(target=zeronet.main) - server.start() - browser = webbrowser.get(browser_name) - url = browser.open("http://127.0.0.1:43110", new=2) - server.join() + sys.argv += ["--open_browser", "default_browser"] + zeronet.main() if __name__ == '__main__': - main() + main()