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