[Python-modules-commits] [django-websocket-redis] 01/05: Import django-websocket-redis_0.4.7.orig.tar.gz

Michael Fladischer fladi at moszumanska.debian.org
Fri Oct 21 07:58:17 UTC 2016


This is an automated email from the git hooks/post-receive script.

fladi pushed a commit to branch master
in repository django-websocket-redis.

commit e523cd2c8ffcd8ef1673e465c5b7585dd65af791
Author: Michael Fladischer <FladischerMichael at fladi.at>
Date:   Fri Oct 21 08:42:43 2016 +0200

    Import django-websocket-redis_0.4.7.orig.tar.gz
---
 PKG-INFO                                     |  2 +-
 django_websocket_redis.egg-info/PKG-INFO     |  2 +-
 django_websocket_redis.egg-info/SOURCES.txt  |  1 +
 django_websocket_redis.egg-info/requires.txt |  6 +-
 ws4redis/__init__.py                         |  2 +-
 ws4redis/_compat.py                          | 13 ++++
 ws4redis/publisher.py                        |  5 +-
 ws4redis/redis_store.py                      | 11 ++--
 ws4redis/static/js/ws4redis.js               | 89 ++++++++++++++++++++++++----
 ws4redis/wsgi_server.py                      | 17 ++++++
 10 files changed, 123 insertions(+), 25 deletions(-)

diff --git a/PKG-INFO b/PKG-INFO
index 74841e6..8cee0b5 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: django-websocket-redis
-Version: 0.4.6
+Version: 0.4.7
 Summary: Websocket support for Django using Redis as datastore
 Home-page: https://github.com/jrief/django-websocket-redis
 Author: Jacob Rief
diff --git a/django_websocket_redis.egg-info/PKG-INFO b/django_websocket_redis.egg-info/PKG-INFO
index 74841e6..8cee0b5 100644
--- a/django_websocket_redis.egg-info/PKG-INFO
+++ b/django_websocket_redis.egg-info/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: django-websocket-redis
-Version: 0.4.6
+Version: 0.4.7
 Summary: Websocket support for Django using Redis as datastore
 Home-page: https://github.com/jrief/django-websocket-redis
 Author: Jacob Rief
diff --git a/django_websocket_redis.egg-info/SOURCES.txt b/django_websocket_redis.egg-info/SOURCES.txt
index e545435..aeca5f5 100644
--- a/django_websocket_redis.egg-info/SOURCES.txt
+++ b/django_websocket_redis.egg-info/SOURCES.txt
@@ -9,6 +9,7 @@ django_websocket_redis.egg-info/not-zip-safe
 django_websocket_redis.egg-info/requires.txt
 django_websocket_redis.egg-info/top_level.txt
 ws4redis/__init__.py
+ws4redis/_compat.py
 ws4redis/context_processors.py
 ws4redis/django_runserver.py
 ws4redis/exceptions.py
diff --git a/django_websocket_redis.egg-info/requires.txt b/django_websocket_redis.egg-info/requires.txt
index 093a791..fd488c1 100644
--- a/django_websocket_redis.egg-info/requires.txt
+++ b/django_websocket_redis.egg-info/requires.txt
@@ -7,8 +7,8 @@ six
 [django-redis-sessions]
 django-redis-sessions>=0.4.0
 
+[uwsgi]
+uWSGI>=1.9.20
+
 [wsaccel]
 wsaccel>=0.6.2
-
-[uwsgi]
-uWSGI>=1.9.20
\ No newline at end of file
diff --git a/ws4redis/__init__.py b/ws4redis/__init__.py
index ebb2c73..33eb38d 100644
--- a/ws4redis/__init__.py
+++ b/ws4redis/__init__.py
@@ -1,2 +1,2 @@
 # -*- coding: utf-8 -*-
-__version__ = '0.4.6'
+__version__ = '0.4.7'
diff --git a/ws4redis/_compat.py b/ws4redis/_compat.py
new file mode 100644
index 0000000..fb32103
--- /dev/null
+++ b/ws4redis/_compat.py
@@ -0,0 +1,13 @@
+def is_authenticated(request):
+    """Wrapper for checking when a request is authenticated. This checks first
+    for a valid request and user, then checks to see if `is_authenticated` is
+    a callable in order to be compatible with Django 1.10, wherein using a
+    callable for `is_authenticated` is deprecated in favor of a property.
+    """
+    if not request:
+        return False
+    if not request.user:
+        return False
+    if callable(request.user.is_authenticated):
+        return request.user.is_authenticated()
+    return request.user.is_authenticated
diff --git a/ws4redis/publisher.py b/ws4redis/publisher.py
index 3b2e55c..74798e5 100644
--- a/ws4redis/publisher.py
+++ b/ws4redis/publisher.py
@@ -2,6 +2,7 @@
 from redis import ConnectionPool, StrictRedis
 from ws4redis import settings
 from ws4redis.redis_store import RedisStore
+from ws4redis._compat import is_authenticated
 
 redis_connection_pool = ConnectionPool(**settings.WS4REDIS_CONNECTION)
 
@@ -32,11 +33,11 @@ class RedisPublisher(RedisStore):
             if request and request.session:
                 channels.append('{prefix}session:{0}:{facility}'.format(request.session.session_key, prefix=prefix, facility=facility))
         if audience in ('user', 'any',):
-            if request and request.user and request.user.is_authenticated():
+            if is_authenticated(request):
                 channels.append('{prefix}user:{0}:{facility}'.format(request.user.get_username(), prefix=prefix, facility=facility))
         if audience in ('group', 'any',):
             try:
-                if request.user.is_authenticated():
+                if is_authenticated(request):
                     groups = request.session['ws4redis:memberof']
                     channels.extend('{prefix}group:{0}:{facility}'.format(g, prefix=prefix, facility=facility)
                                 for g in groups)
diff --git a/ws4redis/redis_store.py b/ws4redis/redis_store.py
index ce69dd8..e8d3160 100644
--- a/ws4redis/redis_store.py
+++ b/ws4redis/redis_store.py
@@ -2,6 +2,7 @@
 import six
 import warnings
 from ws4redis import settings
+from ws4redis._compat import is_authenticated
 
 
 """
@@ -18,7 +19,7 @@ def _wrap_users(users, request):
     """
     result = set()
     for u in users:
-        if u is SELF and request and request.user and request.user.is_authenticated():
+        if u is SELF and is_authenticated(request):
             result.add(request.user.get_username())
         else:
             result.add(u)
@@ -36,7 +37,7 @@ def _wrap_groups(groups, request):
     """
     result = set()
     for g in groups:
-        if g is SELF and request and request.user and request.user.is_authenticated():
+        if g is SELF and is_authenticated(request):
             result.update(request.session.get('ws4redis:memberof', []))
         else:
             result.add(g)
@@ -70,7 +71,7 @@ class RedisMessage(six.binary_type):
                     value = value.encode()
                     return super(RedisMessage, cls).__new__(cls, value)
             elif isinstance(value, bytes):
-                if value != settings.WS4REDIS_HEARTBEAT.encode():
+                if settings.WS4REDIS_HEARTBEAT is None or value != settings.WS4REDIS_HEARTBEAT.encode():
                     return super(RedisMessage, cls).__new__(cls, value)
             elif isinstance(value, list):
                 if len(value) >= 2 and value[0] == b'message':
@@ -129,7 +130,7 @@ class RedisStore(object):
             # message is delivered to all listed groups
             channels.extend('{prefix}group:{0}:{facility}'.format(g, prefix=prefix, facility=facility)
                             for g in _wrap_groups(groups, request))
-        elif groups is True and request and request.user and request.user.is_authenticated():
+        elif groups is True and is_authenticated(request):
             # message is delivered to all groups the currently logged in user belongs to
             warnings.warn('Wrap groups=True into a list or tuple using SELF', DeprecationWarning)
             channels.extend('{prefix}group:{0}:{facility}'.format(g, prefix=prefix, facility=facility)
@@ -146,7 +147,7 @@ class RedisStore(object):
             # message is delivered to all listed users
             channels.extend('{prefix}user:{0}:{facility}'.format(u, prefix=prefix, facility=facility)
                             for u in _wrap_users(users, request))
-        elif users is True and request and request.user and request.user.is_authenticated():
+        elif users is True and is_authenticated(request):
             # message is delivered to browser instances of the currently logged in user
             warnings.warn('Wrap users=True into a list or tuple using SELF', DeprecationWarning)
             channels.append('{prefix}user:{0}:{facility}'.format(request.user.get_username(), prefix=prefix, facility=facility))
diff --git a/ws4redis/static/js/ws4redis.js b/ws4redis/static/js/ws4redis.js
index bbb223f..6d97392 100644
--- a/ws4redis/static/js/ws4redis.js
+++ b/ws4redis/static/js/ws4redis.js
@@ -1,7 +1,15 @@
-
+/**
+ * options.uri - > The Websocket URI
+ * options.connected -> Callback called after the websocket is connected.
+ * options.connecting -> Callback called when the websocket is connecting.
+ * options.disconnected -> Callback called after the websocket is disconnected.
+ * options.receive_message -> Callback called when a message is received from the websocket.
+ * options.heartbeat_msg -> String to identify the heartbeat message.
+ * $ -> JQuery instance.
+ */
 function WS4Redis(options, $) {
 	'use strict';
-	var opts, ws, deferred, timer, attempts = 1;
+	var opts, ws, deferred, timer, attempts = 1, must_reconnect = true;
 	var heartbeat_interval = null, missed_heartbeats = 0;
 
 	if (this === undefined)
@@ -15,6 +23,15 @@ function WS4Redis(options, $) {
 
 	function connect(uri) {
 		try {
+			if (ws && (is_connecting() || is_connected())) {
+				console.log("Websocket is connecting or already connected.");
+				return;
+			}
+			
+			if ($.type(opts.connecting) === 'function') {
+				opts.connecting();
+			}
+			
 			console.log("Connecting to " + uri + " ...");
 			deferred = $.Deferred();
 			ws = new WebSocket(uri);
@@ -24,10 +41,23 @@ function WS4Redis(options, $) {
 			ws.onclose = on_close;
 			timer = null;
 		} catch (err) {
+			try_to_reconnect();
 			deferred.reject(new Error(err));
 		}
 	}
 
+	function try_to_reconnect() {
+		if (must_reconnect && !timer) {
+			// try to reconnect
+			console.log('Reconnecting...');
+			var interval = generate_inteval(attempts);
+			timer = setTimeout(function() {
+				attempts++;
+				connect(ws.url);
+			}, interval);
+		}
+	}
+	
 	function send_heartbeat() {
 		try {
 			missed_heartbeats++;
@@ -38,7 +68,9 @@ function WS4Redis(options, $) {
 			clearInterval(heartbeat_interval);
 			heartbeat_interval = null;
 			console.warn("Closing connection. Reason: " + e.message);
-			ws.close();
+			if ( !is_closing() && !is_closed() ) {
+				ws.close();
+			}
 		}
 	}
 
@@ -51,18 +83,17 @@ function WS4Redis(options, $) {
 			missed_heartbeats = 0;
 			heartbeat_interval = setInterval(send_heartbeat, 5000);
 		}
+		if ($.type(opts.connected) === 'function') {
+			opts.connected();
+		}
 	}
 
 	function on_close(evt) {
 		console.log("Connection closed!");
-		if (!timer) {
-			// try to reconnect
-			var interval = generateInteval(attempts);
-			timer = setTimeout(function() {
-				attempts++;
-				connect(ws.url);
-			}, interval);
+		if ($.type(opts.disconnected) === 'function') {
+			opts.disconnected(evt);
 		}
+		try_to_reconnect();
 	}
 
 	function on_error(evt) {
@@ -74,7 +105,7 @@ function WS4Redis(options, $) {
 		if (opts.heartbeat_msg && evt.data === opts.heartbeat_msg) {
 			// reset the counter for missed heartbeats
 			missed_heartbeats = 0;
-		} else if (typeof opts.receive_message === 'function') {
+		} else if ($.type(opts.receive_message) === 'function') {
 			return opts.receive_message(evt.data);
 		}
 	}
@@ -84,7 +115,7 @@ function WS4Redis(options, $) {
 	// Generate an interval that is randomly between 0 and 2^k - 1, where k is
 	// the number of connection attmpts, with a maximum interval of 30 seconds,
 	// so it starts at 0 - 1 seconds and maxes out at 0 - 30 seconds
-	function generateInteval (k) {
+	function generate_inteval(k) {
 		var maxInterval = (Math.pow(2, k) - 1) * 1000;
 
 		// If the generated interval is more than 30 seconds, truncate it down to 30 seconds.
@@ -99,4 +130,38 @@ function WS4Redis(options, $) {
 	this.send_message = function(message) {
 		ws.send(message);
 	};
+	
+	this.get_state = function() {
+		return ws.readyState;	
+	};
+	
+	function is_connecting() {
+		return ws && ws.readyState === 0;	
+	}
+	
+	function is_connected() {
+		return ws && ws.readyState === 1;	
+	}
+	
+	function is_closing() {
+		return ws && ws.readyState === 2;	
+	}
+
+	function is_closed() {
+		return ws && ws.readyState === 3;	
+	}
+	
+	
+	this.close = function () {
+		clearInterval(heartbeat_interval);
+		must_reconnect = false;
+		if (!is_closing() || !is_closed()) {
+			ws.close();
+		}
+	}
+	
+	this.is_connecting = is_connecting; 
+	this.is_connected = is_connected;
+	this.is_closing = is_closing;
+	this.is_closed = is_closed;
 }
diff --git a/ws4redis/wsgi_server.py b/ws4redis/wsgi_server.py
index 20a8a31..e478802 100644
--- a/ws4redis/wsgi_server.py
+++ b/ws4redis/wsgi_server.py
@@ -37,6 +37,7 @@ class WebsocketWSGIServer(object):
         self.possible_channels = Subscriber.subscription_channels + Subscriber.publish_channels
         self._redis_connection = redis_connection and redis_connection or StrictRedis(**private_settings.WS4REDIS_CONNECTION)
         self.Subscriber = Subscriber
+        self._websockets = set()  # a list of currently active websockets
 
     def assure_protocol_requirements(self, environ):
         if environ.get('REQUEST_METHOD') != 'GET':
@@ -69,6 +70,10 @@ class WebsocketWSGIServer(object):
                 echo_message = True
         return agreed_channels, echo_message
 
+    @property
+    def websockets(self):
+        return self._websockets
+
     def __call__(self, environ, start_response):
         """
         Hijack the main loop from the original thread and listen on events on the Redis
@@ -86,7 +91,16 @@ class WebsocketWSGIServer(object):
             channels, echo_message = self.process_subscriptions(request)
             if callable(private_settings.WS4REDIS_ALLOWED_CHANNELS):
                 channels = list(private_settings.WS4REDIS_ALLOWED_CHANNELS(request, channels))
+            elif private_settings.WS4REDIS_ALLOWED_CHANNELS is not None:
+                try:
+                    mod, callback = private_settings.WS4REDIS_ALLOWED_CHANNELS.rsplit('.', 1)
+                    callback = getattr(import_module(mod), callback, None)
+                    if callable(callback):
+                        channels = list(callback(request, channels))
+                except AttributeError:
+                    pass
             websocket = self.upgrade_websocket(environ, start_response)
+            self._websockets.add(websocket)
             logger.debug('Subscribed to channels: {0}'.format(', '.join(channels)))
             subscriber.set_pubsub_channels(request, channels)
             websocket_fd = websocket.get_file_descriptor()
@@ -116,6 +130,9 @@ class WebsocketWSGIServer(object):
                 # because the websocket can closed previously in the loop.
                 if private_settings.WS4REDIS_HEARTBEAT and not websocket.closed:
                     websocket.send(private_settings.WS4REDIS_HEARTBEAT)
+                # Remove websocket from _websockets if closed
+                if websocket.closed:
+                    self._websockets.remove(websocket)
         except WebSocketError as excpt:
             logger.warning('WebSocketError: {}'.format(excpt), exc_info=sys.exc_info())
             response = http.HttpResponse(status=1001, content='Websocket Closed')

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/django-websocket-redis.git



More information about the Python-modules-commits mailing list