qmsk/web/application.py
changeset 92 e5799432071c
child 103 5263f65c990e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/qmsk/web/application.py	Sat Jun 07 16:21:39 2014 +0300
@@ -0,0 +1,138 @@
+from werkzeug.wrappers import Request, Response
+from werkzeug.exceptions import (
+        HTTPException,
+        BadRequest,         # 400
+        NotFound,           # 404
+)
+from werkzeug.utils import redirect
+
+class Application:
+    URLS = None
+
+    def __init__ (self, urls=None):
+        """
+            urls        - werkzeug.routing.Map -> Handler
+        """
+
+        if not urls:
+            urls = self.URLS
+
+        if not urls:
+            raise ValueError("Required URLS/urls=...")
+
+        self.urls = urls
+
+    def respond (self, request):
+        """
+            Lookup Request -> Handler, params -> Response
+        """
+        
+        # bind to request
+        urls = self.urls.bind_to_environ(request)
+        
+        # lookup
+        handler, params = urls.match()
+
+        # handler instance
+        handler = handler(self, request, urls)
+
+        try :
+            handler.init()
+
+            # apply
+            return handler.respond(**params)
+
+        finally :
+            handler.cleanup()
+
+    @Request.application
+    def __call__ (self, request) :
+        """
+            WSGI entry point, werkzeug Request -> Response
+        """
+
+        try :
+            return self.respond(request)
+        
+        except HTTPException as ex :
+            return ex
+
+class Handler (object) :
+    """
+        Per-Request controller/view, containing the request context and generating the response.
+    """
+    
+    # werkzeug defaults to UTF-8
+    MIMETYPE = 'text/html'
+
+    def __init__ (self, app, request, urls) :
+        """
+            app     - wsgi.Application
+            request - werkzeug.Request
+            urls    - werkzeug.routing.Map.bind_to_environ()
+        """
+
+        self.app = app
+        self.request = request
+        self.urls = urls
+
+    def url (self, handler=None, **params) :
+        """
+            Return an URL for given endpoint, with parameters,
+        """
+
+        if not handler :
+            handler = self.__class__
+
+        return self.urls.build(handler, params)
+
+    ## processing stages
+    def init (self) :
+        """
+            Initialize on request start.
+        """
+
+        pass
+
+    def process (self, **params) :
+        """
+            Process request args to build internal request state.
+
+            May optionally return a Response, to e.g. redirect after POST.
+        """
+
+        pass
+
+    def render (self) :
+        """
+            Render response.
+        """
+
+        raise NotImplementedError()
+
+    def mimetype (self):
+        return self.MIMETYPE
+
+    def status (self):
+        return 200
+
+    def respond (self, **params) :
+        """
+            Generate a response, or raise an HTTPException
+        """
+        
+        # returning e.g. redirect?
+        response = self.process(**params)
+
+        if response :
+            return response
+        
+        return Response(self.render_response(), mimetype=self.mimetype(), status=self.status())
+    
+    def cleanup (self) :
+        """
+            After request processing. Do not fail :)
+        """
+        
+        pass
+