[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