patx/mrhttp-asgi
Add static_cached_timer to update changed files
Commit 9e4ca93 · Mark · 2024-03-19T15:43:16-07:00
Comments
No comments yet.
Diff
diff --git a/src/mrhttp/app.py b/src/mrhttp/app.py
index 64f7ca7..ea45879 100644
--- a/src/mrhttp/app.py
+++ b/src/mrhttp/app.py
@@ -8,7 +8,7 @@ import signal
import asyncio
import traceback
import socket
-import os, sys, random, mrpacker
+import os, sys, random, mrpacker, time
from glob import glob
import multiprocessing
import faulthandler
@@ -71,6 +71,7 @@ class Application(mrhttp.CApp):
self._mrq = None
self._mrq2 = None
self._mrc = None
+ self.static_cached_files = []
self.session_backend = "memcached"
self.uses_session = False
self.uses_mrq = False
@@ -137,19 +138,39 @@ class Application(mrhttp.CApp):
params["type"] = r[4]
self.router.add_route( r[0], r[1], params )
+ #TODO Size limit on files?
+ def static_cached_timer(self):
+ ts = time.time() # Avoid race
+ for item in self.static_cached_files:
+ fn = item[1]
+ if os.path.getmtime(fn) > self.static_cached_timestamp:
+ with open(fn, 'rb') as f:
+ b = f.read()
+ self.router.update_cached_route( [item[0], b] )
+ self.static_cached_timestamp = ts
+ self.loop.call_later(10, self.static_cached_timer)
+
+
+ #TODO Use brotli'd files - if [path].br exists use that instead
def static_cached(self, root, directory):
def removeprefix( prefix, text ):
if text.startswith(prefix):
return text[len(prefix):]
+ if not os.path.isdir(directory):
+ print("WARNING: app.static_cached root dir does not exist")
+ return
files = glob(os.path.join(directory, '**', '*'), recursive=True)
+ self.static_cached_timestamp = time.time()
for fn in files:
if os.path.isdir(fn): continue
with open(fn, 'rb') as f:
b = f.read()
+
if not root.startswith('/'): root = '/'+root
uri = root+removeprefix(directory, fn)
+ self.static_cached_files.append( [uri,fn] )
self.router.add_cached_route( uri, b )
def _get_idle_and_busy_connections(self):
@@ -292,6 +313,7 @@ class Application(mrhttp.CApp):
def _appStart(self):
self.loop.call_soon(self.updateDateString)
+ self.loop.call_soon(self.static_cached_timer)
def _run(self, *, host, port, num_workers=None, debug=None):
diff --git a/src/mrhttp/internals/module.h b/src/mrhttp/internals/module.h
index ff88879..b4d87ed 100644
--- a/src/mrhttp/internals/module.h
+++ b/src/mrhttp/internals/module.h
@@ -74,6 +74,7 @@ static PyGetSetDef Protocol_getset[] = {
static PyMethodDef Router_methods[] = {
{"setupRoutes", (PyCFunction)Router_setupRoutes, METH_NOARGS, ""},
+ {"update_cached_route", (PyCFunction)Router_update_cached_route, METH_O, ""},
{NULL}
};
static PyMethodDef MrhttpApp_methods[] = {
diff --git a/src/mrhttp/internals/protocol.c b/src/mrhttp/internals/protocol.c
index e8f30f6..3feee68 100644
--- a/src/mrhttp/internals/protocol.c
+++ b/src/mrhttp/internals/protocol.c
@@ -896,6 +896,7 @@ PyObject* protocol_task_done(Protocol* self, PyObject* task)
PyObject* result = Py_True;
PipelineRequest *r;
+ // TODO?
// task is the task that just finished.
// If task is at the head of the Q then return the response.
// then continue looping through the Q and return a response for anything that is already done
diff --git a/src/mrhttp/internals/router.c b/src/mrhttp/internals/router.c
index 0eead7d..0c8d487 100644
--- a/src/mrhttp/internals/router.c
+++ b/src/mrhttp/internals/router.c
@@ -51,6 +51,25 @@ static int numInString( char c, char* s, int len ) {
return ret;
}
+PyObject* Router_update_cached_route(Router* self, PyObject* item) {
+
+ PyObject *path = PyList_GET_ITEM( item, 0 );
+ PyObject *b = PyList_GET_ITEM( item, 1 );
+
+ Py_ssize_t plen;
+ char *p = PyUnicode_AsUTF8AndSize( path, &plen );
+
+ Route *r = self->staticRoutes;
+ for (int i = 0; i<self->numStaticRoutes; i++,r++ ) {
+ //DBG printf("request path len %d - %.*s\n", (int)request->path_len, (int)request->path_len, request->path);
+ //DBG printf("route path %.*s \n", (int)r->len, r->path);
+ if ( plen == r->len && !memcmp(r->path, p, plen) ) {
+ r->cached = b;
+ Py_RETURN_NONE;
+ }
+ }
+ Py_RETURN_NONE;
+}
PyObject *Router_setupRoutes (Router* self) {
//PyObject *sroutes = self->pyStaticRoutes; //PyObject_GetAttrString((PyObject*)self, "static_routes");
diff --git a/src/mrhttp/internals/router.h b/src/mrhttp/internals/router.h
index ec10769..25887f2 100644
--- a/src/mrhttp/internals/router.h
+++ b/src/mrhttp/internals/router.h
@@ -40,5 +40,6 @@ PyObject *Router_new (PyTypeObject* self, PyObject *args, PyObject *kwargs);
int Router_init (Router* self, PyObject *args, PyObject *kwargs);
void Router_dealloc(Router* self);
PyObject *Router_setupRoutes(Router* self);
+PyObject* Router_update_cached_route(Router* self, PyObject* item);
Route* router_getRoute(Router* self, Request* request);
diff --git a/tst.py b/tst.py
index 25e40fb..f808765 100755
--- a/tst.py
+++ b/tst.py
@@ -4,7 +4,7 @@ from mrhttp import app
#import asyncmrq, mrpacker
app.config["memcache"] = [ ("127.0.0.1", 11211) ]
-app.static_cached("www","/home/ch/code/web/chatter/www")
+#app.static_cached("www","/path/to/www")
#@app.on('at_start')
#async def setup():