def new_register_packet(type, source_server_address, address=(None, None)) -> Packet: """ :param type: Type of Register packet :param source_server_address: Server address of the packet sender. :param address: If 'type' is 'request' we need an address; The format is like ('192.168.001.001', '05335'). :type type: str :type source_server_address: tuple :type address: tuple :return New Register packet. :rtype Packet """ if type not in (Packet.REQUEST, Packet.RESPONSE): raise ValueError("invalid type") if type == Packet.REQUEST: if not address: raise ValueError("address must be set in request") body = Packet.REQUEST + Node.parse_ip(address[0]) + Node.parse_port(address[1]) else: body = Packet.RESPONSE + Packet.ACK return Packet(1, Packet.TYPE_REGISTER, *source_server_address, body)
def new_reunion_packet(type, source_address, nodes_array: list): """ :param type: Reunion Hello (REQ) or Reunion Hello Back (RES) :param source_address: IP/Port address of the packet sender. :param nodes_array: [(ip0, port0), (ip1, port1), ...] It is the path to the 'destination'. :type type: str :type source_address: tuple :type nodes_array: list :return New reunion packet. :rtype Packet """ if type not in (Packet.REQUEST, Packet.RESPONSE): raise ValueError("invalid type") if len(nodes_array) > 99: raise ValueError("too long nodes_array") entities = [] for ip, port in nodes_array: entities.append(Node.parse_ip(ip)) entities.append(Node.parse_port(port)) body = type + str(len(nodes_array)).zfill(2) + ''.join(entities) return Packet(1, Packet.TYPE_REUNION, *source_address, body)
def new_advertise_packet(type, source_server_address, neighbour: tuple=None): """ :param type: Type of Advertise packet :param source_server_address Server address of the packet sender. :param neighbour: The neighbour for advertise response packet; The format is like ('192.168.001.001', '05335'). :type type: str :type source_server_address: tuple :type neighbour: tuple :return New advertise packet. :rtype Packet """ if type not in (Packet.REQUEST, Packet.RESPONSE): raise ValueError("invalid type") if type == Packet.REQUEST: body = Packet.REQUEST else: if not neighbour: raise ValueError("neighbour should provided for response") body = Packet.RESPONSE + Node.parse_ip(neighbour[0]) + Node.parse_port(neighbour[1]) return Packet(1, Packet.TYPE_ADVERTISE, *source_server_address, body)
def get_node_by_server(self, ip, port, is_register=False): """ Will find the node that has IP/Port address of input. Warnings: 1. Before comparing the address parse it to a standard format with Node.parse_### functions. :param ip: input address IP :param port: input address Port :param is_register: if the node is register node :return: The node that input address. :rtype: Node """ node_address = (Node.parse_ip(ip), Node.parse_port(port)) if is_register: node = self.register_nodes.get(node_address) else: node = self.nodes.get(node_address) # if node is None: # logging.warning( # 'node does not exit, node: ' + str(node_address) + ' stream address: ' + str(self.get_server_address())) return node
def __init__(self, address: tuple): """ The Stream object constructor. Code design suggestion: 1. Make a separate Thread for your TCPServer and start immediately. :param address: (ip, port) 15 characters for ip + 5 characters for port """ self.address = address self._server_in_buf = [] self._nodes = {} # key: (server_address, registered), value: Node def callback(address, queue, data): """ The callback function will run when a new data received from server_buffer. :param address: Source address. :param queue: Response queue. :param data: The data received from the socket. :return: """ queue.put(bytes('ACK', 'utf8')) self._server_in_buf.append(data) real_address = Node.real_address(address) self._server = Server(*real_address, callback) self._server.start()
def get_source_server_ip(self): """ :return: Server IP address for the sender of the packet. :rtype: str """ return Node.parse_ip(self.source_server_ip)
def __init__(self, ip, port): """ The Stream object constructor. Code design suggestion: 1. Make a separate Thread for your TCPServer and start immediately. :param ip: 15 characters :param port: 5 characters """ ip = Node.parse_ip(ip) port = Node.parse_port(port) self.server_address = (ip, port) self._server_in_buf = [] # Dict for nodes {address: node object} and register nodes # address is (ip, port) self.nodes = {} self.register_nodes = {} def callback(address, queue, data): """ The callback function will run when a new data received from server_buffer. :param address: Source address. :param queue: Response queue. :param data: The data received from the socket. :return: """ queue.put(bytes('ACK', 'utf8')) self._server_in_buf.append(data) server = TCPServer(ip, int(port), callback) tcp = threading.Thread(target=server.run) tcp.start()
def parse_buffer(buf): """ In this function we will make a new Packet from input buffer with struct class methods. :param buf: The buffer that should be parse to a validate packet format :return new packet :rtype: Packet """ try: version = buf[0:2] typ = buf[2:4] length = buf[4:8] ip = buf[8:16] port = buf[16:20] body = buf[20:] version = unpack_from('>H', version)[0] type = unpack_from('>H', typ)[0] length = unpack_from('>I', length)[0] ip_tuple = unpack_from('>HHHH', ip) ip = "" for t in ip_tuple: ip += '.' + str(t) ip = ip[1:] port = str(unpack_from('>I', port)[0]) ip = Node.parse_ip(ip) port = Node.parse_port(port) body = body.decode("utf-8") pck = [version, type, length, ip, port, body] return Packet(pck) except: # any error means the packet's format was wrong logging.warning('received packet format was wrong') return None
def add_node(self, server_address, set_register_connection=False) -> Node: """ Will add new a node to our Stream. :param server_address: New node TCPServer address. :param set_register_connection: Shows that is this connection a register_connection or not. :type server_address: tuple :type set_register_connection: bool :return: """ node = Node(server_address, set_register=set_register_connection) self._nodes[server_address, set_register_connection] = node return node
def add_node(self, server_address, set_register_connection=False): """ Will add new a node to our Stream. :param server_address: New node TCPServer address. :param set_register_connection: Shows that is this connection a register_connection or not. :type server_address: tuple :type set_register_connection: bool :return: """ try: node = Node(server_address, set_register_connection) if set_register_connection: self.register_nodes[server_address] = node else: self.nodes[server_address] = node except: logging.warning('node did not added')
def buildTAN(self): self.buildNaiveBayes() # first make a Naive Bayes structure pri_q = Q.PriorityQueue() rootNode = self.graph.getNode(self.train.names[0]) # first attribute pri_q.put(((0, 0, 0), rootNode, Node(None))) # frm is a dummy node visited = set() # a set of visited nodes' names while (not pri_q.empty()) and (len(visited) < self.train.names): item = pri_q.get() # top element stored in priority queue score = item[0] currNode = item[1] # current node object currName = currNode.getId() if currName in visited: continue frmNode = item[2] # frm node object frmName = frmNode.getId() self.graph.addEdge(frmName, currName, score) visited.add(currName) for attrName in self.train.names: if attrName not in visited: CMI = calcCondMI(self.train, currName, attrName, 'class') indexes = self.train.getColIndex([currName, attrName]) score = (-CMI, indexes[0], indexes[1]) nextNode = self.graph.getNode(attrName) pri_q.put((score, nextNode, currNode))
def __init__(self, server_ip, server_port, is_root=False, root_address=None): """ The Peer object constructor. Code design suggestions: 1. Initialise a Stream object for our Peer. 2. Initialise a PacketFactory object. 3. Initialise our UserInterface for interaction with user commandline. 4. Initialise a Thread for handling reunion daemon. Warnings: 1. For root Peer, we need a NetworkGraph object. 2. In root Peer, start reunion daemon as soon as possible. 3. In client Peer, we need to connect to the root of the network, Don't forget to set this connection as a register_connection. :param server_ip: Server IP address for this Peer that should be pass to Stream. :param server_port: Server Port address for this Peer that should be pass to Stream. :param is_root: Specify that is this Peer root or not. :param root_address: Root IP/Port address if we are a client. :type server_ip: str :type server_port: int :type is_root: bool :type root_address: tuple """ self.stream = Stream(server_ip, server_port) self.packet_factory = PacketFactory() self.user_interface = UserInterface() self.start_user_interface() self.is_root = is_root self.address = self.stream.get_server_address() if is_root: self.root_address = self.address else: self.root_address = (Node.parse_ip(root_address[0]), Node.parse_port(root_address[1])) self.parent_address = None self.reunion_daemon = threading.Thread(target=self.run_reunion_daemon) if is_root: # dict, {peer_address: time} self.peer_last_reunion_hello_time = {} self.network_graph = NetworkGraph(self.address) self.reunion_daemon.start() else: self.last_sent_reunion_time = None self.reunion_mode = 'accept' # the maximum depth is 8 self.time_interval = 8 * 2 * 2 + 4 self.reunion_failed = False self.first_advertise_response = True
def parse_address(address: str) -> tuple: return Node.parse_ip(address[:15]), Node.parse_port(address[15:])