123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117 |
- import os
- import re
- import gevent
- from Plugin import PluginManager
- from Config import config
- # Keep archive open for faster reponse times for large sites
- archive_cache = {}
- def closeArchive(archive_path):
- if archive_path in archive_cache:
- del archive_cache[archive_path]
- def openArchive(archive_path):
- if archive_path not in archive_cache:
- if archive_path.endswith("tar.gz"):
- import tarfile
- archive_cache[archive_path] = tarfile.open(archive_path, "r:gz")
- elif archive_path.endswith("tar.bz2"):
- import tarfile
- archive_cache[archive_path] = tarfile.open(archive_path, "r:bz2")
- else:
- import zipfile
- archive_cache[archive_path] = zipfile.ZipFile(archive_path)
- gevent.spawn_later(5, lambda: closeArchive(archive_path)) # Close after 5 sec
- archive = archive_cache[archive_path]
- return archive
- def openArchiveFile(archive_path, path_within):
- archive = openArchive(archive_path)
- if archive_path.endswith(".zip"):
- return archive.open(path_within)
- else:
- return archive.extractfile(path_within.encode("utf8"))
- @PluginManager.registerTo("UiRequest")
- class UiRequestPlugin(object):
- def actionSiteMedia(self, path, **kwargs):
- if ".zip/" in path or ".tar.gz/" in path:
- path_parts = self.parsePath(path)
- file_path = u"%s/%s/%s" % (config.data_dir, path_parts["address"], path_parts["inner_path"].decode("utf8"))
- match = re.match("^(.*\.(?:tar.gz|tar.bz2|zip))/(.*)", file_path)
- archive_path, path_within = match.groups()
- if not os.path.isfile(archive_path):
- site = self.server.site_manager.get(path_parts["address"])
- if not site:
- return self.actionSiteAddPrompt(path)
- # Wait until file downloads
- result = site.needFile(site.storage.getInnerPath(archive_path), priority=10)
- # Send virutal file path download finished event to remove loading screen
- site.updateWebsocket(file_done=site.storage.getInnerPath(file_path))
- if not result:
- return self.error404(path)
- header_allow_ajax = False
- if self.get.get("ajax_key"):
- requester_site = self.server.site_manager.get(path_parts["request_address"])
- if self.get["ajax_key"] == requester_site.settings["ajax_key"]:
- header_allow_ajax = True
- else:
- return self.error403("Invalid ajax_key")
- try:
- file = openArchiveFile(archive_path, path_within)
- content_type = self.getContentType(file_path)
- self.sendHeader(200, content_type=content_type, noscript=kwargs.get("header_noscript", False), allow_ajax=header_allow_ajax)
- return self.streamFile(file)
- except Exception as err:
- self.log.debug("Error opening archive file: %s" % err)
- return self.error404(path)
- return super(UiRequestPlugin, self).actionSiteMedia(path, **kwargs)
- def streamFile(self, file):
- for i in range(100): # Read max 6MB
- try:
- block = file.read(60 * 1024)
- if block:
- yield block
- else:
- raise StopIteration
- except StopIteration:
- file.close()
- break
- @PluginManager.registerTo("SiteStorage")
- class SiteStoragePlugin(object):
- def isFile(self, inner_path):
- if ".zip/" in inner_path or ".tar.gz/" in inner_path:
- match = re.match("^(.*\.(?:tar.gz|tar.bz2|zip))/(.*)", inner_path)
- archive_inner_path, path_within = match.groups()
- return super(SiteStoragePlugin, self).isFile(archive_inner_path)
- else:
- return super(SiteStoragePlugin, self).isFile(inner_path)
- def walk(self, inner_path, *args, **kwags):
- if ".zip" in inner_path or ".tar.gz" in inner_path:
- match = re.match("^(.*\.(?:tar.gz|tar.bz2|zip))(.*)", inner_path)
- archive_inner_path, path_within = match.groups()
- archive = openArchive(self.getPath(archive_inner_path))
- if archive_inner_path.endswith(".zip"):
- namelist = [name for name in archive.namelist() if not name.endswith("/")]
- else:
- namelist = [item.name for item in archive.getmembers() if not item.isdir()]
- return namelist
- else:
- return super(SiteStoragePlugin, self).walk(inner_path, *args, **kwags)
|