1
0

ebrpc.py 2.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. ### ebrpc
  2. ## query = ebencode({'y':'q', 'q':'<method>', 'a':[<params>])
  3. ## response = ebencode({'y':'r', 'r':<return value>}}
  4. ## fault = ebencode({'y':'e','c':'<fault code>', 's':'<fault string>'
  5. from xmlrpclib import Error, Fault
  6. from types import TupleType
  7. from BTL.ebencode import ebencode, ebdecode
  8. def dump_fault(code, msg):
  9. return ebencode({'y':'e', 'c':code, 's':msg})
  10. def dumps(params, methodname=None, methodresponse=None, encoding=None, allow_none=False):
  11. if methodresponse and isinstance(params, TupleType):
  12. assert len(params) == 1, "response tuple must be a singleton"
  13. if methodname:
  14. out = ebencode({'y':'q', 'q':methodname, 'a':params})
  15. elif isinstance(params, Fault):
  16. out = ebencode({'y':'e', 'c':params.faultCode, 's':params.faultString})
  17. elif methodresponse:
  18. out = ebencode({'y':'r', 'r':params[0]})
  19. else:
  20. raise Error("")
  21. return out
  22. def loads(data):
  23. d = ebdecode(data)
  24. if d['y'] == 'e':
  25. raise Fault(d['c'], d['s']) # the server raised a fault
  26. elif d['y'] == 'r':
  27. # why is this return value so weird?
  28. # because it's the way that loads works in xmlrpclib
  29. return (d['r'],), None
  30. elif d['y'] == 'q':
  31. return d['a'], d['q']
  32. raise ValueError
  33. class DFault(Exception):
  34. """Indicates an Datagram EBRPC fault package."""
  35. # If you return a DFault with tid=None from within a function called via
  36. # twispread's TEBRPC.callRemote then TEBRPC will insert the tid for the call.
  37. def __init__(self, faultCode, faultString, tid=None):
  38. self.faultCode = faultCode
  39. self.faultString = faultString
  40. self.tid = tid
  41. self.args = (faultCode, faultString)
  42. def __repr__(self):
  43. return (
  44. "<Fault %s: %s>" %
  45. (self.faultCode, repr(self.faultString))
  46. )
  47. ### datagram interface
  48. ### has transaction ID as third return valuebt
  49. ### slightly different API, returns a tid as third argument in query/response
  50. def dumpd(params, methodname=None, methodresponse=None, encoding=None, allow_none=False, tid=None):
  51. assert tid is not None, "need a transaction identifier"
  52. if methodname:
  53. out = ebencode({'y':'q', 't':tid, 'q':methodname, 'a':params})
  54. elif isinstance(params, DFault):
  55. out = ebencode({'y':'e', 't':tid, 'c':params.faultCode, 's':params.faultString})
  56. elif methodresponse:
  57. out = ebencode({'y':'r', 't':tid, 'r':params})
  58. else:
  59. raise Error("")
  60. return out
  61. def loadd(data):
  62. d = ebdecode(data)
  63. if d['y'] == 'e':
  64. raise DFault(d['c'], d['s'], d['t'])
  65. elif d['y'] == 'r':
  66. return d['r'], None, d['t']
  67. elif d['y'] == 'q':
  68. return d['a'], d['q'], d['t']
  69. raise ValueError