Files
nanofiles/es/um/redes/nanoFiles/udp/message/DirMessage.java
2026-04-20 22:38:38 +02:00

217 lines
6.7 KiB
Java

package es.um.redes.nanoFiles.udp.message;
import es.um.redes.nanoFiles.application.Directory;
import es.um.redes.nanoFiles.application.NanoFiles;
import es.um.redes.nanoFiles.util.FileInfo;
/**
* Clase que modela los mensajes del protocolo de comunicación entre pares para
* implementar el explorador de ficheros remoto (servidor de ficheros). Estos
* mensajes son intercambiados entre las clases DirectoryServer y
* DirectoryConnector, y se codifican como texto en formato "campo:valor".
*
* @author rtitos
*
*/
public class DirMessage {
public static final int PACKET_MAX_SIZE = 65507; // 65535 - 8 (UDP header) - 20 (IP header)
private static final char DELIMITER = ':'; // Define el delimitador
private static final char END_LINE = '\n'; // Define el carácter de fin de línea
/**
* Nombre del campo que define el tipo de mensaje (primera línea)
*/
private static final String FIELDNAME_OPERATION = "operation";
/*
* TODO: (Boletín MensajesASCII) Definir de manera simbólica los nombres de
* todos los campos que pueden aparecer en los mensajes de este protocolo
* (formato campo:valor)
*/
private static final String FIELDNAME_FILENAME = "filename";
private static final String FIELDNAME_FILESIZE = "size";
private static final String FIELDNAME_FILEHASH = "hash";
private static final String FIELDNAME_FILEPATH = "path";
private static final String FIELDNAME_PROTOCOL = "protocol";
/**
* Tipo del mensaje, de entre los tipos definidos en PeerMessageOps.
*/
private String operation = DirMessageOps.OPERATION_INVALID;
/**
* Identificador de protocolo usado, para comprobar compatibilidad del directorio.
*/
private String protocolId;
private FileInfo[] fileList;
/*
* TODO: (Boletín MensajesASCII) Crear un atributo correspondiente a cada uno de
* los campos de los diferentes mensajes de este protocolo.
*/
public DirMessage(String op) {
operation = op;
}
public DirMessage(String op, String nick, String ip, int puerto) {
this(op);
}
/*
* TODO: (Boletín MensajesASCII) Crear diferentes constructores adecuados para
* construir mensajes de diferentes tipos con sus correspondientes argumentos
* (campos del mensaje)
*/
public String getOperation() {
return operation;
}
/*
* TODO: (Boletín MensajesASCII) Crear métodos getter y setter para obtener los
* valores de los atributos de un mensaje. Se aconseja incluir código que
* compruebe que no se modifica/obtiene el valor de un campo (atributo) que no
* esté definido para el tipo de mensaje dado por "operation".
*/
public void setProtocolID(String protocolIdent) {
if (!operation.equals(DirMessageOps.OPERATION_PING)) {
throw new RuntimeException(
"DirMessage: setProtocolId called for message of unexpected type (" + operation + ")");
}
protocolId = protocolIdent;
}
public String getProtocolId() {
return protocolId;
}
public FileInfo[] getFileList () {
return fileList;
}
public void setFileList(FileInfo f) {
if (!operation.equals(DirMessageOps.OPERATION_REQUEST_DIRFILES)) {
throw new RuntimeException (
"DirMessage: setFileList called for message of type " + operation
);
}
}
/**
* Método que convierte un mensaje codificado como una cadena de caracteres, a
* un objeto de la clase PeerMessage, en el cual los atributos correspondientes
* han sido establecidos con el valor de los campos del mensaje.
*
* @param message El mensaje recibido por el socket, como cadena de caracteres
* @return Un objeto PeerMessage que modela el mensaje recibido (tipo, valores,
* etc.)
*/
public static DirMessage fromString(String message) {
System.out.println(message);
/*
* TODO: (Boletín MensajesASCII) Usar un bucle para parsear el mensaje línea a
* línea, extrayendo para cada línea el nombre del campo y el valor, usando el
* delimitador DELIMITER, y guardarlo en variables locales.
*/
// System.out.println("DirMessage read from socket:");
// System.out.println(message);
String[] lines = message.split(END_LINE + "");
// Local variables to save data during parsing
DirMessage m = null;
String filename = null;
long filesize = 0;
String filehash = null;
String filepath = null;
// de alguna forma tengo que hacer un array de FileInfo
// ArrayList y de ahí a array?
for (String line : lines) {
int idx = line.indexOf(DELIMITER); // Posición del delimitador
String fieldName = line.substring(0, idx).toLowerCase(); // minúsculas
String value = line.substring(idx + 1).trim();
switch (fieldName) {
case FIELDNAME_OPERATION: {
assert (m == null);
m = new DirMessage(value);
break;
}
case FIELDNAME_PROTOCOL: {
m.setProtocolID(value);
break;
}
case FIELDNAME_FILENAME: {
filename = value;
break;
}
case FIELDNAME_FILESIZE: {
filesize = Long.parseLong(value);
break;
}
case FIELDNAME_FILEHASH: {
filehash = value;
FileInfo f = new FileInfo(filehash, filename, filesize, filepath);
// fileList += f;
// y esto que, muchas gracias iniesta
}
default:
System.err.println("PANIC: DirMessage.fromString - message with unknown field name " + fieldName);
System.err.println("Message was:\n" + message);
System.exit(-1);
}
}
return m;
}
/**
* Método que devuelve una cadena de caracteres con la codificación del mensaje
* según el formato campo:valor, a partir del tipo y los valores almacenados en
* los atributos.
*
* @return La cadena de caracteres con el mensaje a enviar por el socket.
*/
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append(FIELDNAME_OPERATION + DELIMITER + operation + END_LINE); // Construimos el campo
/*
* TODO: (Boletín MensajesASCII) En función de la operación del mensaje, crear
* una cadena la operación y concatenar el resto de campos necesarios usando los
* valores de los atributos del objeto.
*/
switch (operation) {
case DirMessageOps.OPERATION_PING:
sb.append(FIELDNAME_PROTOCOL + DELIMITER + NanoFiles.PROTOCOL_ID + END_LINE);
break;
case DirMessageOps.OPERATION_DIRFILES:
FileInfo[] filelist = FileInfo.loadFilesFromFolder(Directory.DEFAULT_DIRECTORY_FILES_PATH);
sb.append(FIELDNAME_OPERATION + DELIMITER + operation + END_LINE);
for (FileInfo f : filelist) {
sb.append(FIELDNAME_FILENAME + DELIMITER + f.fileName + END_LINE);
sb.append(FIELDNAME_FILESIZE + DELIMITER + f.fileSize + END_LINE);
sb.append(FIELDNAME_FILEHASH + DELIMITER + f.fileHash + END_LINE);
sb.append(FIELDNAME_FILEPATH + DELIMITER + f.filePath + END_LINE);
}
break;
default:
break;
}
sb.append(END_LINE); // Marcamos el final del mensaje
return sb.toString();
}
}