Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion asgidav/reqres.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ async def _propstat(member: Member, prop_names: Tuple[PropertyName, ...]) -> Ele

# Limit concurrent member lookups so large directories don't overwhelm
# the event loop or the Discord API rate limits.
_MAX_CONCURRENT_MEMBERS = 10
_MAX_CONCURRENT_MEMBERS = 20


async def _propfind_response(
Expand Down
10 changes: 5 additions & 5 deletions dcfs/app/webdav/folder.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ def __init__(self, path: str, client: Client):
self.__client = client
self.__ops = Ops(client)
self.__folder = client.dir_api.root if path == "/" else self.__ops.cd(path)
self.__sub_folders = frozenset([d.name for d in self.__folder.find_dirs()])
self.__sub_files = frozenset([f.name for f in self.__folder.find_files()])
self.__sub_folders = {d.name: d for d in self.__folder.find_dirs()}
self.__sub_files = {f.name: f for f in self.__folder.find_files()}

@property
def fs_cache(self) -> FSCache:
Expand All @@ -28,15 +28,15 @@ async def display_name(self) -> str:
return self.__folder.name

async def member_names(self):
return self.__sub_folders.union(self.__sub_files)
return set(self.__sub_folders.keys()).union(self.__sub_files.keys())

async def member(self, path: str):
path_parts = path.split("/", 1)
if path_parts[0] == "":
return self

if path_parts[0] in self.__sub_files:
return Resource(self._sub_path(path_parts[0]), self.__client)
if fr := self.__sub_files.get(path_parts[0]):
return Resource(self._sub_path(path_parts[0]), self.__client, fr=fr)

if path_parts[0] in self.__sub_folders:
if len(path_parts) > 1:
Expand Down
7 changes: 4 additions & 3 deletions dcfs/app/webdav/resource.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,17 @@


class Resource(_Resource):
def __init__(self, path: str, client: Client):
def __init__(self, path: str, client: Client, fr: Optional[DCFSFileRef] = None):
super().__init__(f"/{client.name}{path}")

self.__relative_path = path
self.__client = client
self.__fs_cache = gfc[client.name]
self.__ops = Ops(client)

if not (fr := self.__ops.stat_file(path)):
raise TechnicalError(f"Resource {path} does not exist")
if fr is None:
if not (fr := self.__ops.stat_file(path)):
raise TechnicalError(f"Resource {path} does not exist")

self.__fr: DCFSFileRef = fr
self.__fd_value: Optional[DCFSFileDesc] = None
Expand Down
48 changes: 43 additions & 5 deletions dcfs/core/repository/impl/fd/dc_msg.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,36 @@


class DCMsgFDRepository(IFDRepository):
def __init__(self, message_api: MessageApi):
def __init__(self, message_api: MessageApi, cache_capacity: int = 1024):
self._message_api = message_api
self._cache_capacity = cache_capacity
self._cache: dict[int, DCFSFileDesc] = {}
self._cache_order: list[int] = []

def _cache_put(self, message_id: int, fd: DCFSFileDesc) -> None:
if message_id in self._cache:
# Refresh position in LRU
self._cache_order.remove(message_id)
elif len(self._cache) >= self._cache_capacity:
# Evict oldest
evict = self._cache_order.pop(0)
self._cache.pop(evict, None)

self._cache[message_id] = fd
self._cache_order.append(message_id)

def _cache_get(self, message_id: int) -> Optional[DCFSFileDesc]:
if message_id in self._cache:
# Refresh position in LRU
self._cache_order.remove(message_id)
self._cache_order.append(message_id)
return self._cache[message_id]
return None

def _cache_invalidate(self, message_id: int) -> None:
if message_id in self._cache:
self._cache.pop(message_id)
self._cache_order.remove(message_id)

async def _send_with_retry(self, text: str) -> int:
"""Send a file descriptor with exponential backoff retry."""
Expand Down Expand Up @@ -81,15 +109,19 @@ async def save(
self, fd: DCFSFileDesc, fr: Optional[DCFSFileRef] = None
) -> FDRepositoryResp:
if fr is None:
message_id = await self._send_with_retry(fd.to_json())
self._cache_put(message_id, fd)
return FDRepositoryResp(
message_id=await self._send_with_retry(fd.to_json()),
message_id=message_id,
fd=fd,
)

message_id = await self._edit_with_retry(
message_id=fr.message_id, text=fd.to_json()
)
self._cache_put(message_id, fd)
return FDRepositoryResp(
message_id=await self._edit_with_retry(
message_id=fr.message_id, text=fd.to_json()
),
message_id=message_id,
fd=fd,
)

Expand Down Expand Up @@ -139,15 +171,21 @@ async def get(
include_all_versions: bool = False,
validate: bool = True,
) -> DCFSFileDesc:
if not validate and (cached := self._cache_get(fr.message_id)):
return cached

message = (await self._message_api.get_messages([fr.message_id]))[0]

if not message:
logging.error(
f"File descriptor (message_id: {fr.message_id}) for {fr.name} not found"
)
self._cache_invalidate(fr.message_id)
return DCFSFileDesc.empty(fr.name)

fd = DCFSFileDesc.from_dict(json.loads(message.text), name=fr.name)
self._cache_put(fr.message_id, fd)

if not validate:
return fd

Expand Down
Loading