Forking what is left of ZeroNet and hopefully adding an AT Proto Frontend/Proxy
at main 193 lines 7.8 kB view raw
1import os 2import re 3 4import gevent 5 6from Plugin import PluginManager 7from Config import config 8from Debug import Debug 9 10# Keep archive open for faster reponse times for large sites 11archive_cache = {} 12 13 14def closeArchive(archive_path): 15 if archive_path in archive_cache: 16 del archive_cache[archive_path] 17 18 19def openArchive(archive_path, file_obj=None): 20 if archive_path not in archive_cache: 21 if archive_path.endswith("tar.gz"): 22 import tarfile 23 archive_cache[archive_path] = tarfile.open(archive_path, fileobj=file_obj, mode="r:gz") 24 else: 25 import zipfile 26 archive_cache[archive_path] = zipfile.ZipFile(file_obj or archive_path) 27 gevent.spawn_later(5, lambda: closeArchive(archive_path)) # Close after 5 sec 28 29 archive = archive_cache[archive_path] 30 return archive 31 32 33def openArchiveFile(archive_path, path_within, file_obj=None): 34 archive = openArchive(archive_path, file_obj=file_obj) 35 if archive_path.endswith(".zip"): 36 return archive.open(path_within) 37 else: 38 return archive.extractfile(path_within) 39 40 41@PluginManager.registerTo("UiRequest") 42class UiRequestPlugin(object): 43 def actionSiteMedia(self, path, **kwargs): 44 if ".zip/" in path or ".tar.gz/" in path: 45 file_obj = None 46 path_parts = self.parsePath(path) 47 file_path = "%s/%s/%s" % (config.data_dir, path_parts["address"], path_parts["inner_path"]) 48 match = re.match("^(.*\.(?:tar.gz|zip))/(.*)", file_path) 49 archive_path, path_within = match.groups() 50 if archive_path not in archive_cache: 51 site = self.server.site_manager.get(path_parts["address"]) 52 if not site: 53 return self.actionSiteAddPrompt(path) 54 archive_inner_path = site.storage.getInnerPath(archive_path) 55 if not os.path.isfile(archive_path): 56 # Wait until file downloads 57 result = site.needFile(archive_inner_path, priority=10) 58 # Send virutal file path download finished event to remove loading screen 59 site.updateWebsocket(file_done=archive_inner_path) 60 if not result: 61 return self.error404(archive_inner_path) 62 file_obj = site.storage.openBigfile(archive_inner_path) 63 if file_obj == False: 64 file_obj = None 65 66 header_allow_ajax = False 67 if self.get.get("ajax_key"): 68 requester_site = self.server.site_manager.get(path_parts["request_address"]) 69 if self.get["ajax_key"] == requester_site.settings["ajax_key"]: 70 header_allow_ajax = True 71 else: 72 return self.error403("Invalid ajax_key") 73 74 try: 75 file = openArchiveFile(archive_path, path_within, file_obj=file_obj) 76 content_type = self.getContentType(file_path) 77 self.sendHeader(200, content_type=content_type, noscript=kwargs.get("header_noscript", False), allow_ajax=header_allow_ajax) 78 return self.streamFile(file) 79 except Exception as err: 80 self.log.debug("Error opening archive file: %s" % Debug.formatException(err)) 81 return self.error404(path) 82 83 return super(UiRequestPlugin, self).actionSiteMedia(path, **kwargs) 84 85 def streamFile(self, file): 86 for i in range(100): # Read max 6MB 87 try: 88 block = file.read(60 * 1024) 89 if block: 90 yield block 91 else: 92 raise StopIteration 93 except StopIteration: 94 file.close() 95 break 96 97 98@PluginManager.registerTo("SiteStorage") 99class SiteStoragePlugin(object): 100 def isFile(self, inner_path): 101 if ".zip/" in inner_path or ".tar.gz/" in inner_path: 102 match = re.match("^(.*\.(?:tar.gz|zip))/(.*)", inner_path) 103 archive_inner_path, path_within = match.groups() 104 return super(SiteStoragePlugin, self).isFile(archive_inner_path) 105 else: 106 return super(SiteStoragePlugin, self).isFile(inner_path) 107 108 def openArchive(self, inner_path): 109 archive_path = self.getPath(inner_path) 110 file_obj = None 111 if archive_path not in archive_cache: 112 if not os.path.isfile(archive_path): 113 result = self.site.needFile(inner_path, priority=10) 114 self.site.updateWebsocket(file_done=inner_path) 115 if not result: 116 raise Exception("Unable to download file") 117 file_obj = self.site.storage.openBigfile(inner_path) 118 if file_obj == False: 119 file_obj = None 120 121 try: 122 archive = openArchive(archive_path, file_obj=file_obj) 123 except Exception as err: 124 raise Exception("Unable to download file: %s" % Debug.formatException(err)) 125 126 return archive 127 128 def walk(self, inner_path, *args, **kwags): 129 if ".zip" in inner_path or ".tar.gz" in inner_path: 130 match = re.match("^(.*\.(?:tar.gz|zip))(.*)", inner_path) 131 archive_inner_path, path_within = match.groups() 132 archive = self.openArchive(archive_inner_path) 133 path_within = path_within.lstrip("/") 134 135 if archive_inner_path.endswith(".zip"): 136 namelist = [name for name in archive.namelist() if not name.endswith("/")] 137 else: 138 namelist = [item.name for item in archive.getmembers() if not item.isdir()] 139 140 namelist_relative = [] 141 for name in namelist: 142 if not name.startswith(path_within): 143 continue 144 name_relative = name.replace(path_within, "", 1).rstrip("/") 145 namelist_relative.append(name_relative) 146 147 return namelist_relative 148 149 else: 150 return super(SiteStoragePlugin, self).walk(inner_path, *args, **kwags) 151 152 def list(self, inner_path, *args, **kwags): 153 if ".zip" in inner_path or ".tar.gz" in inner_path: 154 match = re.match("^(.*\.(?:tar.gz|zip))(.*)", inner_path) 155 archive_inner_path, path_within = match.groups() 156 archive = self.openArchive(archive_inner_path) 157 path_within = path_within.lstrip("/") 158 159 if archive_inner_path.endswith(".zip"): 160 namelist = [name for name in archive.namelist()] 161 else: 162 namelist = [item.name for item in archive.getmembers()] 163 164 namelist_relative = [] 165 for name in namelist: 166 if not name.startswith(path_within): 167 continue 168 name_relative = name.replace(path_within, "", 1).rstrip("/") 169 170 if "/" in name_relative: # File is in sub-directory 171 continue 172 173 namelist_relative.append(name_relative) 174 return namelist_relative 175 176 else: 177 return super(SiteStoragePlugin, self).list(inner_path, *args, **kwags) 178 179 def read(self, inner_path, mode="rb", **kwargs): 180 if ".zip/" in inner_path or ".tar.gz/" in inner_path: 181 match = re.match("^(.*\.(?:tar.gz|zip))(.*)", inner_path) 182 archive_inner_path, path_within = match.groups() 183 archive = self.openArchive(archive_inner_path) 184 path_within = path_within.lstrip("/") 185 186 if archive_inner_path.endswith(".zip"): 187 return archive.open(path_within).read() 188 else: 189 return archive.extractfile(path_within).read() 190 191 else: 192 return super(SiteStoragePlugin, self).read(inner_path, mode, **kwargs) 193