networkclient.xml 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. <class name="NetworkClient">
  2. <constructor>
  3. <body>
  4. self.socket = None
  5. self.host = None
  6. self.received_data = ""
  7. self.send_data = ""
  8. self.parsing_data = ""
  9. self.queue = []
  10. </body>
  11. </constructor>
  12. <scxml>
  13. <parallel id="parallel">
  14. <state id="client" initial="wait_for_destination">
  15. <transition event="connect" cond="self.socket is not None" target="close">
  16. <parameter name="hostname"/>
  17. <parameter name="port"/>
  18. <script>
  19. self.host = (hostname, port)
  20. </script>
  21. </transition>
  22. <transition event="connect" cond="self.socket is None" target="init">
  23. <parameter name="hostname"/>
  24. <parameter name="port"/>
  25. <script>
  26. self.host = (hostname, port)
  27. </script>
  28. </transition>
  29. <state id="wait_for_destination"/>
  30. <state id="init">
  31. <onentry>
  32. <raise scope="output" event="create_socket" output="socket_out"/>
  33. </onentry>
  34. <transition port="socket_in" event="created_socket" target="../connecting">
  35. <parameter name="socket"/>
  36. <script>
  37. self.socket = socket
  38. </script>
  39. </transition>
  40. </state>
  41. <state id="connecting">
  42. <onentry>
  43. <raise scope="output" event="connect_socket" output="socket_out">
  44. <parameter expr="self.socket"/>
  45. <parameter expr="self.host"/>
  46. </raise>
  47. </onentry>
  48. <transition event="connected_socket" port="socket_in" target="../connected">
  49. <raise scope="broad" event="connected"/>
  50. </transition>
  51. </state>
  52. <parallel id="connected">
  53. <!-- We explicitly use the fact that there is no threading -->
  54. <state id="processing" initial="processing">
  55. <state id="processing">
  56. <transition cond="'\0' in self.received_data" target="../parse">
  57. <script>
  58. self.parsing_data, self.received_data = self.received_data.split('\0', 1)
  59. </script>
  60. </transition>
  61. </state>
  62. <state id="parse">
  63. <transition cond="self.parsing_data.startswith('MSG ')" target="../processing">
  64. <raise scope="broad" event="receive_message">
  65. <parameter expr="self.parsing_data[4:]"/>
  66. </raise>
  67. </transition>
  68. <transition cond="self.parsing_data.startswith('ACK MSG')" target="../processing"/>
  69. <transition cond="self.parsing_data.startswith('ACK JOIN')" target="../processing">
  70. <raise scope="broad" event="joined">
  71. <parameter expr="self.parsing_data.split(' ')[2]"/>
  72. </raise>
  73. </transition>
  74. <transition cond="self.parsing_data.startswith('ALIVE')" target="../processing">
  75. <raise scope="broad" event="alive"/>
  76. </transition>
  77. <transition cond="self.parsing_data.startswith('ACK LEAVE')" target="../processing">
  78. <raise scope="broad" event="left"/>
  79. </transition>
  80. </state>
  81. </state>
  82. <state id="receiving">
  83. <state id="receive">
  84. <onentry>
  85. <raise scope="output" event="recv_socket" output="socket_out">
  86. <parameter expr="self.socket"/>
  87. </raise>
  88. </onentry>
  89. <transition port="socket_in" event="received_socket" cond="(self.socket == socket) and (data != '')" target=".">
  90. <parameter name="socket"/>
  91. <parameter name="data"/>
  92. <script>
  93. print("Got data " + repr(data))
  94. print("Total data: " + repr(self.received_data))
  95. self.received_data += data
  96. </script>
  97. </transition>
  98. <!-- For the sake of this exercise, wait for timeout instead of directly signaling this close -->
  99. <transition port="socket_in" event="received_socket" cond="(self.socket == socket) and (data == '')" target=".">
  100. <parameter name="socket"/>
  101. <parameter name="data"/>
  102. <raise event="close"/>
  103. </transition>
  104. </state>
  105. </state>
  106. <state id="sending" initial="waiting_for_inputdata">
  107. <state id="waiting_for_inputdata">
  108. <transition cond="len(self.queue) > 0" target="../transmitting">
  109. <script>
  110. self.send_data = self.queue.pop(0) + "\0"
  111. </script>
  112. </transition>
  113. </state>
  114. <state id="transmitting">
  115. <onentry>
  116. <raise scope="output" event="send_socket" output="socket_out">
  117. <parameter expr="self.socket"/>
  118. <parameter expr="self.send_data"/>
  119. </raise>
  120. </onentry>
  121. <transition port="socket_in" cond="self.socket == socket and (sent == len(self.send_data))" event="sent_socket" target="../waiting_for_inputdata">
  122. <parameter name="socket"/>
  123. <parameter name="sent"/>
  124. <script>
  125. self.send_data = ""
  126. </script>
  127. </transition>
  128. <transition port="socket_in" cond="self.socket == socket and (sent != len(self.send_data))" event="sent_socket" target=".">
  129. <parameter name="socket"/>
  130. <parameter name="sent"/>
  131. <script>
  132. self.send_data = self.send_data[sent:]
  133. </script>
  134. </transition>
  135. </state>
  136. </state>
  137. </parallel>
  138. <transition event="close" target="error_close"/>
  139. <state id="error_close">
  140. <onentry>
  141. <raise scope="output" event="close_socket" output="socket_out">
  142. <parameter expr="self.socket"/>
  143. </raise>
  144. </onentry>
  145. <transition event="closed_socket" cond="self.socket == socket" target="../wait_for_destination">
  146. <parameter name="socket"/>
  147. <script>
  148. self.socket = None
  149. self.host = None
  150. </script>
  151. </transition>
  152. </state>
  153. <state id="close">
  154. <onentry>
  155. <raise scope="output" event="close_socket" output="socket_out">
  156. <parameter expr="self.socket"/>
  157. </raise>
  158. </onentry>
  159. <transition event="closed_socket" cond="self.socket == socket" target="../init">
  160. <parameter name="socket"/>
  161. <raise scope="broad" event="disconnected"/>
  162. </transition>
  163. </state>
  164. <transition event="disconnect" cond="self.socket is not None" target="close">
  165. <script>
  166. print("Closing socket")
  167. </script>
  168. </transition>
  169. <transition event="disconnect" cond="self.socket is None" target="wait_for_destination">
  170. <script>
  171. print("Signaling disconnectedness")
  172. </script>
  173. <raise scope="broad" event="disconnected"/>
  174. </transition>
  175. </state>
  176. <state id="queue">
  177. <state id="queue">
  178. <transition event="send_message" target=".">
  179. <parameter name="data"/>
  180. <script>
  181. self.queue.append("MSG %s: %s" % (socket.gethostname(), data))
  182. </script>
  183. </transition>
  184. <transition event="join" target=".">
  185. <parameter name="data"/>
  186. <script>
  187. self.queue.append("JOIN %s" % data)
  188. </script>
  189. </transition>
  190. <transition event="leave" target=".">
  191. <script>
  192. self.queue.append("LEAVE")
  193. </script>
  194. </transition>
  195. <transition event="poll" target=".">
  196. <script>
  197. self.queue.append("POLL")
  198. </script>
  199. </transition>
  200. </state>
  201. </state>
  202. </parallel>
  203. </scxml>
  204. </class>