moodlefuse/FSNode.py
2023-05-01 01:12:48 +02:00

142 lines
4.3 KiB
Python

import stat
import sys
import time
import requests
from markdownify import markdownify as md
from moodle import Category, Course, Moodle, Section, Folder, File, Label, Url
fileCache = {}
# Virtual Filesystem node
class FSNode:
def __init__(self, name: str, is_dir=True):
self.name = name
self.children = []
self.is_dir = is_dir
self.size = 0
self.url = None
def to_stat_struct(self):
if self.is_dir:
return dict(
st_mode=(stat.S_IFDIR | 0o755),
st_ctime=time.time(),
st_mtime=time.time(),
st_atime=time.time(),
st_nlink=2,
)
else:
return dict(
st_mode=(stat.S_IFREG | 0o755),
st_ctime=time.time(),
st_mtime=time.time(),
st_atime=time.time(),
st_nlink=2,
st_size=self.size
)
def resolve_path(self, path: str):
if path == "/":
return self
path_el = path.split("/")[1:]
return self._recurse_path_traverse(path_el)
def _recurse_path_traverse(self, path_arr: list[str]):
if len(path_arr) == 0:
return self
for child in self.children:
if child.name == path_arr[0]:
return child._recurse_path_traverse(path_arr[1:])
return None
@staticmethod
def from_category(c: Category, m: Moodle):
f = FSNode(c.name, True)
for course in c.courses:
f.children.append(FSNode.from_course(course, m))
return f
@staticmethod
def from_course(c: Course, m: Moodle):
f = FSNode(c.shortname, True)
for s in m.get_course_content(c.id):
f.children.append(FSNode.from_section(s, m))
return f
@staticmethod
def from_section(s: Section, m: Moodle):
f = FSNode(s.name, True)
for mo in s.modules:
f.children.append(FSNode.from_module(mo, m))
if len(s.htmlcontent):
m = FSNode("README.md", False)
m.size = len(s.htmlcontent)
m.url = "html#" + s.htmlcontent
f.children.append(m)
return f
@staticmethod
def from_module(mo, m: Moodle):
if isinstance(mo, Folder):
f = FSNode(mo.name, True)
for el in mo.files:
r = FSNode.from_module(el, m)
if r is not None:
f.children.append(r)
return f
elif isinstance(mo, File):
return FSNode.from_file(mo, m)
elif isinstance(mo, Label):
return FSNode.from_label(mo, m)
elif isinstance(mo, Url):
return FSNode.from_url(mo, m)
return None
@staticmethod
def from_file(el: File, m: Moodle):
f = FSNode(el.name, False)
f.size = el.filesize
f.url = el.fileurl
return f
def read(self, size, offset, mo: Moodle):
global fileCache
if sys.getsizeof(fileCache) > 3 * 100000000 and len(fileCache) > 2:
d = {k: v for k, v in sorted(fileCache.items(), key=lambda item: item["datetime"])}
for k in list(d.keys())[:len(d) // 2]:
del fileCache[k]
del d
if self.url not in fileCache.keys():
if self.url.startswith("html#"):
fileCache[self.url] = {"datetime": time.time(), "content": md(self.url[5:]).encode()}
elif self.url.startswith("url#"):
fileCache[self.url] = {"datetime": time.time(), "content": self.url[4:].encode()}
else:
r = requests.get(self.url + "&token=" + mo.token)
fileCache[self.url] = {"datetime": time.time(), "content": r.content}
return fileCache[self.url]["content"][offset:offset + size]
@staticmethod
def from_moodle(moodle: Moodle):
f = FSNode("/", True)
for cat in moodle.get_enrolled_categories():
f.children.append(FSNode.from_category(cat, moodle))
return f
@staticmethod
def from_label(mo: Label, m):
f = FSNode(mo.name, False)
f.size = len(mo.htmlcontent)
f.url = "html#" + mo.htmlcontent
return f
@staticmethod
def from_url(mo: Url, m):
f = FSNode(mo.name, False)
f.size = len(mo.url)
f.url = "url#" + mo.url
return f