File: http-server.rst

package info (click to toggle)
mopidy 3.4.2-6
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 2,712 kB
  • sloc: python: 16,672; sh: 159; makefile: 127
file content (191 lines) | stat: -rw-r--r-- 6,129 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
.. _http-server-api:

********************
HTTP server side API
********************

The :ref:`ext-http` extension comes with an HTTP server to host Mopidy's
:ref:`http-api`. This web server can also be used by other extensions that need
to expose something over HTTP.

The HTTP server side API can be used to:

- host static files for e.g. a Mopidy client written in pure JavaScript,
- host a `Tornado <https://www.tornadoweb.org/>`__ application, or
- host a WSGI application, including e.g. Flask applications.

To host static files using the web server, an extension needs to register a
name and a file path in the extension registry under the ``http:static`` key.

To extend the web server with a web application, an extension must register a
name and a factory function in the extension registry under the ``http:app``
key.

For details on how to make a Mopidy extension, see the :ref:`extensiondev`
guide.


.. _static-web-client:

Static web client example
=========================

To serve static files, you just need to register an ``http:static`` dictionary
in the extension registry. The dictionary must have two keys: ``name`` and
``path``. The ``name`` is used to build the URL the static files will be
served on. By convention, it should be identical with the extension's
:attr:`~mopidy.ext.Extension.ext_name`, like in the following example. The
``path`` tells Mopidy where on the disk the static files are located.

Assuming that the code below is located in the file
:file:`mywebclient/__init__.py`, the files in the directory
:file:`mywebclient/static/` will be made available at ``/mywebclient/`` on
Mopidy's web server. For example, :file:`mywebclient/static/foo.html` will be
available at http://localhost:6680/mywebclient/foo.html.

::

    import os

    from mopidy import ext


    class MyWebClientExtension(ext.Extension):
        ext_name = 'mywebclient'

        def setup(self, registry):
            registry.add('http:static', {
                'name': self.ext_name,
                'path': os.path.join(os.path.dirname(__file__), 'static'),
            })

        # See the Extension API for the full details on this class


Tornado application example
===========================

The :ref:`ext-http` extension's web server is based on the `Tornado
<https://www.tornadoweb.org/>`__ web framework. Thus, it has first class support
for Tornado request handlers.

In the following example, we create a :class:`tornado.web.RequestHandler`
called :class:`MyRequestHandler` that responds to HTTP GET requests with the
string ``Hello, world! This is Mopidy $version``, where it gets the Mopidy
version from Mopidy's core API.

To hook the request handler into Mopidy's web server, we must register a
dictionary under the ``http:app`` key in the extension registry. The
dictionary must have two keys: ``name`` and ``factory``.

The ``name`` is used to build the URL the app will be served on. By convention,
it should be identical with the extension's
:attr:`~mopidy.ext.Extension.ext_name`, like in the following example.

The ``factory`` must be a function that accepts two arguments, ``config`` and
``core``, respectively a dict structure of Mopidy's config and a
:class:`pykka.ActorProxy` to the full Mopidy core API. The ``factory`` function
must return a list of Tornado request handlers. The URL patterns of the request
handlers should not include the ``name``, as that will be prepended to the URL
patterns by the web server.

When the extension is installed, Mopidy will respond to requests to
http://localhost:6680/mywebclient/ with the string ``Hello, world! This is
Mopidy $version``.

::

    import os

    import tornado.web

    from mopidy import ext


    class MyRequestHandler(tornado.web.RequestHandler):
        def initialize(self, core):
            self.core = core

        def get(self):
            self.write(
                'Hello, world! This is Mopidy %s' %
                self.core.get_version().get())


    def my_app_factory(config, core):
        return [
            ('/', MyRequestHandler, {'core': core})
        ]


    class MyWebClientExtension(ext.Extension):
        ext_name = 'mywebclient'

        def setup(self, registry):
            registry.add('http:app', {
                'name': self.ext_name,
                'factory': my_app_factory,
            })

        # See the Extension API for the full details on this class



WSGI application example
========================

WSGI applications are second-class citizens on Mopidy's HTTP server. The WSGI
applications are run inside Tornado, which is based on non-blocking I/O and a
single event loop. In other words, your WSGI applications will only have a
single thread to run on, and if your application is doing blocking I/O, it will
block all other requests from being handled by the web server as well.

The example below shows how a WSGI application that returns the string
``Hello, world! This is Mopidy $version`` on all requests. The WSGI application
is wrapped as a Tornado application and mounted at
http://localhost:6680/mywebclient/.

::

    import os

    import tornado.web
    import tornado.wsgi

    from mopidy import ext


    def my_app_factory(config, core):

        def wsgi_app(environ, start_response):
            status = '200 OK'
            response_headers = [('Content-type', 'text/plain')]
            start_response(status, response_headers)
            return [
                'Hello, world! This is Mopidy %s\n' %
                self.core.get_version().get()
            ]

        return [
            ('(.*)', tornado.web.FallbackHandler, {
                'fallback': tornado.wsgi.WSGIContainer(wsgi_app),
            }),
        ]


    class MyWebClientExtension(ext.Extension):
        ext_name = 'mywebclient'

        def setup(self, registry):
            registry.add('http:app', {
                'name': self.ext_name,
                'factory': my_app_factory,
            })

        # See the Extension API for the full details on this class


API implementors
================

See the `extension registry <https://mopidy.com/ext/>`_.