Python-ELMO is a Python library which offers an encapsulation of the binary tool ELMO, in order to manipulate it easily in Python and SageMath script.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

protocol.py 3.8KB

  1. import os
  2. import json
  3. class ClosureException(Exception):
  4. pass
  5. # https://stackoverflow.com/questions/20007319/how-to-do-a-large-text-file-transfer-in-python
  6. class SocketTool:
  7. @classmethod
  8. def convert_to_bytes(cl, no):
  9. result = bytearray()
  10. result.append(no & 255)
  11. for i in range(3):
  12. no = no >> 8
  13. result.append(no & 255)
  14. return result
  15. @classmethod
  16. def bytes_to_number(cl, b):
  17. import sys
  18. b = b if (sys.version_info > (3, 0)) else map(ord, b)
  19. res = 0
  20. for i in range(4):
  21. res += b[i] << (i*8)
  22. return res
  23. @classmethod
  24. def send_file(cl, s, filename, mode='rb'):
  25. length = os.path.getsize(filename)
  26. s.send(cl.convert_to_bytes(length)) # has to be 4 bytes
  27. with open(filename, mode) as infile:
  28. d = infile.read(1024*64) # We send by pack of 64 ko
  29. while d:
  30. s.send(d)
  31. d = infile.read(1024*64)
  32. @classmethod
  33. def get_file(cl, s):
  34. size = s.recv(4) # assuming that the size won't be bigger then 1GB
  35. size = cl.bytes_to_number(size)
  36. current_size = 0
  37. buffer = b''
  38. while current_size < size:
  39. data = s.recv(1024*64)
  40. if not data:
  41. break
  42. if len(data) + current_size > size:
  43. data = data[:size-current_size] # trim additional data
  44. buffer += data
  45. # you can stream here to disk
  46. current_size += len(data)
  47. # you have entire file in memory
  48. return buffer
  49. @classmethod
  50. def send_data(cl, s, data):
  51. data = json.dumps(data)
  52. data = data.encode('utf-8')
  53. s.send(cl.convert_to_bytes(len(data))) # has to be 4 bytes
  54. for i in range(0, len(data), 1024*64):
  55. s.send(data[i:i+1024*64])
  56. @classmethod
  57. def get_data(cl, s):
  58. import sys
  59. exception_class = json.decoder.JSONDecodeError if (sys.version_info > (3, 0)) else ValueError
  60. try:
  61. data = cl.get_file(s)
  62. data = data.decode('utf-8')
  63. data = json.loads(data)
  64. return data
  65. except exception_class:
  66. return None
  67. @classmethod
  68. def send_ack(cl, s, positive=True):
  69. data = 'OK' if positive else 'NO'
  70. s.send(data.encode('ascii'))
  71. @classmethod
  72. def get_ack(cl, s):
  73. data = s.recv(2).decode('ascii')
  74. return (data == 'OK')
  75. class Protocol:
  76. def __init__(self, clientsocket):
  77. self.clientsocket = clientsocket
  78. def send_file(self, filename, mode='rb'):
  79. SocketTool.send_file(self.clientsocket, filename, mode)
  80. def get_file(self):
  81. return SocketTool.get_file(self.clientsocket)
  82. def send_data(self, data):
  83. SocketTool.send_data(self.clientsocket, data)
  84. def get_data(self):
  85. return SocketTool.get_data(self.clientsocket)
  86. def send_ack(self, positive=True):
  87. SocketTool.send_ack(self.clientsocket, positive)
  88. def send_nack(self, positive=True):
  89. SocketTool.send_ack(self.clientsocket, not positive)
  90. def get_ack(self):
  91. return SocketTool.get_ack(self.clientsocket)
  92. def please_assert(self, condition):
  93. if not condition:
  94. self.send_nack()
  95. self.clientsocket.close()
  96. raise ClosureException
  97. def get_object_or_nack(self, model, **kwargs):
  98. try:
  99. return model.objects.get(**kwargs)
  100. except model.DoesNotExist:
  101. self.send_nack()
  102. self.clientsocket.close()
  103. raise ClosureException
  104. def close(self):
  105. self.clientsocket.close()