from datetime import timedelta, datetime from sets import Set ONLINE_MINUTES = 2 PURGE_MULTIPLE = 20 _users_seen_per_minute = {} _last_purged = datetime.now() def get_online_user_ids(): """ Returns a sets.Set of user_id's which have made requests in the last ONLINE_MINUTES. Includes partial minutes (i.e. 2 minutes would count up to users seen in 2:59, due to minute rollover). """ current_minute = _get_minute() user_set = Set() for count_minute in [_get_minute(current_minute, -1 * i) for i in range(0, ONLINE_MINUTES+1)]: try: user_set.union_update(_users_seen_per_minute[count_minute]) except KeyError: pass #perhaps no requests that minute? return user_set def _get_minute(base_datetime=None, offset_minutes=0): if base_datetime is None: base_datetime = datetime.now() if offset_minutes != 0: offset = timedelta(minutes=offset_minutes) time = base_datetime + offset else: time = base_datetime return datetime(time.year, time.month, time.day, time.hour, time.minute) def _purge_old_minutes(): global _last_purged now = datetime.now() purge_at = _last_purged + timedelta(minutes=PURGE_MULTIPLE*ONLINE_MINUTES) if purge_at < now: purge_older_than = now - timedelta(minutes=ONLINE_MINUTES+1) for seen_minute in _users_seen_per_minute.keys(): if seen_minute < purge_older_than: del _users_seen_per_minute[seen_minute] _last_purged = now else: pass #not time to purge yet class OnlineUsers(object): def process_request(self, request): #assumes auth middleware earlier in the request chain assert hasattr(request, 'user'), "The OnlineUsers middleware requires auth middleware to be installed. Edit your MIDDLEWARE_CLASSES setting to insert 'django.contrib.auth.middleware.AuthenticationMiddleware'." if request.user.is_anonymous(): #assuming most users are anonymous, this is a fast path for them return #but move down -after- purge if you expect << 1 non-anonymous request per minute. _purge_old_minutes() current_minute = _get_minute() try: _users_seen_per_minute[current_minute].add(request.user.id) except KeyError: #request is first in new minute _users_seen_per_minute[current_minute] = Set([request.user.id])