def removeClientFromChannel(request, channelName, client): """ Remove client from channel. @type request: C{django.http.HttpRequest} @param request: Django Request. @type channelName: C{string} @param channelName: Channel name. @type client: C{string} @param client: Unique Client ID. """ import sputnik srem("sputnik:channel:%s:channel" % channelName, client) # get our username userName = sputnik.get("ses:%s:username" % client) # get all usernames users = smembers("sputnik:channel:%s:users" % channelName) try: # get all clients allClients = [] for cl in smembers("sputnik:channel:%s:channel" % channelName): allClients.append(sputnik.get("ses:%s:username" % cl)) for usr in users: if usr not in allClients: sputnik.srem("sputnik:channel:%s:users" % channelName, usr) addMessageToChannel(request, channelName, {"command": "user_remove", "username": usr}, myself = True) except: from booki.utils.log import printStack printStack(None)
def remote_ping(request, message): import sputnik sputnik.addMessageToChannel(request, "/booki/", {}) _now = time.time() try: locks = sputnik.rkeys("booki:*:locks:*") except: return for key in locks: lastAccess = sputnik.get(key) if type(lastAccess) in [type(' '), type(u' ')]: try: lastAccess = decimal.Decimal(lastAccess) except: continue if lastAccess and decimal.Decimal("%f" % _now) - lastAccess > 30: sputnik.rdelete(key) m = re.match("booki:(\d+):locks:(\d+):(\w+)", key) if m: sputnik.addMessageToChannel(request, "/booki/book/%s/" % m.group(1), {"command": "chapter_status", "chapterID": m.group(2), "status": "normal", "username": m.group(3)}, myself = True)
def removeClientFromChannel(request, channelName, client): """ Remove client from channel. @type request: C{django.http.HttpRequest} @param request: Django Request. @type channelName: C{string} @param channelName: Channel name. @type client: C{string} @param client: Unique Client ID. """ import sputnik srem("sputnik:channel:%s:channel" % channelName, client) # get our username userName = sputnik.get("ses:%s:username" % client) # get all usernames users = smembers("sputnik:channel:%s:users" % channelName) try: # get all clients allClients = [] for cl in smembers("sputnik:channel:%s:channel" % channelName): allClients.append(sputnik.get("ses:%s:username" % cl)) for usr in users: if usr not in allClients: sputnik.srem("sputnik:channel:%s:users" % channelName, usr) addMessageToChannel(request, channelName, { "command": "user_remove", "username": usr }, myself=True) except: from booki.utils.log import printStack printStack(None)
def remote_ping(request, message): """ Sends ping to the server. Just so we know client is still alive. It also removes old locks. This is not the place to do it at all, but once we have normal scheduled calls, will put it there. :Args: - request (:class:`django.http.HttpRequest`): Client Request object - message (dict): Message object """ import sputnik sputnik.addMessageToChannel(request, "/booktype/", {}) # kill old chapters which are no longer under edit keys = sputnik.rkeys("booktype:*:*:editlocks:*") for key in keys: last_ping = sputnik.get(key) try: last_ping = decimal.Decimal(last_ping) except Exception as e: logger.exception(e) if last_ping and decimal.Decimal( "%f" % time.time()) - last_ping > Chapter.EDIT_PING_SECONDS_MAX_DELTA: sputnik.rdelete(key) m = re.match("booktype:(\d+):(\d+).(\d+):editlocks:(\d+):(\w+)", key) if m: bookid, version, chapter_id, username = (m.group(1), "{0}.{1}".format( m.group(2), m.group(3)), m.group(4), m.group(5)) sputnik.addMessageToChannel(request, "/booktype/book/%s/%s/" % (bookid, version), { "command": "chapter_state", "chapterID": chapter_id, "state": "normal", "username": username }, myself=True)
def remote_book_notification(request, message, bookid, version): res = {} import time # rcon.delete(key) # set the initial timer for editor if request.user.username and request.user.username != '': sputnik.set("booki:%s:locks:%s:%s" % (bookid, message["chapterID"], request.user.username), time.time()) if '%s' % sputnik.get("booki:%s:killlocks:%s:%s" % (bookid, message["chapterID"], request.user.username)) == '1': sputnik.rdelete("booki:%s:killlocks:%s:%s" % (bookid, message["chapterID"], request.user.username)) res = {"kill": "please"} return res
def remote_ping(request, message): """ Sends ping to the server. Just so we know client is still alive. It also removes old locks. This is not the place to do it at all, but once we have normal scheduled calls, will put it there. @type request: C{django.http.HttpRequest} @param request: Client Request object @type message: C{dict} @param message: Message object """ import sputnik sputnik.addMessageToChannel(request, "/booki/", {}) _now = time.time() try: locks = sputnik.rkeys("booki:*:locks:*") except: return for key in locks: lastAccess = sputnik.get(key) if type(lastAccess) in [type(' '), type(u' ')]: try: lastAccess = decimal.Decimal(lastAccess) except: continue if lastAccess and decimal.Decimal("%f" % _now) - lastAccess > 30: sputnik.rdelete(key) m = re.match("booki:(\d+):locks:(\d+):(\w+)", key) if m: sputnik.addMessageToChannel(request, "/booki/book/%s/" % m.group(1), { "command": "chapter_status", "chapterID": m.group(2), "status": "normal", "username": m.group(3) }, myself=True)
def debug_redis(request): import sputnik client_id = sputnik.get("sputnik:client_id") sputnikchannels = sputnik.smembers("sputnik:channels") chnl = {} for ch in sputnik.rkeys("sputnik:channel:*:channel"): chnl[ch] = sputnik.smembers(ch) usrs = {} for ch in sputnik.rkeys("sputnik:channel:*:users"): usrs[ch] = sputnik.smembers(ch) # for ch in r.keys('sputnik:*:messages'): # pass allValues = {} import time, decimal _now = time.time() for ses in [k[4:-9] for k in sputnik.rkeys("ses:*:username")]: try: allValues[ses] = { "channels": sputnik.smembers("ses:%s:channels" % ses), "last_access": sputnik.get("ses:%s:last_access" % ses), "access_since": decimal.Decimal("%f" % _now) - sputnik.get("ses:%s:last_access" % ses), "username": sputnik.get("ses:%s:username" % ses) } except: pass locks = {} for ch in sputnik.rkeys("booki:*:locks:*"): locks[ch] = sputnik.get(ch) killlocks = {} for ch in sputnik.rkeys("booki:*:killlocks:*"): killlocks[ch] = sputnik.get(ch) return render_to_response('portal/debug_redis.html', {"request": request, "client_id": client_id, "sputnikchannels": sputnikchannels, "channel": chnl.items(), "users": usrs.items(), "sessions": allValues.items(), "locks": locks.items(), "killlocks": killlocks.items() })
def remove_timeout_clients(request): _now = time.time() try: for k in sputnik.rkeys("ses:*:last_access"): tm = sputnik.get(k) if type(tm) in [type(' '), type(u' ')]: try: tm = decimal.Decimal(tm) except: continue # timeout after 2 minute if tm and decimal.Decimal("%f" % _now) - tm > 60 * 2: sputnik.removeClient(request, k[4:-12]) except: logger.debug("Can not get all the last accesses")
def remote_ping(request, message): """ Sends ping to the server. Just so we know client is still alive. It also removes old locks. This is not the place to do it at all, but once we have normal scheduled calls, will put it there. @type request: C{django.http.HttpRequest} @param request: Client Request object @type message: C{dict} @param message: Message object """ import sputnik sputnik.addMessageToChannel(request, "/booki/", {}) _now = time.time() try: locks = sputnik.rkeys("booki:*:locks:*") except: return for key in locks: lastAccess = sputnik.get(key) if type(lastAccess) in [type(' '), type(u' ')]: try: lastAccess = decimal.Decimal(lastAccess) except: continue if lastAccess and decimal.Decimal("%f" % _now) - lastAccess > 30: sputnik.rdelete(key) m = re.match("booki:(\d+):locks:(\d+):(\w+)", key) if m: sputnik.addMessageToChannel(request, "/booki/book/%s/" % m.group(1), {"command": "chapter_status", "chapterID": m.group(2), "status": "normal", "username": m.group(3)}, myself = True)
def remote_ping(request, message): """ Sends ping to the server. Just so we know client is still alive. It also removes old locks. This is not the place to do it at all, but once we have normal scheduled calls, will put it there. :Args: - request (:class:`django.http.HttpRequest`): Client Request object - message (dict): Message object """ import sputnik sputnik.addMessageToChannel(request, "/booktype/", {}) # kill old chapters which are no longer under edit keys = sputnik.rkeys("booktype:*:*:editlocks:*") for key in keys: last_ping = sputnik.get(key) try: last_ping = decimal.Decimal(last_ping) except Exception as e: logger.exception(e) if last_ping and decimal.Decimal("%f" % time.time()) - last_ping > Chapter.EDIT_PING_SECONDS_MAX_DELTA: sputnik.rdelete(key) m = re.match("booktype:(\d+):(\d+).(\d+):editlocks:(\d+):(\w+)", key) if m: bookid, version, chapter_id, username = (m.group(1), "{0}.{1}".format(m.group(2), m.group(3)), m.group(4), m.group(5)) sputnik.addMessageToChannel(request, "/booktype/book/%s/%s/" % (bookid, version), {"command": "chapter_state", "chapterID": chapter_id, "state": "normal", "username": username}, myself=True)
def get_online_users(self): client_list = sputnik.rkeys("ses:*:username") online_users = {} for us in client_list: clientID = us[4:-9] channel_list = [] for chan in sputnik.smembers('ses:%s:channels' % clientID): if chan.startswith('/booktype/book/'): _s = chan.split('/') if len(_s) > 3: bookID = _s[3] try: b = Book.objects.get(pk=bookID) channel_list.append(b) except Book.DoesNotExist: pass _u = sputnik.get(us) online_users[_u] = channel_list return online_users
def debug_redis(request): """ Django View. This page shows basic debug information about redis. @todo: This should be removed. New Django Application for debuging and monitoring should be created. @type request: C{django.http.HttpRequest} @param request: Client Request object """ import sputnik client_id = sputnik.get("sputnik:client_id") sputnikchannels = sputnik.smembers("sputnik:channels") chnl = {} for ch in sputnik.rkeys("sputnik:channel:*:channel"): chnl[ch] = sputnik.smembers(ch) usrs = {} for ch in sputnik.rkeys("sputnik:channel:*:users"): usrs[ch] = sputnik.smembers(ch) # for ch in r.keys('sputnik:*:messages'): # pass allValues = {} import time, decimal _now = time.time() for ses in [k[4:-9] for k in sputnik.rkeys("ses:*:username")]: try: allValues[ses] = { "channels": sputnik.smembers("ses:%s:channels" % ses), "last_access": sputnik.get("ses:%s:last_access" % ses), "access_since": decimal.Decimal("%f" % _now) - sputnik.get("ses:%s:last_access" % ses), "username": sputnik.get("ses:%s:username" % ses) } except: pass locks = {} for ch in sputnik.rkeys("booki:*:locks:*"): locks[ch] = sputnik.get(ch) killlocks = {} for ch in sputnik.rkeys("booki:*:killlocks:*"): killlocks[ch] = sputnik.get(ch) return render_to_response('portal/debug_redis.html', {"request": request, "client_id": client_id, "sputnikchannels": sputnikchannels, "channel": chnl.items(), "users": usrs.items(), "sessions": allValues.items(), "locks": locks.items(), "killlocks": killlocks.items() })
def dispatcher(request, **sputnik_dict): """ Main Sputnik dispatcher. Every Sputnik request goes through this dispatcher. Input arguments are passed through C{request.POST}: - C{request.POST['messages']} List of messages client is sending to server. - C{request.POST['clientID']} Unique client ID for this connection. This is just another Django view. @todo: Change logging and error handling. @type request: C{django.http.HttpRequest} @param request: Client Request object @type sputnik_dict: C{dict} @param sputnik_dict: Mapping of channels with specific python modules. @rtype: C{HttpResponse} @return: Return C{django.http.HttpResponse} object. """ try: inp = request.POST except IOError: return HttpResponse(simplejson.dumps({"result": False, "messages": []}), mimetype="text/json") results = [] clientID = None messages = simplejson.loads(inp.get("messages", "[]")) if inp.has_key("clientID") and inp["clientID"]: clientID = inp["clientID"] for message in messages: ret = None for mpr in sputnik_dict['map']: mtch = re.match(mpr[0], message["channel"]) if mtch: a = mtch.groupdict() _m = __import__(mpr[1]) for nam in mpr[1].split('.')[1:]: _m = getattr(_m, nam) if _m: # should do hasattr first and then getattr fnc = getattr(_m, "remote_%s" % message['command']) if not hasattr(request, "sputnikID"): request.sputnikID = "%s:%s" % (request.session.session_key, clientID) request.clientID = clientID if fnc: ret = fnc(request, message, **a) if not ret: ret = {} ret["uid"] = message.get("uid") break else: import logging logging.getLogger("booki").error("Could not find function '%s' for Sputnik channel '%d'!" % (message['command'], message['channel'])) if ret: results.append(ret) else: import logging logging.getLogger("booki").error("Sputnik - %s." % simplejson.dumps(message)) n = 0 while True: v = None try: if clientID and clientID.find(' ') == -1: v = sputnik.rpop("ses:%s:%s:messages" % (request.session.session_key, clientID)) except: if n > 20: break import logging logging.getLogger("booki").debug("Sputnik - Coult not get the latest message from the queue session: %s clientID:%s" %(request.session.session_key, clientID)) # from booki.utils.log import printStack # printStack(None) n += 1 if not v: break try: results.append(simplejson.loads(v)) except: import logging logging.getLogger("booki").debug(v) # from booki.utils.log import printStack # printStack(None) import time, decimal try: if request.sputnikID and request.sputnikID.find(' ') == -1: sputnik.set("ses:%s:last_access" % request.sputnikID, time.time()) except: import logging logging.getLogger("booki").debug("Sputnik - CAN NOT SET TIMESTAMP.") # from booki.utils.log import printStack # printStack(None) # this should not be here! # timeout old edit locks locks = {} _now = time.time() try: for k in sputnik.rkeys("ses:*:last_access"): tm = sputnik.get(k) if type(tm) in [type(' '), type(u' ')]: try: tm = decimal.Decimal(tm) except: continue # timeout after 2 minute if tm and decimal.Decimal("%f" % _now) - tm > 60*2: sputnik.removeClient(request, k[4:-12]) except: import logging logging.getLogger("booki").debug("Sputnik - can not get all the last accesses") # from booki.utils.log import printStack # printStack(None) ret = {"result": True, "messages": results} try: return HttpResponse(simplejson.dumps(ret), mimetype="text/json") except: transaction.rollback() finally: transaction.commit()
def remote_init_editor(request, message, bookid, version): book = models.Book.objects.get(id=bookid) book_version = getVersion(book, version) ## get chapters chapters = getTOCForBook(book_version) holdChapters = getHoldChapters(book_version) ## get users def _getUserName(a): if a == request.sputnikID: return "<b>%s</b>" % a return a try: users = [_getUserName(m) for m in list(sputnik.smembers("sputnik:channel:%s:channel" % message["channel"]))] except: users = [] ## get workflow statuses statuses = [(status.id, status.name) for status in models.BookStatus.objects.filter(book=book).order_by("-weight")] ## get attachments try: attachments = getAttachments(book_version) except: attachments = [] ## get metadata metadata = [{'name': v.name, 'value': v.getValue()} for v in models.Info.objects.filter(book=book)] ## notify others sputnik.addMessageToChannel(request, "/chat/%s/" % bookid, {"command": "user_joined", "user_joined": request.user.username}, myself = False) ## get licenses licenses = [(elem.abbrevation, elem.name) for elem in models.License.objects.all().order_by("name")] ## get online users try: _onlineUsers = sputnik.smembers("sputnik:channel:%s:users" % message["channel"]) except: _onlineUsers = [] if request.user.username not in _onlineUsers: try: sputnik.sadd("sputnik:channel:%s:users" % message["channel"], request.user.username) _onlineUsers.append(request.user.username) except: pass ## get mood message for current user ## send mood as seperate message ## set notifications to other clients profile = request.user.get_profile() if profile: moodMessage = profile.mood; else: moodMessage = '' sputnik.addMessageToChannel(request, "/booki/book/%s/%s/" % (bookid, version), {"command": "user_add", "username": request.user.username, "mood": moodMessage} ) ## get online users and their mood messages from django.contrib.auth.models import User def _getUser(_user): try: _u = User.objects.get(username=_user) return (_user, _u.get_profile().mood) except: return None onlineUsers = [x for x in [_getUser(x) for x in _onlineUsers] if x] # for now, this is one big temp here import time, decimal, re _now = time.time() locks = {} try: for key in sputnik.rkeys("booki:*:locks:*"): lastAccess = sputnik.get(key) if type(lastAccess) in [type(' '), type(u' ')]: try: lastAccess = decimal.Decimal(lastAccess) except: continue if lastAccess and decimal.Decimal("%f" % _now) - lastAccess <= 30: m = re.match("booki:(\d+):locks:(\d+):(\w+)", key) if m: if m.group(1) == bookid: locks[m.group(2)] = m.group(3) except: pass return {"licenses": licenses, "chapters": chapters, "metadata": metadata, "hold": holdChapters, "users": users, "locks": locks, "statuses": statuses, "attachments": attachments, "onlineUsers": list(onlineUsers)}
def _get(self, key): return sputnik.get(key)
def dispatcher(request, **sputnik_dict): """ Main Sputnik dispatcher. Every Sputnik request goes through this dispatcher. Input arguments are passed through C{request.POST}: - C{request.POST['messages']} List of messages client is sending to server. - C{request.POST['clientID']} Unique client ID for this connection. This is just another Django view. @todo: Change logging and error handling. @type request: C{django.http.HttpRequest} @param request: Client Request object @type sputnik_dict: C{dict} @param sputnik_dict: Mapping of channels with specific python modules. @rtype: C{HttpResponse} @return: Return C{django.http.HttpResponse} object. """ try: inp = request.POST except IOError: return HttpResponse(simplejson.dumps({"result": False, "messages": []}), mimetype="text/json") results = [] clientID = None try: messages = simplejson.loads(inp.get("messages", "[]")) except ValueError: return HttpResponse(simplejson.dumps({"result": False, "messages": []}), mimetype="text/json") if inp.has_key("clientID") and inp["clientID"]: clientID = inp["clientID"] for message in messages: ret = None for mpr in sputnik_dict['map']: mtch = re.match(mpr[0], message["channel"]) if mtch: a = mtch.groupdict() _m = __import__(mpr[1]) for nam in mpr[1].split('.')[1:]: _m = getattr(_m, nam) if _m: # should do hasattr first and then getattr fnc = getattr(_m, "remote_%s" % message['command']) if not hasattr(request, "sputnikID"): request.sputnikID = "%s:%s" % (request.session.session_key, clientID) request.clientID = clientID if fnc: ret = fnc(request, message, **a) if not ret: ret = {} ret["uid"] = message.get("uid") break else: import logging logging.getLogger("booki").error("Could not find function '%s' for Sputnik channel '%d'!" % (message['command'], message['channel'])) if ret: results.append(ret) else: import logging logging.getLogger("booki").error("Sputnik - %s." % simplejson.dumps(message)) n = 0 while True: v = None try: if clientID and clientID.find(' ') == -1: v = sputnik.rpop("ses:%s:%s:messages" % (request.session.session_key, clientID)) except: if n > 20: break import logging logging.getLogger("booki").debug("Sputnik - Coult not get the latest message from the queue session: %s clientID:%s" %(request.session.session_key, clientID)) # from booki.utils.log import printStack # printStack(None) n += 1 if not v: break try: results.append(simplejson.loads(v)) except: import logging logging.getLogger("booki").debug(v) # from booki.utils.log import printStack # printStack(None) import time, decimal try: if request.sputnikID and request.sputnikID.find(' ') == -1: sputnik.set("ses:%s:last_access" % request.sputnikID, time.time()) except: import logging logging.getLogger("booki").debug("Sputnik - CAN NOT SET TIMESTAMP.") # from booki.utils.log import printStack # printStack(None) # this should not be here! # timeout old edit locks locks = {} _now = time.time() try: for k in sputnik.rkeys("ses:*:last_access"): tm = sputnik.get(k) if type(tm) in [type(' '), type(u' ')]: try: tm = decimal.Decimal(tm) except: continue # timeout after 2 minute if tm and decimal.Decimal("%f" % _now) - tm > 60*2: sputnik.removeClient(request, k[4:-12]) except: import logging logging.getLogger("booki").debug("Sputnik - can not get all the last accesses") # from booki.utils.log import printStack # printStack(None) ret = {"result": True, "messages": results} try: return HttpResponse(simplejson.dumps(ret), mimetype="text/json") except: transaction.rollback() finally: transaction.commit()
def frontpage(request): # check all active online users and what are they doing import sputnik clientList = sputnik.rkeys("ses:*:username") onlineUsers = [] for us in clientList: clientID = us[4:-9] channelList = [] for chan in sputnik.smembers("ses:%s:channels" % clientID): if chan.startswith("/booki/book/"): _s = chan.split("/") if len(_s) > 3: bookID = _s[3] b = models.Book.objects.get(pk=bookID) channelList.append(b) _u = sputnik.get(us) onlineUsers.append((_u, channelList)) # Check the attachment size. # This should not be here in the future. It takes way too much time. from booki.utils import misc attachmentDirectory = "%s/books/" % (settings.DATA_ROOT,) attachmentsSize = misc.getDirectorySize(attachmentDirectory) # Number of books and number of groups number_of_books = len(models.Book.objects.all()) number_of_groups = len(models.BookiGroup.objects.all()) # Number of all users on the system. # This should somehow check only the active users from django.contrib.auth.models import User number_of_users = len(User.objects.all()) # check the database size from django.db import connection cursor = connection.cursor() try: # This will not work if user has new style of configuration for the database # This will also only work for PostgreSQL. Should make another method for checking sqlite database size. cursor.execute("SELECT pg_database_size(%s)", [settings.DATABASES["default"]["NAME"]]) databaseSize = cursor.fetchone()[0] except: databaseSize = 0 # Book activity activityHistory = models.BookHistory.objects.filter(kind__in=[1, 10]).order_by("-modified")[:20] # Booktype version import booki booktypeVersion = ".".join([str(num) for num in booki.version]) return render_to_response( "booktypecontrol/frontpage.html", { "request": request, "booktype_version": booktypeVersion, "admin_options": ADMIN_OPTIONS, "online_users": onlineUsers, "attachments_size": attachmentsSize, "number_of_books": number_of_books, "number_of_users": number_of_users, "number_of_groups": number_of_groups, "database_size": databaseSize, "activity_history": activityHistory, }, )