11import abc
2+ import asyncio
3+ import time
4+ from dataclasses import dataclass , field
25
6+ from waterbutler .core .streams import StringStream
7+ from waterbutler .core .utils import make_provider
8+
9+ from mfr .server import settings
310from mfr .core .metrics import MetricsRecord
11+ from mfr .core .provider import ProviderMetadata
12+ from mfr .tasks .serializer import serializable
413
514
615class BaseExporter (metaclass = abc .ABCMeta ):
@@ -42,19 +51,28 @@ def _get_module_name(self):
4251 .replace ('mfr.extensions.' , '' , 1 ) \
4352 .replace ('.export' , '' , 1 )
4453
45-
54+ @serializable
55+ @dataclass
4656class BaseRenderer (metaclass = abc .ABCMeta ):
47-
48- def __init__ (self , metadata , file_path , url , assets_url , export_url ):
49- self .metadata = metadata
50- self .file_path = file_path
51- self .url = url
52- self .assets_url = f'{ assets_url } /{ self ._get_module_name ()} '
53- self .export_url = export_url
54- self .renderer_metrics = MetricsRecord ('renderer' )
57+ metadata : ProviderMetadata
58+ file_path : str
59+ url : str
60+ assets_url : str
61+ export_url : str
62+ renderer_metrics : MetricsRecord = field (default = None )
63+ metrics : MetricsRecord = field (default = None )
64+
65+ def __post_init__ (self ):
66+ self .assets_url = f'{ self .assets_url } /{ self ._get_module_name ()} '
67+ self .renderer_metrics = MetricsRecord ('renderer' ,)
5568 if self ._get_module_name ():
5669 self .metrics = self .renderer_metrics .new_subrecord (self ._get_module_name ())
5770
71+ if name := self .metadata .name :
72+ self .cache_file_path_str = f'/export/{ self .metadata .unique_key } .{ name } '
73+ else :
74+ self .cache_file_path_str = f'/export/{ self .metadata .unique_key } '
75+
5876 self .renderer_metrics .merge ({
5977 'class' : self ._get_module_name (),
6078 'ext' : self .metadata .ext ,
@@ -73,10 +91,55 @@ def __init__(self, metadata, file_path, url, assets_url, export_url):
7391 except AttributeError :
7492 pass
7593
94+ @property
95+ def cache_provider (self ):
96+ return make_provider (
97+ settings .CACHE_PROVIDER_NAME ,
98+ {}, # User information which can be left blank
99+ settings .CACHE_PROVIDER_CREDENTIALS ,
100+ settings .CACHE_PROVIDER_SETTINGS
101+ )
102+
103+ async def get_cache_file_path (self ):
104+ return await self .cache_provider .validate_path (self .cache_file_path_str )
105+
76106 @abc .abstractmethod
77- def render (self ):
107+ def _render (self ) -> str :
78108 pass
79109
110+ async def render (self ):
111+ if self .use_celery or self .cache_result :
112+ self .cache_file_path = await self .cache_provider .validate_path (self .cache_file_path_str )
113+ if not self .use_celery :
114+ rendition = await self .do_render ()
115+ return StringStream (rendition )
116+ else :
117+ from mfr .tasks .render import render
118+ result = render .delay (self )
119+ for i in range (100 * 60 * 10 ):
120+ if not result .ready ():
121+ time .sleep (0.01 )
122+ else :
123+ return await self .cache_provider .download (self .cache_file_path )
124+
125+ return None
126+
127+ async def do_render (self ):
128+ if self .use_celery or self .cache_result :
129+ file_path_task = asyncio .ensure_future (self .get_cache_file_path ())
130+ rendition = await asyncio .get_running_loop ().run_in_executor (None , self ._render )
131+ if self .use_celery or self .cache_result :
132+ upload_task = asyncio .ensure_future (
133+ self .cache_provider .upload (
134+ StringStream (rendition ),
135+ await file_path_task
136+ )
137+ )
138+ if self .use_celery :
139+ await upload_task
140+ return rendition
141+
142+ @property
80143 @abc .abstractmethod
81144 def file_required (self ):
82145 """Does the rendering html need the raw file content to display correctly?
@@ -85,10 +148,15 @@ def file_required(self):
85148 """
86149 pass
87150
151+ @property
88152 @abc .abstractmethod
89- def cache_result (self ):
153+ def cache_result (self ) -> bool :
90154 pass
91155
156+ @property
157+ def use_celery (self ) -> bool :
158+ return False
159+
92160 def _get_module_name (self ):
93161 return self .__module__ \
94162 .replace ('mfr.extensions.' , '' , 1 ) \
0 commit comments