def _distribute(self, peer, topic, headers, message=None, bus=''): try: subscriptions = self._peer_subscriptions[bus] except KeyError: return 0 subscribers = set() for prefix, subscription in subscriptions.iteritems(): if subscription and topic.startswith(prefix): subscribers |= subscription if subscribers: sender = encode_peer(peer) json_msg = jsonapi.dumps( jsonrpc.json_method(None, 'pubsub.push', [sender, bus, topic, headers, message], None)) frames = [ zmq.Frame(b''), zmq.Frame(b''), zmq.Frame(b'RPC'), zmq.Frame(json_msg) ] socket = self.core().socket for subscriber in subscribers: socket.send(subscriber, flags=SNDMORE) socket.send_multipart(frames, copy=False) return len(subscribers)
def _send_auth_update_to_pubsub(self): user_to_caps = self.get_user_to_capabilities() # Send auth update message to router json_msg = jsonapi.dumpb(dict(capabilities=user_to_caps)) frames = [zmq.Frame(b'auth_update'), zmq.Frame(json_msg)] # <recipient, subsystem, args, msg_id, flags> self.core.socket.send_vip(b'', b'pubsub', frames, copy=False)
def publish(self, peer, topic, headers=None, message=None, bus=''): """Publish a message to a given topic via a peer. Publish headers and message to all subscribers of topic on bus. If peer is None, use self. Adds volttron platform version compatibility information to header as variables min_compatible_version and max_compatible version param peer: peer type peer: str param topic: topic for the publish message type topic: str param headers: header info for the message type headers: None or dict param message: actual message type message: None or any param bus: bus type bus: str return: Number of subscribers the message was sent to. :rtype: int :Return Values: Number of subscribers """ if headers is None: headers = {} headers['min_compatible_version'] = min_compatible_version headers['max_compatible_version'] = max_compatible_version if peer is None: peer = 'pubsub' # For backward compatibility with old pubsub if self._send_via_rpc: return self.rpc().call( peer, 'pubsub.publish', topic=topic, headers=headers, message=message, bus=bus) else: result = next(self._results) # Parameters are stored initially, in case remote agent/platform is using old pubsub if self._parameters_needed: kwargs = dict(op='publish', peer=peer, topic=topic, bus=bus, headers=headers, message=message) self._save_parameters(result.ident, **kwargs) json_msg = jsonapi.dumps(dict(bus=bus, headers=headers, message=message)) frames = [zmq.Frame(b'publish'), zmq.Frame(str(topic)), zmq.Frame(str(json_msg))] #<recipient, subsystem, args, msg_id, flags> self.vip_socket.send_vip(b'', 'pubsub', frames, result.ident, copy=False) return result
def _send_protected_update_to_pubsub(self, contents): protected_topics_msg = jsonapi.dumpb(contents) frames = [ zmq.Frame(b'protected_update'), zmq.Frame(protected_topics_msg) ] if self._is_connected: try: # <recipient, subsystem, args, msg_id, flags> self.core.socket.send_vip(b'', b'pubsub', frames, copy=False) except VIPError as ex: _log.error( "Error in sending protected topics update to clear PubSub: " + str(ex))
def publish_callback(self, peer, sender, bus, topic, headers, message): """ Callback method registered with local message bus to receive PubSub messages subscribed by external platform agents. PubSub component of router will route the message to appropriate external platform subscribers. :return: """ json_msg = jsonapi.dumps( dict(bus=bus, headers=headers, message=message)) # Reformat the message into ZMQ VIP message frames frames = [ sender, '', 'VIP', '', '', 'pubsub', zmq.Frame('publish'), zmq.Frame(str(topic)), zmq.Frame(str(json_msg)) ] self.zmq_router.pubsub.handle_subsystem(frames, '')
def pubsub_peer_publish(self, topic, headers, message=None, bus=''): peer = bytes(self.local.vip_message.peer) try: subscriptions = self._pubsub_peer_subscriptions[bus] except KeyError: return 0 subscribers = set() for prefix, subscription in subscriptions.iteritems(): if subscription and topic.startswith(prefix): subscribers |= subscription if subscribers: json_msg = jsonapi.dumps(jsonrpc.json_method( None, 'pubsub.push', [peer, bus, topic, headers, message], None)) frames = [zmq.Frame(b'RPC'), zmq.Frame(json_msg)] socket = self.vip_socket for subscriber in subscribers: socket.send_vip(subscriber, 'RPC', flags=SNDMORE) socket.send_multipart(frames, copy=False) return len(subscribers)
if __file__.endswith('.pyc') or __file__.endswith('.pyo'): from imp import load_compiled as load else: from imp import load_source as load green = load('.'.join([__name__, 'green']), __file__) import zmq from zmq import NOBLOCK, SNDMORE, ZMQError, EINVAL, DEALER, ROUTER, RCVMORE __all__ = ['ProtocolError', 'Message', 'Socket', 'BaseRouter'] _GREEN = zmq.__name__.endswith('.green') PROTO = b'VIP1' # Create these static frames for non-copy sends as an optimization _PROTO = zmq.Frame(PROTO) _ERROR = zmq.Frame(b'error') _PONG = zmq.Frame(b'pong') _VERSION = zmq.Frame(b'1.0') _WELCOME = zmq.Frame(b'welcome') # Error code to message mapping ERRORS = { 30: 'Peer unknown', 31: 'Peer temporarily unavailable', 40: 'Bad request', 41: 'Unauthorized', 50: 'Internal error', 51: 'Not implemented', }
if __file__.endswith('.pyc') or __file__.endswith('.pyo'): from imp import load_compiled as load else: from imp import load_source as load green = load('.'.join([__name__, 'green']), __file__) # pylint: disable=invalid-name import zmq from zmq import NOBLOCK, SNDMORE, ZMQError, EINVAL, DEALER, ROUTER, RCVMORE __all__ = ['ProtocolError', 'Message', 'Socket', 'BaseRouter'] _GREEN = zmq.__name__.endswith('.green') PROTO = b'VIP1' # Create these static frames for non-copy sends as an optimization _PROTO = zmq.Frame(PROTO) _ERROR = zmq.Frame(b'error') _PONG = zmq.Frame(b'pong') _VERSION = zmq.Frame(b'1.0') _WELCOME = zmq.Frame(b'welcome') # Again, optimizing by pre-creating frames _ROUTE_ERRORS = { errnum: (zmq.Frame(str(errnum).encode('ascii')), zmq.Frame(os.strerror(errnum).encode('ascii'))) for errnum in [zmq.EHOSTUNREACH, zmq.EAGAIN] } _INVALID_SUBSYSTEM = (zmq.Frame(str(zmq.EPROTONOSUPPORT).encode('ascii')), zmq.Frame( os.strerror(zmq.EPROTONOSUPPORT).encode('ascii')))