1"""Node 2 3this module manage node (start server, add peer, ...) 4.. seealso:: Examples in :dir:`examples.node` 5""" 6 7from .client import Client 8from .events import connected_to, disconnected_from, remote 9from .server import Server 10 11from circuits import BaseComponent, handler, Timer 12from circuits.net.events import connect 13 14 15class Node(BaseComponent): 16 17 """Node 18 19 this class manage node (start server, add peer, ...) 20 .. seealso:: Examples in :dir:`examples.node` 21 """ 22 channel = 'node' 23 __peers = {} 24 25 def __init__(self, port=None, channel=channel, **kwargs): 26 """Start node system. 27 28 :param port: An optional keyword argument which if defined, 29 start server on this port. 30 **Default:** ``None`` (don't start the server) 31 :type port: int 32 33 :param server_ip: An optional keyword argument which define 34 ip where the socket has listen to. 35 **Default:** ``0.0.0.0`` (all ip is allowed) 36 :type server_ip: str 37 38 :param channel: An optional keyword argument which if defined, 39 set channel used for node event. **Default:** ``node`` 40 :type channel: str 41 42 :param receive_event_firewall: An optional keyword argument which if 43 defined, set function or method to call 44 to check if event is allowed for sending. 45 **Default:** ``None`` (no firewall) 46 :type receive_event_firewall: function 47 :type receive_event_firewall: method 48 49 :param send_event_firewall: An optional keyword argument which if 50 defined, set function or method to call to 51 check if event is allowed for executing 52 **Default:** ``None`` (no firewall) 53 :type send_event_firewall: function 54 :type send_event_firewall: method 55 """ 56 super(Node, self).__init__(channel=channel, **kwargs) 57 58 if port is not None: 59 self.server = Server( 60 port, channel=channel, **kwargs).register(self) 61 else: 62 self.server = None 63 64 def add(self, connection_name, hostname, port, **kwargs): 65 """Add new peer to the node. 66 67 :param connection_name: Connection name. 68 :type connection_name: str 69 70 :param hostname: hostname of the remote node. 71 :type hostname: str 72 73 :param port: port of the remote node. 74 :type port: int 75 76 :param auto_remote_event: An optional keyword argument which if 77 defined, bind events automatically to remote 78 execution. **Default:** ``{}`` (no events) 79 :type auto_remote_event: dict 80 81 :param channel: An optional keyword argument which if defined, 82 set channel used for client event. If this keyword is 83 not defined the method will generate the channel name 84 automatically. 85 :type channel: str 86 87 :param reconnect_delay: An optional keyword argument which if defined, 88 set auto reconnect delay. 89 **Default:** ``10`` (seconde) 90 :type reconnect_delay: int 91 92 :param receive_event_firewall: An optional keyword argument which if 93 defined, function or method to call for 94 check if event is allowed for sending. 95 **Default:** ``None`` (no firewall) 96 :type receive_event_firewall: function 97 :type receive_event_firewall: method 98 99 :param send_event_firewall: An optional keyword argument which if 100 defined, setfunction or method to call to 101 check if event is allowed for executing 102 **Default:** ``None`` (no firewall) 103 :type send_event_firewall: function 104 :type send_event_firewall: method 105 106 :return: Channel used on client event. 107 :rtype: str 108 """ 109 # automatic send event to peer 110 auto_remote_event = kwargs.pop('auto_remote_event', {}) 111 for event_name in auto_remote_event: 112 for channel in auto_remote_event[event_name]: 113 @handler(event_name, channel=channel) 114 def event_handle(self, event, *args, **kwargs): 115 yield self.call(remote(event, connection_name)) 116 self.addHandler(event_handle) 117 118 client_channel = kwargs.pop( 119 'channel', 120 '%s_client_%s' % (self.channel, connection_name) 121 ) 122 reconnect_delay = kwargs.pop('reconnect_delay', 10) 123 client = Client(hostname, port, channel=client_channel, **kwargs) 124 125 # connected event binding 126 @handler('connected', channel=client_channel) 127 def connected(self, hostname, port): 128 self.fire(connected_to( 129 connection_name, hostname, port, client_channel, client 130 )) 131 self.addHandler(connected) 132 133 # disconnected event binding 134 @handler('disconnected', 'unreachable', channel=client_channel) 135 def disconnected(self, event, *args, **kwargs): 136 if event.name == 'disconnected': 137 self.fire(disconnected_from( 138 connection_name, hostname, port, client_channel, client 139 )) 140 141 # auto reconnect 142 if reconnect_delay > 0: 143 Timer( 144 reconnect_delay, 145 connect(hostname, port), 146 client_channel 147 ).register(self) 148 149 self.addHandler(disconnected) 150 151 client.register(self) 152 self.__peers[connection_name] = client 153 return client_channel 154 155 def get_connection_names(self): 156 """Get connections names 157 158 :return: The list of connections names 159 :rtype: list of str 160 """ 161 return list(self.__peers) 162 163 def get_peer(self, connection_name): 164 """Get a client object by name 165 166 :param connection_name: Connection name. 167 :type connection_name: str 168 169 :return: The Client object 170 :rtype: :class:`circuits.node.client.Client` 171 """ 172 return self.__peers[connection_name] if connection_name in self.__peers\ 173 else None 174 175 @handler('remote', channel='*') 176 def __on_remote(self, event, remote_event, connection_name, channel=None): 177 """Send event to peer 178 179 Event handler to run an event on peer (the event definition is 180 :class:`circuits.node.events.remote`) 181 182 :param event: The event triggered (by the handler) 183 :type event: :class:`circuits.node.events.remote` 184 185 :param remote_event: Event to execute remotely. 186 :type remote_event: :class:`circuits.core.events.Event` 187 188 :param connection_name: Connection name (peer selection). 189 :type connection_name: str 190 191 :param channel: Remote channel (channel to use on peer). 192 :type channel: str 193 194 :return: The result of remote event 195 :rtype: generator 196 197 :Example: 198 ``# hello is your event to execute remotely 199 # peer_test is peer name 200 result = yield self.fire(remote(hello())), 'peer_test') 201 print(result.value)`` 202 """ 203 node = self.__peers[connection_name] 204 remote_event.channels = (channel,) if channel is not None \ 205 else event.channels 206 return node.send(remote_event) 207