Browse Source

add django example for python-socketio

pull/31/head
sillygod 9 years ago
parent
commit
4074cf8272
  1. 0
      examples/django_chat/chat/__init__.py
  2. 3
      examples/django_chat/chat/admin.py
  3. 0
      examples/django_chat/chat/management/__init__.py
  4. 0
      examples/django_chat/chat/management/commands/__init__.py
  5. 108
      examples/django_chat/chat/management/commands/runserver_socketio.py
  6. 0
      examples/django_chat/chat/migrations/__init__.py
  7. 3
      examples/django_chat/chat/models.py
  8. 64
      examples/django_chat/chat/sockets.py
  9. 91
      examples/django_chat/chat/templates/base.html
  10. 3
      examples/django_chat/chat/tests.py
  11. 13
      examples/django_chat/chat/urls.py
  12. 6
      examples/django_chat/chat/views.py
  13. BIN
      examples/django_chat/db.sqlite3
  14. 0
      examples/django_chat/django_chat/__init__.py
  15. 105
      examples/django_chat/django_chat/settings.py
  16. 11
      examples/django_chat/django_chat/urls.py
  17. 16
      examples/django_chat/django_chat/wsgi.py
  18. 10
      examples/django_chat/manage.py
  19. 18
      examples/django_chat/readme.md
  20. 3
      examples/django_chat/requirement.txt
  21. 103
      examples/django_chat/sdjango/__init__.py
  22. 22
      examples/django_chat/sdjango/sd_manager.py
  23. 64
      examples/django_chat/sdjango/sd_middleware.py
  24. 0
      examples/flask_chat/README.rst
  25. 0
      examples/flask_chat/app.py
  26. 0
      examples/flask_chat/latency.py
  27. 0
      examples/flask_chat/requirements.txt
  28. 0
      examples/flask_chat/static/style.css
  29. 0
      examples/flask_chat/templates/index.html
  30. 0
      examples/flask_chat/templates/latency.html

0
examples/django_chat/chat/__init__.py

3
examples/django_chat/chat/admin.py

@ -0,0 +1,3 @@
from django.contrib import admin
# Register your models here.

0
examples/django_chat/chat/management/__init__.py

0
examples/django_chat/chat/management/commands/__init__.py

108
examples/django_chat/chat/management/commands/runserver_socketio.py

@ -0,0 +1,108 @@
from re import match
from _thread import start_new_thread
from time import sleep
from os import getpid, kill, environ
from signal import SIGINT
import six
import copy
from django.conf import settings
from django.core.handlers.wsgi import WSGIHandler
from django.core.management.base import BaseCommand, CommandError
from django.core.management.commands.runserver import naiveip_re, DEFAULT_PORT
from django.utils.autoreload import code_changed, restart_with_reloader
from django.core.wsgi import get_wsgi_application
# from gevent import pywsgi
from sdjango import autodiscover
from sdjango import namespace
from sdjango.sd_manager import SdManager
from sdjango.sd_middleware import SdMiddleware
import socketio
import eventlet
RELOAD = False
def reload_watcher():
global RELOAD
while True:
RELOAD = code_changed()
if RELOAD:
kill(getpid(), SIGINT)
restart_with_reloader()
sleep(1)
class Command(BaseCommand):
def add_arguments(self, parser):
parser.add_argument('addrport', nargs='?', help='Optional port number, or ipaddr:port')
def handle(self, *args, **options):
from django.utils import translation
from django.conf import settings
translation.activate(settings.LANGUAGE_CODE)
addrport = options.get('addrport', None)
if addrport is None:
self.addr = ''
self.port = DEFAULT_PORT
else:
m = match(naiveip_re, addrport)
if m is None:
raise CommandError('"%s" is not a valid port number '
'or address:port pair.' % options['addrport'])
self.addr, _ipv4, ipv6, _fqdn, self.port = m.groups()
if not self.port.isdigit():
raise CommandError('"%s" is not a valid port number' % self.port)
if not self.addr:
self.addr = '127.0.0.1'
# Make the port available here for the path:
# socketio_tags.socketio ->
# socketio_scripts.html ->
# io.Socket JS constructor
# allowing the port to be set as the client-side default there.
environ["DJANGO_SOCKETIO_PORT"] = str(self.port)
if settings.DEBUG is True:
start_new_thread(reload_watcher, ())
try:
bind = (self.addr, int(self.port))
print("SocketIOServer running on %s:%s" % bind)
handler = self.get_handler(*args, **options)
# sio = socketio.Server(client_manager=SdManager(), async_mode='gevent')
sio = socketio.Server(client_manager=SdManager(), async_mode='eventlet')
autodiscover()
namespace.insert_in_server(sio)
app = get_wsgi_application()
app = SdMiddleware(sio, handler)
eventlet.wsgi.server(eventlet.listen(bind), app)
except KeyboardInterrupt:
# eventlet server will handle exception
# server.stop()
# if RELOAD:
# print("Reloading...")
# restart_with_reloader()
pass
def get_handler(self, *args, **options):
"""
Returns the django.contrib.staticfiles handler.
"""
handler = WSGIHandler()
try:
from django.contrib.staticfiles.handlers import StaticFilesHandler
except ImportError:
return handler
use_static_handler = options.get('use_static_handler', True)
insecure_serving = options.get('insecure_serving', False)
if (settings.DEBUG and use_static_handler or
(use_static_handler and insecure_serving)):
handler = StaticFilesHandler(handler)
return handler

0
examples/django_chat/chat/migrations/__init__.py

3
examples/django_chat/chat/models.py

@ -0,0 +1,3 @@
from django.db import models
# Create your models here.

64
examples/django_chat/chat/sockets.py

@ -0,0 +1,64 @@
import logging
from sdjango import namespace
online_user_num = 0
@namespace('/test')
class TestNamespace:
def __init__(self, name):
self.name = name
self.request = None # django request object
def _get_socket(self, sid):
socket = namespace.server.eio._get_socket(sid)
return socket
def _get_request(self, sid):
socket = self._get_socket(sid)
return socket._request
def emit(self, *args, **kwargs):
if 'namespace' not in kwargs:
kwargs['namespace'] = self.name
namespace.server.emit(*args, **kwargs)
def on_my_event(self, sid, message):
self.emit('my response', {'data': message['data']}, room=sid)
def on_my_broadcast_event(self, sid, message):
self.emit('my response', {'data': message['data']})
def on_join(self, sid, message):
namespace.server.enter_room(sid, message['room'], namespace='/test')
self.emit('my response', {'data': 'Entered room: '+message['room']}, room=sid)
def on_leave(self, sid, message):
namespace.server.leave_room(sid, message['room'], namespace='/test')
self.emit('my response', {'data': 'Left room:'+message['room']}, room=sid)
def on_close_room(self, sid, message):
self.emit('my response', {'data': 'Room '+message['room']+ ' is closing'},
room=message['room'])
namespace.server.close_room(message['room'], namespace='/test')
def on_my_room_event(self, sid, message):
self.emit('my response', {'data': message['data']}, room=message['room'])
def on_disconnect_request(self, sid):
namespace.server.disconnect(sid, namespace='/test')
# two method must have
def on_connect(self, sid, environ):
if 'django_request' in environ:
request = environ['django_request']
socket = self._get_socket(sid)
socket._request = request
self.emit('my response', {'data': "{} Connected".format(request.user), "count": 0}, room=sid)
def on_disconnect(self, sid):
print('Client disconnected')

91
examples/django_chat/chat/templates/base.html

@ -0,0 +1,91 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Django-SocketIO Test</title>
<script type="text/javascript" src="//code.jquery.com/jquery-2.1.4.min.js"></script>
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/socket.io/1.3.5/socket.io.min.js"></script>
<script type="text/javascript" charset="utf-8">
$(document).ready(function(){
namespace = '/test';
var socket = io.connect('http://' + document.domain + ':' + location.port + namespace);
socket.on('connect', function() {
socket.emit('my event', {data: 'I\'m connected!'});
});
socket.on('disconnect', function() {
$('#log').append('<br>Disconnected');
});
socket.on('my response', function(msg) {
$('#log').append('<br>Received: ' + msg.data);
});
// event handler for server sent data
// the data is displayed in the "Received" section of the page
// handlers for the different forms in the page
// these send data to the server in a variety of ways
$('form#emit').submit(function(event) {
socket.emit('my event', {data: $('#emit_data').val()});
return false;
});
$('form#broadcast').submit(function(event) {
socket.emit('my broadcast event', {data: $('#broadcast_data').val()});
return false;
});
$('form#join').submit(function(event) {
socket.emit('join', {room: $('#join_room').val()});
return false;
});
$('form#leave').submit(function(event) {
socket.emit('leave', {room: $('#leave_room').val()});
return false;
});
$('form#send_room').submit(function(event) {
socket.emit('my room event', {room: $('#room_name').val(), data: $('#room_data').val()});
return false;
});
$('form#close').submit(function(event) {
socket.emit('close room', {room: $('#close_room').val()});
return false;
});
$('form#disconnect').submit(function(event) {
socket.emit('disconnect request');
return false;
});
});
</script>
</head>
<body>
<h1>Flask-SocketIO Test</h1>
<h2>Send:</h2>
<form id="emit" method="POST" action='#'>
<input type="text" name="emit_data" id="emit_data" placeholder="Message">
<input type="submit" value="Echo">
</form>
<form id="broadcast" method="POST" action='#'>
<input type="text" name="broadcast_data" id="broadcast_data" placeholder="Message">
<input type="submit" value="Broadcast">
</form>
<form id="join" method="POST" action='#'>
<input type="text" name="join_room" id="join_room" placeholder="Room Name">
<input type="submit" value="Join Room">
</form>
<form id="leave" method="POST" action='#'>
<input type="text" name="leave_room" id="leave_room" placeholder="Room Name">
<input type="submit" value="Leave Room">
</form>
<form id="send_room" method="POST" action='#'>
<input type="text" name="room_name" id="room_name" placeholder="Room Name">
<input type="text" name="room_data" id="room_data" placeholder="Message">
<input type="submit" value="Send to Room">
</form>
<form id="close" method="POST" action="#">
<input type="text" name="close_room" id="close_room" placeholder="Room Name">
<input type="submit" value="Close Room">
</form>
<form id="disconnect" method="POST" action="#">
<input type="submit" value="Disconnect">
</form>
<h2>Receive:</h2>
<div><p id="log"></p></div>
</body>
</html>

3
examples/django_chat/chat/tests.py

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

13
examples/django_chat/chat/urls.py

@ -0,0 +1,13 @@
from django.conf.urls import (
url, patterns, include
)
import sdjango
from .views import socket_base
urlpatterns = [
url(r'^socket\.io', include(sdjango.urls)),
url(r'^$', socket_base, name='socket_base'),
]

6
examples/django_chat/chat/views.py

@ -0,0 +1,6 @@
from django.shortcuts import render
def socket_base(request, template="base.html"):
context={}
return render(request, template, context)

BIN
examples/django_chat/db.sqlite3

Binary file not shown.

0
examples/django_chat/django_chat/__init__.py

105
examples/django_chat/django_chat/settings.py

@ -0,0 +1,105 @@
"""
Django settings for django_chat project.
Generated by 'django-admin startproject' using Django 1.8.
For more information on this file, see
https://docs.djangoproject.com/en/1.8/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/1.8/ref/settings/
"""
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
import os
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.8/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'n_&k)3!sn-79f5=g93(t$&a09*b@6w)4hf!2e%hbdp=3v-e(v9'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = (
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
# local app
'chat',
)
MIDDLEWARE_CLASSES = (
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'django.middleware.security.SecurityMiddleware',
)
ROOT_URLCONF = 'django_chat.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
WSGI_APPLICATION = 'django_chat.wsgi.application'
# Database
# https://docs.djangoproject.com/en/1.8/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
# Internationalization
# https://docs.djangoproject.com/en/1.8/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.8/howto/static-files/
STATIC_URL = '/static/'

11
examples/django_chat/django_chat/urls.py

@ -0,0 +1,11 @@
from django.conf.urls import include, url
from django.contrib import admin
urlpatterns = [
# Examples:
# url(r'^$', 'django_chat.views.home', name='home'),
# url(r'^blog/', include('blog.urls')),
url(r'^admin/', include(admin.site.urls)),
url('', include('chat.urls')),
]

16
examples/django_chat/django_chat/wsgi.py

@ -0,0 +1,16 @@
"""
WSGI config for django_chat project.
It exposes the WSGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/1.8/howto/deployment/wsgi/
"""
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "django_chat.settings")
application = get_wsgi_application()

10
examples/django_chat/manage.py

@ -0,0 +1,10 @@
#!/usr/bin/env python
import os
import sys
if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "django_chat.settings")
from django.core.management import execute_from_command_line
execute_from_command_line(sys.argv)

18
examples/django_chat/readme.md

@ -0,0 +1,18 @@
# python-socketio with django example
This example is for who wants to use django with pyton-socketio. Some tricks used in this example is inspired by gevent-socketio.
# How to Setup
```sh
pip install -r requirement.txt
python manage.py migrate
```
# How to Run
```sh
python manage.py runserver_socketio
```
open http://127.0.0.1:8000/ with your browser to see the result

3
examples/django_chat/requirement.txt

@ -0,0 +1,3 @@
Django<1.9
eventlet
python-socketio

103
examples/django_chat/sdjango/__init__.py

@ -0,0 +1,103 @@
import logging
import inspect
from django.http import HttpResponse
from django.views.decorators.csrf import csrf_exempt
from django.core.wsgi import get_wsgi_application
try:
# Django version >= 1.9
from django.utils.module_loading import import_module
except ImportError:
# Django version < 1.9
from django.utils.importlib import import_module
from django.conf.urls import patterns, url, include
LOADING_SOCKETIO = False
def autodiscover():
"""
Auto-discover INSTALLED_APPS sockets.py modules and fail silently when
not present. NOTE: socketio_autodiscover was inspired/copied from
django.contrib.admin autodiscover
"""
global LOADING_SOCKETIO
if LOADING_SOCKETIO:
return
LOADING_SOCKETIO = True
import imp
from django.conf import settings
for app in settings.INSTALLED_APPS:
try:
app_path = import_module(app).__path__
except AttributeError:
continue
try:
imp.find_module('sockets', app_path)
except ImportError:
continue
import_module("%s.sockets" % app)
LOADING_SOCKETIO = False
class namespace:
"""This is a event handler keeper for socketio event
used as a decorators
"""
handler_container = {}
server = None
def __init__(self, name=''):
if not name.startswith('/'):
self.name = '/'+name
self.name = name
def __call__(self, handler):
instance = handler(self.name)
if self.name not in namespace.handler_container:
namespace.handler_container[self.name] = []
methods = inspect.getmembers(instance, predicate=inspect.ismethod)
for key, value in methods:
if key.startswith('on_'):
namespace.handler_container[self.name].append(value)
return True
@classmethod
def insert_in_server(cls, server):
"""a special method to dynamic add event for socketio server
"""
namespace.server = server
for name, handlers in namespace.handler_container.items():
for obj in handlers:
event_name = obj.__name__.replace('on_', '').replace('_', ' ')
server.on(event_name, obj, name)
namespace.handler_container = {} # reset to empty dict
@csrf_exempt
def socketio(request):
try:
request.environ['django_request'] = request
except:
logging.getLogger("socketio").error("Exception while handling socketio connection", exc_info=True)
return HttpResponse(200)
urls = patterns("", (r'', socketio))

22
examples/django_chat/sdjango/sd_manager.py

@ -0,0 +1,22 @@
from socketio.base_manager import BaseManager
class SdManager(BaseManager):
"""
"""
def initialize(self, server):
# import pdb; pdb.set_trace()
super().initialize(server)
def connect(self, sid, namespace):
"""Register a client connection to a namespace.
and set the django request object?
"""
# TODO: process user authentication here?
# if 'django_request' in self.server.environ[sid]:
# print(self.server.environ[sid]['django_request'].user)
self.enter_room(sid, namespace, None)
self.enter_room(sid, namespace, sid)

64
examples/django_chat/sdjango/sd_middleware.py

@ -0,0 +1,64 @@
import urllib
import engineio
class SdMiddleware(engineio.Middleware):
"""WSGI middleware for Socket.IO.
This middleware dispatches traffic to a Socket.IO application, and
optionally forwards regular HTTP traffic to a WSGI application.
:param socketio_app: The Socket.IO server.
:param wsgi_app: The WSGI app that receives all other traffic.
:param socketio_path: The endpoint where the Socket.IO application should
be installed. The default value is appropriate for
most cases.
Example usage::
import socketio
import eventlet
from . import wsgi_app
sio = socketio.Server()
app = socketio.Middleware(sio, wsgi_app)
eventlet.wsgi.server(eventlet.listen(('', 8000)), app)
"""
def __init__(self, socketio_app, wsgi_app=None, socketio_path='socket.io'):
super().__init__(socketio_app, wsgi_app, socketio_path)
def __call__(self, environ, start_response):
if 'gunicorn.socket' in environ:
# gunicorn saves the socket under environ['gunicorn.socket'], while
# eventlet saves it under environ['eventlet.input']. Eventlet also
# stores the socket inside a wrapper class, while gunicon writes it
# directly into the environment. To give eventlet's WebSocket
# module access to this socket when running under gunicorn, here we
# copy the socket to the eventlet format.
class Input(object):
def __init__(self, socket):
self.socket = socket
def get_socket(self):
return self.socket
environ['eventlet.input'] = Input(environ['gunicorn.socket'])
path = environ['PATH_INFO']
if path is not None and \
path.startswith('/{0}/'.format(self.engineio_path)):
query = urllib.parse.parse_qs(environ.get('QUERY_STRING', ''))
sid = query.get('sid', None)
if sid is None:
self.wsgi_app(environ, start_response)
engineio_res = self.engineio_app.handle_request(environ, start_response)
return engineio_res
elif self.wsgi_app is not None:
return self.wsgi_app(environ, start_response)
else:
start_response("404 Not Found", [('Content-type', 'text/plain')])
return ['Not Found']

0
examples/README.rst → examples/flask_chat/README.rst

0
examples/app.py → examples/flask_chat/app.py

0
examples/latency.py → examples/flask_chat/latency.py

0
examples/requirements.txt → examples/flask_chat/requirements.txt

0
examples/static/style.css → examples/flask_chat/static/style.css

0
examples/templates/index.html → examples/flask_chat/templates/index.html

0
examples/templates/latency.html → examples/flask_chat/templates/latency.html

Loading…
Cancel
Save