async def call_node(self, path: str, data): self.log.info("Got request for path %s", path) if path == "search": if isinstance(data, query_pb2.Query): query = data else: query = query_pb2.Query() query.ParseFromString(data) if not self._am_i_closer_and_update_query(query): return [] data = query.SerializeToString() elif path == "update": self.error("GOT update", data) if isinstance(data, update_pb2.Update): data = data.SerializeToString() result = await self.callMe(path, data) if path == "update": self.notify_update() elif path == "search": #TODO(AB): HACK. do this in a nice way core_id = self._id.replace("-search", "-core").encode("UTF-8") res = response_pb2.SearchResponse() res.ParseFromString(result) for r in res.result: if r.key == core_id: r.distance = self.location.distance( query.directed_search.target.geo) result = res.SerializeToString() return result
async def async_search(self, query): self.log.info("Got search query with TTL %d", query.ttl) my_location = self.search_com.call("get", "location") my_distance = my_location.distance(query.directed_search.target.geo) query.source_key = self._bin_id query.directed_search.distance.geo = my_distance + 1. result = await self.search_com.call_node("search", query) res = response_pb2.SearchResponse() res.ParseFromString(result) for r in res.result: if r.key == self._bin_id: res.result.remove(r) return res
def merge_response(self, resps: List[DataWrapper[response_pb2.SearchResponse]]) -> \ DataWrapper[response_pb2.SearchResponse]: resp = response_pb2.SearchResponse() error_code = 1000 narrative = [] keys = [] success = False for r in resps: result = [] success |= r.success error_code = min(error_code, r.error_code) narrative.extend(r.narrative) for rr in r.data.result: if rr.key in keys: continue keys.append(rr.key) result.append(rr) resp.result.extend(result) return DataWrapper(success, "search", resp, error_code, "", narrative)
async def handle_message( self, msg: query_pb2.Query) -> DataWrapper[response_pb2.SearchResponse]: global _count_request, _count_success, _count_exception, _count_ignored, _count_empty resp = response_pb2.SearchResponse() distance = None _count_request.inc() try: location = self._dap_manager.getPlaneInformation( "location")["values"] if len(location) > 1: self.warning( "Got more then 1 location from dapManager (I'm using first, ignoring the rest now): ", location) #TODO: multiple core location = location[0].value.l prev_distance = msg.directed_search.distance.geo target = msg.directed_search.target.geo distance = geo_distance(location, target) if prev_distance > 0 and distance > prev_distance: #ignore query _count_ignored.inc() self.warning( "Ignoring query with TTL %d, because source (%s) distance (%.3f) was smaller then " "my distance (%.3f)", msg.ttl, msg.source_key.decode("UTF-8"), prev_distance, distance) return DataWrapper(False, "search", resp, 601, "Ignoring query because distance!") else: self.info( "Handling query with TTL %d, because source (%s) distance (%.3f) was greater then" " my distance (%.3f)", msg.ttl, msg.source_key.decode("UTF-8"), prev_distance, distance) except Exception as e: #TODO: what? self.info("Exception during location check: ", str(e)) #return DataWrapper(False, "search", resp, 600, "Ignoring query, location check error!") _count_exception.inc() try: query = self._proto_wrapper.get_instance(msg) result = self._dap_manager.execute(query.toDapQuery()) items = {} for element in result.identifiers: core, agent_id = element.core, element.agent if core not in items: item = response_pb2.SearchResponse.Item() address = element.uri.split(":") if len(address) == 2: item.ip = address[0] item.port = int(address[1]) elif len(address) == 3: item.ip = address[1] item.port = int(address[2]) else: self.warning("No valid address for core: ", core, "! address=", address) continue item.key = core items[core] = item if distance: #TODO multiple core item.distance = distance agent = items[core].agents.add() agent.key = agent_id agent.score = element.score resp.result.extend(items.values()) self.info("SEARCH RESULT: ", resp) if len(items) == 0: _count_empty.inc() except Exception as e: self.exception("Exception while processing query: ", str(e)) _count_exception.inc() return DataWrapper(False, "search", resp, 500, str(e)) _count_success.inc() return DataWrapper(True, "search", resp)
def get_response_type(self): return response_pb2.SearchResponse().__class__