├── templates ├── track.html ├── main.html └── pymeetups.html ├── requirements.txt ├── .gitignore ├── request-track.py ├── README.md ├── LICENSE └── app.py /templates/track.html: -------------------------------------------------------------------------------- 1 | 2 | Django District 3 | 4 |

Django Distrct

5 |

trackdata received.

6 | 7 | 8 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | bidict==0.21.2 2 | certifi==2020.12.5 3 | chardet==4.0.0 4 | click==7.1.2 5 | Flask==1.1.2 6 | Flask-SocketIO==5.0.1 7 | gevent==20.12.1 8 | gevent-websocket==0.10.1 9 | greenlet==0.4.17 10 | idna==2.10 11 | itsdangerous==1.1.0 12 | Jinja2==2.11.2 13 | MarkupSafe==1.1.1 14 | python-engineio==4.0.0 15 | python-socketio==5.0.4 16 | redis==3.5.3 17 | requests==2.25.1 18 | urllib3==1.26.2 19 | Werkzeug==1.0.1 20 | zope.event==4.5.0 21 | zope.interface==5.2.0 22 | -------------------------------------------------------------------------------- /templates/main.html: -------------------------------------------------------------------------------- 1 | 2 | Django District 3 | 4 |

Django Distrct

5 |

{{ connected }} 6 | users are on this page right now.

7 | 8 | 10 | 11 | 12 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | 5 | # C extensions 6 | *.so 7 | 8 | # Distribution / packaging 9 | .Python 10 | env/ 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | lib/ 17 | lib64/ 18 | parts/ 19 | sdist/ 20 | var/ 21 | *.egg-info/ 22 | .installed.cfg 23 | *.egg 24 | 25 | # PyInstaller 26 | # Usually these files are written by a python script from a template 27 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 28 | *.manifest 29 | *.spec 30 | 31 | # Installer logs 32 | pip-log.txt 33 | pip-delete-this-directory.txt 34 | 35 | # Unit test / coverage reports 36 | htmlcov/ 37 | .tox/ 38 | .coverage 39 | .cache 40 | nosetests.xml 41 | coverage.xml 42 | 43 | # Translations 44 | *.mo 45 | *.pot 46 | 47 | # Django stuff: 48 | *.log 49 | 50 | # Sphinx documentation 51 | docs/_build/ 52 | 53 | # PyBuilder 54 | target/ 55 | -------------------------------------------------------------------------------- /request-track.py: -------------------------------------------------------------------------------- 1 | import requests, json 2 | 3 | URL = 'http://localhost:5000/track' 4 | 5 | params = { 6 | 'dept': 'Dept', 7 | 'mcode': 'MCODE', 8 | 'device': 'Device', 9 | 'agency': 'Agency', 10 | 'name': 'Name', 11 | 'mobile': 'Mobile', 12 | 'parent_name': 'ParentName', 13 | 'parent_mobile': 'ParentMobile', 14 | 'call_date': '2020-12-30', 15 | 'image_url': 'https://example.com/image.jpg', 16 | 'lon': 127.269311, 17 | 'lat': 126.734086, 18 | 'geom': 'GeomText', 19 | 'init_time': '2020-12-30 16:59', 20 | 'address': 'Address', 21 | # 'addr': settlements 22 | } 23 | params = ( 24 | ('name', params['name']), 25 | ('mobile', params['mobile']), 26 | ('parent_name', params['parent_name']), 27 | ('parent_mobile', params['parent_mobile']), 28 | ('address', params['address']), 29 | ('image_url', params['image_url']) 30 | ) 31 | headers = {} 32 | 33 | res = requests.get(URL, headers=headers, params=params) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Async Python Web Apps with WebSockets Demo Code 2 | Example code for my live coded demo at the January 2015 3 | [SF Python meetup](http://www.meetup.com/sfpython/events/219577721/) 4 | and updated for 5 | [Django District](http://www.meetup.com/django-district/events/220439364/) 6 | in March 2015. 7 | 8 | Note: I ran this demo with gunicorn behind an 9 | [Nginx](https://www.fullstackpython.com/nginx.html) reverse proxy with 10 | the appropriate WebSocket configuraiton .conf file. There can be issues 11 | upgrading the connection via the local Flask development server. 12 | 13 | Watch the [live-coded demo video for full effect](https://www.youtube.com/watch?v=L5YQbNrFfyw). The [slides are available](http://www.mattmakai.com/presentations/2015-sfpython-websockets.html) 14 | but fair warning, they won't make much sense without corresponding audio/video. 15 | 16 | This talk goes along with the 17 | [Full Stack Python WebSockets page](http://www.fullstackpython.com/websockets.html) 18 | and 19 | [Resources for WebSockets with Python](http://www.mattmakai.com/websockets-python-resources.html) 20 | blog post. 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Matthew Makai 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /templates/pymeetups.html: -------------------------------------------------------------------------------- 1 | 2 | Django District 3 | 4 |

In what cities other than DC have you gone to Python meetups?

5 |
6 | 7 | 8 | 9 |
10 |
11 | 12 | 14 | 15 | 16 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /app.py: -------------------------------------------------------------------------------- 1 | from gevent import monkey 2 | import cgi 3 | import redis 4 | from flask import Flask, render_template, request 5 | from flask_socketio import SocketIO 6 | from engineio.payload import Payload 7 | 8 | monkey.patch_all() 9 | Payload.max_decode_packets = 1024 10 | 11 | app = Flask(__name__) 12 | db = redis.StrictRedis('localhost', 6379, 0) 13 | socketio = SocketIO(app) 14 | 15 | 16 | @app.route('/') 17 | def main(): 18 | return render_template('main.html') 19 | 20 | 21 | @app.route('/track') 22 | def track(): 23 | print(request.args.get('name'), request.args.get('mobile')) 24 | data = { 25 | 'track': { 26 | 'name': request.args.get('name'), 27 | 'mobile': request.args.get('mobile'), 28 | 'parent_name': request.args.get('parent_name'), 29 | 'parent_mobile': request.args.get('parent_mobile'), 30 | 'image_url': request.args.get('image_url'), 31 | 'address': request.args.get('address') 32 | }} 33 | socketio.emit('msg', data, namespace='/dd') 34 | return render_template('track.html') 35 | 36 | 37 | @app.route('/pymeetups/') 38 | def pymeetups(): 39 | return render_template('pymeetups.html') 40 | 41 | 42 | @socketio.on('connect', namespace='/dd') 43 | def ws_conn(): 44 | c = db.incr('connected') 45 | socketio.emit('msg', {'count': c}, namespace='/dd') 46 | socketio.emit('msg', {'track': 'track-data'}, namespace='/dd') 47 | 48 | 49 | @socketio.on('disconnect', namespace='/dd') 50 | def ws_disconn(): 51 | c = db.decr('connected') 52 | socketio.emit('msg', {'count': c}, namespace='/dd') 53 | 54 | 55 | @socketio.on('city', namespace='/dd') 56 | def ws_city(message): 57 | print(message['city']) 58 | socketio.emit('city', {'city': cgi.escape(message['city'])}, 59 | namespace="/dd") 60 | 61 | 62 | if __name__ == '__main__': 63 | socketio.run(app, "0.0.0.0", port=5000) 64 | --------------------------------------------------------------------------------