socket.xml 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. <class name="Socket">
  2. <relationships>
  3. <association name="parent" class="Server" min="1" max="1"/>
  4. </relationships>
  5. <constructor>
  6. <parameter name="my_socket"/>
  7. <body>
  8. <![CDATA[
  9. self.socket = my_socket
  10. self.received_data = ""
  11. self.send_data = ""
  12. self.closed = False
  13. self.association_name = None
  14. ]]>
  15. </body>
  16. </constructor>
  17. <scxml initial="init">
  18. <state id="init">
  19. <transition event="set_association_name" target="../connected">
  20. <parameter name="association_name"/>
  21. <script>
  22. self.association_name = association_name
  23. </script>
  24. </transition>
  25. </state>
  26. <parallel id="connected">
  27. <state id="listening" initial="listen">
  28. <state id="listen">
  29. <onentry>
  30. <raise scope="output" port="socket_out" event="recv_socket">
  31. <parameter expr="self.socket"/>
  32. </raise>
  33. </onentry>
  34. <transition event="received_socket" port="socket_in" cond="(self.socket == socket) and (len(data) > 0)" target=".">
  35. <parameter name="socket"/>
  36. <parameter name="data"/>
  37. <script>
  38. if sys.version_info[0] > 2:
  39. if isinstance(data, bytes):
  40. data = data.decode()
  41. self.received_data += data
  42. </script>
  43. <raise event="received_data"/>
  44. </transition>
  45. <transition event="received_socket" port="socket_in" cond="(self.socket == socket) and (len(data) == 0)" target="../closed">
  46. <parameter name="socket"/>
  47. <parameter name="data"/>
  48. <raise event="received_data"/>
  49. </transition>
  50. </state>
  51. <state id="closed">
  52. <onentry>
  53. <script>
  54. self.closed = True
  55. </script>
  56. </onentry>
  57. </state>
  58. </state>
  59. <state id="sending" initial="waiting_for_data">
  60. <state id="waiting_for_data">
  61. <transition cond="len(self.send_data) > 0" target="../transferring">
  62. <raise scope="output" port="socket_out" event="send_socket">
  63. <parameter expr="self.socket"/>
  64. <parameter expr="self.send_data"/>
  65. </raise>
  66. </transition>
  67. </state>
  68. <state id="transferring">
  69. <transition event="sent_socket" port="socket_in" cond="self.socket == socket" target="../waiting_for_data">
  70. <parameter name="socket"/>
  71. <parameter name="sent_bytes"/>
  72. <script>
  73. self.send_data = self.send_data[sent_bytes:]
  74. </script>
  75. </transition>
  76. </state>
  77. </state>
  78. <state id="queueing">
  79. <state id="queueing">
  80. <transition event="HTTP_input" target=".">
  81. <parameter name="data"/>
  82. <script>
  83. #post_data = "&amp;".join(["%s=%s" % (k, v) for k, v in data.iteritems()])
  84. post_data = data
  85. self.send_data += "HTTP/1.0 200 OK\r\n"
  86. self.send_data += "Content-Length: %s\r\n" % len(post_data)
  87. self.send_data += "Content-Type: %s; charset=UTF-8\r\n" % "text/plain"
  88. self.send_data += "\r\n"
  89. self.send_data += str(post_data)
  90. </script>
  91. </transition>
  92. </state>
  93. </state>
  94. <state id="parsing" initial="wait_for_header">
  95. <state id="wait_for_header">
  96. <transition cond="'\r\n\r\n' in self.received_data and self.received_data.startswith('POST')" target="../wait_for_payload">
  97. <script>
  98. header, self.received_data = self.received_data.split("\r\n\r\n", 1)
  99. header = header.lower()
  100. if "content-length" in header:
  101. _, after = header.split("content-length:", 1)
  102. after = after.split("\r\n", 1)[0]
  103. after = after.strip()
  104. self.length = int(after)
  105. else:
  106. self.length = float('inf')
  107. </script>
  108. </transition>
  109. <transition cond="self.closed and len(self.received_data) == 0" target="../closing">
  110. </transition>
  111. </state>
  112. <state id="closing">
  113. <transition after="0.1" target=".">
  114. <raise event="close"/>
  115. </transition>
  116. </state>
  117. <state id="wait_for_payload">
  118. <transition cond="len(self.received_data) >= self.length or self.closed" target="../wait_for_header">
  119. <script>
  120. if self.length == float('inf'):
  121. data = self.received_data
  122. self.received_data = ""
  123. else:
  124. data = self.received_data[:self.length]
  125. self.received_data = self.received_data[self.length:]
  126. # We support POST data only, so everything is in the data
  127. try:
  128. params = dict([p.split('=') for p in data.split('&amp;')])
  129. data = {k: unquote_plus(v) for k, v in params.items()}
  130. except Exception as e:
  131. print("Problem receiving data in socket: ")
  132. print(str(e))
  133. data = {}
  134. </script>
  135. <raise event="HTTP_output" scope="narrow" target="'parent'">
  136. <parameter expr="self.association_name"/>
  137. <parameter expr="data"/>
  138. </raise>
  139. </transition>
  140. </state>
  141. </state>
  142. <transition event="close" target="../close"/>
  143. </parallel>
  144. <state id="close">
  145. <onentry>
  146. <raise port="socket_out" event="close_socket">
  147. <parameter expr="self.socket"/>
  148. </raise>
  149. <raise scope="narrow" target="'parent'" event="close_socket">
  150. <parameter expr="self.association_name"/>
  151. </raise>
  152. </onentry>
  153. </state>
  154. </scxml>
  155. </class>