arcology-fastapi/arcology/feeds.py

103 lines
3.8 KiB
Python

# [[file:../arcology-feedgen.org::*Invoking Pandoc for the Feed Generator][Invoking Pandoc for the Feed Generator:1]]
import re
from fastapi import Response, HTTPException
import asyncio
from sqlmodel import Session
from async_lru import alru_cache
from typing import Optional
from arcology.html import rewrite_html
from arcology.key import ArcologyKey
from arcology.parse import parse_sexp, print_sexp
from arcology.arroyo import Page
# Invoking Pandoc for the Feed Generator:1 ends here
# [[file:../arcology-feedgen.org::*Invoking Pandoc for the Feed Generator][Invoking Pandoc for the Feed Generator:2]]
class ExportException(BaseException):
code: int
stderr: str
def __init__(self, code, stderr=None):
self.code = code
self.stderr = stderr
@alru_cache(maxsize=64)
async def export_pandoc(file: str, hash: str) -> str:
proc = await asyncio.create_subprocess_shell(
f"pandoc {file} --lua-filter=./arcology/pandoc/make-atom.lua --template=./arcology/pandoc/atom.xml -s",
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE)
stdout, stderr = await proc.communicate()
if proc.returncode == 0:
return stdout.decode()
else:
raise ExportException(code=proc.returncode, stderr=stderr.decode())
async def render_feed_from_file(_request, file: str, engine, site) -> Optional[Response]:
with Session(engine) as session:
p = Page.from_file(file, session)
if p is None:
raise HTTPException(status_code=404, detail="Feed not found.")
try:
xml = await export_pandoc(file, p.hash)
except ExportException as e:
raise HTTPException(status_code=500, detail=f"pandoc exited {e.code} w/ {e.stderr}")
return hydrate_feed(file, xml, session)
# Invoking Pandoc for the Feed Generator:2 ends here
# [[file:../arcology-feedgen.org::*Invoking Pandoc for the Feed Generator][Invoking Pandoc for the Feed Generator:3]]
def hydrate_feed(filename: str, xml: str, session) -> str:
page = Page.from_file(filename, session)
def feed_page_replacement_fn(match):
return page.get_file()
akey = ArcologyKey(page.get_key())
out_xml = xml
out_xml = re.sub(r'{ARCOLOGY_FEED_PAGE}', akey.to_url(), out_xml)
out_xml = rewrite_html(out_xml, session) # lol dangerous
return out_xml
# Invoking Pandoc for the Feed Generator:3 ends here
# [[file:../arcology-feedgen.org::*Listing the Arcology Feeds][Listing the Arcology Feeds:1]]
from typing import List
from sqlmodel import select, Session
from arcology.arroyo import Keyword
from arcology.parse import parse_sexp
from arcology.key import ArcologyKey
# Listing the Arcology Feeds:1 ends here
# [[file:../arcology-feedgen.org::*Listing the Arcology Feeds][Listing the Arcology Feeds:2]]
def arcology_feed_q():
return select(Keyword).where(Keyword.keyword=='"ARCOLOGY_FEED"')
def get_feed_keys(session) -> List[str]:
return [parse_sexp(row.value) for row in session.exec(arcology_feed_q())]
def get_feed_files(session) -> List[str]:
return [parse_sexp(row.file) for row in session.exec(arcology_feed_q())]
# Listing the Arcology Feeds:2 ends here
# [[file:../arcology-feedgen.org::*Listing the Arcology Feeds][Listing the Arcology Feeds:5]]
def make_feed_entries(site_key: str, session):
feed_page_titles = dict() # file -> title
for feed_file in get_feed_files(session):
p = Page.from_file(feed_file, session)
if p.get_site().key == site_key:
feed_page_titles[feed_file] = p.get_title()
ret = list()
for feed_key in get_feed_keys(session):
feed_url = ArcologyKey(feed_key).to_url()
feed_file = Keyword.get("ARCOLOGY_FEED", feed_key, session=session).filename()
if feed_page_titles.get(feed_file, None):
ret.append((feed_url, feed_page_titles[feed_file]))
return ret
# Listing the Arcology Feeds:5 ends here