├── .hgignore ├── requirements.txt ├── .gitignore ├── examples ├── chat │ ├── requirements.txt │ ├── README.md │ ├── chat.py │ └── index.tpl └── echo │ ├── requirements.txt │ ├── README.md │ ├── echo.py │ └── index.tpl ├── bottle_websocket ├── __init__.py ├── plugin.py └── server.py ├── README.md ├── setup.py └── LICENSE /.hgignore: -------------------------------------------------------------------------------- 1 | syntax: glob 2 | *.pyc 3 | build/ 4 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | gevent 2 | gevent-websocket 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.egg-info 2 | *.pyc 3 | .idea 4 | dist/ 5 | build/ 6 | -------------------------------------------------------------------------------- /examples/chat/requirements.txt: -------------------------------------------------------------------------------- 1 | bottle 2 | gevent 3 | gevent-websocket 4 | -------------------------------------------------------------------------------- /examples/echo/requirements.txt: -------------------------------------------------------------------------------- 1 | bottle 2 | gevent 3 | gevent-websocket 4 | -------------------------------------------------------------------------------- /bottle_websocket/__init__.py: -------------------------------------------------------------------------------- 1 | from .plugin import websocket 2 | from .server import GeventWebSocketServer 3 | 4 | __all__ = ['websocket', 'GeventWebSocketServer'] 5 | __version__ = '0.2.9' 6 | -------------------------------------------------------------------------------- /bottle_websocket/plugin.py: -------------------------------------------------------------------------------- 1 | from bottle import request 2 | 3 | def websocket(callback): 4 | def wrapper(*args, **kwargs): 5 | callback(request.environ.get('wsgi.websocket'), *args, **kwargs) 6 | 7 | return wrapper 8 | -------------------------------------------------------------------------------- /examples/chat/README.md: -------------------------------------------------------------------------------- 1 | # Chat Example 2 | Simple chat server example. 3 | 4 | ## Install 5 | Install dependencies: 6 | ```bash 7 | $ pip install -r requirements.txt 8 | ``` 9 | 10 | ## Usage 11 | Run the server: 12 | ```bash 13 | $ python chat.py 14 | ``` 15 | -------------------------------------------------------------------------------- /examples/echo/README.md: -------------------------------------------------------------------------------- 1 | # Echo Example 2 | Simple echo server example. 3 | 4 | ## Install 5 | Install dependencies: 6 | ```bash 7 | $ pip install -r requirements.txt 8 | ``` 9 | 10 | ## Usage 11 | Run the server: 12 | ```bash 13 | $ python echo.py 14 | ``` 15 | -------------------------------------------------------------------------------- /examples/echo/echo.py: -------------------------------------------------------------------------------- 1 | from bottle import get, run, template 2 | from bottle.ext.websocket import GeventWebSocketServer 3 | from bottle.ext.websocket import websocket 4 | 5 | @get('/') 6 | def index(): 7 | return template('index') 8 | 9 | @get('/websocket', apply=[websocket]) 10 | def echo(ws): 11 | while True: 12 | msg = ws.receive() 13 | if msg is not None: 14 | ws.send(msg) 15 | else: break 16 | 17 | run(host='127.0.0.1', port=8080, server=GeventWebSocketServer) 18 | -------------------------------------------------------------------------------- /examples/chat/chat.py: -------------------------------------------------------------------------------- 1 | from bottle import get, template, run 2 | from bottle.ext.websocket import GeventWebSocketServer 3 | from bottle.ext.websocket import websocket 4 | 5 | users = set() 6 | 7 | @get('/') 8 | def index(): 9 | return template('index') 10 | 11 | @get('/websocket', apply=[websocket]) 12 | def chat(ws): 13 | users.add(ws) 14 | while True: 15 | msg = ws.receive() 16 | if msg is not None: 17 | for u in users: 18 | u.send(msg) 19 | else: 20 | break 21 | users.remove(ws) 22 | 23 | run(host='127.0.0.1', port=8080, server=GeventWebSocketServer) 24 | -------------------------------------------------------------------------------- /bottle_websocket/server.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from bottle import ServerAdapter 3 | from gevent import pywsgi 4 | from geventwebsocket.handler import WebSocketHandler 5 | from geventwebsocket.logging import create_logger 6 | 7 | 8 | class GeventWebSocketServer(ServerAdapter): 9 | def run(self, handler): 10 | server = pywsgi.WSGIServer((self.host, self.port), handler, handler_class=WebSocketHandler, **self.options) 11 | 12 | if not self.quiet: 13 | server.logger = create_logger('geventwebsocket.logging') 14 | server.logger.setLevel(logging.INFO) 15 | server.logger.addHandler(logging.StreamHandler()) 16 | 17 | server.serve_forever() 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This project adds websocket capabilities to [bottle](http://bottlepy.org), leveraging [gevent-websocket](http://www.gelens.org/code/gevent-websocket/) and [gevent](http://www.gevent.org/). 2 | 3 | ### Install 4 | Use `pip` or `easy_install`: 5 | 6 | pip install bottle-websocket 7 | 8 | ### Usage 9 | Usage is pretty straight-forward, just import the server and plugin: 10 | 11 | ```python 12 | from bottle.ext.websocket import GeventWebSocketServer 13 | from bottle.ext.websocket import websocket 14 | ``` 15 | 16 | You can use the websocket plugin to turn routes websocket handlers, the websocket is passed to the route as the first argument: 17 | 18 | ```python 19 | @get('/websocket', apply=[websocket]) 20 | def echo(ws): 21 | while True: 22 | msg = ws.receive() 23 | if msg is not None: 24 | ws.send(msg) 25 | else: break 26 | ``` 27 | 28 | And then use the provided server: 29 | 30 | ```python 31 | run(host='127.0.0.1', port=8080, server=GeventWebSocketServer) 32 | ``` 33 | 34 | ### Contributors 35 | - [zeekay](https://github.com/zeekay) 36 | - [xeross](https://github.com/xeross) 37 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | 3 | 4 | try: 5 | long_description = open('README.md').read() 6 | except: 7 | long_description = "Easy websockets for bottle." 8 | 9 | setup( 10 | name='bottle-websocket', 11 | version='0.2.9', 12 | license='MIT', 13 | url='https://github.com/zeekay/bottle-websocket', 14 | author='Zach Kelling', 15 | author_email='zk@monoid.io', 16 | packages=['bottle_websocket',], 17 | package_data={'': ['README.md']}, 18 | description='WebSockets for bottle', 19 | long_description=long_description, 20 | long_description_content_type="text/markdown", 21 | install_requires=['bottle', 'gevent-websocket'], 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='bottle websockets', 32 | ) 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012-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 | -------------------------------------------------------------------------------- /examples/chat/index.tpl: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 |