def DumpPeerData(self): # we need a client to talk to the peer head client = Simple_Client(self.host, self.port) msg = "DUMP_PEER_DATA|" # send the data and return response = client.connect_send__receive_close(self.host, self.port, msg) return response
def locateHash(self, hash): # we need a client to talk to the peer head client = Simple_Client(self.host, self.port) msg = "LOOKUP|" + hash # send the data and return response = client.connect_send__receive_close(self.host, self.port, msg) return response
def findPeer(self): # we need a client to talk to the peer head client = Simple_Client(self.host, self.port) msg = "FIND_PEER|" + self.host # send the data and return response = client.connect_send__receive_close(self.host, self.port, msg) return response
def leave(self, pred_node, succ_node): # First update successor of our predecessor # create a client for this operation client = Simple_Client(self.host, self.port) # the insert request is like lookup msg = "UPDATE_SUCC|{0}|{1}|{2}".format(succ_node.hash, succ_node.host, succ_node.port) # the server at succ is contacted, response is the pred node of our # node response = client.attempt_to_connect(pred_node.host, pred_node.port, msg) # the server returned the predecessor if response == "": print("NO INSERT RESPONSE ERROR!") exit(0) # Next, update predecessor of our successor msg = "UPDATE_PRED|{0}|{1}|{2}".format(pred_node.hash, pred_node.host, pred_node.port) # the server at succ is contacted, response is the pred node of our # node response = client.attempt_to_connect(succ_node.host, succ_node.port, msg) # the server returned the successor if response == "": print("NO INSERT RESPONSE ERROR!") exit(0) # Okay return "OK"
def joinNetwork(self): # we need a client to talk to the peer head client = Simple_Client(self.host, self.port) msg = "JOIN_NETWORK|" # send the data and return response = client.connect_send__receive_close(self.host, self.port, msg) return response
def insert(self, hash_code, succ_node): # create a client for this operation client = Simple_Client(self.host, self.port) # the insert request is like lookup msg = "INSERT|{0}|{1}|{2}".format(hash_code, self.host, self.port) # the server at succ is contacted, response is the pred node of our # node response = client.attempt_to_connect(succ_node.host, succ_node.port, msg) # the server returned the predecessor if response == "": print("NO INSERT RESPONSE ERROR!") exit(0) # the response should be a string of strings, separated by ':', but # there is no type checking, sorry # the response contained the pred node after the coord in the network # was complete pred_hash, pred_host, pred_port_str = response.split(':') # pred_port_str was sent as a string and now is converted to an int pred_port = int(pred_port_str) # we create a remote node for this pred pred_node = NetNode(pred_host, (int(pred_port))) # then we stop and return the remote node return pred_node
def deleteFromNet(self, key): # we need a client to talk to the peer head client = Simple_Client(self.host, self.port) # put a header so the app_support server knows what to do with the data string msg = "DELETE|" + key # send the data and return return client.connect_send__receive_close(self.host, self.port, msg)
def readFromNet(self, key): # we need a client to talk to the peer head client = Simple_Client(self.host, self.port) # put a header so the app_support server knows what to do with the data # string msg = "READ_DATA|{0}".format(key) # send the data and return return client.connect_send__receive_close(self.host, self.port, msg)
def writeToNet(self, value): # we need a client to talk to the peer head client = Simple_Client(self.host, self.port) # put a header so the app_support server knows what to do with the data string d_item = DataItem(value) msg = "WRITE_DATA|" + d_item.key + "|" + d_item.value # send the data and return client.connect_send__receive_close(self.host, self.port, msg) return d_item.key
def getNeighbors(self, mode): # we need a client to talk to the peer head client = Simple_Client(self.host, self.port) if mode == "FULL": msg = "GET_NET_STAT|FULL" else: msg = "GET_NET_STAT|CSV" # send the data and return return client.connect_send__receive_close(self.host, self.port, msg)
def hasListener(self): response = "" client = Simple_Client(self.host, self.port) try: response = client.connect_send__receive_close(self.host, self.port, "PING|") except: return False if response == "OK": return True return False
def read(self, key, succ_node): # create a client for this operation client = Simple_Client(self.host, self.port) # the insert request is like lookup msg = "READ_DATA|{0}|{1}|{2}".format(key, self.host, self.port) # the server at succ is contacted, response is the okay response = client.attempt_to_connect(succ_node.host, succ_node.port, msg) # the server returned the predecessor if response == "": return ("NO READ RESPONSE ERROR!") if response == " ": return None return response
def write(self, key, value, succ_node): # create a client for this operation client = Simple_Client(self.host, self.port) # the insert request is like lookup msg = "WRITE_DATA" + "|" + key + "|" + value + "|" + self.host + "|" + str( self.port) # the server at succ is contacted, response is the okay response = client.attempt_to_connect(succ_node.host, succ_node.port, msg) # the server returned the predecessor if response == "": return ("NO READ RESPONSE ERROR!") if response == "OK": return True return False
def lookup(self, hash_code, net_node): # create a client for this operation client = Simple_Client(self.host, self.port) # the lookup request is always the same msg = "LOOKUP|{0}|{1}|{2}".format(hash_code, self.host, self.port) succ_node = NetNode("None", 0) # since this implementation of lookup is iterative, so we need to keep # track of the nodes we've queried the last hash inits as the code we # are looking for, but is updated as the last node we checked last_hash = hash_code # our successor's hash inits as the entry node of the lookup succ_hash = net_node.hash succ_host = net_node.host succ_port = net_node.port # if the pred and succ hashes ever are equal, it means that the node we # are going to check next is the same node as the one we just checked, # which means we are done searching while not (last_hash == succ_hash): # the server at succ is contacted, response is the succ node to the # hash response = client.attempt_to_connect(succ_host, succ_port, msg) # print ("Lookup:" + response) # since we just checked succ, we can copy that info to last_hash last_hash = succ_hash # the response should be a few strings, separated by ':', but there # is no type checking, sorry if not response == "": # the response contained the next node to check, so it is # assigned to the current successor succ_hash, succ_host, succ_port_str = response.split(':') # succ_port_str was sent as a string and now is converted to an # int succ_port = int(succ_port_str) else: return ("NO LOOKUP RESPONSE ERROR!") # we create a remote node for this succ succ_node = NetNode(succ_host, (int(succ_port))) # the server returned self or its succ, if it returned self, then we # will exit the loop and return return succ_node
def find_peer(self, target_host, min_port, port_range): # the concept is to start at a random port, loop around until we get to a host that will respond max_port = min_port + port_range # find the max range random_offset = 0 # = random.randint(min_port, self.port) # choose a random port in range # create a client for this operation client = Simple_Client(self.host, self.port) # instruct the client to 'broadcast' and loop through all peer addresses response = client.iterative_broadcast(target_host, min_port, random_offset, port_range, "FIND_PEER") if response == "": return (NetNode("None", 0)) # the response should be a tuple, separated by ':', but there is no type checking, sorry r_host, r_port = response.split(':') # we create a remote node for this r_node = NetNode(r_host, (int(r_port))) # then we stop and return the remote node return r_node
def networkSize(self): # we need a client to talk to the peer head client = Simple_Client(self.host, self.port) msg = "NETWORK_SIZE|" # send the data and return return client.connect_send__receive_close(self.host, self.port, msg)
def leaveNetwork(self): # we need a client to talk to the peer head client = Simple_Client(self.host, self.port) msg = "LEAVE_NETWORK|" # send the data and return return client.connect_send__receive_close(self.host, self.port, msg)
def performAction(self, msg): m = msg.split('|') if (m[0] == "FIND_PEER"): #return this nodes info, easily done return self.host + ":" + str(self.port) if (m[0] == "LOOKUP"): #lookup() code = m[1] #hash_code being sent as a lookup host = m[2] #host of the requester port = int(m[3]) #port of the requester mine = self.head.node.hash #my hashed ID succ = self.head.router.succ.hash # my succ's hashed ID pred = self.head.router.pred.hash # my pred's hashed ID # 4 ways that the lookup returns my node (SELF RESPONSES INDICATE Completion) # 1: if pred = mine = succ: (one node network) if (pred == mine) and (mine == succ): #send succ(hash_code) = mine ID back to client return (mine + ":" + self.host + ":" + str(self.port)) # 2: if pred < hash_code and hash_code <= self and pred < self: # (no boundary check, if my node is the last, but not the first) if (pred < code) and (code <= mine) and (pred < mine): #send succ(hash_code) = mine ID back to client return (mine + ":" + self.host + ":" + str(self.port)) # 3: if pred < hash_code and hash_code > self and pred > self: # (pred is last node before flip, id first after, hash is before the flip) if (pred < code) and (code > mine) and (pred > mine): #send succ(hash_code) = mine ID back to client return (mine + ":" + self.host + ":" + str(self.port)) # 4: if pred > hash_code and hash_code <= self and pred > self: # (pred is last node before flip, id first after, hash is after the flip) if (pred > code) and (code <= mine) and (pred > mine): #send succ(hash_code) = mine ID back to client return (mine + ":" + self.host + ":" + str(self.port)) # ALL OTHER CASES Return the successor (which implicitly indicates non completion) # Alternate implementations could have server call lookup on successor (recursive) # But this implementation returns the succ for the client to do next lookup (iterative) return (succ + ":" + self.head.router.succ.host + ":" + str(self.head.router.succ.port)) if (m[0] == "INSERT"): #insert() code = m[1] #hash_code being sent in insert host = m[2] #host of the requester port = int(m[3]) #port of the requester # we need to save the old pred info in case we overwrite the object old_pred_code = self.head.router.pred.hash old_pred_host = self.head.router.pred.host old_pred_port = self.head.router.pred.port #creating the new predecessor object from the message new_pred = NetNode(host, port) #if this is a new network, set all to the new node, return self info if ((old_pred_code == self.head.node.hash) and (self.head.router.succ.hash == self.head.node.hash)): self.head.router.setPred(new_pred) self.head.router.setSucc(new_pred) self.head.router.setEntry(new_pred) return (old_pred_code + ":" + old_pred_host + ":" + str(old_pred_port)) #INSERT is the 1st of 3 messages, the 2nd is sent to the pred # we need a temp client for that temp_client = Simple_Client(self.host, self.port) # craft a message for the old_pred server to update its successor to the new pred msg = "UPDATE_SUCC" + "|" + code + "|" + host + "|" + str(port) # connect to the current predecessor to update pointer to succ response = temp_client.attempt_to_connect(old_pred_host, old_pred_port, msg) # if the response was "UPDATED_SUCC_OK" then we set the new_pred and return the old one if (response == "UPDATED_SUCC_OK"): # update the new predecessor self.head.router.setPred(new_pred) # return info on the old predecessor return (old_pred_code + ":" + old_pred_host + ":" + str(old_pred_port)) #else: return "" if (m[0] == "UPDATE_SUCC"): #update_succ() code = m[ 1] #hash_code being sent in update_succ is that of the new succ host = m[2] #host of the new succ port = int(m[3]) #port of the new succ #creating the new successor object from the message new_succ = NetNode(host, port) #updating the app_support node self.head.router.setSucc(new_succ) #no error checking yet return "UPDATED_SUCC_OK" if (m[0] == "WRITE_DATA"): #write() key = m[1] #hash_code being sent in write value = m[2] host = m[3] #host of the requester port = int(m[4]) #port of the requester self.head.data.write(key, value) return "OK" #Implement these handlers if (m[0] == "READ_DATA"): key = m[1] return self.head.data.read(key) #not using this, just write("0") if (m[0] == "DELETE_DATA"): return self.host + str(self.port) + " Reading Data..." return "CMD NOT FOUND"