]> git.mar77i.info Git - hublib/blob - hub/staticresource.py
e1e86dd633b50cc0d9eb4368f22ee11aed1f6045
[hublib] / hub / staticresource.py
1 from io import BytesIO
2 import json
3 import mimetypes
4 import os
5 from pathlib import Path
6
7 from .utils import scramble
8
9
10 class StaticFile:
11 template_ext = ".tpl"
12 template_filters = {
13 b"tojson": lambda value: json.dumps(value)
14 }
15
16 def __init__(self, path):
17 self.path = path
18 self.mime_type = mimetypes.guess_type(self.remove_template_ext(str(path)))[0]
19 self.mtime = None
20 self.content = None
21
22 def load_content(self):
23 with open(self.path, "rb") as fh:
24 return fh.read()
25
26 def get(self, context_vars):
27 content = self.load_content() if self.path.stat().st_mtime != self.mtime else self.content
28 if self.path.suffix == self.template_ext:
29 content = self.render(content, context_vars)
30 self.content = content
31 return content
32
33 def render(self, content, context_vars):
34 bio = BytesIO()
35 pos = 0
36 while True:
37 new_pos = content.find(b"{{", pos)
38 if new_pos < 0:
39 break
40 bio.write(content[pos:new_pos])
41 end_pos = content.find(b"}}", new_pos)
42 assert end_pos > 0
43 full_tag = content[new_pos + 2:end_pos].split(b"|", 1)
44 value = context_vars[full_tag[0].strip().decode()]
45 if len(full_tag) == 2:
46 value = self.template_filters[full_tag[1].strip()](value)
47 bio.write(value.encode())
48 pos = end_pos + 2
49 bio.write(content[pos:])
50 return bio.getvalue()
51
52 def __str__(self):
53 return f"<StaticFile at \"{os.sep.join(self.path.parts[-2:])}\" [{self.mime_type}]>"
54
55 @classmethod
56 def remove_template_ext(cls, filename):
57 if filename.endswith(cls.template_ext):
58 filename = filename[:-4]
59 return filename
60
61
62 class StaticResource:
63 def __init__(self, secret, current_hubapp):
64 mimetypes.init()
65 self.static_files = {}
66 self.context_vars = {}
67 self.master_uri = ""
68 self.setup(secret, current_hubapp)
69
70 def setup(self, secret, current_hubapp):
71 hubapp_dir = Path(__file__).parents[1] / "hubapps" / current_hubapp
72 for file in os.listdir(hubapp_dir):
73 uri_file = StaticFile.remove_template_ext(file)
74 if uri_file.startswith("master."):
75 uri = f"/{scramble(secret, uri_file)}"
76 if uri_file == "master.html":
77 self.master_uri = uri
78 self.context_vars[uri_file.replace(".", "_")] = uri
79 else:
80 uri = f"/{uri_file}"
81 self.static_files[uri] = StaticFile(hubapp_dir / file)
82 if uri_file == "index.html":
83 self.static_files["/"] = self.static_files[uri]
84
85 async def on_get(self, req, resp):
86 path = req.path
87 index_uri = f"/index.html"
88 if path == "/":
89 path = index_uri
90 res = self.static_files[path]
91 resp.data = res.get(self.context_vars)
92 resp.content_type = res.mime_type
93
94 def add_routes(self, app):
95 for uri_template in self.static_files:
96 app.add_route(uri_template, self)