def send_keep_alive(self): message = "Keep-Alive " + self.util.get_iso_8601(time.time(), show_ms=True) envelope = EventEnvelope() envelope.set_to(self.OUTGOING_WS_PATH).set_header( 'type', 'text').set_body(message) self.platform.send_event(envelope)
def exists(self, routes: any): if isinstance(routes, str): single_route = routes if self.has_route(single_route): return True if self.cloud_ready(): event = EventEnvelope() event.set_to(self.SERVICE_QUERY).set_header( 'type', 'find').set_header('route', single_route) result = self.request(event, 8.0) if isinstance(result, EventEnvelope): if result.get_body() is not None: return result.get_body() if isinstance(routes, list): if len(routes) > 0: remote_routes = list() for r in routes: if not self.platform.has_route(r): remote_routes.append(r) if len(remote_routes) == 0: return True if self.platform.cloud_ready(): # tell service query to use the route list in body event = EventEnvelope() event.set_to(self.SERVICE_QUERY).set_header('type', 'find') event.set_header('route', '*').set_body(routes) result = self.request(event, 8.0) if isinstance( result, EventEnvelope) and result.get_body() is not None: return result.get_body() return False
def send_payload(self, data: dict): payload = msgpack.packb(data, use_bin_type=True) payload_len = len(payload) if 'type' in data and data[ 'type'] == 'event' and 'event' in data and payload_len > self.max_ws_payload: evt = data['event'] if 'id' in evt: msg_id = evt['id'] total = int(payload_len / self.max_ws_payload) if payload_len > total: total += 1 buffer = io.BytesIO(payload) count = 0 for i in range(total): count += 1 block = EventEnvelope() block.set_header('id', msg_id) block.set_header('count', count) block.set_header('total', total) block.set_body(buffer.read(self.max_ws_payload)) block_map = dict() block_map['type'] = 'block' block_map['block'] = block.to_map() block_payload = msgpack.packb(block_map, use_bin_type=True) envelope = EventEnvelope() envelope.set_to(self.OUTGOING_WS_PATH).set_header( 'type', 'bytes').set_body(block_payload) self.platform.send_event(envelope) else: envelope = EventEnvelope() envelope.set_to(self.OUTGOING_WS_PATH).set_header( 'type', 'bytes').set_body(payload) self.platform.send_event(envelope)
def _life_cycle(self, headers: dict, body: any): for subscriber in self._subscription: try: event = EventEnvelope() event.set_to(subscriber).set_headers(headers).set_body(body) self.platform.send_event(event) except ValueError as e: self.log.warn( f'Unable to relay life cycle event {headers} to {subscriber} - {e}' )
def logger(self, event: EventEnvelope): if isinstance(event, EventEnvelope): self.log.info('trace=' + str(event.get_headers()) + ', annotations=' + str(event.get_body())) # forward to user provided distributed trace logger if any current_time = time.time() if self._dt_last_check is None or current_time - self._dt_last_check > 5.0: self._dt_last_check = current_time self._dt_found = self.platform.exists(self._dt_processor) if self._dt_found: te = EventEnvelope() te.set_to(self._dt_processor).set_body(event.get_body()) for h in event.get_headers(): te.set_header(h, event.get_header(h)) self.platform.send_event(te)
def logger(self, event: EventEnvelope): if isinstance(event, EventEnvelope): self.log.info( f'trace={event.get_headers()}, annotations={event.get_body()}') if self.platform.is_trace_supported(): # forward to user provided distributed trace logger if any current_time = time.time() if self._dt_last_check is None or current_time - self._dt_last_check > 5.0: self._dt_last_check = current_time self._dt_found = self.platform.exists(self._dt_processor) if self._dt_found: trace_event = EventEnvelope() trace_event.set_to(self._dt_processor).set_body( {'annotations': event.get_body()}) for h in event.get_headers(): trace_event.set_header(h, event.get_header(h)) self.platform.send_event(trace_event)
def _get_server_config(self, headers: dict, body: any): if 'type' in headers: # at this point, login is successful if headers['type'] == 'system.config' and isinstance(body, dict): if self.MAX_PAYLOAD in body: self.max_ws_payload = body[self.MAX_PAYLOAD] self.log.info( 'Automatic segmentation when event payload exceeds ' + format(self.max_ws_payload, ',d')) # advertise public routes to language connector for r in self.platform.get_routes('public'): self.send_payload({'type': 'add', 'route': r}) # tell server that I am ready self.send_payload({'type': 'ready'}) # server acknowledges my ready signal if headers['type'] == 'ready': self.ready = True self.log.info('Ready') # redo subscription if any if self.platform.has_route('pub.sub.sync'): event = EventEnvelope() event.set_to('pub.sub.sync').set_header( 'type', 'subscription_sync') self.platform.send_event(event)
async def connection_handler(self, url): try: async with aiohttp.ClientSession( loop=self._loop, timeout=aiohttp.ClientTimeout(total=10)) as session: full_path = url + '/' + self.origin self.ws = await session.ws_connect(full_path) envelope = EventEnvelope() envelope.set_to(self.INCOMING_WS_PATH).set_header( 'type', 'open') self.platform.send_event(envelope) self.log.info("Connected to " + full_path) closed = False self.last_active = time.time() while self.normal: try: msg = await self.ws.receive(timeout=1) except asyncio.TimeoutError: if not self.normal: break else: # idle - send keep-alive now = time.time() if self.is_connected( ) and now - self.last_active > 30: self.last_active = now self.send_keep_alive() continue # receive incoming event self.last_active = time.time() if msg.type == aiohttp.WSMsgType.TEXT: if self.platform.has_route(self.INCOMING_WS_PATH): envelope = EventEnvelope() envelope.set_to(self.INCOMING_WS_PATH).set_header( 'type', 'text').set_body(msg.data) self.platform.send_event(envelope) else: break elif msg.type == aiohttp.WSMsgType.BINARY: if self.platform.has_route(self.INCOMING_WS_PATH): envelope = EventEnvelope() envelope.set_to(self.INCOMING_WS_PATH).set_header( 'type', 'bytes').set_body(msg.data) self.platform.send_event(envelope) else: break else: if msg.type == aiohttp.WSMsgType.ERROR: self.log.error("Unexpected connection error") if msg.type == aiohttp.WSMsgType.CLOSING: # closing signal received - close the connection now self.log.info("Disconnected, status=" + str(self.close_code) + ", message=" + self.close_message) await self.ws.close(code=self.close_code, message=bytes( self.close_message, 'utf-8')) if self.platform.has_route(self.INCOMING_WS_PATH): envelope = EventEnvelope() envelope.set_to(self.INCOMING_WS_PATH).set_body(self.close_message)\ .set_header('type', 'close').set_header('status', self.close_code) self.platform.send_event(envelope) closed = True if msg.type == aiohttp.WSMsgType.CLOSE or msg.type == aiohttp.WSMsgType.CLOSED: self.close_code = 1001 if msg.data is None else msg.data self.close_message = 'OK' if msg.extra is None else str( msg.extra) self.log.info("Disconnected, status=" + str(self.close_code) + ", message=" + self.close_message) if self.platform.has_route(self.INCOMING_WS_PATH): envelope = EventEnvelope() envelope.set_to(self.INCOMING_WS_PATH).set_body(self.close_message)\ .set_header('type', 'close').set_header('status', self.close_code) self.platform.send_event(envelope) closed = True break if not closed: await self.ws.close(code=1000, message=b'OK') self.ws = None if self.platform.has_route(self.INCOMING_WS_PATH): envelope = EventEnvelope() envelope.set_to(self.INCOMING_WS_PATH).set_body('OK')\ .set_header('type', 'close').set_header('status', 1000) self.platform.send_event(envelope) except aiohttp.ClientConnectorError: self._skip_url() self.log.warn("Unreachable " + url)
def _send_life_cycle_event(self, headers: dict): event = EventEnvelope() event.set_to(self.CONNECTOR_LIFECYCLE).set_headers(headers) self.platform.send_event(event)