diff --git a/examples/django_chat/chat/__init__.py b/examples/django_chat/chat/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/examples/django_chat/chat/admin.py b/examples/django_chat/chat/admin.py
new file mode 100644
index 0000000..8c38f3f
--- /dev/null
+++ b/examples/django_chat/chat/admin.py
@@ -0,0 +1,3 @@
+from django.contrib import admin
+
+# Register your models here.
diff --git a/examples/django_chat/chat/management/__init__.py b/examples/django_chat/chat/management/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/examples/django_chat/chat/management/commands/__init__.py b/examples/django_chat/chat/management/commands/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/examples/django_chat/chat/management/commands/runserver_socketio.py b/examples/django_chat/chat/management/commands/runserver_socketio.py
new file mode 100644
index 0000000..55a0a98
--- /dev/null
+++ b/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
diff --git a/examples/django_chat/chat/migrations/__init__.py b/examples/django_chat/chat/migrations/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/examples/django_chat/chat/models.py b/examples/django_chat/chat/models.py
new file mode 100644
index 0000000..71a8362
--- /dev/null
+++ b/examples/django_chat/chat/models.py
@@ -0,0 +1,3 @@
+from django.db import models
+
+# Create your models here.
diff --git a/examples/django_chat/chat/sockets.py b/examples/django_chat/chat/sockets.py
new file mode 100644
index 0000000..664f98c
--- /dev/null
+++ b/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')
diff --git a/examples/django_chat/chat/templates/base.html b/examples/django_chat/chat/templates/base.html
new file mode 100644
index 0000000..19e11b6
--- /dev/null
+++ b/examples/django_chat/chat/templates/base.html
@@ -0,0 +1,91 @@
+
+
+
+ Django-SocketIO Test
+
+
+
+
+
+ Flask-SocketIO Test
+ Send:
+
+
+
+
+
+
+
+ Receive:
+
+
+
diff --git a/examples/django_chat/chat/tests.py b/examples/django_chat/chat/tests.py
new file mode 100644
index 0000000..7ce503c
--- /dev/null
+++ b/examples/django_chat/chat/tests.py
@@ -0,0 +1,3 @@
+from django.test import TestCase
+
+# Create your tests here.
diff --git a/examples/django_chat/chat/urls.py b/examples/django_chat/chat/urls.py
new file mode 100644
index 0000000..8afd17e
--- /dev/null
+++ b/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'),
+]
diff --git a/examples/django_chat/chat/views.py b/examples/django_chat/chat/views.py
new file mode 100644
index 0000000..8e9a471
--- /dev/null
+++ b/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)
diff --git a/examples/django_chat/django_chat/__init__.py b/examples/django_chat/django_chat/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/examples/django_chat/django_chat/settings.py b/examples/django_chat/django_chat/settings.py
new file mode 100644
index 0000000..8d3e4be
--- /dev/null
+++ b/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/'
diff --git a/examples/django_chat/django_chat/urls.py b/examples/django_chat/django_chat/urls.py
new file mode 100644
index 0000000..d895120
--- /dev/null
+++ b/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')),
+]
diff --git a/examples/django_chat/django_chat/wsgi.py b/examples/django_chat/django_chat/wsgi.py
new file mode 100644
index 0000000..3ed4e71
--- /dev/null
+++ b/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()
diff --git a/examples/django_chat/manage.py b/examples/django_chat/manage.py
new file mode 100755
index 0000000..0f0e198
--- /dev/null
+++ b/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)
diff --git a/examples/django_chat/readme.md b/examples/django_chat/readme.md
new file mode 100644
index 0000000..4303bca
--- /dev/null
+++ b/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
diff --git a/examples/django_chat/requirement.txt b/examples/django_chat/requirement.txt
new file mode 100644
index 0000000..57cfa47
--- /dev/null
+++ b/examples/django_chat/requirement.txt
@@ -0,0 +1,3 @@
+Django<1.9
+eventlet
+python-socketio
diff --git a/examples/django_chat/sdjango/__init__.py b/examples/django_chat/sdjango/__init__.py
new file mode 100644
index 0000000..600aab4
--- /dev/null
+++ b/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))
diff --git a/examples/django_chat/sdjango/sd_manager.py b/examples/django_chat/sdjango/sd_manager.py
new file mode 100644
index 0000000..0e8bf86
--- /dev/null
+++ b/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)
diff --git a/examples/django_chat/sdjango/sd_middleware.py b/examples/django_chat/sdjango/sd_middleware.py
new file mode 100644
index 0000000..1ab446e
--- /dev/null
+++ b/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']
diff --git a/examples/README.rst b/examples/flask_chat/README.rst
similarity index 100%
rename from examples/README.rst
rename to examples/flask_chat/README.rst
diff --git a/examples/app.py b/examples/flask_chat/app.py
similarity index 100%
rename from examples/app.py
rename to examples/flask_chat/app.py
diff --git a/examples/latency.py b/examples/flask_chat/latency.py
similarity index 100%
rename from examples/latency.py
rename to examples/flask_chat/latency.py
diff --git a/examples/requirements.txt b/examples/flask_chat/requirements.txt
similarity index 100%
rename from examples/requirements.txt
rename to examples/flask_chat/requirements.txt
diff --git a/examples/static/style.css b/examples/flask_chat/static/style.css
similarity index 100%
rename from examples/static/style.css
rename to examples/flask_chat/static/style.css
diff --git a/examples/templates/index.html b/examples/flask_chat/templates/index.html
similarity index 100%
rename from examples/templates/index.html
rename to examples/flask_chat/templates/index.html
diff --git a/examples/templates/latency.html b/examples/flask_chat/templates/latency.html
similarity index 100%
rename from examples/templates/latency.html
rename to examples/flask_chat/templates/latency.html