Module mcjsonrpc
[hide private]
[frames] | no frames]

Source Code for Module mcjsonrpc

# -*- coding: utf-8 -*-

############################################################################
# mcjsonrpc.py
#
# Class that represents the JSONRPC server.
# 
# (C) 2009 Likya Software Ltd.
############################################################################

import sys
import md5
import time
import base64
import cPickle, zlib, random

from twisted.web import server
from txjsonrpc.web import jsonrpc
from twisted.internet import defer, task

from clientrequest import ClientRequest
from mcerror import MCUnauthorizedLoginError
from mcuser import MCUser
from constants import Constants
from util import Util

class MCJsonRpc(jsonrpc.JSONRPC):

    def __init__(self, server):
        '''
        Creates a JSON_RPC server object.
        '''
        jsonrpc.JSONRPC.__init__(self)
        self._server = server
        
        # Sessions of anonymous clients
        self.anonymousSessions = {}
        
        # Sessions of clients with real users
        self.realUserSessions = {}
        
        # Create a tracker for tracking sessions
        self.sessionTrackerTask = task.LoopingCall(self.trackSessions)
        self.sessionTrackerTask.start(1)
    
    def server(self):
        '''
        Return the application server of this json-rpc server.
        '''
        return self._server

    def trackSessions(self):
        '''
        Tracks the sessions for timeout.
        '''
        now = time.time()
        # Anonymous Users
        for sessionID in self.anonymousSessions.keys():
            if now - self.anonymousSessions[sessionID]['lastAccess'] > Constants.JSON_RPC_SESSION_TIMEOUT:
                del self.anonymousSessions[sessionID]
        # Real Users
        for sessionID in self.realUserSessions.keys():
            if now - self.realUserSessions[sessionID]['lastAccess'] > Constants.JSON_RPC_SESSION_TIMEOUT:
                self.jsonrpc_logout(sessionID)
    
    def checkSession(self, sessionId):
        '''
        Checks if the session with id sessionId is valid.
        If not, gives an error, else updates the session access time.
        '''
        # Update the access time of the session if valis.
        if self.realUserSessions.has_key(sessionId):
            self.realUserSessions[sessionId]['lastAccess'] = time.time()
        elif self.anonymousSessions.has_key(sessionId):
            self.anonymousSessions[sessionId]['lastAccess'] = time.time()
        else:
            raise "ERROR"
    
    @defer.inlineCallbacks
    def runByVirtualUser(self, domain, taskPath, prm, kw):
        '''
        Run the task in the server by virtual user.
        '''
        # Create a virtual user of the requested domain to run the task
        user = MCUser({'username': Constants.VIRTUAL_USER_NAME, 'domain': domain}, virtual=True)
        # Run the task with the virtual user just created
        cr = ClientRequest(domainName, taskPath, 
            *cPickle.loads(zlib.decompress(base64.decodestring(prm))), 
            **cPickle.loads(zlib.decompress(base64.decodestring(kw)))
        )
        data = yield self.run(user, taskPath, cr.dumps())
        defer.returnValue(data)
    
    @defer.inlineCallbacks
    def jsonrpc_run(self, sessionID, clientRequestDumped):
        '''
        To run a task from a JSON_RPC request.
        '''
        cr = ClientRequest.loads(base64.decodestring(clientRequestDumped))
        # If the session is valid.
        if self.realUserSessions.has_key(sessionID):
            # Create the user of the session
            userName = self.realUserSessions[sessionID]['userName']
            domainName = self.realUserSessions[sessionID]['domainName']
            domain = self.server().domainManager().domain(domainName)
            user = MCUser({'username': userName, 'domain': domain})
            # Run the task
            cr.setDomain(domain)
            data = yield self.server().run(user, cr.dumps())
            defer.returnValue(base64.encodestring(data))
        
        # The session is not valid, throw an exception.
        else:
            rt = base64.encodestring(zlib.compress(cPickle.dumps(Exception('MCUnauthorizedLoginError'))))
            defer.returnValue(rt)

    @defer.inlineCallbacks
    def jsonrpc_getRemoteCode(self, sessionID, codePath):
        '''
        To get packages from the mocop server to the Json server.
        '''
        # If the session is valid.
        if self.realUserSessions.has_key(sessionID):
            
            # Create the user of the session
            userName = self.realUserSessions[sessionID]['userName']
            domainName = self.realUserSessions[sessionID]['domainName']
            domain = self.server().domainManager().domain(domainName)
            user = MCUser({'username': userName, 'domain': domain})
            # Run the task
            cr = ClientRequest(domainName, 'worker.MOCSender', codePath)
            cr.setDomain(domain)
            data = yield self.server().run(user, cr.dumps())
            defer.returnValue(base64.encodestring(data))
        
        # The session is not valid, throw an exception.
        else:
            exc = base64.encodestring(zlib.compress(cPickle.dumps((Exception('MCUnauthorizedLoginError'), None))))
            defer.returnValue(exc)

    def jsonrpc_getPackages(self, packageList):
        '''
        To get the package code from Mocop Server to Json Server.
        '''
        packageDict = {}
        for packageName in packageList:
            f = open(packageName+'.pyc', 'rb')
            data = f.read()
            f.close()
            packageDict[packageName] = data
        rt = base64.encodestring(zlib.compress(cPickle.dumps(packageDict)))
        return rt

    def jsonrpc_getUserInfo(self, sessionID):
        '''
        Returns the user info related with the session with sessionID.
        '''
        # If the session is valid.
        if self.realUserSessions.has_key(sessionID):
            
            userName = self.realUserSessions[sessionID]['userName']
            domainName = self.realUserSessions[sessionID]['domainName']
            domain = self.server().domainManager().domain(domainName)
            user = MCUser({'username': userName, 'domain': domain})
            user = user.toDict()
            user['_domainName'] = domainName
            user['_domain'] = domain.toDict()
            return user
        
        # The session is not valid, throw an exception.
        else:
            exc = base64.encodestring(zlib.compress(cPickle.dumps(Exception('MCUnauthorizedLoginError'))))
            defer.returnValue(exc)

    @defer.inlineCallbacks
    def jsonrpc_login(self, domainName, userName, password):
        '''
        To login a domain with a user.
        '''
        if not domainName or not userName or not password:
            raise MCUnauthorizedLoginError
        
        try:
            realPassword = yield self.server().getLoginPassword(domainName, userName)
        except Exception, e:
            raise MCUnauthorizedLoginError
        
        if password != realPassword:
            raise MCUnauthorizedLoginError
        
        # Create a session
        sessionID = Util.uniq()
        self.realUserSessions[sessionID] = {
            'userName': userName,
            'domainName': domainName,
            'lastAccess': time.time(),
        }
        defer.returnValue(sessionID)

    def jsonrpc_logout(self, sessionID):
        '''
        To logout from the server.
        Used also in session timeout
        '''
        if self.realUserSessions.has_key(sessionID):
            del self.realUserSessions[sessionID]
        return 'OK'