Exemple #1
0
    def service_wrapper(func):
        @functools.wraps(func)
        def wrapper(environ, start_response):
            _handle_notify_before(environ, FROM_ENVIRON, notify_before)
            # 'service' passes the WSGI request straight through
            # to the handler so there's almost no point in
            # setting up the environment. However, I can conceive
            # of tools which might access 'environ' directly, and
            # I want to be consistent with the simple* interfaces.
            new_request(environ)
            result = func(environ, start_response)

            # You need to make sure you sent the correct content-type!
            result, ctype, length = convert_body(result, None, encoding, writer)
            result = _handle_notify_after(environ, result, notify_after)
            return result

        pth = path
        if pth is None:
            pth = func.__name__

        # If an outer WSGI wrapper was specified, place it around the service wrapper being created
        if wsgi_wrapper:
            wrapper = wsgi_wrapper(wrapper)

        #For purposes of inspection (not a good idea to change these otherwise you'll lose sync with the values closed over)
        wrapper.content_type = content_type
        wrapper.encoding = encoding
        wrapper.writer = writer

        registry.register_service(service_id, pth, wrapper, query_template=query_template)
        return wrapper
Exemple #2
0
def register_pipeline(ident, path=None, stages=None, doc=None):
    if not stages:
        raise TypeError("a pipeline must have stages")
    stages = [_normalize_stage(stage) for stage in stages]

    # Should I check that the dependent stages are already registered?

    pipeline = Pipeline(ident, path, stages, doc)
    registry.register_service(ident, path, pipeline, doc)
Exemple #3
0
 def method_dispatcher_wrapper(func):
     # Have to handle a missing docstring here as otherwise
     # the registry will try to get it from the dispatcher.
     doc = inspect.getdoc(func) or ""
     pth = path
     if pth is None:
         pth = func.__name__
     dispatcher = service_method_dispatcher(pth, wsgi_wrapper)
     registry.register_service(service_id, pth, dispatcher, doc)
     return service_dispatcher_decorator(dispatcher)
Exemple #4
0
 def method_dispatcher_wrapper(func):
     # Have to handle a missing docstring here as otherwise
     # the registry will try to get it from the dispatcher.
     doc = inspect.getdoc(func) or ""
     pth = path
     if pth is None:
         pth = func.__name__
     dispatcher = service_method_dispatcher(pth, wsgi_wrapper)
     registry.register_service(service_id, pth, dispatcher, doc)
     return service_dispatcher_decorator(dispatcher)
Exemple #5
0
    def service_wrapper(func):
        @functools.wraps(func)
        def wrapper(environ, start_response):
            _handle_notify_before(environ, FROM_ENVIRON, notify_before)
            # 'service' passes the WSGI request straight through
            # to the handler so there's almost no point in
            # setting up the environment. However, I can conceive
            # of tools which might access 'environ' directly, and
            # I want to be consistent with the simple* interfaces.
            new_request(environ)
            result = func(environ, start_response)

            # You need to make sure you sent the correct content-type!
            result, ctype, length = convert_body(result, None, encoding,
                                                 writer)
            result = _handle_notify_after(environ, result, notify_after)
            return result

        pth = path
        if pth is None:
            pth = func.__name__

        # If an outer WSGI wrapper was specified, place it around the service wrapper being created
        if wsgi_wrapper:
            wrapper = wsgi_wrapper(wrapper)

        #For purposes of inspection (not a good idea to change these otherwise you'll lose sync with the values closed over)
        wrapper.content_type = content_type
        wrapper.encoding = encoding
        wrapper.writer = writer

        registry.register_service(service_id,
                                  pth,
                                  wrapper,
                                  query_template=query_template)
        return wrapper
Exemple #6
0
        # This is a very simple implementation of conditional GET with
        # the Last-Modified header. It makes media files a bit speedier
        # because the files are only read off disk for the first request
        # (assuming the browser/client supports conditional GET).
        mtime = formatdate(os.stat(filename).st_mtime, usegmt=True)
        headers = [('Last-Modified', mtime)]
        if environ.get('HTTP_IF_MODIFIED_SINCE', None) == mtime:
            status = '304 Not Modified'
            output = ()
        else:
            status = '200 OK'
            mime_type = mimetypes.guess_type(filename)[0]
            if mime_type:
                headers.append(('Content-Type', mime_type))
            output = [fp.read()]
            fp.close()
        start_response(status, headers)
        return output


import akara

if not akara.module_config():
    akara.logger.warn("No configuration section found for %r" % (__name__, ))

paths = akara.module_config().get("paths", {})

for path, root in paths.items():
    handler = MediaHandler(root)
    registry.register_service(SERVICE_ID, path, handler)
Exemple #7
0
def simple_service(method, service_id, path=None,
                   content_type=None, encoding="utf-8", writer="xml",
                   allow_repeated_args=False,
                   query_template=None,
                   wsgi_wrapper=None,
                   notify_before=None, notify_after=None):
    """Add the function as an Akara resource

    These affect how the resource is registered in Akara
      method - the supported HTTP method (either "GET" or "POST")
      service_id - a string which identifies this service; should be a URL
      path - the local URL path to the resource (must not at present
           contain a '/') If None, use the function's name as the path.
      query_template - An Akara URL service template (based on OpenSource; see akara.opensource)
           Can be used to help consumers compose resources withing this service.  The same
           template is used for all HTTP methods

    These control how to turn the return value into an HTTP response
      content_type - the response content-type. If not specified, and if
          "Content-Type" is not listed in akara.response.headers then infer
          the content-type based on what the decorated function returns.
          (See akara.services.convert_body for details)
      encoding - Used to convert a returned Unicode string or an Amara tree
          to the bytes used in the HTTP response
      writer - Used to serialize the Amara tree for the HTTP response.
          This must be a name which can be used as an Amara.writer.lookup.

    This affects how to convert the QUERY_STRING into function call parameters
      allow_repeated_args - The query string may have multiple items with the
          same name, as in "?a=x&a=y&a=z&b=w". If True, this is converted into
          a function call parameter like "f(a=['x','y','z'], b=['w'])". If
          False then this is treated as an error. Suppose the query string
          contains no repeated arguments, as in "?a=x&b=w". If
          allow_repeated_args is True then the function is called as
          as "f(a=['x'], b=['w'])" and if False, like "f(a='x', b='w')".
    
    A simple_service decorated function can get request information from
    akara.request and use akara.response to set the HTTP reponse code
    and the HTTP response headers.

    Here is an example of use:

      @simple_service("GET", "http://example.com/get_date")
      def date(format="%Y-%m-%d %H:%M:%S"):
          '''get the current date'''
          import datetime
          return datetime.datetime.now().strftime(format)

    which can be called with URLs like:

      http://localhost:8880/date
      http://localhost:8880/date?format=%25m-%25d-%25Y

    Integration with other WSGI components:

    The @simple_service decorator creates and returns a low-level handler 
    function that conforms to the WSGI calling conventions. However,
    it is not safe to directly use the resulting handler with arbitrary
    third-party WSGI components (e.g., to wrap the Akara handler with
    an WSGI middleware component).   This is because Akara handlers return
    values other than sequences of byte-strings.  For example, they might
    return XML trees, Unicode, or other data types that would not be 
    correctly interpreted by other WSGI components.

    To integrate other WSGI components with Akara, use the wsgi_wrapper
    argument to @simple_service.  For example:

    def wrapper(app):
        # Create an WSGI wrapper around WSGI application app
        ...
        return wrapped_app

    @simple_service("GET", "http://example.com/get_date", wsgi_wrapper=wrapper)
    def date(format):
        ...
    When specified, Akara will do the following:

         - Arrange to have the wsgi_wrapper placed at the outermost layer 
           of Akara's processing.   That is, control will pass into 
           the WSGI wrapper before any Akara-specific processing related
           to the @simple_service handler takes place.

         - Ensure that all output returned back to the WSGI wrapper
           strictly conforms to the WSGI standard (is a sequence of bytes)

    The wrapper function given with wsgi_wrapper should accept a function
    as input and return an WSGI application as output.  This application
    should be a callable that accepts (environ, start_response).

    See implementation notes in the code below.

"""
    _no_slashes(path)
    _check_is_valid_method(method)
    if method not in ("GET", "POST"):
        raise ValueError(
            "simple_service only supports GET and POST methods, not %s" % (method,))

    def service_wrapper(func):
        @functools.wraps(func)
        def wrapper(environ, start_response):
            try:
                if environ.get("REQUEST_METHOD") != method:
                    if method == "GET":
                        raise _HTTP405(["GET"])
                    else:
                        raise _HTTP405(["POST"])
                args, kwargs = _get_function_args(environ, allow_repeated_args)
            except _HTTPError, err:
                return err.make_wsgi_response(environ, start_response)
            if args:
                body = args[0]
            else:
                body = ""
            _handle_notify_before(environ, body, notify_before)

            new_request(environ)
            result = func(*args, **kwargs)

            result, ctype, clength = convert_body(result, content_type, encoding, writer)
            send_headers(start_response, ctype, clength)
            result = _handle_notify_after(environ, result, notify_after)
            return result

        pth = path
        if pth is None:
            pth = func.__name__

        # Construct the default query template, if needed and possible.
        qt = query_template
        if qt is None and method == "GET" and not allow_repeated_args:
            qt = _make_query_template(func)
        if qt is not None:
            qt = pth + qt

        # If an wsgi_wrapper was given, wrapper the service wrapper with it
        if wsgi_wrapper:
           wrapper = wsgi_wrapper(wrapper)

        #For purposes of inspection (not a good idea to change these otherwise you'll lose sync with the values closed over)
        wrapper.content_type = content_type
        wrapper.encoding = encoding
        wrapper.writer = writer

        registry.register_service(service_id, pth, wrapper, query_template=qt)
        return wrapper
Exemple #8
0
        # This is a very simple implementation of conditional GET with
        # the Last-Modified header. It makes media files a bit speedier
        # because the files are only read off disk for the first request
        # (assuming the browser/client supports conditional GET).
        mtime = formatdate(os.stat(filename).st_mtime, usegmt=True)
        headers = [('Last-Modified', mtime)]
        if environ.get('HTTP_IF_MODIFIED_SINCE', None) == mtime:
            status = '304 Not Modified'
            output = ()
        else:
            status = '200 OK'
            mime_type = mimetypes.guess_type(filename)[0]
            if mime_type:
                headers.append(('Content-Type', mime_type))
            output = [fp.read()]
            fp.close()
        start_response(status, headers)
        return output

import akara

if not akara.module_config():
    akara.logger.warn("No configuration section found for %r" % (__name__,))
    
paths = akara.module_config().get("paths", {})

for path, root in paths.items():
    handler = MediaHandler(root)
    registry.register_service(SERVICE_ID, path, handler)
Exemple #9
0
def simple_service(method,
                   service_id,
                   path=None,
                   content_type=None,
                   encoding="utf-8",
                   writer="xml",
                   allow_repeated_args=False,
                   query_template=None,
                   wsgi_wrapper=None,
                   notify_before=None,
                   notify_after=None):
    """Add the function as an Akara resource

    These affect how the resource is registered in Akara
      method - the supported HTTP method (either "GET" or "POST")
      service_id - a string which identifies this service; should be a URL
      path - the local URL path to the resource (must not at present
           contain a '/') If None, use the function's name as the path.
      query_template - An Akara URL service template (based on OpenSource; see akara.opensource)
           Can be used to help consumers compose resources withing this service.  The same
           template is used for all HTTP methods

    These control how to turn the return value into an HTTP response
      content_type - the response content-type. If not specified, and if
          "Content-Type" is not listed in akara.response.headers then infer
          the content-type based on what the decorated function returns.
          (See akara.services.convert_body for details)
      encoding - Used to convert a returned Unicode string or an Amara tree
          to the bytes used in the HTTP response
      writer - Used to serialize the Amara tree for the HTTP response.
          This must be a name which can be used as an Amara.writer.lookup.

    This affects how to convert the QUERY_STRING into function call parameters
      allow_repeated_args - The query string may have multiple items with the
          same name, as in "?a=x&a=y&a=z&b=w". If True, this is converted into
          a function call parameter like "f(a=['x','y','z'], b=['w'])". If
          False then this is treated as an error. Suppose the query string
          contains no repeated arguments, as in "?a=x&b=w". If
          allow_repeated_args is True then the function is called as
          as "f(a=['x'], b=['w'])" and if False, like "f(a='x', b='w')".
    
    A simple_service decorated function can get request information from
    akara.request and use akara.response to set the HTTP reponse code
    and the HTTP response headers.

    Here is an example of use:

      @simple_service("GET", "http://example.com/get_date")
      def date(format="%Y-%m-%d %H:%M:%S"):
          '''get the current date'''
          import datetime
          return datetime.datetime.now().strftime(format)

    which can be called with URLs like:

      http://localhost:8880/date
      http://localhost:8880/date?format=%25m-%25d-%25Y

    Integration with other WSGI components:

    The @simple_service decorator creates and returns a low-level handler 
    function that conforms to the WSGI calling conventions. However,
    it is not safe to directly use the resulting handler with arbitrary
    third-party WSGI components (e.g., to wrap the Akara handler with
    an WSGI middleware component).   This is because Akara handlers return
    values other than sequences of byte-strings.  For example, they might
    return XML trees, Unicode, or other data types that would not be 
    correctly interpreted by other WSGI components.

    To integrate other WSGI components with Akara, use the wsgi_wrapper
    argument to @simple_service.  For example:

    def wrapper(app):
        # Create an WSGI wrapper around WSGI application app
        ...
        return wrapped_app

    @simple_service("GET", "http://example.com/get_date", wsgi_wrapper=wrapper)
    def date(format):
        ...
    When specified, Akara will do the following:

         - Arrange to have the wsgi_wrapper placed at the outermost layer 
           of Akara's processing.   That is, control will pass into 
           the WSGI wrapper before any Akara-specific processing related
           to the @simple_service handler takes place.

         - Ensure that all output returned back to the WSGI wrapper
           strictly conforms to the WSGI standard (is a sequence of bytes)

    The wrapper function given with wsgi_wrapper should accept a function
    as input and return an WSGI application as output.  This application
    should be a callable that accepts (environ, start_response).

    See implementation notes in the code below.

"""
    _no_slashes(path)
    _check_is_valid_method(method)
    if method not in ("GET", "POST"):
        raise ValueError(
            "simple_service only supports GET and POST methods, not %s" %
            (method, ))

    def service_wrapper(func):
        @functools.wraps(func)
        def wrapper(environ, start_response):
            try:
                if environ.get("REQUEST_METHOD") != method:
                    if method == "GET":
                        raise _HTTP405(["GET"])
                    else:
                        raise _HTTP405(["POST"])
                args, kwargs = _get_function_args(environ, allow_repeated_args)
            except _HTTPError, err:
                return err.make_wsgi_response(environ, start_response)
            if args:
                body = args[0]
            else:
                body = ""
            _handle_notify_before(environ, body, notify_before)

            new_request(environ)
            result = func(*args, **kwargs)

            result, ctype, clength = convert_body(result, content_type,
                                                  encoding, writer)
            send_headers(start_response, ctype, clength)
            result = _handle_notify_after(environ, result, notify_after)
            return result

        pth = path
        if pth is None:
            pth = func.__name__

        # Construct the default query template, if needed and possible.
        qt = query_template
        if qt is None and method == "GET" and not allow_repeated_args:
            qt = _make_query_template(func)
        if qt is not None:
            qt = pth + qt

        # If an wsgi_wrapper was given, wrapper the service wrapper with it
        if wsgi_wrapper:
            wrapper = wsgi_wrapper(wrapper)

        #For purposes of inspection (not a good idea to change these otherwise you'll lose sync with the values closed over)
        wrapper.content_type = content_type
        wrapper.encoding = encoding
        wrapper.writer = writer

        registry.register_service(service_id, pth, wrapper, query_template=qt)
        return wrapper