# Path: flask_sockets.py
# class Sockets(object):
# 
#     def __init__(self, app=None):
#         self.app = app
# 
#     def route(self, rule, **options):
# 
#         def decorator(f):
#             @wraps(f)
#             def inner(*args, **kwargs):
#                 return f(request.environ['wsgi.websocket'], *args, **kwargs)
# 
#             if self.app:
#                 endpoint = options.pop('endpoint', None)
#                 self.app.add_url_rule(rule, endpoint, inner, **options)
#             return inner
# 
#         return decorator
# 
# Path: chain/settings.py
# USE_X_FORWARDED_HOST = True
# CORS_ORIGIN_ALLOW_ALL = True
# SITE_ID = 1
# USE_I18N = True
# USE_L10N = True
# USE_TZ = True
# MEDIA_ROOT = ''
# MEDIA_URL = ''
# STATIC_ROOT = '/srv/chain/static/'
# STATIC_URL = '/static/'
# STATICFILES_DIRS = (
#     # Put strings here, like "/home/html/static" or "C:/www/django/static".
#     # Always use forward slashes, even on Windows.
#     # Don't forget to use absolute paths, not relative paths.
# )
# STATICFILES_FINDERS = (
#     'django.contrib.staticfiles.finders.FileSystemFinder',
#     'django.contrib.staticfiles.finders.AppDirectoriesFinder',
#     # 'django.contrib.staticfiles.finders.DefaultStorageFinder',
# )
# TEMPLATE_LOADERS = (
#     'django.template.loaders.filesystem.Loader',
#     'django.template.loaders.app_directories.Loader',
#     # 'django.template.loaders.eggs.Loader',
# )
# MIDDLEWARE_CLASSES = (
#     # 'debug_toolbar.middleware.DebugToolbarMiddleware',
#     'corsheaders.middleware.CorsMiddleware',
#     'django.middleware.common.CommonMiddleware',
#     'django.contrib.sessions.middleware.SessionMiddleware',
#     'django.middleware.csrf.CsrfViewMiddleware',
#     'django.contrib.auth.middleware.AuthenticationMiddleware',
#     'django.contrib.messages.middleware.MessageMiddleware',
#     # Uncomment the next line for simple clickjacking protection:
#     # 'django.middleware.clickjacking.XFrameOptionsMiddleware',
# )
# ROOT_URLCONF = 'chain.urls'
# WSGI_APPLICATION = 'chain.wsgi.application'
# TEMPLATE_DIRS = (
#     # Put strings here, like "/home/html/django_templates"
#     # Always use forward slashes, even on Windows.
#     # Don't forget to use absolute paths, not relative paths.
# )
# INSTALLED_APPS = (
#     'django.contrib.auth',
#     'django.contrib.contenttypes',
#     'django.contrib.sessions',
#     'django.contrib.sites',
#     'django.contrib.messages',
#     'django.contrib.staticfiles',
#     # 'debug_toolbar',
#     'chain.core',
#     'django_extensions',
#     'corsheaders',
#     # Uncomment the next line to enable the admin:
#     'django.contrib.admin',
#     # Uncomment the next line to enable admin documentation:
#     # 'django.contrib.admindocs',
# )
# SOUTH_TESTS_MIGRATE = False
# TEST_RUNNER = 'django.test.runner.DiscoverRunner'
# DEBUG_TOOLBAR_PATCH_SETTINGS = False
# INTERNAL_IPS = ['127.0.0.1', '18.85.58.156']
# LOGGING = {
#     'version': 1,
#     'disable_existing_loggers': False,
#     'filters': {
#         'require_debug_false': {
#             '()': 'django.utils.log.RequireDebugFalse'
#         }
#     },
#     'handlers': {
#         'mail_admins': {
#             'level': 'ERROR',
#             'filters': ['require_debug_false'],
#             'class': 'chain.helpers.logging.ThrottledAdminEmailHandler'
#         },
#         # null handler to throw away messages
#         'null': {
#             'level': 'DEBUG',
#             'class': 'logging.NullHandler',
#         },
#     },
#     'loggers': {
#         # Silence SuspiciousOperation.DisallowedHost exception ('Invalid
#         # HTTP_HOST' header messages). Set the handler to 'null' so we don't
#         # get those annoying emails.
#         'django.security.DisallowedHost': {
#             'handlers': ['null'],
#             'propagate': False,
#         },
#         'django.request': {
#             'handlers': ['mail_admins'],
#             'level': 'ERROR',
#             'propagate': True,
#         },
#     }
# }


import zmq.green as zmq
import gevent
import logging
import coloredlogs
from flask import Flask
from flask_sockets import Sockets
from zmq_passthrough import passthrough
from chain.settings import ZMQ_PASSTHROUGH_URL_PUB
        tag_subscribers[tag].add(ws)
    else:
        zmq_sock = zmq_ctx.socket(zmq.SUB)
        zmq_sock.connect(ZMQ_PASSTHROUGH_URL_PUB)
        # note that flask gives us tag as a unicode string
        zmq_sock.setsockopt_string(zmq.SUBSCRIBE, tag)
        zmq_socks.add(zmq_sock)
        zmq_socks_tag[zmq_sock] = tag
        tag_zmq_sock[tag] = zmq_sock
        tag_subscribers[tag] = {ws}
    while True:
        try:
            # Read from ws socket continuously.
            # XXX:  This builds up a lot of threads.  Is there ANY way we could do
            #       this for many connected ws clients in a non-blocking fashion (like select).
            # NOTE that ws dies if site_socket function exits...
            received = ws.receive()
            logger.info("Received from ws client: %s" % received)
        except Exception as e:
            tag_subscribers[tag].remove(ws)
            if len(tag_subscribers) == 0:
                close_socket(tag_zmq_sock[tag])
            break
    # return an empty response so Flask doesn't complain
    return ''

def close_socket(zmq_sock):
    tag = zmq_socks_tag[zmq_sock]
    logger.info('Disconnecting ZMQ Socket for tag "%s"' % tag)
    try:

# Path: flask_sockets.py
# class Sockets(object):
# 
#     def __init__(self, app=None):
#         self.app = app
# 
#     def route(self, rule, **options):
# 
#         def decorator(f):
#             @wraps(f)
#             def inner(*args, **kwargs):
#                 return f(request.environ['wsgi.websocket'], *args, **kwargs)
# 
#             if self.app:
#                 endpoint = options.pop('endpoint', None)
#                 self.app.add_url_rule(rule, endpoint, inner, **options)
#             return inner
# 
#         return decorator
# 
# Path: chain/settings.py
# USE_X_FORWARDED_HOST = True
# CORS_ORIGIN_ALLOW_ALL = True
# SITE_ID = 1
# USE_I18N = True
# USE_L10N = True
# USE_TZ = True
# MEDIA_ROOT = ''
# MEDIA_URL = ''
# STATIC_ROOT = '/srv/chain/static/'
# STATIC_URL = '/static/'
# STATICFILES_DIRS = (
#     # Put strings here, like "/home/html/static" or "C:/www/django/static".
#     # Always use forward slashes, even on Windows.
#     # Don't forget to use absolute paths, not relative paths.
# )
# STATICFILES_FINDERS = (
#     'django.contrib.staticfiles.finders.FileSystemFinder',
#     'django.contrib.staticfiles.finders.AppDirectoriesFinder',
#     # 'django.contrib.staticfiles.finders.DefaultStorageFinder',
# )
# TEMPLATE_LOADERS = (
#     'django.template.loaders.filesystem.Loader',
#     'django.template.loaders.app_directories.Loader',
#     # 'django.template.loaders.eggs.Loader',
# )
# MIDDLEWARE_CLASSES = (
#     # 'debug_toolbar.middleware.DebugToolbarMiddleware',
#     'corsheaders.middleware.CorsMiddleware',
#     'django.middleware.common.CommonMiddleware',
#     'django.contrib.sessions.middleware.SessionMiddleware',
#     'django.middleware.csrf.CsrfViewMiddleware',
#     'django.contrib.auth.middleware.AuthenticationMiddleware',
#     'django.contrib.messages.middleware.MessageMiddleware',
#     # Uncomment the next line for simple clickjacking protection:
#     # 'django.middleware.clickjacking.XFrameOptionsMiddleware',
# )
# ROOT_URLCONF = 'chain.urls'
# WSGI_APPLICATION = 'chain.wsgi.application'
# TEMPLATE_DIRS = (
#     # Put strings here, like "/home/html/django_templates"
#     # Always use forward slashes, even on Windows.
#     # Don't forget to use absolute paths, not relative paths.
# )
# INSTALLED_APPS = (
#     'django.contrib.auth',
#     'django.contrib.contenttypes',
#     'django.contrib.sessions',
#     'django.contrib.sites',
#     'django.contrib.messages',
#     'django.contrib.staticfiles',
#     # 'debug_toolbar',
#     'chain.core',
#     'django_extensions',
#     'corsheaders',
#     # Uncomment the next line to enable the admin:
#     'django.contrib.admin',
#     # Uncomment the next line to enable admin documentation:
#     # 'django.contrib.admindocs',
# )
# SOUTH_TESTS_MIGRATE = False
# TEST_RUNNER = 'django.test.runner.DiscoverRunner'
# DEBUG_TOOLBAR_PATCH_SETTINGS = False
# INTERNAL_IPS = ['127.0.0.1', '18.85.58.156']
# LOGGING = {
#     'version': 1,
#     'disable_existing_loggers': False,
#     'filters': {
#         'require_debug_false': {
#             '()': 'django.utils.log.RequireDebugFalse'
#         }
#     },
#     'handlers': {
#         'mail_admins': {
#             'level': 'ERROR',
#             'filters': ['require_debug_false'],
#             'class': 'chain.helpers.logging.ThrottledAdminEmailHandler'
#         },
#         # null handler to throw away messages
#         'null': {
#             'level': 'DEBUG',
#             'class': 'logging.NullHandler',
#         },
#     },
#     'loggers': {
#         # Silence SuspiciousOperation.DisallowedHost exception ('Invalid
#         # HTTP_HOST' header messages). Set the handler to 'null' so we don't
#         # get those annoying emails.
#         'django.security.DisallowedHost': {
#             'handlers': ['null'],
#             'propagate': False,
#         },
#         'django.request': {
#             'handlers': ['mail_admins'],
#             'level': 'ERROR',
#             'propagate': True,
#         },
#     }
# }


# Path: chain/websocketd.py
import zmq.green as zmq
import gevent
import logging
import coloredlogs
from flask import Flask
from flask_sockets import Sockets
from zmq_passthrough import passthrough
from chain.settings import ZMQ_PASSTHROUGH_URL_PUB

        tag_subscribers[tag].add(ws)
    else:
        zmq_sock = zmq_ctx.socket(zmq.SUB)
        zmq_sock.connect(ZMQ_PASSTHROUGH_URL_PUB)
        # note that flask gives us tag as a unicode string
        zmq_sock.setsockopt_string(zmq.SUBSCRIBE, tag)
        zmq_socks.add(zmq_sock)
        zmq_socks_tag[zmq_sock] = tag
        tag_zmq_sock[tag] = zmq_sock
        tag_subscribers[tag] = {ws}
    while True:
        try:
            # Read from ws socket continuously.
            # XXX:  This builds up a lot of threads.  Is there ANY way we could do
            #       this for many connected ws clients in a non-blocking fashion (like select).
            # NOTE that ws dies if site_socket function exits...
            received = ws.receive()
            logger.info("Received from ws client: %s" % received)
        except Exception as e:
            tag_subscribers[tag].remove(ws)
            if len(tag_subscribers) == 0:
                close_socket(tag_zmq_sock[tag])
            break
    # return an empty response so Flask doesn't complain
    return ''

def close_socket(zmq_sock):
    tag = zmq_socks_tag[zmq_sock]
    logger.info('Disconnecting ZMQ Socket for tag "%s"' % tag)
    try:

        zmq_sock.disconnect(ZMQ_PASSTHROUGH_URL_PUB)