Performance upgrade, lock fix.
This commit is contained in:
parent
d23ed3711a
commit
13f1d2f390
@ -1,8 +1,8 @@
|
|||||||
import logging
|
import logging
|
||||||
import pathlib
|
import pathlib
|
||||||
|
import asyncio
|
||||||
logging.basicConfig(level=logging.DEBUG)
|
logging.basicConfig(level=logging.DEBUG)
|
||||||
|
from app.cache import time_cache,time_cache_async
|
||||||
import base64
|
import base64
|
||||||
import datetime
|
import datetime
|
||||||
import mimetypes
|
import mimetypes
|
||||||
@ -18,8 +18,13 @@ from lxml import etree
|
|||||||
@aiohttp.web.middleware
|
@aiohttp.web.middleware
|
||||||
async def debug_middleware(request, handler):
|
async def debug_middleware(request, handler):
|
||||||
print(request.method, request.path, request.headers)
|
print(request.method, request.path, request.headers)
|
||||||
return await handler(request)
|
result = await handler(request)
|
||||||
|
print(result.status)
|
||||||
|
try:
|
||||||
|
print(await result.text())
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
return result
|
||||||
|
|
||||||
class WebdavApplication(aiohttp.web.Application):
|
class WebdavApplication(aiohttp.web.Application):
|
||||||
def __init__(self, parent, *args, **kwargs):
|
def __init__(self, parent, *args, **kwargs):
|
||||||
@ -29,7 +34,6 @@ class WebdavApplication(aiohttp.web.Application):
|
|||||||
self.locks = {}
|
self.locks = {}
|
||||||
|
|
||||||
self.relative_url = "/webdav"
|
self.relative_url = "/webdav"
|
||||||
print(self.router)
|
|
||||||
|
|
||||||
self.router.add_route("OPTIONS", "/{filename:.*}", self.handle_options)
|
self.router.add_route("OPTIONS", "/{filename:.*}", self.handle_options)
|
||||||
self.router.add_route("GET", "/{filename:.*}", self.handle_get)
|
self.router.add_route("GET", "/{filename:.*}", self.handle_get)
|
||||||
@ -53,15 +57,6 @@ class WebdavApplication(aiohttp.web.Application):
|
|||||||
return self.parent.services
|
return self.parent.services
|
||||||
|
|
||||||
async def authenticate(self, request):
|
async def authenticate(self, request):
|
||||||
# session = request.session
|
|
||||||
# if session.get('uid'):
|
|
||||||
# request['user'] = await self.services.user.get(uid=session['uid'])
|
|
||||||
#try:
|
|
||||||
# request['home'] = await self.services.user.get_home_folder(user_uid=request['user']['uid'])
|
|
||||||
#except:
|
|
||||||
# pass
|
|
||||||
#return request['user']
|
|
||||||
|
|
||||||
auth_header = request.headers.get("Authorization", "")
|
auth_header = request.headers.get("Authorization", "")
|
||||||
if not auth_header.startswith("Basic "):
|
if not auth_header.startswith("Basic "):
|
||||||
return False
|
return False
|
||||||
@ -75,9 +70,7 @@ class WebdavApplication(aiohttp.web.Application):
|
|||||||
request["home"] = await self.services.user.get_home_folder(
|
request["home"] = await self.services.user.get_home_folder(
|
||||||
request["user"]["uid"]
|
request["user"]["uid"]
|
||||||
)
|
)
|
||||||
except Exception as ex:
|
except Exception:
|
||||||
print("GRRRRRRRRRR")
|
|
||||||
print(ex)
|
|
||||||
pass
|
pass
|
||||||
return request["user"]
|
return request["user"]
|
||||||
|
|
||||||
@ -109,7 +102,6 @@ class WebdavApplication(aiohttp.web.Application):
|
|||||||
status=401, headers={"WWW-Authenticate": 'Basic realm="WebDAV"'}
|
status=401, headers={"WWW-Authenticate": 'Basic realm="WebDAV"'}
|
||||||
)
|
)
|
||||||
file_path = request["home"] / request.match_info["filename"]
|
file_path = request["home"] / request.match_info["filename"]
|
||||||
print("WRITETO_", file_path)
|
|
||||||
file_path.parent.mkdir(parents=True, exist_ok=True)
|
file_path.parent.mkdir(parents=True, exist_ok=True)
|
||||||
async with aiofiles.open(file_path, "wb") as f:
|
async with aiofiles.open(file_path, "wb") as f:
|
||||||
while chunk := await request.content.read(1024):
|
while chunk := await request.content.read(1024):
|
||||||
@ -177,7 +169,6 @@ class WebdavApplication(aiohttp.web.Application):
|
|||||||
"DAV": "1, 2",
|
"DAV": "1, 2",
|
||||||
"Allow": "OPTIONS, GET, PUT, DELETE, MKCOL, MOVE, COPY, PROPFIND, PROPPATCH",
|
"Allow": "OPTIONS, GET, PUT, DELETE, MKCOL, MOVE, COPY, PROPFIND, PROPPATCH",
|
||||||
}
|
}
|
||||||
print("RETURN")
|
|
||||||
return aiohttp.web.Response(status=200, headers=headers)
|
return aiohttp.web.Response(status=200, headers=headers)
|
||||||
|
|
||||||
def get_current_utc_time(self, filepath):
|
def get_current_utc_time(self, filepath):
|
||||||
@ -189,25 +180,33 @@ class WebdavApplication(aiohttp.web.Application):
|
|||||||
"%a, %d %b %Y %H:%M:%S GMT"
|
"%a, %d %b %Y %H:%M:%S GMT"
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_directory_size(self, directory):
|
@time_cache_async(10)
|
||||||
|
async def get_file_size(self, path):
|
||||||
|
loop = self.parent.loop
|
||||||
|
stat = await loop.run_in_executor(None,os.stat, path)
|
||||||
|
return stat.st_size
|
||||||
|
|
||||||
|
@time_cache_async(10)
|
||||||
|
async def get_directory_size(self, directory):
|
||||||
total_size = 0
|
total_size = 0
|
||||||
for dirpath, _, filenames in os.walk(directory):
|
for dirpath, _, filenames in os.walk(directory):
|
||||||
for f in filenames:
|
for f in filenames:
|
||||||
fp = pathlib.Path(dirpath) / f
|
fp = pathlib.Path(dirpath) / f
|
||||||
if fp.exists():
|
if fp.exists():
|
||||||
total_size += fp.stat().st_size
|
total_size += await self.get_file_size(str(fp))
|
||||||
return total_size
|
return total_size
|
||||||
|
|
||||||
def get_disk_free_space(self, path):
|
|
||||||
statvfs = os.statvfs(path)
|
@time_cache_async(30)
|
||||||
|
async def get_disk_free_space(self, path="/"):
|
||||||
|
loop = self.parent.loop
|
||||||
|
statvfs = await loop.run_in_executor(None,os.statvfs, path)
|
||||||
return statvfs.f_bavail * statvfs.f_frsize
|
return statvfs.f_bavail * statvfs.f_frsize
|
||||||
|
|
||||||
async def create_node(self, request, response_xml, full_path, depth):
|
async def create_node(self, request, response_xml, full_path, depth):
|
||||||
request.match_info.get("filename", "")
|
|
||||||
abs_path = pathlib.Path(full_path)
|
abs_path = pathlib.Path(full_path)
|
||||||
relative_path = str(full_path.relative_to(request["home"]))
|
relative_path = str(full_path.relative_to(request["home"]))
|
||||||
|
|
||||||
|
|
||||||
href_path = f"{self.relative_url}/{relative_path}".strip(".")
|
href_path = f"{self.relative_url}/{relative_path}".strip(".")
|
||||||
href_path = href_path.replace("./","/")
|
href_path = href_path.replace("./","/")
|
||||||
href_path = href_path.replace("//", "/")
|
href_path = href_path.replace("//", "/")
|
||||||
@ -223,12 +222,12 @@ class WebdavApplication(aiohttp.web.Application):
|
|||||||
creation_date, last_modified = self.get_current_utc_time(full_path)
|
creation_date, last_modified = self.get_current_utc_time(full_path)
|
||||||
etree.SubElement(prop, "{DAV:}creationdate").text = creation_date
|
etree.SubElement(prop, "{DAV:}creationdate").text = creation_date
|
||||||
etree.SubElement(prop, "{DAV:}quota-used-bytes").text = str(
|
etree.SubElement(prop, "{DAV:}quota-used-bytes").text = str(
|
||||||
full_path.stat().st_size
|
await self.get_file_size(full_path)
|
||||||
if full_path.is_file()
|
if full_path.is_file()
|
||||||
else self.get_directory_size(full_path)
|
else await self.get_directory_size(full_path)
|
||||||
)
|
)
|
||||||
etree.SubElement(prop, "{DAV:}quota-available-bytes").text = str(
|
etree.SubElement(prop, "{DAV:}quota-available-bytes").text = str(
|
||||||
self.get_disk_free_space(request["home"])
|
await self.get_disk_free_space(request["home"])
|
||||||
)
|
)
|
||||||
etree.SubElement(prop, "{DAV:}getlastmodified").text = last_modified
|
etree.SubElement(prop, "{DAV:}getlastmodified").text = last_modified
|
||||||
etree.SubElement(prop, "{DAV:}displayname").text = full_path.name
|
etree.SubElement(prop, "{DAV:}displayname").text = full_path.name
|
||||||
@ -237,9 +236,9 @@ class WebdavApplication(aiohttp.web.Application):
|
|||||||
if full_path.is_file():
|
if full_path.is_file():
|
||||||
etree.SubElement(prop, "{DAV:}contenttype").text = mimetype
|
etree.SubElement(prop, "{DAV:}contenttype").text = mimetype
|
||||||
etree.SubElement(prop, "{DAV:}getcontentlength").text = str(
|
etree.SubElement(prop, "{DAV:}getcontentlength").text = str(
|
||||||
full_path.stat().st_size
|
await self.get_file_size(full_path)
|
||||||
if full_path.is_file()
|
if full_path.is_file()
|
||||||
else self.get_directory_size(full_path)
|
else await self.get_directory_size(full_path)
|
||||||
)
|
)
|
||||||
supported_lock = etree.SubElement(prop, "{DAV:}supportedlock")
|
supported_lock = etree.SubElement(prop, "{DAV:}supportedlock")
|
||||||
lock_entry_1 = etree.SubElement(supported_lock, "{DAV:}lockentry")
|
lock_entry_1 = etree.SubElement(supported_lock, "{DAV:}lockentry")
|
||||||
@ -254,7 +253,7 @@ class WebdavApplication(aiohttp.web.Application):
|
|||||||
etree.SubElement(lock_type_2, "{DAV:}write")
|
etree.SubElement(lock_type_2, "{DAV:}write")
|
||||||
etree.SubElement(propstat, "{DAV:}status").text = "HTTP/1.1 200 OK"
|
etree.SubElement(propstat, "{DAV:}status").text = "HTTP/1.1 200 OK"
|
||||||
|
|
||||||
if abs_path.is_dir():
|
if abs_path.is_dir() and depth > 0:
|
||||||
for item in abs_path.iterdir():
|
for item in abs_path.iterdir():
|
||||||
await self.create_node(request, response_xml, item, depth - 1)
|
await self.create_node(request, response_xml, item, depth - 1)
|
||||||
|
|
||||||
@ -269,8 +268,6 @@ class WebdavApplication(aiohttp.web.Application):
|
|||||||
depth = int(request.headers.get("Depth", "0"))
|
depth = int(request.headers.get("Depth", "0"))
|
||||||
except ValueError:
|
except ValueError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
print(request)
|
|
||||||
|
|
||||||
requested_path = request.match_info.get("filename", "")
|
requested_path = request.match_info.get("filename", "")
|
||||||
|
|
||||||
@ -285,7 +282,6 @@ class WebdavApplication(aiohttp.web.Application):
|
|||||||
xml_output = etree.tostring(
|
xml_output = etree.tostring(
|
||||||
response_xml, encoding="utf-8", xml_declaration=True
|
response_xml, encoding="utf-8", xml_declaration=True
|
||||||
).decode()
|
).decode()
|
||||||
print(xml_output)
|
|
||||||
return aiohttp.web.Response(
|
return aiohttp.web.Response(
|
||||||
status=207, text=xml_output, content_type="application/xml"
|
status=207, text=xml_output, content_type="application/xml"
|
||||||
)
|
)
|
||||||
@ -302,10 +298,10 @@ class WebdavApplication(aiohttp.web.Application):
|
|||||||
return aiohttp.web.Response(
|
return aiohttp.web.Response(
|
||||||
status=401, headers={"WWW-Authenticate": 'Basic realm="WebDAV"'}
|
status=401, headers={"WWW-Authenticate": 'Basic realm="WebDAV"'}
|
||||||
)
|
)
|
||||||
request.match_info.get("filename", "/")
|
resource = request.match_info.get("filename", "/")
|
||||||
lock_id = str(uuid.uuid4())
|
lock_id = str(uuid.uuid4())
|
||||||
# self.locks[resource] = lock_id
|
self.locks[resource] = lock_id
|
||||||
xml_response = self.generate_lock_response(lock_id)
|
xml_response = await self.generate_lock_response(lock_id)
|
||||||
headers = {
|
headers = {
|
||||||
"Lock-Token": f"opaquelocktoken:{lock_id}",
|
"Lock-Token": f"opaquelocktoken:{lock_id}",
|
||||||
"Content-Type": "application/xml",
|
"Content-Type": "application/xml",
|
||||||
@ -320,13 +316,13 @@ class WebdavApplication(aiohttp.web.Application):
|
|||||||
resource = request.match_info.get("filename", "/")
|
resource = request.match_info.get("filename", "/")
|
||||||
lock_token = request.headers.get("Lock-Token", "").replace(
|
lock_token = request.headers.get("Lock-Token", "").replace(
|
||||||
"opaquelocktoken:", ""
|
"opaquelocktoken:", ""
|
||||||
)
|
)[1:-1]
|
||||||
if self.locks.get(resource) == lock_token:
|
if self.locks.get(resource) == lock_token:
|
||||||
del self.locks[resource]
|
del self.locks[resource]
|
||||||
return aiohttp.web.Response(status=204)
|
return aiohttp.web.Response(status=204)
|
||||||
return aiohttp.web.Response(status=400, text="Invalid Lock Token")
|
return aiohttp.web.Response(status=400, text="Invalid Lock Token")
|
||||||
|
|
||||||
def generate_lock_response(self, lock_id):
|
async def generate_lock_response(self, lock_id):
|
||||||
nsmap = {"D": "DAV:"}
|
nsmap = {"D": "DAV:"}
|
||||||
root = etree.Element("{DAV:}prop", nsmap=nsmap)
|
root = etree.Element("{DAV:}prop", nsmap=nsmap)
|
||||||
lock_discovery = etree.SubElement(root, "{DAV:}lockdiscovery")
|
lock_discovery = etree.SubElement(root, "{DAV:}lockdiscovery")
|
||||||
@ -357,7 +353,6 @@ class WebdavApplication(aiohttp.web.Application):
|
|||||||
)
|
)
|
||||||
|
|
||||||
requested_path = request.match_info.get("filename", "")
|
requested_path = request.match_info.get("filename", "")
|
||||||
print(requested_path)
|
|
||||||
abs_path = request["home"] / requested_path
|
abs_path = request["home"] / requested_path
|
||||||
|
|
||||||
if not abs_path.exists():
|
if not abs_path.exists():
|
||||||
|
Loading…
Reference in New Issue
Block a user