├── dev-requirements.txt
├── .gitignore
├── examples
├── echo
│ ├── echo.py
│ └── templates
│ │ └── index.html
├── echo-gevent
│ ├── echo.py
│ └── templates
│ │ └── index.html
├── echo-asyncio
│ ├── echo.py
│ └── templates
│ │ └── index.html
├── chat-gevent
│ ├── chat.py
│ └── templates
│ │ └── index.html
├── chat-asyncio
│ ├── chat.py
│ └── templates
│ │ └── index.html
└── pubsub-asyncio
│ ├── pubsub.py
│ └── templates
│ └── index.html
├── flask_uwsgi_websocket
├── _async.py
├── __init__.py
├── _uwsgi.py
├── _asyncio.py
├── _gevent.py
└── websocket.py
├── LICENSE
├── setup.py
└── README.rst
/dev-requirements.txt:
--------------------------------------------------------------------------------
1 | Flask
2 | uwsgi
3 | gevent
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.egg-info
2 | *.pyc
3 | *.pyo
4 | dist/
5 | build/
6 |
--------------------------------------------------------------------------------
/examples/echo/echo.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | from flask import Flask, render_template
3 | from flask_uwsgi_websocket import WebSocket
4 |
5 | app = Flask(__name__)
6 | ws = WebSocket(app)
7 |
8 | @app.route('/')
9 | def index():
10 | return render_template('index.html')
11 |
12 | @ws.route('/websocket')
13 | def echo(ws):
14 | while True:
15 | msg = ws.receive()
16 | if msg is not None:
17 | ws.send(msg)
18 | else: return
19 |
20 | if __name__ == '__main__':
21 | app.run(debug=True, threads=16)
22 |
--------------------------------------------------------------------------------
/examples/echo-gevent/echo.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | from flask import Flask, render_template
3 | from flask_uwsgi_websocket import GeventWebSocket
4 |
5 | app = Flask(__name__)
6 | ws = GeventWebSocket(app)
7 |
8 | @app.route('/')
9 | def index():
10 | return render_template('index.html')
11 |
12 | @ws.route('/websocket')
13 | def echo(ws):
14 | while True:
15 | msg = ws.receive()
16 | if msg is not None:
17 | ws.send(msg)
18 | else: return
19 |
20 | if __name__ == '__main__':
21 | app.run(debug=True, gevent=100)
22 |
--------------------------------------------------------------------------------
/flask_uwsgi_websocket/_async.py:
--------------------------------------------------------------------------------
1 | from .websocket import WebSocket, WebSocketClient, WebSocketMiddleware
2 | from ._uwsgi import uwsgi
3 |
4 |
5 | class AsyncWebSocketClient(WebSocketClient):
6 | def receive(self):
7 | while True:
8 | uwsgi.wait_fd_read(self.fd, self.timeout)
9 | uwsgi.suspend()
10 | if uwsgi.ready_fd() == self.fd:
11 | return uwsgi.websocket_recv_nb()
12 |
13 |
14 | class AsyncWebSocketMiddleware(WebSocketMiddleware):
15 | client = AsyncWebSocketClient
16 |
17 |
18 | class AsyncWebSocket(WebSocket):
19 | middleware = AsyncWebSocketMiddleware
20 |
--------------------------------------------------------------------------------
/examples/echo-asyncio/echo.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | from flask import Flask, render_template
3 | from flask_uwsgi_websocket import AsyncioWebSocket
4 | from asyncio import coroutine
5 |
6 | app = Flask(__name__)
7 | ws = AsyncioWebSocket(app)
8 |
9 | @app.route('/')
10 | def index():
11 | return render_template('index.html')
12 |
13 | @ws.route('/websocket')
14 | @coroutine
15 | def echo(ws):
16 | while True:
17 | msg = yield from ws.receive()
18 | if msg is not None:
19 | yield from ws.send(msg)
20 | else: return
21 |
22 | if __name__ == '__main__':
23 | app.run(debug=True, asyncio=100, greenlet=True)
24 |
--------------------------------------------------------------------------------
/examples/chat-gevent/chat.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | from collections import deque
3 | from flask import Flask, render_template
4 | from flask_uwsgi_websocket import GeventWebSocket
5 |
6 | app = Flask(__name__)
7 | ws = GeventWebSocket(app)
8 |
9 | users = {}
10 | backlog = deque(maxlen=10)
11 |
12 | @app.route('/')
13 | def index():
14 | return render_template('index.html')
15 |
16 | @ws.route('/websocket')
17 | def chat(ws):
18 | users[ws.id] = ws
19 |
20 | for msg in backlog:
21 | ws.send(msg)
22 |
23 | while True:
24 | msg = ws.receive()
25 | if msg is not None:
26 | backlog.append(msg)
27 | for id in users:
28 | if id != ws.id:
29 | users[id].send(msg)
30 | else:
31 | break
32 |
33 | del users[ws.id]
34 |
35 | if __name__ == '__main__':
36 | app.run(debug=True, gevent=100)
37 |
--------------------------------------------------------------------------------
/examples/chat-asyncio/chat.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | from collections import deque
3 | from flask import Flask, render_template
4 | from flask_uwsgi_websocket import AsyncioWebSocket
5 | from asyncio import coroutine
6 |
7 | app = Flask(__name__)
8 | ws = AsyncioWebSocket(app)
9 |
10 | users = {}
11 | backlog = deque(maxlen=10)
12 |
13 | @app.route('/')
14 | def index():
15 | return render_template('index.html')
16 |
17 | @ws.route('/websocket')
18 | @coroutine
19 | def chat(ws):
20 | users[ws.id] = ws
21 |
22 | for msg in backlog:
23 | yield from ws.send(msg)
24 |
25 | while True:
26 | msg = yield from ws.receive()
27 | if msg is not None:
28 | backlog.append(msg)
29 | for id in users:
30 | if id != ws.id:
31 | yield from users[id].send(msg)
32 | else:
33 | break
34 |
35 | del users[ws.id]
36 |
37 | if __name__ == '__main__':
38 | app.run(debug=True, asyncio=100, greenlet=True)
39 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2013-2014 Zach Kelling
2 |
3 | Permission is hereby granted, free of charge, to any person
4 | obtaining a copy of this software and associated documentation
5 | files (the "Software"), to deal in the Software without
6 | restriction, including without limitation the rights to use,
7 | copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the
9 | Software is furnished to do so, subject to the following
10 | conditions:
11 |
12 | The above copyright notice and this permission notice shall be
13 | included in all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 | OTHER DEALINGS IN THE SOFTWARE.
23 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | from setuptools import find_packages, setup
3 |
4 | setup(
5 | name='Flask-uWSGI-WebSocket',
6 | version='0.6.1',
7 | url='https://github.com/zeekay/flask-uwsgi-websocket',
8 | license='MIT',
9 | author='Zach Kelling',
10 | author_email='zk@monoid.io',
11 | description='High-performance WebSockets for your Flask apps powered by uWSGI.',
12 | long_description=open('README.rst').read(),
13 | py_modules=['flask_uwsgi_websocket'],
14 | zip_safe=False,
15 | include_package_data=True,
16 | packages=find_packages(),
17 | platforms='any',
18 | install_requires=[
19 | 'Flask',
20 | 'uwsgi',
21 | ],
22 | classifiers=[
23 | 'Environment :: Web Environment',
24 | 'Intended Audience :: Developers',
25 | 'License :: OSI Approved :: MIT License',
26 | 'Operating System :: OS Independent',
27 | 'Programming Language :: Python',
28 | 'Topic :: Internet :: WWW/HTTP :: Dynamic Content',
29 | 'Topic :: Software Development :: Libraries :: Python Modules'
30 | ],
31 | keywords='uwsgi flask websockets'
32 | )
33 |
--------------------------------------------------------------------------------
/flask_uwsgi_websocket/__init__.py:
--------------------------------------------------------------------------------
1 | '''
2 | Flask-uWSGI-WebSocket
3 | ---------------------
4 | High-performance WebSockets for your Flask apps powered by `uWSGI `_.
5 | '''
6 |
7 | __docformat__ = 'restructuredtext'
8 | __version__ = '0.6.1'
9 | __license__ = 'MIT'
10 | __author__ = 'Zach Kelling'
11 |
12 | import sys
13 |
14 | from ._async import *
15 | from ._uwsgi import uwsgi
16 | from .websocket import *
17 |
18 | class GeventNotInstalled(Exception):
19 | pass
20 |
21 | try:
22 | from ._gevent import *
23 | except ImportError:
24 | class GeventWebSocket(object):
25 | def __init__(self, *args, **kwargs):
26 | raise GeventNotInstalled("Gevent must be installed to use GeventWebSocket. Try: `pip install gevent`.")
27 |
28 | class AsyncioNotAvailable(Exception):
29 | pass
30 |
31 | try:
32 | assert sys.version_info > (3,4)
33 | from ._asyncio import *
34 | except (AssertionError, ImportError):
35 | class AsyncioWebSocket(object):
36 | def __init__(self, *args, **kwargs):
37 | raise AsyncioNotAvailable("Asyncio should be enabled at uwsgi compile time. Try: `UWSGI_PROFILE=asyncio pip install uwsgi`.")
38 |
--------------------------------------------------------------------------------
/examples/pubsub-asyncio/pubsub.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | from collections import deque
3 | from flask import Flask, render_template, Blueprint
4 | from flask_uwsgi_websocket import AsyncioWebSocket
5 | import asyncio
6 | import asyncio_redis
7 |
8 | app = Flask(__name__)
9 | wschat = Blueprint('wsBlueprint', __name__)
10 | ws = AsyncioWebSocket(app)
11 |
12 | @app.route('/')
13 | def index():
14 | return render_template('index.html')
15 |
16 | @wschat.route('/')
17 | @asyncio.coroutine
18 | def chat(ws, channel):
19 | yield from ws.send("Welcome to channel <{}>".format(channel))
20 |
21 | asyncio.get_event_loop().create_task(redis_subscribe(ws, channel))
22 | conn = yield from asyncio_redis.Connection.create()
23 |
24 | while True:
25 | msg = yield from ws.receive()
26 | if msg is not None:
27 | yield from conn.publish(channel, msg.decode('utf-8'))
28 | else:
29 | break
30 |
31 | ws.register_blueprint(wschat, url_prefix='/websocket')
32 |
33 | @asyncio.coroutine
34 | def redis_subscribe(ws, channel):
35 | conn = yield from asyncio_redis.Connection.create()
36 | sub = yield from conn.start_subscribe()
37 | yield from sub.subscribe([channel])
38 | while ws.connected:
39 | reply = yield from sub.next_published()
40 | yield from ws.send(reply.value.encode('utf-8'))
41 |
42 | if __name__ == '__main__':
43 | app.run(debug=True, asyncio=100, greenlet=True)
44 |
--------------------------------------------------------------------------------
/examples/echo-gevent/templates/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | WebSocket Echo Example
5 |
6 |
9 |
10 |
11 |
37 |
38 |
39 | WebSocket Echo Example
40 |
44 |
45 |
46 |