mirror of
https://github.com/binlaab/nanofiles.git
synced 2026-07-01 18:16:29 +02:00
práctica 3, falta la última parte
This commit is contained in:
43
es/um/redes/nanoFiles/util/FileDatabase.java
Normal file
43
es/um/redes/nanoFiles/util/FileDatabase.java
Normal file
@@ -0,0 +1,43 @@
|
||||
package es.um.redes.nanoFiles.util;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author rtitos
|
||||
*
|
||||
* Utility class acting as database of local files shared by this peer.
|
||||
*/
|
||||
|
||||
public class FileDatabase {
|
||||
|
||||
private Map<String, FileInfo> files;
|
||||
|
||||
public FileDatabase(String sharedFolder) {
|
||||
File theDir = new File(sharedFolder);
|
||||
if (!theDir.exists()) {
|
||||
theDir.mkdirs();
|
||||
}
|
||||
this.files = FileInfo.loadFileMapFromFolder(new File(sharedFolder));
|
||||
if (files.size() == 0) {
|
||||
System.err.println("*WARNING: No files found in folder " + sharedFolder);
|
||||
}
|
||||
}
|
||||
|
||||
public FileInfo[] getFiles() {
|
||||
FileInfo[] fileinfoarray = new FileInfo[files.size()];
|
||||
int numFiles = 0;
|
||||
for (FileInfo f : files.values()) {
|
||||
fileinfoarray[numFiles++] = f;
|
||||
}
|
||||
return fileinfoarray;
|
||||
}
|
||||
|
||||
public String lookupFilePath(String fileHash) {
|
||||
FileInfo f = files.get(fileHash);
|
||||
if (f != null) {
|
||||
return f.filePath;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
109
es/um/redes/nanoFiles/util/FileDigest.java
Normal file
109
es/um/redes/nanoFiles/util/FileDigest.java
Normal file
@@ -0,0 +1,109 @@
|
||||
package es.um.redes.nanoFiles.util;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
/**
|
||||
* @author rtitos
|
||||
*
|
||||
* Utility class with static methods to abstract handling of file
|
||||
* checksums (message digests) to other classes.
|
||||
*/
|
||||
public class FileDigest {
|
||||
/**
|
||||
* Message digest algorithm used to identify files in nanoP2P.
|
||||
*/
|
||||
public static final String algorithm = "SHA-1";
|
||||
|
||||
/**
|
||||
* Get size of digests generated by this class
|
||||
*
|
||||
* @return The size (in bytes) of digest, or 0 in case of error.
|
||||
*/
|
||||
public static int getFileDigestSize() {
|
||||
try {
|
||||
return getDigestSize(algorithm);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
e.printStackTrace();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get size of digests generated for this algorithm
|
||||
*
|
||||
* @param algorithm The desired digest algorithm
|
||||
* @return The size (in bytes) of its digests
|
||||
* @throws NoSuchAlgorithmException
|
||||
*/
|
||||
private static int getDigestSize(String algorithm) throws NoSuchAlgorithmException {
|
||||
MessageDigest md = MessageDigest.getInstance(algorithm);
|
||||
String input = "";
|
||||
byte[] fileDigest = md.digest(input.getBytes());
|
||||
return fileDigest.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes file digest for a given file.
|
||||
*
|
||||
* @param filename - the system-dependent file name.
|
||||
* @return Byte array with resulting file digest.
|
||||
*/
|
||||
public static String computeFileChecksumString(String filename) {
|
||||
return FileDigest.getChecksumHexString(computeFileChecksum(filename));
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes file digest for a given file.
|
||||
*
|
||||
* @param filename - the system-dependent file name.
|
||||
* @return Byte array with resulting file digest.
|
||||
*/
|
||||
private static byte[] computeFileChecksum(String filename) {
|
||||
MessageDigest md;
|
||||
try {
|
||||
md = MessageDigest.getInstance(algorithm);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
InputStream fis;
|
||||
try {
|
||||
fis = new FileInputStream(filename);
|
||||
int numRead;
|
||||
byte[] buffer = new byte[4096];
|
||||
do {
|
||||
numRead = fis.read(buffer);
|
||||
if (numRead > 0) {
|
||||
md.update(buffer, 0, numRead);
|
||||
}
|
||||
} while (numRead != -1);
|
||||
fis.close();
|
||||
|
||||
} catch (FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
|
||||
return md.digest();
|
||||
}
|
||||
|
||||
private static String getChecksumHexString(byte[] digest) {
|
||||
// This bytes[] has bytes in decimal format;
|
||||
// Convert it to hexadecimal format
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < digest.length; i++) {
|
||||
sb.append(Integer.toString((digest[i] & 0xff) + 0x100, 16).substring(1));
|
||||
}
|
||||
|
||||
// return complete hash
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
176
es/um/redes/nanoFiles/util/FileInfo.java
Normal file
176
es/um/redes/nanoFiles/util/FileInfo.java
Normal file
@@ -0,0 +1,176 @@
|
||||
package es.um.redes.nanoFiles.util;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Vector;
|
||||
|
||||
import es.um.redes.nanoFiles.shell.NFShell;
|
||||
|
||||
/**
|
||||
* @author rtitos
|
||||
*
|
||||
* Utility class with static methods to abstract handling of file
|
||||
* metadata, loading shared failes, search by name substring, etc.
|
||||
*/
|
||||
public class FileInfo {
|
||||
public String fileHash;
|
||||
public String fileName;
|
||||
public String filePath;
|
||||
public long fileSize = -1;
|
||||
|
||||
public FileInfo(String hash, String name, long size, String path) {
|
||||
fileHash = hash;
|
||||
fileName = name;
|
||||
fileSize = size;
|
||||
filePath = path;
|
||||
}
|
||||
|
||||
public FileInfo() {
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuffer strBuf = new StringBuffer();
|
||||
|
||||
strBuf.append(String.format("%1$-30s", fileName));
|
||||
strBuf.append(String.format("%1$10s", fileSize));
|
||||
strBuf.append(String.format(" %1$-45s", fileHash));
|
||||
return strBuf.toString();
|
||||
}
|
||||
|
||||
public static void printToSysout(FileInfo[] files) {
|
||||
StringBuffer strBuf = new StringBuffer();
|
||||
strBuf.append(String.format("%1$-30s", "Name"));
|
||||
strBuf.append(String.format("%1$10s", "Size"));
|
||||
strBuf.append(String.format(" %1$-45s", "Hash"));
|
||||
System.out.println(strBuf);
|
||||
for (FileInfo file : files) {
|
||||
System.out.println(file);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans the given directory and returns an array of FileInfo objects, one for
|
||||
* each file recursively found in the given folder and its subdirectories.
|
||||
*
|
||||
* @param sharedFolderPath The folder to be scanned
|
||||
* @return An array of file metadata (FileInfo) of all the files found
|
||||
*/
|
||||
public static FileInfo[] loadFilesFromFolder(String sharedFolderPath) {
|
||||
File folder = new File(sharedFolderPath);
|
||||
|
||||
Map<String, FileInfo> files = loadFileMapFromFolder(folder);
|
||||
|
||||
FileInfo[] fileinfoarray = new FileInfo[files.size()];
|
||||
Iterator<FileInfo> itr = files.values().iterator();
|
||||
int numFiles = 0;
|
||||
while (itr.hasNext()) {
|
||||
fileinfoarray[numFiles++] = itr.next();
|
||||
}
|
||||
return fileinfoarray;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans the given directory and returns a map of <filehash,FileInfo> pairs.
|
||||
*
|
||||
* @param folder The folder to be scanned
|
||||
* @return A map of the metadata (FileInfo) of all the files recursively found
|
||||
* in the given folder and its subdirectories.
|
||||
*/
|
||||
protected static Map<String, FileInfo> loadFileMapFromFolder(final File folder) {
|
||||
Map<String, FileInfo> files = new HashMap<String, FileInfo>();
|
||||
scanFolderRecursive(folder, files);
|
||||
return files;
|
||||
}
|
||||
|
||||
private static void scanFolderRecursive(final File folder, Map<String, FileInfo> files) {
|
||||
if (folder.exists() == false) {
|
||||
System.err.println("scanFolder cannot find folder " + folder.getPath());
|
||||
return;
|
||||
}
|
||||
if (folder.canRead() == false) {
|
||||
System.err.println("scanFolder cannot access folder " + folder.getPath());
|
||||
return;
|
||||
}
|
||||
|
||||
for (final File fileEntry : folder.listFiles()) {
|
||||
if (fileEntry.isDirectory()) {
|
||||
scanFolderRecursive(fileEntry, files);
|
||||
} else {
|
||||
String fileName = fileEntry.getName();
|
||||
String filePath = fileEntry.getPath();
|
||||
String fileHash = FileDigest.computeFileChecksumString(filePath);
|
||||
long fileSize = fileEntry.length();
|
||||
if (fileSize > 0) {
|
||||
files.put(fileHash, new FileInfo(fileHash, fileName, fileSize, filePath));
|
||||
} else {
|
||||
if (fileName.equals(NFShell.FILENAME_TEST_SHELL)) {
|
||||
NFShell.enableVerboseShell();
|
||||
System.out.println("[Enabling verbose shell]");
|
||||
} else {
|
||||
System.out.println("Ignoring empty file found in shared folder: " + filePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static FileInfo[] lookupFilenameSubstring(FileInfo[] files, String filenameSubstr) {
|
||||
String needle = filenameSubstr.toLowerCase();
|
||||
Vector<FileInfo> matchingFiles = new Vector<FileInfo>();
|
||||
for (int i = 0; i < files.length; i++) {
|
||||
if (files[i].fileName.toLowerCase().contains(needle)) {
|
||||
matchingFiles.add(files[i]);
|
||||
}
|
||||
}
|
||||
FileInfo[] result = new FileInfo[matchingFiles.size()];
|
||||
matchingFiles.toArray(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static FileInfo[] lookupHashSubstring(FileInfo[] files, String hashSubstr) {
|
||||
String needle = hashSubstr.toLowerCase();
|
||||
Vector<FileInfo> matchingFiles = new Vector<FileInfo>();
|
||||
for (int i = 0; i < files.length; i++) {
|
||||
if (files[i].fileHash.toLowerCase().contains(needle)) {
|
||||
matchingFiles.add(files[i]);
|
||||
}
|
||||
}
|
||||
FileInfo[] result = new FileInfo[matchingFiles.size()];
|
||||
matchingFiles.toArray(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Serialización sencilla para enviar listas de FileInfo por TCP
|
||||
public static byte[] serializeList(FileInfo[] files) throws IOException {
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
ObjectOutputStream oos = new ObjectOutputStream(bos);
|
||||
oos.writeInt(files.length);
|
||||
for (FileInfo f : files) {
|
||||
oos.writeUTF(f.fileHash);
|
||||
oos.writeUTF(f.fileName);
|
||||
oos.writeLong(f.fileSize);
|
||||
}
|
||||
oos.flush();
|
||||
return bos.toByteArray();
|
||||
}
|
||||
|
||||
public static FileInfo[] deserializeList(byte[] data) throws IOException {
|
||||
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(data));
|
||||
int n = ois.readInt();
|
||||
FileInfo[] files = new FileInfo[n];
|
||||
for (int i = 0; i < n; i++) {
|
||||
String hash = ois.readUTF();
|
||||
String name = ois.readUTF();
|
||||
long size = ois.readLong();
|
||||
files[i] = new FileInfo(hash, name, size, null);
|
||||
}
|
||||
return files;
|
||||
}
|
||||
}
|
||||
22
es/um/redes/nanoFiles/util/FileNameUtil.java
Normal file
22
es/um/redes/nanoFiles/util/FileNameUtil.java
Normal file
@@ -0,0 +1,22 @@
|
||||
package es.um.redes.nanoFiles.util;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
public class FileNameUtil {
|
||||
|
||||
/**
|
||||
* Devuelve una ruta disponible a partir de un nombre base. Si ya existe,
|
||||
* añade sufijos .1, .2, etc. hasta encontrar un nombre libre.
|
||||
*/
|
||||
public static Path chooseAvailableName(String baseName) {
|
||||
Path path = Paths.get(baseName);
|
||||
int suffix = 1;
|
||||
while (Files.exists(path)) {
|
||||
path = Paths.get(baseName + "." + suffix);
|
||||
suffix++;
|
||||
}
|
||||
return path;
|
||||
}
|
||||
}
|
||||
25
es/um/redes/nanoFiles/util/NickGenerator.java
Normal file
25
es/um/redes/nanoFiles/util/NickGenerator.java
Normal file
@@ -0,0 +1,25 @@
|
||||
package es.um.redes.nanoFiles.util;
|
||||
|
||||
public class NickGenerator {
|
||||
|
||||
private static final String[] TEMPLATES = { "jim", "tim", "jay", "sam", "pat", "max", "liz", "ivy", "zoe", "mia",
|
||||
"bea", "gus", "ted", "ana", "eva", "amy", "leo", "ben", "lou", "joel", "ivan", "otto", "alex", "casey",
|
||||
"riley", "toby", "felix", "edith", "fran", "simon", "eric", "danny", "roger" };
|
||||
|
||||
/**
|
||||
* Genera un nickname aleatorio base: prefijo de la lista y un dígito.
|
||||
*/
|
||||
public static String randomNickname() {
|
||||
int idx = (int) (Math.random() * TEMPLATES.length);
|
||||
int digit = (int) (Math.random() * 10);
|
||||
return TEMPLATES[idx] + digit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Genera una variante del nickname original añadiendo un único dígito.
|
||||
*/
|
||||
public static String variantWithDigit(String base) {
|
||||
int digit = (int) (Math.random() * 10);
|
||||
return base + digit;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user