import hashlib import json import logging from base64 import b64decode import requests from django.conf import settings from django.core.cache import caches from judge.utils.file_cache import HashFileCache from judge.utils.unicode import utf8bytes logger = logging.getLogger("judge.texoid") TEXOID_ENABLED = hasattr(settings, "TEXOID_URL") class TexoidRenderer(object): def __init__(self): self.cache = HashFileCache( settings.TEXOID_CACHE_ROOT, settings.TEXOID_CACHE_URL, settings.TEXOID_GZIP ) self.meta_cache = caches[settings.TEXOID_META_CACHE] self.meta_cache_ttl = settings.TEXOID_META_CACHE_TTL def query_texoid(self, document, hash): self.cache.create(hash) try: response = requests.post( settings.TEXOID_URL, data=utf8bytes(document), headers={ "Content-Type": "application/x-tex", }, ) response.raise_for_status() except requests.HTTPError as e: if e.response.status == 400: logger.error( "Texoid failed to render: %s\n%s", document, e.response.text ) else: logger.exception("Failed to connect to texoid for: %s", document) return except Exception: logger.exception("Failed to connect to texoid for: %s", document) return try: data = response.json() except ValueError: logger.exception( "Invalid texoid response for: %s\n%s", document, response.text ) return if not data["success"]: logger.error("Texoid failure for: %s\n%s", document, data) return {"error": data["error"]} meta = data["meta"] self.cache.cache_data( hash, "meta", utf8bytes(json.dumps(meta)), url=False, gzip=False ) result = { "png": self.cache.cache_data(hash, "png", b64decode(data["png"])), "svg": self.cache.cache_data(hash, "svg", data["svg"].encode("utf-8")), "meta": meta, } return result def query_cache(self, hash): result = { "svg": self.cache.get_url(hash, "svg"), "png": self.cache.get_url(hash, "png"), } key = "texoid:meta:" + hash cached_meta = self.meta_cache.get(key) if cached_meta is None: cached_meta = json.loads(self.cache.read_data(hash, "meta").decode("utf-8")) self.meta_cache.set(key, cached_meta, self.meta_cache_ttl) result["meta"] = cached_meta return result def get_result(self, formula): hash = hashlib.sha1(utf8bytes(formula)).hexdigest() if self.cache.has_file(hash, "svg"): return self.query_cache(hash) else: return self.query_texoid(formula, hash)