ws.py 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. '''This file is part of AToMPM - A Tool for Multi-Paradigm Modelling
  2. Copyright 2011 by the AToMPM team and licensed under the LGPL
  3. See COPYING.lesser and README.md in the root of this project for full details'''
  4. import re, ___websocket as websocket, threading, json, httplib, logging
  5. '''
  6. a friendly wrapper around python-websockets that doubles as a socketio client
  7. _opened true when the socket is first opened
  8. _chlogh a reference to an object that implements onchangelog(), this
  9. method is called upon reception of changelogs from the asworker
  10. we're subscribed to
  11. _dummy true if this is a 'dummy' websocket... see note in main.py
  12. subscribed describes the current state of our subscription to our asworker
  13. None: don't know yet
  14. True: subscribed
  15. False: subscription failed
  16. _ws the python-websocket '''
  17. class WebSocket :
  18. #socket.io messages types
  19. DISCONNECT = '0'
  20. CONNECT = '1'
  21. HEARTBEAT = '2'
  22. MESSAGE = '3'
  23. JSON_MESSAGE = '4'
  24. EVENT = '5'
  25. ACK = '6'
  26. ERROR = '7'
  27. NOOP = '8'
  28. def __init__(self,chlogh=None) :
  29. assert chlogh == None or 'onchangelog' in dir(chlogh)
  30. self._opened = False
  31. self._chlogh = chlogh
  32. self._dummy = (chlogh == None)
  33. self.subscribed = None
  34. self.connect()
  35. '''
  36. connect to the socketio server
  37. 1. perform the HTTP handshake
  38. 2. open a websocket connection
  39. REF:: https://github.com/LearnBoost/socket.io-spec '''
  40. def connect(self) :
  41. conn = httplib.HTTPConnection('127.0.0.1:8124')
  42. conn.request('POST','/socket.io/1/')
  43. resp = conn.getresponse()
  44. if resp.status == 200 :
  45. hskey = resp.read().split(':')[0]
  46. self._ws = websocket.WebSocket(
  47. 'ws://127.0.0.1:8124/socket.io/1/websocket/'+hskey,
  48. onopen = self._onopen,
  49. onmessage = self._onmessage)
  50. else :
  51. raise Exception('websocket initialization failed :: '+str(resp.reason))
  52. '''
  53. close the socket '''
  54. def close(self) :
  55. self._ws.close()
  56. '''
  57. parse and handle incoming message '''
  58. def _onmessage(self,msg) :
  59. if not self._dummy :
  60. logging.debug('## msg recvd '+msg)
  61. msgType = msg[0]
  62. if msgType == WebSocket.CONNECT :
  63. return
  64. elif msgType == WebSocket.ERROR :
  65. raise Exception('received error from socketio :: '+str(msg))
  66. elif msgType == WebSocket.HEARTBEAT :
  67. self._ws.send('2::')
  68. elif msgType == WebSocket.EVENT :
  69. msg = json.loads(msg[len(WebSocket.EVENT+':::'):])
  70. if msg['name'] != 'message' :
  71. raise Exception('received unexpected socketio event :: '+str(msg))
  72. msg = msg['args'][0]
  73. if 'statusCode' in msg and msg['statusCode'] != None :
  74. #on POST /changeListener response
  75. if msg['statusCode'] == 201 :
  76. self.subscribed = True
  77. else :
  78. self.subscribed = False
  79. elif self._chlogh and self.subscribed :
  80. self._chlogh.onchangelog(msg['data'])
  81. else :
  82. pass
  83. '''
  84. mark socket connection as opened '''
  85. def _onopen(self) :
  86. self._opened = True
  87. '''
  88. subscribe to specified asworker '''
  89. def subscribe(self,aswid) :
  90. if not self._opened :
  91. t = threading.Timer(0.25,self.subscribe,[aswid])
  92. t.start()
  93. else :
  94. self._ws.send(
  95. '4:::{"method":"POST","url":"/changeListener?wid='+aswid+'"}')