summaryrefslogtreecommitdiff
path: root/docs
diff options
authorPaulo Henrique de Lima Santana (phls) <paulo@phls.com.br>2018-11-26 16:14:30 -0200
committergit-ubuntu importer <ubuntu-devel-discuss@lists.ubuntu.com>2018-11-27 10:42:00 +0000
commit4585371edeb6da9bafe5403c337c9c0835dd6953 (patch)
tree6d7655b21f084fa22bed75de9b6c9f28a7ff25b2 /docs
parent564674aaeb5b692ecf2cd7d1f23af763ea7d68e7 (diff)
Imported using git-ubuntu import.
Notes
Notes: * New upstream release (Closes: #904383). * debian/compat: deleted. * debian/control: - Added dependencies to allow tests and man page creation. - Bumped Standards-Version to 4.2.1. - New format to debhelper-compat and updated level to 11. - Updated Paulo's email. * debian/copyright: - Updated Paulo's email. - Updated long description. - Updated packaging copyright years. * debian/manpages: created. * debian/README.source: created to explain about source missing in examples. * debian/rules: - Added override_dh_auto_build to create man page. - Removed override_dh_auto_test to allow tests. * debian/tests/*: added to perform tests. * debian/upstream/metadata: created.
Diffstat (limited to 'docs')
-rw-r--r--docs/Makefile19
-rw-r--r--docs/_static/README.md1
-rw-r--r--docs/api.rst38
-rw-r--r--docs/conf.py185
-rw-r--r--docs/deployment.rst279
-rw-r--r--docs/index.rst24
-rw-r--r--docs/intro.rst148
-rw-r--r--docs/make.bat35
8 files changed, 729 insertions, 0 deletions
diff --git a/docs/Makefile b/docs/Makefile
new file mode 100644
index 0000000..298ea9e
--- /dev/null
+++ b/docs/Makefile
@@ -0,0 +1,19 @@
+# Minimal makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS =
+SPHINXBUILD = sphinx-build
+SOURCEDIR = .
+BUILDDIR = _build
+
+# Put it first so that "make" without argument is like "make help".
+help:
+ @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
+
+.PHONY: help Makefile
+
+# Catch-all target: route all unknown targets to Sphinx using the new
+# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
+%: Makefile
+ @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) \ No newline at end of file
diff --git a/docs/_static/README.md b/docs/_static/README.md
new file mode 100644
index 0000000..0d94aa7
--- /dev/null
+++ b/docs/_static/README.md
@@ -0,0 +1 @@
+Place static files used by the documentation here.
diff --git a/docs/api.rst b/docs/api.rst
new file mode 100644
index 0000000..9427ce3
--- /dev/null
+++ b/docs/api.rst
@@ -0,0 +1,38 @@
+API Reference
+=============
+
+.. toctree::
+ :maxdepth: 3
+
+.. module:: engineio
+
+``Server`` class
+----------------
+
+.. autoclass:: Server
+ :members:
+
+``AsyncServer`` class
+---------------------
+
+.. autoclass:: AsyncServer
+ :members:
+ :inherited-members:
+
+``WSGIApp`` class
+-----------------
+
+.. autoclass:: WSGIApp
+ :members:
+
+``ASGIApp`` class
+-----------------
+
+.. autoclass:: ASGIApp
+
+``Middleware`` class (deprecated)
+---------------------------------
+
+.. autoclass:: Middleware
+ :members:
+
diff --git a/docs/conf.py b/docs/conf.py
new file mode 100644
index 0000000..e7bfde4
--- /dev/null
+++ b/docs/conf.py
@@ -0,0 +1,185 @@
+# -*- coding: utf-8 -*-
+#
+# Configuration file for the Sphinx documentation builder.
+#
+# This file does only contain a selection of the most common options. For a
+# full list see the documentation:
+# http://www.sphinx-doc.org/en/master/config
+
+# -- Path setup --------------------------------------------------------------
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#
+# import os
+# import sys
+# sys.path.insert(0, os.path.abspath('.'))
+
+
+# -- Project information -----------------------------------------------------
+
+project = 'python-engineio'
+copyright = '2018, Miguel Grinberg'
+author = 'Miguel Grinberg'
+
+# The short X.Y version
+version = ''
+# The full version, including alpha/beta/rc tags
+release = ''
+
+
+# -- General configuration ---------------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+#
+# needs_sphinx = '1.0'
+
+# Add any Sphinx extension module names here, as strings. They can be
+# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
+# ones.
+extensions = [
+ 'sphinx.ext.autodoc',
+]
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix(es) of source filenames.
+# You can specify multiple suffix as a list of string:
+#
+# source_suffix = ['.rst', '.md']
+source_suffix = '.rst'
+
+# The master toctree document.
+master_doc = 'index'
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#
+# This is also used if you do content translation via gettext catalogs.
+# Usually you set "language" from the command line for these cases.
+language = None
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+# This pattern also affects html_static_path and html_extra_path.
+exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = None
+
+
+# -- Options for HTML output -------------------------------------------------
+
+# The theme to use for HTML and HTML Help pages. See the documentation for
+# a list of builtin themes.
+#
+html_theme = 'alabaster'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further. For a list of options available for each theme, see the
+# documentation.
+#
+html_theme_options = {
+ 'github_user': 'miguelgrinberg',
+ 'github_repo': 'python-engineio',
+ 'github_banner': True,
+ 'github_button': True,
+ 'github_type': 'star',
+ 'fixed_sidebar': True,
+
+}
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['_static']
+
+# Custom sidebar templates, must be a dictionary that maps document names
+# to template names.
+#
+# The default sidebars (for documents that don't match any pattern) are
+# defined by theme itself. Builtin themes are using these templates by
+# default: ``['localtoc.html', 'relations.html', 'sourcelink.html',
+# 'searchbox.html']``.
+#
+# html_sidebars = {}
+
+
+# -- Options for HTMLHelp output ---------------------------------------------
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'python-engineiodoc'
+
+
+# -- Options for LaTeX output ------------------------------------------------
+
+latex_elements = {
+ # The paper size ('letterpaper' or 'a4paper').
+ #
+ # 'papersize': 'letterpaper',
+
+ # The font size ('10pt', '11pt' or '12pt').
+ #
+ # 'pointsize': '10pt',
+
+ # Additional stuff for the LaTeX preamble.
+ #
+ # 'preamble': '',
+
+ # Latex figure (float) alignment
+ #
+ # 'figure_align': 'htbp',
+}
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title,
+# author, documentclass [howto, manual, or own class]).
+latex_documents = [
+ (master_doc, 'python-engineio.tex', 'python-engineio Documentation',
+ 'Miguel Grinberg', 'manual'),
+]
+
+
+# -- Options for manual page output ------------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [
+ (master_doc, 'python-engineio', 'python-engineio Documentation',
+ [author], 1)
+]
+
+
+# -- Options for Texinfo output ----------------------------------------------
+
+# Grouping the document tree into Texinfo files. List of tuples
+# (source start file, target name, title, author,
+# dir menu entry, description, category)
+texinfo_documents = [
+ (master_doc, 'python-engineio', 'python-engineio Documentation',
+ author, 'python-engineio', 'One line description of project.',
+ 'Miscellaneous'),
+]
+
+
+# -- Options for Epub output -------------------------------------------------
+
+# Bibliographic Dublin Core info.
+epub_title = project
+
+# The unique identifier of the text. This can be a ISBN number
+# or the project homepage.
+#
+# epub_identifier = ''
+
+# A unique identification for the text.
+#
+# epub_uid = ''
+
+# A list of files that should not be packed into the epub file.
+epub_exclude_files = ['search.html']
+
+
+# -- Extension configuration -------------------------------------------------
diff --git a/docs/deployment.rst b/docs/deployment.rst
new file mode 100644
index 0000000..a92e0ba
--- /dev/null
+++ b/docs/deployment.rst
@@ -0,0 +1,279 @@
+Deployment
+==========
+
+The following sections describe a variety of deployment strategies for
+Engine.IO servers.
+
+aiohttp
+-------
+
+`aiohttp <http://aiohttp.readthedocs.io/>`_ provides a framework with support
+for HTTP and WebSocket, based on asyncio. Support for this framework is limited
+to Python 3.5 and newer.
+
+Instances of class ``engineio.AsyncServer`` will automatically use aiohttp
+for asynchronous operations if the library is installed. To request its use
+explicitly, the ``async_mode`` option can be given in the constructor::
+
+ eio = engineio.AsyncServer(async_mode='aiohttp')
+
+A server configured for aiohttp must be attached to an existing application::
+
+ app = web.Application()
+ eio.attach(app)
+
+The aiohttp application can define regular routes that will coexist with the
+Engine.IO server. A typical pattern is to add routes that serve a client
+application and any associated static files.
+
+The aiohttp application is then executed in the usual manner::
+
+ if __name__ == '__main__':
+ web.run_app(app)
+
+Tornado
+-------
+
+`Tornado <http://www.tornadoweb.org//>`_ is a web framework with support
+for HTTP and WebSocket. Support for this framework requires Python 3.5 and
+newer. Only Tornado version 5 and newer are supported, thanks to its tight
+integration with asyncio.
+
+Instances of class ``engineio.AsyncServer`` will automatically use tornado
+for asynchronous operations if the library is installed. To request its use
+explicitly, the ``async_mode`` option can be given in the constructor::
+
+ eio = engineio.AsyncServer(async_mode='tornado')
+
+A server configured for tornado must include a request handler for
+Engine.IO::
+
+ app = tornado.web.Application(
+ [
+ (r"/engine.io/", engineio.get_tornado_handler(eio)),
+ ],
+ # ... other application options
+ )
+
+The tornado application can define other routes that will coexist with the
+Engine.IO server. A typical pattern is to add routes that serve a client
+application and any associated static files.
+
+The tornado application is then executed in the usual manner::
+
+ app.listen(port)
+ tornado.ioloop.IOLoop.current().start()
+
+Sanic
+-----
+
+`Sanic <http://sanic.readthedocs.io/>`_ is a very efficient asynchronous web
+server for Python 3.5 and newer.
+
+Instances of class ``engineio.AsyncServer`` will automatically use Sanic for
+asynchronous operations if the framework is installed. To request its use
+explicitly, the ``async_mode`` option can be given in the constructor::
+
+ eio = engineio.AsyncServer(async_mode='sanic')
+
+A server configured for Sanic must be attached to an existing application::
+
+ app = Sanic()
+ eio.attach(app)
+
+The Sanic application can define regular routes that will coexist with the
+Engine.IO server. A typical pattern is to add routes that serve a client
+application and any associated static files to this application.
+
+The Sanic application is then executed in the usual manner::
+
+ if __name__ == '__main__':
+ app.run()
+
+Uvicorn, Daphne, and other ASGI servers
+---------------------------------------
+
+The ``engineio.ASGIApp`` class is an ASGI compatible application that can
+forward Engine.IO traffic to an ``engineio.AsyncServer`` instance::
+
+ eio = engineio.AsyncServer(async_mode='asgi')
+ app = engineio.ASGIApp(eio)
+
+The application can then be deployed with any ASGI compatible web server.
+
+Eventlet
+--------
+
+`Eventlet <http://eventlet.net/>`_ is a high performance concurrent networking
+library for Python 2 and 3 that uses coroutines, enabling code to be written in
+the same style used with the blocking standard library functions. An Engine.IO
+server deployed with eventlet has access to the long-polling and WebSocket
+transports.
+
+Instances of class ``engineio.Server`` will automatically use eventlet for
+asynchronous operations if the library is installed. To request its use
+explicitly, the ``async_mode`` option can be given in the constructor::
+
+ eio = engineio.Server(async_mode='eventlet')
+
+A server configured for eventlet is deployed as a regular WSGI application,
+using the provided ``engineio.Middleware``::
+
+ app = engineio.Middleware(eio)
+ import eventlet
+ eventlet.wsgi.server(eventlet.listen(('', 8000)), app)
+
+Using Gunicorn with Eventlet
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+An alternative to running the eventlet WSGI server as above is to use
+`gunicorn <gunicorn.org>`_, a fully featured pure Python web server. The
+command to launch the application under gunicorn is shown below::
+
+ $ gunicorn -k eventlet -w 1 module:app
+
+Due to limitations in its load balancing algorithm, gunicorn can only be used
+with one worker process, so the ``-w 1`` option is required. Note that a
+single eventlet worker can handle a large number of concurrent clients.
+
+Another limitation when using gunicorn is that the WebSocket transport is not
+available, because this transport it requires extensions to the WSGI standard.
+
+Note: Eventlet provides a ``monkey_patch()`` function that replaces all the
+blocking functions in the standard library with equivalent asynchronous
+versions. While python-engineio does not require monkey patching, other
+libraries such as database drivers are likely to require it.
+
+Gevent
+------
+
+`Gevent <http://gevent.org>`_ is another asynchronous framework based on
+coroutines, very similar to eventlet. An Engine.IO server deployed with
+gevent has access to the long-polling transport. If project
+`gevent-websocket <https://bitbucket.org/Jeffrey/gevent-websocket/>`_ is
+installed, the WebSocket transport is also available. Note that when using the
+uWSGI server, the native WebSocket implementation of uWSGI can be used instead
+of gevent-websocket (see next section for details on this).
+
+Instances of class ``engineio.Server`` will automatically use gevent for
+asynchronous operations if the library is installed and eventlet is not
+installed. To request gevent to be selected explicitly, the ``async_mode``
+option can be given in the constructor::
+
+ # gevent alone or with gevent-websocket
+ eio = engineio.Server(async_mode='gevent')
+
+A server configured for gevent is deployed as a regular WSGI application,
+using the provided ``engineio.Middleware``::
+
+ from gevent import pywsgi
+ app = engineio.Middleware(eio)
+ pywsgi.WSGIServer(('', 8000), app).serve_forever()
+
+If the WebSocket transport is installed, then the server must be started as
+follows::
+
+ from gevent import pywsgi
+ from geventwebsocket.handler import WebSocketHandler
+ app = engineio.Middleware(eio)
+ pywsgi.WSGIServer(('', 8000), app,
+ handler_class=WebSocketHandler).serve_forever()
+
+Using Gunicorn with Gevent
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+An alternative to running the gevent WSGI server as above is to use
+`gunicorn <gunicorn.org>`_, a fully featured pure Python web server. The
+command to launch the application under gunicorn is shown below::
+
+ $ gunicorn -k gevent -w 1 module:app
+
+Or to include WebSocket::
+
+ $ gunicorn -k geventwebsocket.gunicorn.workers.GeventWebSocketWorker -w 1 module: app
+
+Same as with eventlet, due to limitations in its load balancing algorithm,
+gunicorn can only be used with one worker process, so the ``-w 1`` option is
+required. Note that a single gevent worker can handle a large number of
+concurrent clients.
+
+Note: Gevent provides a ``monkey_patch()`` function that replaces all the
+blocking functions in the standard library with equivalent asynchronous
+versions. While python-engineio does not require monkey patching, other
+libraries such as database drivers are likely to require it.
+
+uWSGI
+-----
+
+When using the uWSGI server in combination with gevent, the Engine.IO server
+can take advantage of uWSGI's native WebSocket support.
+
+Instances of class ``engineio.Server`` will automatically use this option for
+asynchronous operations if both gevent and uWSGI are installed and eventlet is
+not installed. To request this asynchoronous mode explicitly, the
+``async_mode`` option can be given in the constructor::
+
+ # gevent with uWSGI
+ eio = engineio.Server(async_mode='gevent_uwsgi')
+
+A complete explanation of the configuration and usage of the uWSGI server is
+beyond the scope of this documentation. The uWSGI server is a fairly complex
+package that provides a large and comprehensive set of options. It must be
+compiled with WebSocket and SSL support for the WebSocket transport to be
+available. As way of an introduction, the following command starts a uWSGI
+server for the ``latency.py`` example on port 5000::
+
+ $ uwsgi --http :5000 --gevent 1000 --http-websockets --master --wsgi-file latency.py --callable app
+
+Standard Threads
+----------------
+
+While not comparable to eventlet and gevent in terms of performance,
+the Engine.IO server can also be configured to work with multi-threaded web
+servers that use standard Python threads. This is an ideal setup to use with
+development servers such as `Werkzeug <http://werkzeug.pocoo.org>`_. Only the
+long-polling transport is currently available when using standard threads.
+
+Instances of class ``engineio.Server`` will automatically use the threading
+mode if neither eventlet nor gevent are not installed. To request the
+threading mode explicitly, the ``async_mode`` option can be given in the
+constructor::
+
+ eio = engineio.Server(async_mode='threading')
+
+A server configured for threading is deployed as a regular web application,
+using any WSGI complaint multi-threaded server. The example below deploys an
+Engine.IO application combined with a Flask web application, using Flask's
+development web server based on Werkzeug::
+
+ eio = engineio.Server(async_mode='threading')
+ app = Flask(__name__)
+ app.wsgi_app = engineio.Middleware(eio, app.wsgi_app)
+
+ # ... Engine.IO and Flask handler functions ...
+
+ if __name__ == '__main__':
+ app.run(threaded=True)
+
+When using the threading mode, it is important to ensure that the WSGI server
+can handle multiple concurrent requests using threads, since a client can have
+up to two outstanding requests at any given time. The Werkzeug server is
+single-threaded by default, so the ``threaded=True`` option is required.
+
+Note that servers that use worker processes instead of threads, such as
+gunicorn, do not support an Engine.IO server configured in threading mode.
+
+Scalability Notes
+-----------------
+
+Engine.IO is a stateful protocol, which makes horizontal scaling more
+difficult. To deploy a cluster of Engine.IO processes hosted on one or
+multiple servers the following conditions must be met:
+
+- Each Engine.IO server process must be able to handle multiple requests
+ concurrently. This is required because long-polling clients send two
+ requests in parallel. Worker processes that can only handle one request at a
+ time are not supported.
+- The load balancer must be configured to always forward requests from a client
+ to the same process. Load balancers call this *sticky sessions*, or
+ *session affinity*.
diff --git a/docs/index.rst b/docs/index.rst
new file mode 100644
index 0000000..0d672a7
--- /dev/null
+++ b/docs/index.rst
@@ -0,0 +1,24 @@
+.. python-engineio documentation master file, created by
+ sphinx-quickstart on Sat Nov 24 09:42:25 2018.
+ You can adapt this file completely to your liking, but it should at least
+ contain the root `toctree` directive.
+
+python-engineio
+===============
+
+This project implements an Engine.IO server that can run standalone or
+integrated with a variety of Python web frameworks.
+
+.. toctree::
+ :maxdepth: 2
+
+ intro
+ deployment
+ api
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
diff --git a/docs/intro.rst b/docs/intro.rst
new file mode 100644
index 0000000..84bd9fb
--- /dev/null
+++ b/docs/intro.rst
@@ -0,0 +1,148 @@
+.. engineio documentation master file, created by
+ sphinx-quickstart on Sat Jun 13 23:41:23 2015.
+ You can adapt this file completely to your liking, but it should at least
+ contain the root `toctree` directive.
+
+Getting Started
+===============
+
+What is Engine.IO?
+------------------
+
+Engine.IO is a lightweight transport protocol that enables real-time
+bidirectional event-based communication between clients (typically web
+browsers) and a server. The official implementations of the client and
+server components are written in JavaScript.
+
+The Engine.IO protocol is extremely simple. The example that follows shows the
+client-side Javascript code required to setup an Engine.IO connection to
+a server::
+
+ var socket = eio('http://chat.example.com');
+ socket.on('open', function() { alert('connected'); });
+ socket.on('message', function(data) { alert(data); });
+ socket.on('close', function() { alert('disconnected'); });
+ socket.send('Hello from the client!');
+
+Features
+--------
+
+- Fully compatible with the Javascript
+ `engine.io-client <https://github.com/Automattic/engine.io-client>`_ library,
+ and with other Engine.IO clients.
+- Compatible with Python 2.7 and Python 3.3+.
+- Supports large number of clients even on modest hardware due to being
+ asynchronous.
+- Compatible with `aiohttp <http://aiohttp.readthedocs.io/>`_,
+ `sanic <http://sanic.readthedocs.io/>`_,
+ `tornado <http://www.tornadoweb.org/>`_,
+ `eventlet <http://eventlet.net/>`_,
+ `gevent <http://gevent.org>`_,
+ or any `WSGI <https://wsgi.readthedocs.io/en/latest/index.html>`_ or
+ `ASGI <https://asgi.readthedocs.io/en/latest/>`_ compatible server.
+- Includes WSGI and ASGI middlewares that integrate Engine.IO traffic with
+ other web applications.
+- Uses an event-based architecture implemented with decorators that hides the
+ details of the protocol.
+- Implements HTTP long-polling and WebSocket transports.
+- Supports XHR2 and XHR browsers as clients.
+- Supports text and binary messages.
+- Supports gzip and deflate HTTP compression.
+- Configurable CORS responses to avoid cross-origin problems with browsers.
+
+Examples
+--------
+
+The following application is a basic example that uses the Eventlet
+asynchronous server and includes a small Flask application that serves the
+HTML/Javascript to the client::
+
+ import engineio
+ import eventlet
+ from flask import Flask, render_template
+
+ eio = engineio.Server()
+ app = Flask(__name__)
+
+ @app.route('/')
+ def index():
+ """Serve the client-side application."""
+ return render_template('index.html')
+
+ @eio.on('connect')
+ def connect(sid, environ):
+ print("connect ", sid)
+
+ @eio.on('message')
+ def message(sid, data):
+ print("message ", data)
+ eio.send(sid, 'reply')
+
+ @eio.on('disconnect')
+ def disconnect(sid):
+ print('disconnect ', sid)
+
+ if __name__ == '__main__':
+ # wrap Flask application with engineio's middleware
+ app = engineio.Middleware(eio, app)
+
+ # deploy as an eventlet WSGI server
+ eventlet.wsgi.server(eventlet.listen(('', 8000)), app)
+
+Below is a similar application, coded for asyncio (Python 3.5+ only) with the
+aiohttp framework::
+
+ from aiohttp import web
+ import engineio
+
+ eio = engineio.AsyncServer()
+ app = web.Application()
+
+ # attach the Engine.IO server to the application
+ eio.attach(app)
+
+ async def index(request):
+ """Serve the client-side application."""
+ with open('index.html') as f:
+ return web.Response(text=f.read(), content_type='text/html')
+
+ @eio.on('connect')
+ def connect(sid, environ):
+ print("connect ", sid)
+
+ @eio.on('message')
+ async def message(sid, data):
+ print("message ", data)
+ await eio.send(sid, 'reply')
+
+ @eio.on('disconnect')
+ def disconnect(sid):
+ print('disconnect ', sid)
+
+ app.router.add_static('/static', 'static')
+ app.router.add_get('/', index)
+
+ if __name__ == '__main__':
+ # run the aiohttp application
+ web.run_app(app)
+
+The client-side application must include the
+`engine.io-client <https://github.com/Automattic/engine.io-client>`_ library
+(version 1.5.0 or newer recommended).
+
+Each time a client connects to the server the ``connect`` event handler is
+invoked with the ``sid`` (session ID) assigned to the connection and the WSGI
+environment dictionary. The server can inspect authentication or other headers
+to decide if the client is allowed to connect. To reject a client the handler
+must return ``False``.
+
+When the client sends a message to the server the ``message`` event handler is
+invoked with the ``sid`` and the message.
+
+Finally, when the connection is broken, the ``disconnect`` event is called,
+allowing the application to perform cleanup.
+
+Because Engine.IO is a bidirectional protocol, the server can send messages to
+any connected client at any time. The ``engineio.Server.send()`` method takes
+the client's ``sid`` and the message payload, which can be of type ``str``,
+``bytes``, ``list`` or ``dict`` (the last two are JSON encoded).
diff --git a/docs/make.bat b/docs/make.bat
new file mode 100644
index 0000000..27f573b
--- /dev/null
+++ b/docs/make.bat
@@ -0,0 +1,35 @@
+@ECHO OFF
+
+pushd %~dp0
+
+REM Command file for Sphinx documentation
+
+if "%SPHINXBUILD%" == "" (
+ set SPHINXBUILD=sphinx-build
+)
+set SOURCEDIR=.
+set BUILDDIR=_build
+
+if "%1" == "" goto help
+
+%SPHINXBUILD% >NUL 2>NUL
+if errorlevel 9009 (
+ echo.
+ echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
+ echo.installed, then set the SPHINXBUILD environment variable to point
+ echo.to the full path of the 'sphinx-build' executable. Alternatively you
+ echo.may add the Sphinx directory to PATH.
+ echo.
+ echo.If you don't have Sphinx installed, grab it from
+ echo.http://sphinx-doc.org/
+ exit /b 1
+)
+
+%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
+goto end
+
+:help
+%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
+
+:end
+popd