class OEFConnection(Connection): """The OEFConnection connects the to the mailbox.""" def __init__(self, oef_addr: str, oef_port: int = 10000, **kwargs): """ Initialize. :param oef_addr: the OEF IP address. :param oef_port: the OEF port. :param kwargs: the keyword arguments (check the parent constructor) """ if kwargs.get("configuration") is None and kwargs.get("connection_id") is None: kwargs["connection_id"] = PublicId("fetchai", "oef", "0.1.0") super().__init__(**kwargs) self.oef_addr = oef_addr self.oef_port = oef_port self._core = AsyncioCore(logger=logger) # type: AsyncioCore self.in_queue = None # type: Optional[asyncio.Queue] self.channel = OEFChannel(self.address, self.oef_addr, self.oef_port, core=self._core) # type: ignore self._connection_check_task = None # type: Optional[asyncio.Future] async def connect(self) -> None: """ Connect to the channel. :return: None :raises Exception if the connection to the OEF fails. """ if self.connection_status.is_connected: return try: self.connection_status.is_connecting = True self._core.run_threaded() loop = asyncio.get_event_loop() self.in_queue = asyncio.Queue() await self._try_connect() self.connection_status.is_connecting = False self.connection_status.is_connected = True self.channel.loop = loop self.channel.in_queue = self.in_queue self._connection_check_task = asyncio.ensure_future( self._connection_check(), loop=self._loop ) except (CancelledError, Exception) as e: # pragma: no cover self._core.stop() self.connection_status.is_connected = False raise e async def _try_connect(self) -> None: """ Try connect to the channel. :return: None :raises Exception if the connection to the OEF fails. """ while not self.connection_status.is_connected: if not self.channel.connect(): logger.warning("Cannot connect to OEFChannel. Retrying in 5 seconds...") await asyncio.sleep(5.0) else: break async def _connection_check(self) -> None: """ Check for connection to the channel. Try to reconnect if connection is dropped. :return: None """ while self.connection_status.is_connected: await asyncio.sleep(2.0) if not self.channel.get_state() == "connected": # pragma: no cover self.connection_status.is_connected = False self.connection_status.is_connecting = True logger.warning( "Lost connection to OEFChannel. Retrying to connect soon ..." ) await self._try_connect() self.connection_status.is_connected = True logger.warning("Successfully re-established connection to OEFChannel.") async def disconnect(self) -> None: """ Disconnect from the channel. :return: None """ assert ( self.connection_status.is_connected or self.connection_status.is_connecting ), "Call connect before disconnect." assert self.in_queue is not None self.connection_status.is_connected = False self.connection_status.is_connecting = False if self._connection_check_task is not None: self._connection_check_task.cancel() self._connection_check_task = None self.channel.disconnect() await self.in_queue.put(None) self._core.stop() async def receive(self, *args, **kwargs) -> Optional["Envelope"]: """ Receive an envelope. Blocking. :return: the envelope received, or None. """ try: assert self.in_queue is not None envelope = await self.in_queue.get() if envelope is None: logger.debug("Received None.") return None logger.debug("Received envelope: {}".format(envelope)) return envelope except CancelledError: logger.debug("Receive cancelled.") return None except Exception as e: logger.exception(e) return None async def send(self, envelope: "Envelope") -> None: """ Send an envelope. :param envelope: the envelope to send. :return: None """ if self.connection_status.is_connected: self.channel.send(envelope) @classmethod def from_config( cls, address: Address, configuration: ConnectionConfig ) -> "Connection": """ Get the OEF connection from the connection configuration. :param address: the address of the agent. :param configuration: the connection configuration object. :return: the connection object """ oef_addr = cast(str, configuration.config.get("addr")) oef_port = cast(int, configuration.config.get("port")) return OEFConnection( oef_addr, oef_port, address=address, configuration=configuration )
core.run_threaded() # create and connect the agent agent = WeatherClient("weatherCLient", oef_addr="127.0.0.1", oef_port=10000, core=core) agent.connect() # look for service agents registered as 'weather_station' that: # - provide measurements for temperature # - provide measurements for air pressure # - provide measurements for humidity query = Query([ Constraint(TEMPERATURE_ATTR.name, Eq(True)), Constraint(AIR_PRESSURE_ATTR.name, Eq(True)), Constraint(HUMIDITY_ATTR.name, Eq(True)) ], WEATHER_DATA_MODEL) agent.search_services(0, query) try: agent.run() time.sleep(3) except Exception as ex: print("EXCEPTION:", ex) finally: agent.stop() agent.disconnect() core.stop()
class OEFConnection(Connection): """The OEFConnection connects the to the mailbox.""" restricted_to_protocols = set() # type: Set[str] def __init__(self, public_key: str, oef_addr: str, oef_port: int = 10000, connection_id: str = "oef", restricted_to_protocols: Optional[Set[str]] = None): """ Initialize. :param public_key: the public key of the agent. :param oef_addr: the OEF IP address. :param oef_port: the OEF port. :param connection_id: the identifier of the connection object. :param restricted_to_protocols: the only supported protocols for this connection. """ super().__init__(connection_id=connection_id, restricted_to_protocols=restricted_to_protocols) self._core = AsyncioCore(logger=logger) # type: AsyncioCore self.in_queue = None # type: Optional[asyncio.Queue] self.channel = OEFChannel(public_key, oef_addr, oef_port, core=self._core) self._connection_check_thread = None # type: Optional[Thread] async def connect(self) -> None: """ Connect to the channel. :return: None :raises Exception if the connection to the OEF fails. """ if self.connection_status.is_connected: return try: self._core.run_threaded() loop = asyncio.get_event_loop() self.in_queue = asyncio.Queue() await self._try_connect() self.connection_status.is_connected = True self.channel.loop = loop self.channel.in_queue = self.in_queue self._connection_check_thread = Thread( target=self._connection_check) self._connection_check_thread.start() except (CancelledError, Exception) as e: # pragma: no cover self._core.stop() self.connection_status.is_connected = False raise e async def _try_connect(self) -> None: """ Try connect to the channel. :return: None :raises Exception if the connection to the OEF fails. """ while not self.connection_status.is_connected: if not self.channel.connect(): logger.warning( "Cannot connect to OEFChannel. Retrying in 5 seconds...") await asyncio.sleep(5.0) else: break def _connection_check(self) -> None: """ Check for connection to the channel. Try to reconnect if connection is dropped. :return: None """ loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) while self.connection_status.is_connected: time.sleep(2.0) if not self.channel.get_state() == "connected": # pragma: no cover self.connection_status.is_connected = False logger.warning( "Lost connection to OEFChannel. Retrying to connect soon ..." ) loop.run_until_complete(self._try_connect()) self.connection_status.is_connected = True logger.warning( "Successfully re-established connection to OEFChannel.") async def disconnect(self) -> None: """ Disconnect from the channel. :return: None """ assert self._connection_check_thread is not None, "Call connect before disconnect." assert self.in_queue is not None self.connection_status.is_connected = False self._connection_check_thread.join() self._connection_check_thread = None self.channel.disconnect() await self.in_queue.put(None) self._core.stop() async def receive(self, *args, **kwargs) -> Optional['Envelope']: """ Receive an envelope. Blocking. :return: the envelope received, or None. """ try: assert self.in_queue is not None envelope = await self.in_queue.get() if envelope is None: logger.debug("Received None.") return None logger.debug("Received envelope: {}".format(envelope)) return envelope except CancelledError: logger.debug("Receive cancelled.") return None except Exception as e: logger.exception(e) return None async def send(self, envelope: 'Envelope') -> None: """ Send an envelope. :param envelope: the envelope to send. :return: None """ if self.connection_status.is_connected: self.channel.send(envelope) @classmethod def from_config( cls, public_key: str, connection_configuration: ConnectionConfig) -> 'Connection': """ Get the OEF connection from the connection configuration. :param public_key: the public key of the agent. :param connection_configuration: the connection configuration object. :return: the connection object """ oef_addr = cast(str, connection_configuration.config.get("addr")) oef_port = cast(int, connection_configuration.config.get("port")) return OEFConnection( public_key, oef_addr, oef_port, connection_id=connection_configuration.name, restricted_to_protocols=set( connection_configuration.restricted_to_protocols))