예제 #1
0
    def SayHello(self, request, context):
        """
        This method will be remotely invoked by a node who wants to get added to the network
        """
        logger.info("SayHello invoked from {}".format(request.client_node_ip))
        globals.my_coordinates = globals.node_connections.connection_dict[
            NodePosition.CENTER].node_coordinates
        logger.debug("my_coordinates: {}".format(globals.my_coordinates))

        logger.debug("node_connections: {}".format(
            globals.node_connections.connection_dict))

        neighbor_pos_coord_dict = helper.get_neighbor_coordinates(
            globals.my_coordinates)
        logger.debug(
            "neighbor_pos_coord_dict: {}".format(neighbor_pos_coord_dict))
        available_pos_coord_dict = {}
        unavailable_pos_coord_dict = {}

        for position in neighbor_pos_coord_dict.keys():
            if position in globals.node_connections.connection_dict.keys():
                unavailable_pos_coord_dict[position] = neighbor_pos_coord_dict[
                    position]
            else:
                available_pos_coord_dict[position] = neighbor_pos_coord_dict[
                    position]

        logger.debug(
            "available_pos_coord_dict: {}".format(available_pos_coord_dict))
        logger.debug("unavailable_pos_coord_dict: {}".format(
            unavailable_pos_coord_dict))

        # TODO: if available_pos == 0 forward the request
        if len(available_pos_coord_dict) == 0:
            logger.debug("len(available_pos_coord_dict) == 0")
            return greet_pb2.HelloReply(
                message='Hello, %s!' % request.client_node_ip,
                client_node_coordinates=str(None),
                server_node_coordinates=str(globals.my_coordinates))

        # Find position/coordinates such that it creates a compact network structure
        # Check neighbor or neighbor's neighbor for deciding the position
        if len(available_pos_coord_dict) == 4:
            # All positions are available
            new_node_position = NodePosition.RIGHT  # default to right position
            new_node_coordinates = available_pos_coord_dict[new_node_position]

            # Add client to NodeConnections
            channel = grpc.insecure_channel(request.client_node_ip + ":" +
                                            str(globals.port))
            conn = connection.Connection(channel=channel,
                                         node_position=new_node_position,
                                         node_coordinates=new_node_coordinates,
                                         node_ip=request.client_node_ip)
            globals.node_connections.add_connection(conn)
            logger.debug("node_connections: {}".format(
                globals.node_connections.connection_dict))

            logger.debug(
                "new_node_coordinates: {}".format(new_node_coordinates))
            logger.debug("additional_connections=[]")

            return greet_pb2.HelloReply(
                message='Hello, %s!' % request.client_node_ip,
                client_node_coordinates=str(new_node_coordinates),
                server_node_coordinates=str(globals.my_coordinates),
                additional_connections=str([]))

        # Eliminate the farthest position
        if len(available_pos_coord_dict) == 3:
            logger.debug(
                "len(available_pos) == 3; available_pos_coord_dict: (before)".
                format(available_pos_coord_dict))
            if NodePosition.TOP in unavailable_pos_coord_dict \
                    and neighbor_pos_coord_dict[NodePosition.TOP] == unavailable_pos_coord_dict[NodePosition.TOP]:
                del available_pos_coord_dict[NodePosition.BOTTOM]
            elif NodePosition.BOTTOM in unavailable_pos_coord_dict \
                    and neighbor_pos_coord_dict[NodePosition.BOTTOM] == unavailable_pos_coord_dict[NodePosition.BOTTOM]:
                del available_pos_coord_dict[NodePosition.TOP]
            elif NodePosition.LEFT in unavailable_pos_coord_dict.keys() \
                    and neighbor_pos_coord_dict[NodePosition.LEFT] == unavailable_pos_coord_dict[NodePosition.LEFT]:
                del available_pos_coord_dict[NodePosition.RIGHT]
            elif NodePosition.RIGHT in unavailable_pos_coord_dict \
                    and neighbor_pos_coord_dict[NodePosition.RIGHT] == unavailable_pos_coord_dict[NodePosition.RIGHT]:
                del available_pos_coord_dict[NodePosition.LEFT]
            logger.debug(
                "len(available_pos) == 3; available_pos_coord_dict: (after)".
                format(available_pos_coord_dict))

        new_node_position = None
        new_node_coordinates = None
        my_neighbors_neighbor_pos_coord = {}
        neighbor_coord_ip_dict = {}

        # Eliminate one more option
        if len(available_pos_coord_dict) == 2:
            logger.debug(
                "len(available_pos) == 2; available_pos_coord_dict: (before) {}"
                .format(available_pos_coord_dict))
            # Two options available - Left & Right or Top & Bottom
            for my_neighbor_position in unavailable_pos_coord_dict.keys():
                my_neighbor_coordinates = unavailable_pos_coord_dict[
                    my_neighbor_position]  # tuple(x,y)
                my_neighbor_ip = globals.node_connections.connection_dict[
                    my_neighbor_position].node_ip  # ip
                logger.debug("my_neighbor_coordinates: {}".format(
                    my_neighbor_coordinates))
                logger.debug("my_neighbor_ip: {}".format(my_neighbor_ip))

                server_node_ip = my_neighbor_ip
                channel = grpc.insecure_channel(server_node_ip + ":" +
                                                str(globals.port))
                network_manager_stub = network_manager_pb2_grpc.NetworkManagerStub(
                    channel)

                logger.debug(
                    "Calling GetNodeMetaData in {}".format(server_node_ip))
                response = network_manager_stub.GetNodeMetaData(
                    network_manager_pb2.GetNodeMetaDataRequest(
                        client_node_ip=globals.my_ip))
                logger.debug("GetNodeMetaData response from {}: {}".format(
                    server_node_ip, response))

                neighbor_coord_ip_dict = eval(response.server_coord_ip_dict)

                logger.debug("neighbor_coord_ip_dict: {}".format(
                    neighbor_coord_ip_dict))

                # Check your neighbor's connections
                # Assign the same position as your neighbor's neighbor to the new node
                # L->L else R; T->T else B
                logger.debug("my_neighbor_coordinates: {}".format(
                    my_neighbor_coordinates))
                my_neighbors_neighbor_pos_coord = helper.get_neighbor_coordinates(
                    my_neighbor_coordinates)
                logger.debug("my_neighbors_neighbor_pos_coord: {}".format(
                    my_neighbors_neighbor_pos_coord))

                if NodePosition.TOP in available_pos_coord_dict \
                        and my_neighbors_neighbor_pos_coord[NodePosition.TOP] in neighbor_coord_ip_dict \
                        and neighbor_coord_ip_dict[my_neighbors_neighbor_pos_coord[NodePosition.TOP]] != globals.my_ip:
                    new_node_position = NodePosition.TOP
                if NodePosition.BOTTOM in available_pos_coord_dict \
                        and my_neighbors_neighbor_pos_coord[NodePosition.BOTTOM] in neighbor_coord_ip_dict \
                        and neighbor_coord_ip_dict[my_neighbors_neighbor_pos_coord[NodePosition.BOTTOM]] != globals.my_ip:
                    new_node_position = NodePosition.BOTTOM
                if NodePosition.LEFT in available_pos_coord_dict \
                        and my_neighbors_neighbor_pos_coord[NodePosition.LEFT] in neighbor_coord_ip_dict \
                        and neighbor_coord_ip_dict[my_neighbors_neighbor_pos_coord[NodePosition.LEFT]] != globals.my_ip:
                    new_node_position = NodePosition.LEFT
                if NodePosition.RIGHT in available_pos_coord_dict \
                        and my_neighbors_neighbor_pos_coord[NodePosition.RIGHT] in neighbor_coord_ip_dict \
                        and neighbor_coord_ip_dict[my_neighbors_neighbor_pos_coord[NodePosition.RIGHT]] != globals.my_ip:
                    new_node_position = NodePosition.RIGHT

                if new_node_coordinates:
                    del available_pos_coord_dict[new_node_position]

                if new_node_position is not None:
                    new_node_coordinates = available_pos_coord_dict[
                        new_node_position]
                    break

            logger.debug(
                "new_node_coordinates: {}".format(new_node_coordinates))
            logger.debug("new_node_position: {}".format(new_node_position))
            logger.debug(
                "len(available_pos) == 2; available_pos_coord_dict: (after) {}"
                .format(available_pos_coord_dict))

        if new_node_coordinates is None:
            logger.info("new_node_coordinates == ():")
            # assign random position
            random_position = random.choice(
                list(available_pos_coord_dict.keys()))
            new_node_coordinates = available_pos_coord_dict[random_position]
            new_node_position = random_position
            logger.debug(
                "new_node_coordinates: {}".format(new_node_coordinates))
            logger.debug("new_node_position: {}".format(new_node_position))

        # Assign node a position
        try:
            additional_connections = [
                neighbor_coord_ip_dict[
                    my_neighbors_neighbor_pos_coord[new_node_position]]
            ]
        except KeyError:
            additional_connections = []

        logger.info(
            "additional_connections: {}".format(additional_connections))
        logger.info("new_node_coordinates: {}".format(new_node_coordinates))

        # Add new node to NodeConnections
        channel = grpc.insecure_channel(request.client_node_ip + ":" +
                                        str(globals.port))
        conn = connection.Connection(channel=channel,
                                     node_position=new_node_position,
                                     node_coordinates=new_node_coordinates,
                                     node_ip=request.client_node_ip)

        if not globals.node_connections.add_connection(conn):
            logger.debug("Node {} already in the network".format(
                request.client_node_ip))
            return greet_pb2.HelloReply(
                message='Hello, %s!' % request.client_node_ip,
                client_node_coordinates=str(None),
                server_node_coordinates=str(globals.my_coordinates))

        logger.info("node_connections: {}".format(
            globals.node_connections.connection_dict))

        # Send my position and the added node's position
        return greet_pb2.HelloReply(
            message='Hello, %s!' % request.client_node_ip,
            client_node_coordinates=str(new_node_coordinates),
            server_node_coordinates=str(globals.my_coordinates),
            additional_connections=str(additional_connections))
예제 #2
0
    def greet(server_node_ip):
        """
        This method is used to get connected/added to the network.
        :param server_node_ip: ip address of any node in the network.
        :return: None
        """
        logger.info("Connecting to {} at port {}...".format(
            server_node_ip, globals.port))
        channel = grpc.insecure_channel(server_node_ip + ":" +
                                        str(globals.port))
        greeter_stub = greet_pb2_grpc.GreeterStub(channel)
        response = greeter_stub.SayHello(
            greet_pb2.HelloRequest(client_node_ip=globals.my_ip))

        logger.info("Response from {}: {}".format(server_node_ip, response))
        if eval(response.client_node_coordinates) is None:
            logger.error(
                "Cannot join {}. Maximum node connection capacity reached or node already in the network."
                .format(server_node_ip))
            return

        # Get coordinates => tuple(x,y)
        globals.my_coordinates = eval(response.client_node_coordinates)

        # Add yourself to NodeConnections
        my_conn = connection.Connection(
            channel=None,
            node_position=globals.my_position,
            node_coordinates=globals.my_coordinates,
            node_ip=globals.my_ip)
        globals.node_connections.add_connection(my_conn)
        logger.debug("NodeConnections.connection_dict: {}".format(
            globals.node_connections.connection_dict))

        # Calculate server node's position
        server_node_coordinates = eval(response.server_node_coordinates)

        neighbor_pos_coord_dict = helper.get_neighbor_coordinates(
            globals.my_coordinates)
        logger.debug(
            "neighbor_pos_coord_dict: {}".format(neighbor_pos_coord_dict))

        server_node_position = None
        for item in neighbor_pos_coord_dict.items():
            if item[1] == server_node_coordinates:
                server_node_position = item[0]  # eg.: NodePosition.TOP
                break
        logger.debug(("server_node_position: {}".format(server_node_position)))

        # Add server node to NodeConnections
        server_node_conn = connection.Connection(
            channel=channel,
            node_position=server_node_position,
            node_coordinates=server_node_coordinates,
            node_ip=server_node_ip)
        globals.node_connections.add_connection(server_node_conn)
        logger.debug("node_connections: {}".format(
            globals.node_connections.connection_dict))

        additional_connections = eval(response.additional_connections)
        logger.debug(
            "additional_connections: {}".format(additional_connections))

        # If the new node (this node) has neighbors then make additional connections with them
        for server_node_ip in additional_connections:
            logger.info("Making necessary additional connections...")
            channel = grpc.insecure_channel(server_node_ip + ":" +
                                            str(globals.port))
            logger.info("Connecting to {} at port {}...".format(
                server_node_ip, globals.port))

            logger.info("Informing new neighbors to form connections...")
            logger.debug(
                "Calling rpc UpdateNeighborMetaData with args: client_node_ip {}, client_node_coordinates: {}"
                .format(globals.my_ip, globals.my_coordinates))
            network_manager_stub = network_manager_pb2_grpc.NetworkManagerStub(
                channel)
            response = network_manager_stub.UpdateNeighborMetaData(
                network_manager_pb2.UpdateNeighborMetaDataRequest(
                    client_node_ip=globals.my_ip,
                    client_node_coordinates=str(globals.my_coordinates)))

            logger.info("Response from {}: {}".format(server_node_ip,
                                                      response))

            server_node_coordinates = eval(response.server_node_coordinates)
            server_node_position = None
            for item in neighbor_pos_coord_dict.items():
                if item[1] == server_node_coordinates:
                    server_node_position = item[0]
                    break

            # Add server node to NodeConnections
            server_node_conn = connection.Connection(
                channel=channel,
                node_position=server_node_position,
                node_coordinates=server_node_coordinates,
                node_ip=server_node_ip)
            globals.node_connections.add_connection(server_node_conn)
            logger.debug("node_connections: {}".format(
                globals.node_connections.connection_dict))
        logger.info("Node added to the network successfully...")
        logger.info(
            "Node details: node_coordinates: {}, node_connections: {}".format(
                globals.node_connections.connection_dict[
                    globals.my_position].node_coordinates,
                globals.node_connections.connection_dict))