Пример #1
0
    def __init__(self, myPortNumber, orangeIP, orangePortNumber):
        '''
		Constructor de objetos de clase GreenNode.
		Recibe como parametros el numero de puerto del nodo por construir,
		y la IP y puerto del nodo naranja que usa para conectarse.
		Incluye la etapa de inicialización del nodo verde.
		'''
        # Inicializar servicios basicos
        self.myPort = myPortNumber
        self.myID = -1

        self.orangeIP = orangeIP
        self.orangePort = orangePortNumber

        self.tcpl = TCPL()

        self.tcpl.startService(self.myPort)
        self.processSystem = ProcessSystem(self.myPort, True)

        # Diccionario con GreenNodeToken
        self.neighboursTable = dict()
        # Registros en tabla: nodoDestino [0] | distancia [1] | vecino [2]
        self.routingTable = dict()

        self.fileSystem = FileSystem(self.myPort)

        self.assemblePackage = AssemblePackageFactory()
 def __init__(self, greenNum, greenIp, greenPort, ownPort):
     self._greenId = greenNum
     self._greenIp = greenIp
     self._greenPort = greenPort  # TCPL
     self._greenReliTransPort = greenPort + 1000
     self._ownPort = ownPort
     self._processSystem = ProcessSystem(ownPort, False)
     self._tcpl = TCPL()
     self._tcpl.startService(self._ownPort)
 def __init__(self, id, ip, port):
     self.adyacentNodes = dict()
     self.id = id
     self.tcplService = TCPL()
     # Estas listas deberían ser atrributos de instancia
     self.freeNodeList = []
     self.orangeNodesList = []
     # Lista de nombres de nodos esperando por ser instanciados
     self.instantiatingList = []
     self.localIp = ip
     self.localPort = port
     self.assemblePackage = AssemblePackageFactory()
     ''' Lista (dict) utilizada para llevar registro de cuáles solicitudes
      naranja - naranja han sido confirmadas, por ejemplo, aumentar
      la entrada [546] de la solicitud REQUESTPOS con ese mismo número
     cuando se reciba un REQUESTPOSACK '''
     self.confirmationCounters = dict()
def recibirInfo():
    packet, address = tcplService.receivePackage()
    numeroDeRequest, inicioConfirmacionRespuesta, numeroDeServicio, tamCuerpoPrioridad, datos = factoria.unpackPackage(
        packet)
    print("ID = ", inicioConfirmacionRespuesta)
    while 1:
        packet, address = tcplService.receivePackage()
        numeroDeRequest, inicioConfirmacionRespuesta, numeroDeServicio, tamCuerpoPrioridad, datos = factoria.unpackPackage(
            packet)
        print("Vecino = ", int.from_bytes(datos[0:2], byteorder='big'))


puerto = sys.argv[1]
ipNaranja = sys.argv[2]
puertoNaranja = sys.argv[3]
tcplService = TCPL()
tcplService.startService(puerto)
factoria = AssemblePackageFactory()
paquete = factoria.assemblePackage(37, 1, 200, 1,
                                   int(1).to_bytes(256, byteorder='big'))
enviado = tcplService.sendPackage(paquete, ipNaranja, puertoNaranja)
print(enviado)
if (enviado):
    print("Esperando respuesta naranja")
    threadReceiving = threading.Thread(target=recibirInfo())
    threadReceiving.start()
    threadReceiving.join()

else:
    print("Fallo")
Пример #5
0
class GreenNode:
    ''' CÓDIGOS DE MENSAJES '''
    ROUTING_MESSAGE = 80
    GREET_NEIGHBOR = 100
    GREET_NEIGHBOR_ACK = 101
    FILE_EXISTS = 102
    FILE_EXISTS_ACK = 103
    FILE_COMPLETE = 104
    FILE_COMPLETE_ACK = 105
    LOCATE_FILE = 106
    LOCATE_FILE_ACK = 107
    REMOVE_FILE = 108
    REMOVE_FILE_ACK = 109
    PUT_FILE = 110
    PUT_FILE_ACK = 111
    GET_FILE = 112
    GET_FILE_ACK = 113
    EXEC = 114
    EXEC_ACK = 115
    EXEC_STOP = 116
    EXEC_STOP_ACK = 117
    SEND_ROUTE = 118
    SEND_ROUTE_ACK = 119
    CONNECT_ACK = 201

    SEND_PROCESS = 50
    RUN_PROCESS = 51
    ASK_FOR_PROCESS = 52
    PROCESS_OUTPUT = 53
    # ...

    WAITFORACKTIMEOUT = 5
    DATA_MAX_SIZE = 1015
    MAX_RANDOM = 65000
    FILE_NAME_SIZE = 32
    '''  # # #  # # #  # # #  Procedimientos dentro del mismo nodo  # # #  # # #  # # #  '''
    def __init__(self, myPortNumber, orangeIP, orangePortNumber):
        '''
		Constructor de objetos de clase GreenNode.
		Recibe como parametros el numero de puerto del nodo por construir,
		y la IP y puerto del nodo naranja que usa para conectarse.
		Incluye la etapa de inicialización del nodo verde.
		'''
        # Inicializar servicios basicos
        self.myPort = myPortNumber
        self.myID = -1

        self.orangeIP = orangeIP
        self.orangePort = orangePortNumber

        self.tcpl = TCPL()

        self.tcpl.startService(self.myPort)
        self.processSystem = ProcessSystem(self.myPort, True)

        # Diccionario con GreenNodeToken
        self.neighboursTable = dict()
        # Registros en tabla: nodoDestino [0] | distancia [1] | vecino [2]
        self.routingTable = dict()

        self.fileSystem = FileSystem(self.myPort)

        self.assemblePackage = AssemblePackageFactory()

        # Solicitar unirse al grafo
        # Esperar identificacion

    def _execution(self):
        '''
		Etapa de ejecucion del nodo verde.
		'''
        self.isRunning = True
        # Esperar nuevos vecinos (de parte de naranja)
        paquete = self.assemblePackage.assemblePackageConnect()
        #Si logra enviar su paquete connect puede empezar a escuchar request.
        if (self.tcpl.sendPackage(paquete, self.orangeIP, self.orangePort)):
            package, address = self.tcpl.receivePackage()
            requestNumber, beginConfirmationAnswer, serviceNumber, sizeBodyPriority, ttl, fuente, destino, data = self.assemblePackage.unpackPackage(
                package)
            self.myID = int.from_bytes(data[0:2], byteorder='big')
            threadReceiving = threading.Thread(target=self._receiveMessages)
            threadRouting = threading.Thread(target=self._routingThread)
            threadRouting.start()
            threadReceiving.start()
        else:
            print(
                "No fue posible enviar el paquete para solicitar ID al nodo Naranja"
            )
            return -1

    def _termination(self):
        '''
		Etapa de finalizacion del nodo verde.
		'''
        # Rechazar solicitudes de otros nodos
        # Avisar a un naranja sobre la terminacion
        # Avisar a sus vecinos verdes sobre la finalizacion
        pass

    def run(self):
        '''
		Ejecuta toda la funcionalidad del nodo verde, incluyendo las etapas
		de ejecucion y ,terminacion.
		'''
        self._execution()
        self._termination()

    def _extractPortAndIp(self, data):
        ''' la informacion
		:return: retorna el numero de puerto y la ip.
		'''
        ip = ""
        ip += str(data[0]) + "."
        ip += str(data[1]) + "."
        ip += str(data[2]) + "."
        ip += str(data[3])
        port = str(int.from_bytes(data[4:6], byteorder='big'))
        return port, ip

    def _receiveMessages(self):
        '''
		Recibe constantemente mensajes de otros nodos, y los atiende
		si son solicitudes para el nodo actual.
		'''
        while self.isRunning:
            #print("Estoy recibiendo mensajes.")
            package, address = self.tcpl.receivePackage()
            # Si es el nodo destino se ruteo
            destination = int.from_bytes(package[13:15], byteorder='big')
            #Si el ID destino del mensaje no coincide con el mio entonces tengo que rutearlo.
            if destination != self.myID and destination != 0:
                if destination in self.routingTable:
                    ip = self.neighboursTable[self.routingTable[destination]
                                              [2]].ip
                    port = self.neighboursTable[self.routingTable[destination]
                                                [2]].port
                    print("Ruteando paquete hacia ", destination,
                          " por vecino: ", self.routingTable[destination][2],
                          ip, port)
                    self.tcpl.sendPackage(package, ip, port)
                else:
                    print("Mensaje hacia nodo: ", destination,
                          " desechado, no hay entrada en la tabla de ruteo.")
            else:
                hiloDeAtencionRequest = threading.Thread(
                    target=self._attendRequests, args=(package, address))
                hiloDeAtencionRequest.start()

    def sendGreetNeighbor(self, indice):
        '''
			Subrutina que se encarga de saludar a los vecinos de los que se tienen conocimiento de que estan instanciados.
		'''
        if self.neighboursTable.get(indice).ip != "0.0.0.0":
            package = self.assemblePackage.assemblePackageGreetNeighbor(
                self.myID, self.myID,
                self.neighboursTable.get(indice).id)
            self.tcpl.sendPackage(package,
                                  self.neighboursTable.get(indice).ip,
                                  self.neighboursTable.get(indice).port)
        pass

    def _attendRequests(self, package, ipPort):
        '''
		Atiende una solicitud hecha al nodo actual.
		'''
        requestNumber, beginConfirmationAnswer, serviceNumber, sizeBodyPriority, ttl, fuente, destino, data = self.assemblePackage.unpackPackage(
            package)

        if serviceNumber == self.CONNECT_ACK:  #Se reciben los vecio
            self._connect(beginConfirmationAnswer, data)

        elif serviceNumber == self.GREET_NEIGHBOR:  #Se me informa que tengo un vecino
            print("Mi vecino me saludo y tiene la direccion: ", ipPort)
            self._greetNeighbor(requestNumber, beginConfirmationAnswer, ipPort)
            self.imprimirListVecinos()

        elif serviceNumber == self.GREET_NEIGHBOR_ACK:  # recibo un ack de que mi vecino ya sabe que existo
            pass

        elif serviceNumber == self.SEND_ROUTE:  #Se me envia la tabla de enrutamiento.
            self._checkRouteTable(data, fuente)

        elif serviceNumber == self.SEND_ROUTE_ACK:  #Se me indica que la tabla que mande se recibio correctamente.
            pass

        elif serviceNumber == self.FILE_EXISTS:  #Recibo un mensaje de pregunta si un archivo existe
            self._fileExistInSelf(requestNumber, data, ipPort)
            pass

        elif serviceNumber == self.FILE_EXISTS_ACK:  #Se medio una respuesta acerca de la existencia de un archivo.
            pass

        elif serviceNumber == self.FILE_COMPLETE:  #Se me pregunta si un archivo x(viene en los datos) esta completo
            pass
        elif serviceNumber == self.LOCATE_FILE:  #Se me pregunta por la lista de nodos que tiene x archivo
            pass
        elif serviceNumber == self.LOCATE_FILE_ACK:  # Respuesta con una lista de ids que contienen el archivo.
            pass
        elif serviceNumber == self.REMOVE_FILE:  # Se me indica que debo borrar X archivo de mi almacenamiento
            #self.removeFile(requestNumber)
            pass
        elif serviceNumber == self.REMOVE_FILE_ACK:  # Respuesta de que un archivo pudo ser borrado.
            pass
        elif serviceNumber == self.PUT_FILE:  # Se me indica que debo almacenar x archivo.
            pass
        elif serviceNumber == self.PUT_FILE_ACK:  #Se me contesta acerca de si se guardo el archivo.
            pass
        elif serviceNumber == self.GET_FILE:  #Se me solicita y fragmento de x archivo.
            pass
        elif serviceNumber == self.GET_FILE_ACK:  #Se me da Y fragmento de x archivo que solicite.
            pass
        elif serviceNumber == self.EXEC:  # Se me indica que debo correr un proceso.
            pass
        elif serviceNumber == self.SEND_PROCESS:
            print("Recibi una solicitud para recibir proceso.")
            # Acá se pueden poner condiciones para recibir el proceso o no
            if True:
                answer = bytearray(package)
                # Activamos trans conf por medio del sistema de procesos
                receiveProcessThread = threading.Thread(
                    target=self._receiveProcess, args=(bytes(package), ))
                receiveProcessThread.start()
                # Aceptamos la solicitud
                answer[15] = 1
            else:
                # Denegamos la solicitud
                answer[15] = 0
            self.tcpl.sendPackage(answer, ipPort[0], ipPort[1])
        elif serviceNumber == self.RUN_PROCESS:
            print("Recibi una solicitud para correr proceso:",
                  package[15:75].decode(), ".")
            runProcessThread = threading.Thread(target=self._runProcess,
                                                args=(bytes(package), ))
            runProcessThread.start()
            self.tcpl.sendPackage(package, ipPort[0], ipPort[1])
        elif serviceNumber == self.ASK_FOR_PROCESS:
            procName = package[15:75].decode().strip('\x00')
            print("Se me consultó el estado del proceso:", procName, ".")
            answer = bytearray(package)
            state = self.processSystem.isProcessDone(str(procName))
            answer[15] = state
            # Enviamos la respuesta
            print("El proceso:", procName, "está en estado", state, ".")
            self.tcpl.sendPackage(answer, ipPort[0], ipPort[1])

    '''  # # #  # # #  # # #  Solicitudes de azules  # # #  # # #  # # #  '''

    def _receiveProcess(self, requestPack):
        '''
		Recibe un proceso de un nodo azul.
		'''
        program = requestPack[15:75].decode('utf-8').strip('\x00')
        executable = requestPack[75:125].decode('utf-8').strip('\x00')
        print("Proceso:", program, ", ejecutable:", executable)
        # Recibimos el archivo por trans confiable
        self.processSystem.receiveProcess(program, executable, self.myPort)

    def _migrateProcess(self, requestPack):
        '''
		Migrar un proces 3 en la lista de adyacencias
	o reanudable a otro nodo.
		'''
        pass

    def _runProcess(self, requestPack):
        '''
		Ejecutar un proceso.
		'''
        program = requestPack[15:75].decode('utf-8').strip('\x00')
        self.processSystem.executeProcess(program)

    '''  # # #  # # #  # # #  Transacciones con otros verdes  # # #  # # #  # # #  '''

    def _greetNeighbor(self, requestNumber, beginConfirmationAnswer, ipPort):
        '''
		Envía un mensaje saludando a un vecino instanciado.
		'''
        self.neighboursTable[beginConfirmationAnswer].ip = ipPort[0]
        self.neighboursTable[beginConfirmationAnswer].port = ipPort[1]
        self.neighboursTable[beginConfirmationAnswer].state = True
        package = self.assemblePackage.assemblePackageGreetNeighborACK(
            requestNumber, self.myID,
            self.neighboursTable.get(beginConfirmationAnswer).id)
        self.tcpl.sendPackage(package, ipPort[0], ipPort[1])

    def _routingThread(self):
        #Hilo que se va a encargar de enviar la tabla de ruteo cada 1 segundo.
        while (1):
            print("Esoty enviando la tabla de enrutamiento")
            self.imprimirTablaDeEnrutamiento()
            self._sendRouteTable()
            time.sleep(25)

    def _sendRouteTable(self):
        '''
		Enviar tabla de enrutamiento a vecinos (actualizar tabla de enrutamiento)
		'''
        routingTable = self.routingTable
        neighboursTable = self.neighboursTable

        # Se crea el payload con la tabla, cada registro son 2 bytes
        table = bytearray(1000)
        offset = 0
        for node in routingTable:
            table[offset:(offset + 2)] = routingTable[node][0].to_bytes(
                2, byteorder='big')  # nodo
            table[(offset + 2):(offset + 4)] = routingTable[node][1].to_bytes(
                2, byteorder='big')  # distancia
            offset += 4

        # Se envían los mensajes a los vecinos
        tableMessage = bytearray(self.DATA_MAX_SIZE)
        # ToDo: Agregar código de enviar la tabla
        tableMessage[4:6] = bytearray(2)  # 0
        tableMessage[6] = self.SEND_ROUTE
        tableMessage[7:9] = bytearray(2)  # sin prioridad
        tableMessage[9:11] = int(50).to_bytes(2, byteorder='big')
        tableMessage[15:] = table
        # ...

        for neighbour in neighboursTable:
            # fuente - destino
            if neighboursTable[neighbour].state is True:
                tableMessage[0:4] = random.randrange(self.MAX_RANDOM).to_bytes(
                    4, byteorder='big')
                tableMessage[11:13] = int(self.myID).to_bytes(2,
                                                              byteorder='big')
                tableMessage[13:15] = int(neighbour).to_bytes(2,
                                                              byteorder='big')
                ip = neighboursTable[neighbour].ip
                port = neighboursTable[neighbour].port
                self.tcpl.sendPackage(tableMessage, ip, port)

    def _checkRouteTable(self, receivedTable, sender):
        '''
		Confirmar que la tabla de enrutamiento está actualizada (tras recibir tabla de enrutamiento)
		'''
        ownTable = self.routingTable
        items = 0
        offset = 0
        while int.from_bytes(receivedTable[offset:offset + 2],
                             byteorder='big') != 0:
            items += 1

            # 2 bytes de nodo + 2 bytes de distancia = 4 bytes
            nodeNum = int.from_bytes(receivedTable[offset:offset + 2],
                                     byteorder='big')
            distance = int.from_bytes(receivedTable[offset + 2:offset + 4],
                                      byteorder='big')

            # Se compraran los datos con nuestra tabla
            # Si ya tenemos la ruta en la tabla checkeamos su distancia
            if nodeNum in ownTable:
                if int.from_bytes(receivedTable[offset + 2:offset + 4],
                                  byteorder='big') < ownTable[nodeNum][1]:
                    # Nueva distancia
                    ownTable[nodeNum][1] = distance + 1
                    # Nuevo nodo enlace (quizá)
                    ownTable[nodeNum][2] = sender
            else:
                # Si no tenemos esa ruta, la agregamos
                ownTable[nodeNum] = [nodeNum, distance + 1, sender]

            offset += 4
        #print("Recibi una tabla de tamaño: ", items, " del vecino ", sender)

    def _receiveRelocatedProcess(self, package):
        '''
		Recibir un proceso reanudable.
		'''
        pass

    def _updateRoutingTable(self, requestPack):
        '''
		Actualiza entradas de la tabla de enrutamiento segun nuevos datos
		enviados por un vecino.
		'''
        pass

    def imprimirListVecinos(self):
        diccionario = self.neighboursTable.copy()
        print("Mi numero de ID es: ", self.myID, " Y la tabla de adyacencias")
        for i in diccionario:
            print("ID: ", diccionario.get(i).id)
            print("Ip: ", diccionario.get(i).ip)
            print("Puerto: ", diccionario.get(i).port)
            print("°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°")
        print(
            "--------------------------Aqui termina la tabla de adyacencias-----------------------"
        )

    '''  # # #  # # #  # # #  Solicitudes de/ a naranjas  # # #  # # #  # # #  '''
    '''
	Agregar un vecino nuevo y presentarse si esta instanciado.
	'''

    def _addNeighbour(self, requestPack):
        # Agregar a tabla de vecinos
        # Presentarse al vecino si está instanciado
        pass

    def _connect(self, beginConfirmationAnswer, data):
        '''
		Se recibe la respuesta de un connect y se añade su id propio y el de sus vecinos con sus respectivas IPs si estan instanciados.
		:param beginConfirmationAnswer:
		:param data:
		:return:
		'''
        neighbourID = int.from_bytes(data[0:2], byteorder='big')
        # El primer mensaje que se envia es su ID. Asi que revisamos que este mensaje no sea el primero para añadirlo en la lista de adyacencias.
        if (beginConfirmationAnswer != neighbourID):
            neighbourNode = GreenNodeToken(neighbourID)
            port, ip = self._extractPortAndIp(data[2:8])
            # Si viene una IP validad en el paquete debemos proceder añadirla a la lista y saludar, de lo contrario no se añade ninguna IP.
            if ip != "0.0.0.0":
                neighbourNode.ip = ip
                neighbourNode.port = port
                neighbourNode.state = True
                self.neighboursTable[neighbourID] = neighbourNode
                self.sendGreetNeighbor(neighbourID)
            else:
                self.neighboursTable[neighbourID] = neighbourNode
            # Siempre añadimos a nuestra tabla de ruteo al vecino aunque no este instanciado.
            arrayTable = [neighbourID, 1, neighbourID]
            self.routingTable[neighbourID] = arrayTable
            self.imprimirListVecinos()
        else:  # Guardamos cual es nuestro ID.
            self.myID = beginConfirmationAnswer

    def imprimirTablaDeEnrutamiento(self):
        tabla = self.routingTable
        print("Esta es la tabla de enrutamiento actual: ")
        for indice in tabla:
            print(tabla[indice])
        print(
            "-------------------------------------------Final Tabla enrutamiento--------------------------------------------"
        )
class BlueNode:

    MESSAGE_MAX_SIZE = 1015
    MAX_RANDOM = 65000
    SEND_PROCESS = 50
    RUN_PROCESS = 51
    ASK_FOR_PROCESS = 52
    PROCESS_OUTPUT = 53

    def __init__(self, greenNum, greenIp, greenPort, ownPort):
        self._greenId = greenNum
        self._greenIp = greenIp
        self._greenPort = greenPort  # TCPL
        self._greenReliTransPort = greenPort + 1000
        self._ownPort = ownPort
        self._processSystem = ProcessSystem(ownPort, False)
        self._tcpl = TCPL()
        self._tcpl.startService(self._ownPort)

    '''
    def start(self):
        pass

    def runInterface(self):
        pass
    '''

    def displayMenuOptions(self):
        print("\n\n # # #   # # #   # # #  Nodo azul  # # #   # # #  # # # \n")
        num = -1
        while True:
            print("1. Enviar un programa.")
            print("2. Ejecutar un programa.")
            print("3. Preguntar el estado de un proceso.")
            print("4. Salir.")

            try:
                num = int(input("\nSeleccione una opción: "))
                if 0 < num and num < 5:
                    break

            except ValueError:
                pass

            print("\nPor favor seleccione una opción válida.\n")

        return num

    def menu(self):
        option = 0
        while option is not 4:
            option = self.displayMenuOptions()

            if option is 1:
                print("\n\n # # # Envío de un programa # # #")
                processName = input(
                    "Ingrese el nombre del proceso que quiere enviar al nodo verde:\n"
                )
                print(
                    "Ingrese la ruta del archivo ejecutable que desea correr, seguido por"
                )
                print(
                    "las rutas de los demás archivos necesarios para la ejecución, separadas"
                )
                print("por espacios.")
                routes = input("\nArchivos: ")
                print("\n")
                routes = routes.split()

                # Remove a linebreak if it exists:
                if routes[-1][-1] is '\n':
                    routes[-1] = routes[-1][:-1]

                allFound = True
                for route in routes:
                    if not os.path.isfile(route):
                        allFound = False
                        print("Archivo", route, "no fue encontrado...")

                if allFound:
                    # Run the program sender
                    self.sendProcessToGreen(processName, routes)
                    pass
                else:
                    print("Por favor revise las rutas e intente de nuevo.")

            elif option is 2:
                pName = input("Ingrese el nombre del proceso a ejecutar: ")
                self.sendExecutionToGreen(pName)
            elif option is 3:
                pName = input("Ingrese el nombre del proceso a consultar: ")
                self.askForProcessToGreen(pName)
            else:  # option is 4:
                pass

    def sendProcessToGreen(self, processName, filesRoutes):
        # Creamos un mensaje de solicitud de enviar proceso a verde
        message = bytearray(self.MESSAGE_MAX_SIZE)
        message[0:4] = int(random.randrange(self.MAX_RANDOM)).to_bytes(
            4, byteorder='big')
        message[4:6] = bytearray(2)  # 0
        message[6] = self.SEND_PROCESS
        message[7:9] = bytearray(2)  # sin prioridad
        message[9:11] = int(10).to_bytes(2, byteorder='big')  # TTL irrelevante
        message[11:13] = bytearray(2)  # sin fuente
        message[13:15] = int(self._greenId).to_bytes(2, byteorder='big')
        # Agregamos el nombre del proceso y los archivos que necesita
        message[15:75] = processName.encode()
        message[75:125] = filesRoutes[0].encode(
        )  # el primero es el ejecutable
        print("Proceso:", processName, ", ejecutable:", filesRoutes)
        # Enviamos la solicitud
        self._tcpl.sendPackage(message, self._greenIp, self._greenPort)
        # Esperamos la respuesta
        print("Esperando respuesta del verde...")
        answer, ipPort = self._tcpl.receivePackage()
        # Si la respuesta es positiva, el verde activó trans confiable
        if answer[15] == 1:
            self._processSystem.sendProcess\
            (processName, filesRoutes, self._greenIp, self._greenPort, self._ownPort)
            print("Proceso enviado.")
        else:
            print("Error: El nodo verde se niega a recibir el archivo.")

    def sendExecutionToGreen(self, processName):
        # Creamos un mensaje de solicitud de enviar proceso a verde
        message = bytearray(self.MESSAGE_MAX_SIZE)
        message[0:4] = int(random.randrange(self.MAX_RANDOM)).to_bytes(
            4, byteorder='big')
        message[4:6] = bytearray(2)  # 0
        message[6] = self.RUN_PROCESS
        message[7:9] = bytearray(2)  # sin prioridad
        message[9:11] = int(10).to_bytes(2, byteorder='big')  # TTL irrelevante
        message[11:13] = bytearray(2)  # sin fuente
        message[13:15] = int(self._greenId).to_bytes(2, byteorder='big')
        # Agregamos el nombre del proceso y los archivos que necesita
        message[15:75] = processName.encode()
        # Enviamos la solicitud
        self._tcpl.sendPackage(message, self._greenIp, self._greenPort)
        # Esperamos la respuesta
        print("Esperando respuesta del verde...")
        answer, ipPort = self._tcpl.receivePackage()
        print("El proceso:", processName, "se mandó a ejecutar.")

    def askForProcessToGreen(self, processName):
        # Creamos un mensaje de solicitud de enviar proceso a verde
        message = bytearray(self.MESSAGE_MAX_SIZE)
        message[0:4] = int(random.randrange(self.MAX_RANDOM)).to_bytes(
            4, byteorder='big')
        message[4:6] = bytearray(2)  # 0
        message[6] = self.ASK_FOR_PROCESS
        message[7:9] = bytearray(2)  # sin prioridad
        message[9:11] = int(10).to_bytes(2, byteorder='big')  # TTL irrelevante
        message[11:13] = bytearray(2)  # sin fuente
        message[13:15] = int(self._greenId).to_bytes(2, byteorder='big')
        # Agregamos el nombre del proceso y los archivos que necesita
        message[15:75] = processName.encode()
        # Enviamos la solicitud
        self._tcpl.sendPackage(message, self._greenIp, self._greenPort)
        # Esperamos la respuesta
        print("Esperando respuesta del verde...")
        answer, ipPort = self._tcpl.receivePackage()
        # Si la respuesta es positiva, el verde activó trans confiable
        if answer[15] == 0:
            print("\n***El programa", processName, "no ha sido ejecutado***\n")
        elif answer[15] == 1:
            print("El programa", processName, " esta corriendo***\n")
        elif answer[15] == 2:
            print("\n***El programa", processName, " ya terminó***\n")
        else:
            print("\n***El programa", processName,
                  " no se encuentra en el nodo verde***\n")
class OrangeNode:
    # deberia ser un atributo de instancia (ver constructor)
    #PUERTO = "6666"
    DATA_MAX_SIZE = 1009
    POSNUMEROSERVICIO = 6
    CONNECT = 200

    REQUESTPOS = 205
    REQUESTPOSACK = 206
    CONFIRMPOS = 210
    CONFIRMPOSACK = 211
    DISCONNECT = 216
    DISCONNECTACK = 220
    REMOVE = 220
    REMOVEACK = 221
    WAITFORACKDELAY = 1
    WAITFORACKTIMEOUT = 5

    def __init__(self, id, ip, port):
        self.adyacentNodes = dict()
        self.id = id
        self.tcplService = TCPL()
        # Estas listas deberían ser atrributos de instancia
        self.freeNodeList = []
        self.orangeNodesList = []
        # Lista de nombres de nodos esperando por ser instanciados
        self.instantiatingList = []
        self.localIp = ip
        self.localPort = port
        self.assemblePackage = AssemblePackageFactory()
        ''' Lista (dict) utilizada para llevar registro de cuáles solicitudes
         naranja - naranja han sido confirmadas, por ejemplo, aumentar
         la entrada [546] de la solicitud REQUESTPOS con ese mismo número
        cuando se reciba un REQUESTPOSACK '''
        self.confirmationCounters = dict()

    # Inicia el nodo, creando hilos e iniciando objetos/estructuras necesarias

    # ToDo: TCPL requiere su propio hilo
    def start(self, csvPath, orangesPath):
        #1 debe cargar lista de nodos naranjas.
        #2 cargamos el grafo verde.
        #3 Empezamos tcpl para que escuche solicitudes
        #4 Empezamos un hilo que retire mensajes de la bolsa de tcpl y atienda solicutes.
        #
        ruta = orangesPath
        textReader = TxtReader()
        self.loadOrangeNeighboring(textReader.readTxt(ruta))
        self.adyacentNodes = self.loadGreenGraph(csvPath)
        #self.freeNodeList.append(1)
        #self.freeNodeList.append(72)
        self.tcplService.startService(self.localPort)
        threadReceiving = threading.Thread(target=self.popPackage())
        threadReceiving.start()  #
        ''' esto es en otra subrutina
        while 1:
            package = self.popPackage() '''

        pass

    ''' Construye el grafo de nodos verdes para un nodo naranja a partir del
    archivo csv en la ruta filePath.
    Retorna un diccionario donde la llave indica el número de un nodo y
    el valor corresponde a la lista de números de los nodos adyacentes.
    ToDo: crear una subrutina o implementar en el cosntructor que se llame esta
    subrutina para cargar el grafo, asì como llenar la lista dde nodos verdes libres
    freeNodeList() '''

    def loadGreenGraph(self, filePath):
        ''' NEWER VERSION:
        graphFile = open (filePath, 'r') 
        reader = csv.reader(graphFile)

        # Diccionario vacío
        graphDictionary = dict()

        # Build dictionary
        for row in reader:
            graphDictionary[row[0]] = row[1:]

        readLine = graphFile.readline()

        graphFile.close()
        return graphDictionary
        '''

        graphFile = open(filePath, 'r')
        readLine = graphFile.readline()

        # Diccionario vacío
        graphDictionary = dict()

        while readLine:
            # Separa la línea leída usando co
            splitLine = readLine.split(",")
            # El nodo actual es el primero en la línea
            currentNodeId = int(splitLine[0])
            # Creamos una lista de nodo/vecinos para cada nodo
            graphDictionary[currentNodeId] = list()
            # El primero de la lista que precede a sus vecinos
            graphDictionary[currentNodeId].append(
                GreenNodeToken(currentNodeId))
            # Los nodos adyacentes son los demás
            adyacentNodes = list()
            for nodeId in splitLine[1:]:
                adyacentNodes.append(GreenNodeToken(int(nodeId)))
            # Agregar lista de vecinos a la cabeza de la lista
            graphDictionary[currentNodeId].extend(adyacentNodes)

            # Lee la siguiente línea
            readLine = graphFile.readline()
            self.freeNodeList.append(currentNodeId)
        graphFile.close()

        return graphDictionary

    ''' INTERFACE '''

    def checkNodeNumber(self, nodeNumber):
        """Si devuelve un True es que el nodo ya ha sido instanciado. """
        #self.lis
        pass

    def instantiateNode(self, numeroDeNodo, ip, port):
        self.adyacentNodes.get(numeroDeNodo)[0].ip = ip
        self.adyacentNodes.get(numeroDeNodo)[0].port = port
        self.adyacentNodes.get(numeroDeNodo)[0].state = True
        print("Instancié el nodo:", numeroDeNodo, "en la lista de adyacencias")
        #self.printAdyacencyList(self.adyacentNodes)

    # Subrutina que atiende requests y actúa según la que recibe

    # Envía el nombre a un nodo verde cuándo se logró ser instanciado, además de su
    # lista de vecinos
    def sendGreenInfo(self):
        pass

    #Bug nunca envia el confirmPosAck
    def attendRequests(self, package, ipPort):
        numeroDeRequest, inicioConfirmacionRespuesta, numeroDeServicio, tamCuerpoPrioridad, ttl, fuente, destino, datos = self.assemblePackage.unpackPackage(
            package)
        #print(numeroDeRequest, inicioConfirmacionRespuesta, numeroDeServicio, tamCuerpoPrioridad, ipPort, "\n")
        ''' Para REQUESTPOS es mas facil si la subrutina genera el número de nodo las veces
        que sean necesarias y retorna la instanciada. Por esto no estara "position" como parámetro de la 
        funcion. '''
        ipFuente, puertoFuente = ipPort
        if numeroDeServicio == self.REQUESTPOS:
            #print("Este es el numero de de tamaño cuerpo prioridad", tamCuerpoPrioridad)
            print("Recibí un request pos de:", tamCuerpoPrioridad)
            #Si es un request service se debe sacar un nodo verde no instanciado
            #preguntar a los demas si no lo tienen instancido
            self.requestPosACK(inicioConfirmacionRespuesta, ipPort, package)

        elif numeroDeServicio == self.REQUESTPOSACK:
            #Confirma que un id de nodo verde no esta usado.
            #Algun tipo de contador para cuando reciba los
            if inicioConfirmacionRespuesta == 1 and numeroDeRequest in self.confirmationCounters:
                self.confirmationCounters[
                    numeroDeRequest] += 1  #Aumentamos el contador de request ack recibidos.
            else:  #Nota para los programadores: Esto nunca esta pasando, ya que antes habian un remove y como era un diccionario debia caerse.
                if numeroDeRequest in self.confirmationCounters:
                    #print("Estoy popeando el numero de request (esoy en request pos ack) ", numeroDeRequest)
                    self.confirmationCounters.pop(numeroDeRequest)
                    #print(self.instantiatingList)
                    #self.instantiatingList.remove(inicioConfirmacionRespuesta)
        elif numeroDeServicio == self.CONFIRMPOS:
            #Debe armar un corfirm pos ack
            print("Recibí un request pos de:", tamCuerpoPrioridad)
            #self.freeNodeList.remove(inicioConfirmacionRespuesta) #removemos el nodo que ya fue instanciado
            port, ip = self.extractPortAndIp(
                datos)  # Extraemos la direccion del nodo que instanciaron.
            self.instantiateNode(
                inicioConfirmacionRespuesta, ip,
                port)  #Instanciamos ese nodo con un puerto e ip.
            self.freeNodeList.remove(inicioConfirmacionRespuesta)
            #Armamos el paquete.
            self.tcplService.sendPackage(
                self.assemblePackage.assemblePackageConfirmPosACK(
                    1, numeroDeRequest), ipFuente, puertoFuente)

        elif numeroDeServicio == self.CONFIRMPOSACK:
            self.confirmationCounters[numeroDeRequest] += 1

            #dependiendo si ya me confirmaron todos los nodos
        elif numeroDeServicio == self.CONNECT:
            #print("Si me llego un connect")
            #Cuando recibe una solicitud de conexion:
            #1- Se busca un nodo que no este instanciado
            #se pregunta a los demas nodos si lo tienen libre.
            listaPaquetes = []
            numeroDeNodo = self.requestPos(ipPort)  #No hay direccion broadcast
            if numeroDeNodo is not 0:  #Si no es 0 es que habia un nodo disponible.
                #print("Esta es la lista de adyacentes",numeroDeNodo , self.adyacentNodes.get(numeroDeNodo))
                listaDeAdyacencia = self.listAdyacentGenerator(numeroDeNodo)
                listaPaquetes = self.assemblePackage.assemblePackageConnectACK(
                    package, numeroDeNodo, listaDeAdyacencia)
                for indice in range(
                        len(listaPaquetes)
                ):  #Enviamos la lista de paquetes al nodo verde que se aba de conectar.
                    self.tcplService.sendPackage(listaPaquetes[indice],
                                                 ipFuente, puertoFuente)
            else:
                print("No hay nodos disponibles")
                self.tcplService.sendPackage(
                    self.assemblePackage.assemblePackage(
                        numeroDeRequest, 0, 201, 0, 50, 0, 0, bytearray(0)),
                    ipFuente, puertoFuente)
            #Tenemos que buscar ID
            #Hacemos request pos para los demas

    def extractPortAndIp(self, datos):
        '''
        Subrutina que extrae el puerto e ip de un bytearray
        :param datos: datos de los que se va a extraer la informacion
        :return: retorna el numero de puerto y la ip.
        '''
        ip = ""
        ip += str(datos[0]) + "."
        ip += str(datos[1]) + "."
        ip += str(datos[2]) + "."
        ip += str(datos[3])
        port = str(int.from_bytes(datos[4:6], byteorder='big'))
        return port, ip

    def assignAddressToNode(self, id, ip, puerto):
        pass

    def loadOrangeNeighboring(self, orangeNodes):
        listaDeIpsYpuertos = orangeNodes.split()
        #print("El tamaño de la lista es", len(listaDeIpsYpuertos))
        for i in range(0, len(listaDeIpsYpuertos), 2):
            #print(i, "\n")
            #print("Hola ",listaDeIpsYpuertos[i], "\n")
            if self.localIp != listaDeIpsYpuertos[i]:
                self.orangeNodesList.append(
                    [listaDeIpsYpuertos[i], listaDeIpsYpuertos[i + 1]])

    '''
    Genera un numero de nodo verde entre los disponibles
    Si hay nodos disponibles retorna uno generado aleatoriamente,
    De lo contrario retorna 0
    '''

    def getAvailableGreenNum(self):
        #print(len(self.freeNodeList))
        while len(self.freeNodeList):
            nodeNumIndex = random.randint(0, len(self.freeNodeList) - 1)
            #print("Numero de index ", nodeNumIndex)
            if not self.freeNodeList[nodeNumIndex] in self.instantiatingList:
                #print("Generé el nombre de nodo: ", self.freeNodeList[nodeNumIndex], " aleatoriamiente")
                return self.freeNodeList[nodeNumIndex]
        return 0

    # Pregunta si un nodo ha sido instanciado a los de más nodos naranjas
    # retorna la posición instanciada
    def requestPos(self, ipPort):
        """
        Pregunta si un nodo ha sido instanciado a los de más nodos naranjas
        @:param ipPort Ip broadcast
        @:return: La posición instanciada para el nodo verde
        """
        requested = False
        while not requested:
            # Crear paquete para REQUEST_POS
            # Generar un numero aleatorio entre los disponibles
            position = self.getAvailableGreenNum()

            # Si se generó un 0, no hay nodos disponibles, retornamos fallo
            if position == 0:
                return 0

            # Agregar paquete a lista de nodos instanciandose
            self.instantiatingList.append(position)
            #print("Instanciando nodos:", self.instantiatingList)

            #print(self.instantiatingList)
            #print(ipPort)
            # Se ensambla el paquete
            requestPosPacket = self.assemblePackage.assemblePackageRequestPos(
                position, self.id)
            requestNum = int.from_bytes(requestPosPacket[0:4], byteorder='big')
            self.confirmationCounters[requestNum] = 0

            # Enviamos la solicitud a todos los naranjas
            for node in self.orangeNodesList:
                ip, puerto = node
                self.tcplService.sendPackage(requestPosPacket, ip, puerto)
                # hacer broadcast
            timeout = time.time() + self.WAITFORACKTIMEOUT  # en segundo
            # esperar confirmación de todos (si tardan mas de determinado tiempo)
            while requestNum in self.confirmationCounters\
            and position in self.instantiatingList\
            and self.confirmationCounters[requestNum] < len(self.orangeNodesList)\
            and time.time() < timeout:
                ''' Acá se espera a que el hilo que recibe request aumente el contador
                respectivo para saber si todos confirmaron, pero si se eliminó la entrada,
                es porque otro naranja no aceptó el request pos '''

                # Utilizamos un pequeño delay para el ciclo
                time.sleep(self.WAITFORACKDELAY)
            ''' Si se aceptó el request pos, se puede proseguir
            notar que si no se obtuvo respuesta de todos pero tampoco una denegación,
            se instancia. '''
            if requestNum in self.confirmationCounters and position in self.instantiatingList:
                requested = True

                self.confirmationCounters.pop(
                    requestNum)  #Se saca de el diccionario y se instancia.
            else:
                print("Se me denegó request pos para: ", position)
                #return 0

        # Si se instanció la posición, lo sacamos de la lista de disponible y retornamos
        if self.confirmPos(position, ipPort):
            self.freeNodeList.remove(position)
            self.instantiatingList.remove(position)
            self.instantiateNode(position, ipPort[0], ipPort[1])
            print("Logré instanciar a nodo:", position)
            #print("Lista de adyacencias:")
            #self.printAdyacencyList(self.adyacentNodes)
            return position

    def listAdyacentGenerator(self, numeroNodo):
        listAdyacent = []
        for indice in self.adyacentNodes[numeroNodo]:
            #print(type(indice.id))
            #print("Añadiendo: ", self.adyacentNodes.get(indice.id)[0].id, "del nodo: ", numeroNodo)
            listAdyacent.append(self.adyacentNodes.get(indice.id)[0])
        return listAdyacent

    def requestPosACK(self, position, ipPort, packageRequest):
        """
        Envia un ACK indicando si una posición ya está instanciada o no
        @:param position posición que se determinará si esta usada o no
        @:param ipPort Ip y peurto al que se devuelve el ACK instantiated = True
        @:param packageRequest paquete request sobre el cuál se devuelve el ACK
        """
        priority = int.from_bytes(
            packageRequest[7:9], byteorder='big'
        )  #Estaba de 7 a 9 que si corresponden a las posiciones si se empiza a contar desde 1.
        ''' Revisamos si no está instanciado, no se está intentando instanciar y 
        el request tiene mayor prioridad. '''
        if (position in self.freeNodeList) and not (position
                                                    in self.instantiatingList):
            instantiated = 1  #El id no esta instaciado
        else:
            instantiated = 0  #El id esta instaciado
        print("Recibí un request pos para: ", position, "con prioridad",
              priority)
        ''' Si este nodo tiene menor prioridad y se está instanciando esa misma posición, 
        debe sacar el nodo de la lista de instanciamiento. '''
        if priority < self.id and position in self.instantiatingList:
            self.instantiatingList.remove(position)
            instantiated = 1
        #print("Responderé al request pos con un:", instantiated)
        # Ensamblamos y enviamos el paquete según el estado de esa posición
        ackPacket = self.assemblePackage.assemblePackageRequestACK(
            packageRequest, instantiated)
        self.tcplService.sendPackage(ackPacket, ipPort[0], ipPort[1])

    def popPackage(self):
        while 1:
            #print("Pop package...")
            package, address = self.tcplService.receivePackage()
            hiloDeAtencionRequest = threading.Thread(
                target=self.attendRequests, args=(package, address))
            hiloDeAtencionRequest.start()
        pass

    # Anuncia a lo demás nodos naranajs la instanciación de un nodo verde
    # Retornta True si todos confirmaron
    def confirmPos(self, position, ipPort):
        """
    Anuncia a lo demás nodos naranjas la instanciación de un nodo verde
    @:param position posición a confirmar
    @param ipPort ip broadcast
    @:return: True si se confirmó la posición por parte de los demás naranjas
        """
        confirmed = False
        while not confirmed:
            # Crear paquete para CONFIRM_POS

            # Se ensambla el paquete
            requestPosPacket = self.assemblePackage.assemblePackageConfirmPos(
                position, ipPort)
            requestNum = int.from_bytes(requestPosPacket[0:4], byteorder='big')

            self.confirmationCounters[requestNum] = 0

            # Enviamos la solicitud a todos los naranjas
            for node in self.orangeNodesList:
                ip, puerto = node
                self.tcplService.sendPackage(requestPosPacket, ip, puerto)
                # hacer broadcast

            #print("Envié un confirm pos para: ", position)
            timeout = time.time() + self.WAITFORACKTIMEOUT  # en segundo
            # esperar confirmación de todos (si tardan mas de determinado tiempo)
            while requestNum in self.confirmationCounters\
            and self.confirmationCounters[requestNum] < len(self.orangeNodesList)\
            and time.time() < timeout:
                ''' Acá se espera a que el hilo que recibe request aumente el contador
                respectivo para saber si todos confirmaron, pero si se eliminó la entrada,
                es porque otro naranja no aceptó el request pos '''

                # Utilizamos un pequeño delay para el ciclo
                time.sleep(self.WAITFORACKDELAY)
            # Si los demás recibieron el confirm pos, se puede proseguir
            if requestNum in self.confirmationCounters:
                confirmed = True
                #print("Estoy popeando el numero de request (estoy en request pos)", requestNum)
                self.confirmationCounters.pop(requestNum)
                #print("confirm pos para: ", position, "entregado")
        return True

    def confirmPosACK(self, position, ipPort):
        """
    Envia un ACK confirmando la instanciación de una posición
    @:param position posición a confirmar
    @:param ipPort ip del nodo que hizo el request
        """
        print("Recibí un confirm pos para: ", position)
        # Ensamblamos y enviamos el ACK (ya se debio agregar la posicion de instanciado)
        ackPacket = self.assemblePackage.assemblePackageConfirmPos(
            position, ipPort)
        self.tcplService.sendPackage(ackPacket, ipPort[0], ipPort[1])

    def printAdyacencyList(self, lista):
        # La lista contiene: #nodo, ip, puerto, ¿instanciado?
        for node in lista:
            #for data in lista[node]:
            nodeinfo = lista[node][0]
            print(nodeinfo.id, nodeinfo.ip, nodeinfo.port, nodeinfo.state)
        print("-----------")