moodlefuse/FSNode.py

142 lines
4.3 KiB
Python
Raw Normal View History

2023-05-01 01:12:48 +02:00
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