# -*- 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'