def __init__(self, ip: str, port: int):
        """
        The Stream object constructor.

        Code design suggestion:
            1. Make a separate Thread for your TCPServer and start immediately.


        :param ip: str
        :param port: int
        """

        self.ip = parse_ip(ip)
        self.port = port

        self.nodes: List[Node] = []
        self._server_in_buf: List[bytearray] = []

        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:
            """
            log('New data received.')
            queue.put(bytes('ACK', 'utf8'))
            self._server_in_buf.append(data)

        # ServerThread(ip, port, callback).start()
        formatted_ip = ".".join(str(int(part)) for part in ip.split("."))
        self.tcp = TCPServer(formatted_ip, port, callback)
        self.th = threading.Thread(target=self.tcp.run).start()
Beispiel #2
0
    def add_node(self, ip: str, port: int, father_address: Address) -> None:
        """
        Add a new node with node_address if it does not exist in our NetworkGraph and set its father.

        Warnings:
            1. Don't forget to set the new node as one of the father_address children.
            2. Before using this function make sure that there is a node which has father_address.

        :param ip: IP address of the new node.
        :param port: Port of the new node.
        :param father_address: Father address of the new node

        :type ip: str
        :type port: int
        :type father_address: tuple


        :return:
        """
        father_node = self.find_node(father_address)
        new_node_address = (parse_ip(ip), port)
        old_graph_node = self.find_node(new_node_address)
        if old_graph_node:
            old_graph_node.keep_alive()
            old_graph_node.set_parent(father_node)
            self.level_node(old_graph_node, father_node)
            father_node.add_child(old_graph_node)
            return
        new_node = GraphNode(new_node_address)
        new_node.set_parent(father_node)
        self.level_node(new_node, father_node)
        father_node.add_child(new_node)
        self.nodes.append(new_node)
        self.draw_graph()
Beispiel #3
0
    def get_source_server_address(self) -> Address:
        """

        :return: Server address; The format is like ('192.168.001.001', 5335).
        :rtype: Address
        """
        return parse_ip(self.source_ip), self.source_port
    def __init__(self,
                 server_ip: str,
                 server_port: int,
                 is_root: bool = False,
                 root_address: Address = None,
                 command_line=True) -> 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: Address
        """
        self.server_ip = parse_ip(server_ip)
        self.server_port = server_port
        self.address = (self.server_ip, self.server_port)
        self.is_root = is_root
        self.root_address = root_address
        self.reunion_daemon = ReunionThread(self.run_reunion_daemon)
        self.reunion_mode = ReunionMode.ACCEPTANCE

        self.registered: List[SemiNode] = []
        self.parent_address: Address = None
        self.children_addresses: List[Address] = []
        self.stream = Stream(server_ip, server_port)
        self.user_interface = UserInterface()

        self.last_hello_back_time = None  # When you received your last hello back from root
        self.last_hello_time = None  # When you sent your last hello to root

        if is_root:
            self.network_graph = NetworkGraph(
                GraphNode((self.server_ip, self.server_port)))
            self.reunion_daemon.start()
        elif command_line:
            self.start_user_interface()
Beispiel #5
0
    def new_register_packet(register_type: RegisterType, source_server_address: Address) -> Packet:
        """
        :param register_type: Type of Register packet
        :param source_server_address: Server address of the packet sender.

        :type register_type: RegisterType
        :type source_server_address: Address

        :return New Register packet.
        :rtype Packet

        """
        body = 'REQ' + parse_ip(source_server_address[0]) + parse_port(source_server_address[1]) \
            if register_type == RegisterType.REQ else 'RES' + 'ACK'
        length = len(body)
        return Packet(VERSION, PacketType.REGISTER, length, source_server_address[0], source_server_address[1], body)
Beispiel #6
0
    def new_advertise_packet(advertise_type: AdvertiseType, source_server_address: Address,
                             neighbour: Address = None) -> Packet:
        """
        :param advertise_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', 5335).

        :type advertise_type: AdvertiseType
        :type source_server_address: Address
        :type neighbour: Address

        :return New advertise packet.
        :rtype Packet

        """
        body = 'REQ' if advertise_type == AdvertiseType.REQ else \
            'RES' + parse_ip(neighbour[0]) + parse_port(neighbour[1])
        length = len(body)
        return Packet(VERSION, PacketType.ADVERTISE, length, source_server_address[0], source_server_address[1], body)
Beispiel #7
0
    def new_reunion_packet(reunion_type: ReunionType, source_address: Address, addresses: List[Address]) -> Packet:
        """
        :param reunion_type: Reunion Hello (REQ) or Reunion Hello Back (RES)
        :param source_address: IP/Port address of the packet sender.
        :param addresses: [(ip0, port0), (ip1, port1), ...] It is the path to the 'destination'.

        :type reunion_type: str
        :type source_address: Address
        :type addresses: List[Address]

        :return New reunion packet.
        :rtype Packet
        """
        n_entries = len(addresses)
        body = reunion_type.value + str(n_entries).zfill(2)
        for address in addresses:
            ip, port = address
            body += (parse_ip(ip) + parse_port(port))
        length = len(body)
        source_ip, source_port = source_address
        return Packet(VERSION, PacketType.REUNION, length, source_ip, source_port, body)
    def get_node_by_address(self,
                            ip: str,
                            port: int,
                            want_register: bool = False) -> Optional[Node]:
        """

        Will find the node that has IP/Port address of input.

        Warnings:
            1. Before comparing the address parse it to a standard format with parse_### functions.

        :param ip: input address IP
        :param port: input address Port
        :param want_register: do you want a register node?

        :return: The node that input address.
        :rtype: Node
        """
        for node in self.nodes:
            if node.get_server_address() == (
                    parse_ip(ip), port) and node.is_register == want_register:
                return node
    def __init__(self,
                 server_address: Address,
                 set_register: bool = False) -> None:
        """
        The Node object constructor.

        This object is our low-level abstraction for other peers in the network.
        Every node has a ClientSocket that should bind to the Node TCPServer address.

        Warnings:
            1. Insert an exception handler when initializing the ClientSocket; when a socket closed here we will face to
               an exception and we should detach this Node and clear its output buffer.

        :param server_address:
        :param set_register:
        """
        self.server_ip = parse_ip(server_address[0])
        self.server_port = server_address[1]

        log(f"Node({server_address}): Initialized.")

        self.out_buff: List[Packet] = []
        self.is_register = set_register
        self.__initialize_client_socket()
 def __init__(self, ip: str, port: int):
     self.ip = parse_ip(ip)
     self.port = port