142 lines
4.3 KiB
Python
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
|