def proccess_message(self, data, addr, running_in_thread=False): # data = json.loads(msg) if data['operation'] != 'DISCOVER': print("Data received: " + str(data)) if data['operation'] == 'DISCOVER': if data['join']: # addr = str(data['sender'][1]), int(data['sender'][2]) if addr != (self.node.ip, self.node.port): answer = { 'operation': 'CONTACT', 'sender': list(self.node), 'key': data['key'] } self.send_udp_msg(json.dumps(answer).encode(), addr) self.update(tuple(data['sender'])) print(f"{data['sender']} joined") else: if addr != (self.node.ip, self.node.port): ip, port = str(data['ip']), int(data['port']) server_addr = (self.node.ip, self.tcp_server_port) try: self.sendall(server_addr, ip, port) except: pass elif data['operation'] == 'CONTACT': contact = tuple(data['sender']) self.update(contact) self.lookup_node(self.node.ID) # A peer has to perform a method specified by other peer by RPC elif data['operation'] == 'EXECUTE': result = None if data['method'] == 'FIND_NODE': result = self.node.FIND_NODE(data['id']) elif data['method'] == 'FIND_VALUE': result = self.node.FIND_VALUE(data['id']) answer = {'operation': 'RESPONSE', 'result': result, 'key': data['key'], 'sender': [self.node.ID, self.node.ip, self.node.port] } self.sendall(answer, addr[1]) if 'sender' in data: self.update(tuple(data['sender'])) return elif data['method'] == 'PING': result = self.node.PING() elif data['method'] == 'STORE': key, value = data['store_key'], data['store_value'] publisher, sender = tuple(data['publisher']), tuple(data['sender']) result = self.node.STORE(key, value, publisher, sender, to_update=data['to_update']) elif data['method'] == 'LOOKUP': result = self.lookup_value(data["id"]) elif data['method'] == 'PUBLISH': node = self.node.asTuple() self.publish(data, node, node) if result is not None: answer = {'operation': 'RESPONSE', 'result': result, 'key': data['key'], 'sender': [self.node.ID, self.node.ip, self.node.port] } answer = utils.dumps_json(answer).encode() self.send_udp_msg(answer, addr) if 'sender' in data: self.update(tuple(data['sender'])) # A peer is requested to perform a RPC to other peer elif data['operation'] == 'RPC': msg = None if data['method'] == 'FIND_NODE': msg = utils.build_FIND_NODE_msg(data['id'], self.node) elif data['method'] == 'FIND_VALUE': msg = utils.build_FIND_VALUE_msg(data['id'], self.node) elif data['method'] == 'PING': msg = utils.build_PING_msg(self.node) elif data['method'] == 'STORE': msg = utils.build_STORE_msg(data['storeKey'], data['store_value'], self.node, self.node) if msg is not None: # The address of the remote peer wich it will be used as the target of the RPC addr = (data['ip'], data['port']) msg = utils.dumps_json(msg).encode() self.send_udp_msg(msg, addr) # The peer receives the answer of a RPC made before elif data['operation'] == 'RESPONSE': self.set_response(data['key'], data) if not Node.Equals(data['sender'], self.node): self.update(data['sender']) if running_in_thread: exit_thread()
def lookup_value(self, ID): to_query = self.node.get_n_closest(ID, self.node.alpha) pending = [] heapq.heapify(pending) myinfo = (self.node.ID ^ ID, self.node.asTuple()) enquired = [myinfo] alives = [myinfo] if len(to_query) == 0: founded, data, file_bytes = self.node.FIND_VALUE(ID) if founded: return (True, data, file_bytes) else: return (False, myinfo, None) else: founded, data, file_bytes = self.node.FIND_VALUE(ID) if founded: return (True, data, file_bytes) closest_node = heapq.nsmallest(1, to_query)[0][0] round = 1 while True: for d,n in to_query: k_closest, data = [], None if not Node.Equals(n, self.node): msg = utils.build_FIND_VALUE_msg(ID, self.node.asTuple()) sock = self.sendall(msg, n[1], close=False) # data = self.get_response(msg['key']) data = self.recvall(sock) utils.close_connection(sock) if data != None: data = json.loads(data) if data['result'][0]: return data['result'] # if data['result'][0]: return data k_closest = [(t[0], tuple(t[1])) for t in data['result'][1]] self.update(tuple(data['sender'])) if (d,n) not in enquired: enquired.append((d, n)) if data != None and (d,n) not in alives: alives.append((d, n)) for t in k_closest: if not t in enquired and not t in to_query and not t in pending: pending.append(t) to_query.clear() if pending == []: break c = heapq.nsmallest(1, pending)[0][0] top = self.node.alpha if c <= closest_node else self.node.k closest_node = min(closest_node, c) for _ in range(top): try: to_query.append(heapq.heappop(pending)) except: break round += 1 return (False, heapq.nsmallest(self.node.k, enquired), None)
def attend(client): while True: msg = self.recvall(client) if not msg: break # print(f'RECEIVED MSG {msg}') data = {'method': None} try: data = json.loads(msg) except: pass if data['method'] == 'PUBLISH': node = self.node.asTuple() self.publish(data, node, node) elif data['method'] == 'LOOKUP': answer = self.lookup_value(data['id']) founded, result, file_bytes = answer[0], answer[1], answer[2] if founded and result['value_type'] == 'file': if not file_bytes: file_bytes = self.recv_file() # try: client.sendall(file_bytes) # except: pass client.sendall(file_bytes) else: if not founded: result = None client.sendall(utils.dumps_json(result).encode() + b'\r\n\r\n') client.close() elif data['method'] == 'PING': client.send(b'PING') elif data['method'] == 'STORE': key, value = data['store_key'], data['store_value'] publisher, sender = tuple(data['publisher']), tuple(data['sender']) real_value = None if data['value_type'] == 'file': real_value = self.recv_file() self.node.STORE(key, value, publisher, sender, data['value_type'], real_value, data['to_update']) elif data['method'] == 'FIND_VALUE': founded, result, file_bytes = self.node.FIND_VALUE(data['id']) answer = {'operation': 'RESPONSE', 'result': (founded, result, file_bytes), 'key': data['key'], 'sender': [self.node.ID, self.node.ip, self.node.port] } # client.sendall(utils.dumps_json(answer).encode() + b'\r\n\r\n') answer = utils.dumps_json(answer) client.sendall(answer.encode() + b'\r\n\r\n') if founded and result['value_type'] == 'file': # files_bytes = utils.load_file(result['value']) self._send_file(file_bytes, data['sender'][1]) if not Node.Equals(data['sender'], self.node): self.update(data['sender']) elif data['method'] == 'UPDATE': self._update(data['store_key'], data['store_value'], data['publisher'], data['sender']) elif data['method'] == 'FIND_NODE': result = self.node.FIND_NODE(data['id']) answer = {'operation': 'RESPONSE', 'result': result, 'key': data['key'], 'sender': [self.node.ID, self.node.ip, self.node.port] } # client.sendall(utils.dumps_json(answer).encode() + b'\r\n\r\n') answer = utils.dumps_json(answer) client.sendall(answer.encode() + b'\r\n\r\n') if not Node.Equals(data['sender'], self.node): self.update(data['sender']) exit_thread()
def lookup_node(self, ID): ID = int(ID) to_query = self.node.get_n_closest(ID, self.node.alpha) pending = [] heapq.heapify(pending) myinfo = (self.node.ID ^ ID, self.node.asTuple()) enquired = [myinfo] alives = [myinfo] if len(to_query) == 0: return [(self.node.ID ^ ID, self.node.asTuple())] # return [] closest_node = heapq.nsmallest(1, to_query)[0][0] round = 1 while True: for d,n in to_query: k_closest, data = [], None if not Node.Equals(n, self.node): # k_closest = n[1].FIND_NODE(ID, self.node.k) msg = utils.build_FIND_NODE_msg(ID, self.node.asTuple()) ip, port = n[1], n[2] # self.send_udp_msg(utils.dumps_json(msg).encode(), (ip, port)) # # data = self.get_answer(msg['key']) # data = self.get_response(msg['key']) sock = self.sendall(msg, n[1], close=False) # data = self.get_response(msg['key']) data = self.recvall(sock) try: data = json.loads(data) except: data = None utils.close_connection(sock) if data: k_closest = [(t[0], tuple(t[1])) for t in data['result']] self.update(tuple(data['sender'])) if (d,n) not in enquired: enquired.append((d, n)) if data != None and (d,n) not in alives: alives.append((d, n)) for t in k_closest: if not t in enquired and not t in to_query and not t in pending: pending.append(t) to_query.clear() if pending == []: break c = heapq.nsmallest(1, pending)[0][0] # print(c) #print(closest_node) top = self.node.alpha if c <= closest_node else self.node.k closest_node = min(closest_node, c) for _ in range(top): try: to_query.append(heapq.heappop(pending)) except: break round += 1 # return heapq.nsmallest(self.node.k, enquired) return heapq.nsmallest(self.node.k, alives)