PageRenderTime 42ms CodeModel.GetById 8ms RepoModel.GetById 0ms app.codeStats 0ms

/extra addons/extra addons/extra-trunk/crm_livechat/crm-lc/livechat/rpc.py

http://hornerp.googlecode.com/
Python | 463 lines | 431 code | 7 blank | 25 comment | 0 complexity | e44af2190783da5848e3da0b6062b344 MD5 | raw file
Possible License(s): MIT, MPL-2.0-no-copyleft-exception, GPL-2.0, GPL-3.0
  1. # -*- encoding: utf-8 -*-
  2. ##############################################################################
  3. #
  4. # OpenERP, Open Source Management Solution
  5. # Copyright (C) 2004-2008 Tiny SPRL (<http://tiny.be>). All Rights Reserved
  6. # $Id$
  7. #
  8. # This program is free software: you can redistribute it and/or modify
  9. # it under the terms of the GNU General Public License as published by
  10. # the Free Software Foundation, either version 3 of the License, or
  11. # (at your option) any later version.
  12. #
  13. # This program is distributed in the hope that it will be useful,
  14. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. # GNU General Public License for more details.
  17. #
  18. # You should have received a copy of the GNU General Public License
  19. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  20. #
  21. ##############################################################################
  22. """
  23. This module provides wrappers arround xmlrpclib that allows accessing
  24. Tiny resources in pythonic way.
  25. """
  26. import time
  27. import socket
  28. import xmlrpclib
  29. import tiny_socket
  30. import common
  31. from tools.translate import _
  32. class RPCException(Exception):
  33. def __init__(self, code, backtrace):
  34. self.code = code
  35. lines = code.split('\n')
  36. self.type = lines[0].split(' -- ')[0]
  37. self.message = ''
  38. if len(lines[0].split(' -- ')) > 1:
  39. self.message = lines[0].split(' -- ')[1]
  40. self.data = '\n'.join(lines[2:])
  41. self.backtrace = backtrace
  42. def __str__(self):
  43. return self.message
  44. class RPCGateway(object):
  45. """Gateway abstraction, that implement common stuffs for rpc gateways.
  46. All RPC gateway should extends this class.
  47. """
  48. def __init__(self, host, port, protocol):
  49. self.protocol = protocol
  50. self.host = host
  51. self.port = port
  52. def _get_db(self):
  53. return session.db
  54. def _get_uid(self):
  55. return session.uid
  56. def _get_passwd(self):
  57. return session.passwd
  58. db = property(_get_db)
  59. uid = property(_get_uid)
  60. passwd = property(_get_passwd)
  61. def get_url(self):
  62. """Get the url
  63. """
  64. return "%s://%s:%s/"%(self.protocol, self.host, self.port)
  65. def listdb(self):
  66. """Get the list of databases.
  67. """
  68. pass
  69. def login(self, db, user, passwd):
  70. """Do login.
  71. @param db: the database
  72. @param user: the user
  73. @param passwd: the password
  74. @return: 1 on success else negative error value
  75. """
  76. pass
  77. def execute(self, obj, method, *args):
  78. """Excecute the method of the obj with the given arguments.
  79. @param obj: the object
  80. @param method: the method to execute
  81. @param args: the arguments
  82. @return: the result of the method
  83. """
  84. pass
  85. def execute_db(self, method, *args):
  86. """Execute a database related method.
  87. """
  88. pass
  89. class XMLRPCGateway(RPCGateway):
  90. """XMLRPC implementation.
  91. """
  92. def __init__(self, host, port, protocol='http'):
  93. """Create new instance of XMLRPCGateway.
  94. @param host: the host
  95. @param port: the port
  96. @param protocol: either http or https
  97. """
  98. super(XMLRPCGateway, self).__init__(host, port, protocol)
  99. self.url = self.get_url() + 'xmlrpc/'
  100. def listdb(self):
  101. sock = xmlrpclib.ServerProxy(self.url + 'db')
  102. try:
  103. return sock.list()
  104. except Exception, e:
  105. return -1
  106. def login(self, db, user, passwd):
  107. sock = xmlrpclib.ServerProxy(self.url + 'common')
  108. try:
  109. res = sock.login(db, user, passwd)
  110. except Exception, e:
  111. return -1
  112. return res
  113. def execute(self, obj, method, *args):
  114. sock = xmlrpclib.ServerProxy(self.url + str(obj))
  115. try:
  116. result = getattr(sock, method)(self.db, self.uid, self.passwd, *args)
  117. return result
  118. except socket.error, (e1, e2):
  119. raise common.error(_('Connection refused !'), e1, e2)
  120. except xmlrpclib.Fault, err:
  121. raise RPCException(err.faultCode, err.faultString)
  122. def execute_db(self, method, *args):
  123. sock = xmlrpclib.ServerProxy(self.url + 'db')
  124. return getattr(sock, method)(*args)
  125. class NETRPCGateway(RPCGateway):
  126. """NETRPC Implementation.
  127. """
  128. def __init__(self, host, port):
  129. super(NETRPCGateway, self).__init__(host, port, 'socket')
  130. def listdb(self):
  131. sock = tiny_socket.mysocket()
  132. try:
  133. sock.connect(self.host, self.port)
  134. sock.mysend(('db', 'list'))
  135. res = sock.myreceive()
  136. sock.disconnect()
  137. return res
  138. except Exception, e:
  139. return -1
  140. def login(self, db, user, passwd):
  141. sock = tiny_socket.mysocket()
  142. try:
  143. sock.connect(self.host, self.port)
  144. sock.mysend(('common', 'login', db, user, passwd))
  145. res = sock.myreceive()
  146. sock.disconnect()
  147. except Exception, e:
  148. return -1
  149. return res
  150. def execute(self, obj, method, *args):
  151. sock = tiny_socket.mysocket()
  152. try:
  153. sock.connect(self.host, self.port)
  154. sock.mysend((obj, method, self.db, self.uid, self.passwd)+ args)
  155. res = sock.myreceive()
  156. sock.disconnect()
  157. return res
  158. except socket.error, (e1, e2):
  159. raise common.error(_('Connection refused !'), e1, e2)
  160. except xmlrpclib.Fault, err:
  161. raise RPCException(err.faultCode, err.faultString)
  162. except tiny_socket.Myexception, err:
  163. raise RPCException(err.faultCode, err.faultString)
  164. def execute_db(self, method, *args):
  165. sock = tiny_socket.mysocket()
  166. sock.connect(self.host, self.port)
  167. sock.mysend(('db', method) + args)
  168. res = sock.myreceive()
  169. sock.disconnect()
  170. return res
  171. class RPCSession(object):
  172. """This is a wrapper class that provides Pythonic way to handle RPC (remote procedure call).
  173. It also provides a way to store session data into different kind of storage.
  174. """
  175. __slots__ = ['host', 'port', 'protocol', 'storage', 'gateway']
  176. def __init__(self, host, port, protocol='socket', storage={}):
  177. """Create new instance of RPCSession.
  178. @param host: the tinyerp-server host
  179. @params port: the tinyerp-server port
  180. @params protocol: the tinyerp-server protocol
  181. @param storage: a dict like storage that will be used to store session data
  182. """
  183. self.host = host
  184. self.port = port
  185. self.protocol = protocol
  186. self.storage = storage
  187. if protocol == 'http':
  188. self.gateway = XMLRPCGateway(host, port, 'http')
  189. elif protocol == 'https':
  190. self.gateway = XMLRPCGateway(host, port, 'https')
  191. elif protocol == 'socket':
  192. self.gateway = NETRPCGateway(host, port)
  193. else:
  194. raise common.error(_("Connection refused !"), _("Unsupported protocol: %s" % protocol))
  195. def __getattr__(self, name):
  196. try:
  197. return super(RPCSession, self).__getattribute__(name)
  198. except:
  199. pass
  200. return self.storage.get(name)
  201. def __setattr__(self, name, value):
  202. if name in self.__slots__:
  203. super(RPCSession, self).__setattr__(name, value)
  204. else:
  205. self.storage[name] = value
  206. def __getitem__(self, name):
  207. return self.storage.get(name)
  208. def __setitem__(self, name, value):
  209. self.storage[name] = value
  210. def __delitem__(self, name):
  211. try:
  212. del self.storage[name]
  213. except:
  214. pass
  215. def get(self, name, default=None):
  216. return self.storage.get(name, default)
  217. def get_url(self):
  218. return self.gateway.get_url()
  219. def listdb(self):
  220. return self.gateway.listdb()
  221. def login(self, db, user, passwd):
  222. if passwd is None:
  223. return -1
  224. uid = self.gateway.login(db, user or '', passwd or '')
  225. if uid <= 0:
  226. return -1
  227. self.uid = uid
  228. self.db = db
  229. self.passwd = passwd
  230. self.open = True
  231. # read the full name of the user
  232. self.user_name = self.execute('object', 'execute', 'res.users', 'read', [uid], ['name'])[0]['name']
  233. # set the context
  234. self.context_reload()
  235. return uid
  236. def logout(self):
  237. try:
  238. self.storage.clear()
  239. except Exception, e:
  240. pass
  241. def is_logged(self):
  242. return self.uid and self.open
  243. def context_reload(self):
  244. """Reload the context for the current user
  245. """
  246. self.context = {'client': 'web'}
  247. self.timezone = 'utc'
  248. # self.uid
  249. context = self.execute('object', 'execute', 'ir.values', 'get', 'meta', False, [('res.users', self.uid or False)], False, {}, True, True, False)
  250. for c in context:
  251. if c[2]:
  252. self.context[c[1]] = c[2]
  253. if c[1] == 'lang':
  254. pass
  255. # ids = self.execute('object', 'execute', 'res.lang', 'search', [('code', '=', c[2])])
  256. # if ids:
  257. # l = self.execute('object', 'execute', 'res.lang', 'read', ids, ['direction'])
  258. # if l and 'direction' in l[0]:
  259. # common.DIRECTION = l[0]['direction']
  260. # import gtk
  261. # if common.DIRECTION == 'rtl':
  262. # gtk.widget_set_default_direction(gtk.TEXT_DIR_RTL)
  263. # else:
  264. # gtk.widget_set_default_direction(gtk.TEXT_DIR_LTR)
  265. elif c[1] == 'tz':
  266. self.timezone = self.execute('common', 'timezone_get')
  267. try:
  268. import pytz
  269. except:
  270. common.warning(_('You select a timezone but Tiny ERP could not find pytz library !\nThe timezone functionality will be disable.'))
  271. # set locale in session
  272. self.locale = self.context.get('lang')
  273. def __convert(self, result):
  274. if isinstance(result, basestring):
  275. return ustr(result)
  276. elif isinstance(result, list):
  277. return [self.__convert(val) for val in result]
  278. elif isinstance(result, tuple):
  279. return tuple([self.__convert(val) for val in result])
  280. elif isinstance(result, dict):
  281. newres = {}
  282. for key, val in result.items():
  283. newres[key] = self.__convert(val)
  284. return newres
  285. else:
  286. return result
  287. def execute(self, obj, method, *args):
  288. if not self.is_logged():
  289. raise common.error(_('Authorization Error !'), _('Not logged...'))
  290. try:
  291. # print "TERP-CALLING:", obj, method, args
  292. result = self.gateway.execute(obj, method, *args)
  293. # print "TERP-RESULT:", result
  294. return self.__convert(result)
  295. except socket.error, (e1, e2):
  296. raise common.error(_('Connection refused !'), e1, e2)
  297. except RPCException, err:
  298. if err.type in ('warning', 'UserError'):
  299. raise common.warning(err.data)
  300. else:
  301. raise common.error(_('Application Error !'), err.code, err.backtrace)
  302. except Exception, e:
  303. raise common.error(_('Application Error !'), str(e))
  304. def execute_db(self, method, *args):
  305. return self.gateway.execute_db(method, *args)
  306. # Client must initialise session with storage.
  307. # for example: session = RPCSession('localhost', 8070, 'socket', storage=dict())
  308. session = None
  309. class RPCProxy(object):
  310. """A wrapper arround xmlrpclib, provides pythonic way to access tiny resources.
  311. For example,
  312. >>> users = RPCProxy("ir.users")
  313. >>> res = users.read([1], ['name', 'active_id'], session.context)
  314. """
  315. def __init__(self, resource):
  316. """Create new instance of RPCProxy for the give tiny resource
  317. @param resource: the tinyresource
  318. """
  319. self.resource = resource
  320. self.__attrs = {}
  321. def __getattr__(self, name):
  322. if not name in self.__attrs:
  323. self.__attrs[name] = RPCFunction(self.resource, name)
  324. return self.__attrs[name]
  325. class RPCFunction(object):
  326. """A wrapper arround xmlrpclib, provides pythonic way to execute tiny methods.
  327. """
  328. def __init__(self, object, func_name):
  329. """Create a new instance of RPCFunction.
  330. @param object: name of a tiny object
  331. @param func_name: name of the function
  332. """
  333. self.object = object
  334. self.func = func_name
  335. def __call__(self, *args):
  336. return session.execute("object", "execute", self.object, self.func, *args)
  337. if __name__=="__main__":
  338. host = 'localhost'
  339. port = '8070'
  340. protocol = 'socket'
  341. session = RPCSession(host, port, protocol, storage=dict())
  342. res = session.listdb()
  343. print res
  344. res = session.login('test421', 'admin', 'admin')
  345. print res
  346. res = RPCProxy('res.users').read([session.uid], ['name'])
  347. print res
  348. res = RPCProxy('ir.values').get('action', 'tree_but_open', [('ir.ui.menu', 73)], False, {})
  349. print res
  350. # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: