Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

112 строки
3.6KB

  1. import pickle
  2. import re
  3. try:
  4. import eventlet.green.zmq as zmq
  5. except ImportError:
  6. zmq = None
  7. import six
  8. from .pubsub_manager import PubSubManager
  9. class ZmqManager(PubSubManager): # pragma: no cover
  10. """zmq based client manager.
  11. NOTE: this zmq implementation should be considered experimental at this
  12. time. At this time, eventlet is required to use zmq.
  13. This class implements a zmq backend for event sharing across multiple
  14. processes. To use a zmq backend, initialize the :class:`Server` instance as
  15. follows::
  16. url = 'zmq+tcp://hostname:port1+port2'
  17. server = socketio.Server(client_manager=socketio.ZmqManager(url))
  18. :param url: The connection URL for the zmq message broker,
  19. which will need to be provided and running.
  20. :param channel: The channel name on which the server sends and receives
  21. notifications. Must be the same in all the servers.
  22. :param write_only: If set to ``True``, only initialize to emit events. The
  23. default of ``False`` initializes the class for emitting
  24. and receiving.
  25. A zmq message broker must be running for the zmq_manager to work.
  26. you can write your own or adapt one from the following simple broker
  27. below::
  28. import zmq
  29. receiver = zmq.Context().socket(zmq.PULL)
  30. receiver.bind("tcp://*:5555")
  31. publisher = zmq.Context().socket(zmq.PUB)
  32. publisher.bind("tcp://*:5556")
  33. while True:
  34. publisher.send(receiver.recv())
  35. """
  36. name = 'zmq'
  37. def __init__(self, url='zmq+tcp://localhost:5555+5556',
  38. channel='socketio',
  39. write_only=False,
  40. logger=None):
  41. if zmq is None:
  42. raise RuntimeError('zmq package is not installed '
  43. '(Run "pip install pyzmq" in your '
  44. 'virtualenv).')
  45. r = re.compile(r':\d+\+\d+$')
  46. if not (url.startswith('zmq+tcp://') and r.search(url)):
  47. raise RuntimeError('unexpected connection string: ' + url)
  48. url = url.replace('zmq+', '')
  49. (sink_url, sub_port) = url.split('+')
  50. sink_port = sink_url.split(':')[-1]
  51. sub_url = sink_url.replace(sink_port, sub_port)
  52. sink = zmq.Context().socket(zmq.PUSH)
  53. sink.connect(sink_url)
  54. sub = zmq.Context().socket(zmq.SUB)
  55. sub.setsockopt_string(zmq.SUBSCRIBE, u'')
  56. sub.connect(sub_url)
  57. self.sink = sink
  58. self.sub = sub
  59. self.channel = channel
  60. super(ZmqManager, self).__init__(channel=channel,
  61. write_only=write_only,
  62. logger=logger)
  63. def _publish(self, data):
  64. pickled_data = pickle.dumps(
  65. {
  66. 'type': 'message',
  67. 'channel': self.channel,
  68. 'data': data
  69. }
  70. )
  71. return self.sink.send(pickled_data)
  72. def zmq_listen(self):
  73. while True:
  74. response = self.sub.recv()
  75. if response is not None:
  76. yield response
  77. def _listen(self):
  78. for message in self.zmq_listen():
  79. if isinstance(message, six.binary_type):
  80. try:
  81. message = pickle.loads(message)
  82. except Exception:
  83. pass
  84. if isinstance(message, dict) and \
  85. message['type'] == 'message' and \
  86. message['channel'] == self.channel and \
  87. 'data' in message:
  88. yield message['data']
  89. return