279 lines
9.0 KiB
Java
279 lines
9.0 KiB
Java
package clientP2P;
|
||
|
||
import java.util.Arrays;
|
||
import java.util.Scanner;
|
||
import java.util.List;
|
||
import java.security.MessageDigest;
|
||
import java.security.NoSuchAlgorithmException;
|
||
import java.io.IOException;
|
||
import java.nio.file.Files;
|
||
import java.nio.file.Paths;
|
||
import java.net.UnknownHostException;
|
||
import protocolP2P.RequestResponseCode;
|
||
import protocolP2P.FileList;
|
||
import protocolP2P.ProtocolP2PPacket;
|
||
import protocolP2P.DiscoverRequest;
|
||
import protocolP2P.DiscoverResponse;
|
||
import protocolP2P.Payload;
|
||
import protocolP2P.HashAlgorithm;
|
||
import localException.ProtocolError;
|
||
import localException.InternalError;
|
||
import localException.ProtocolError;
|
||
import localException.SizeError;
|
||
import localException.TransmissionError;
|
||
import localException.VersionError;
|
||
import localException.SocketClosed;
|
||
import remoteException.EmptyFile;
|
||
import remoteException.EmptyDirectory;
|
||
import remoteException.InternalRemoteError;
|
||
import remoteException.NotFound;
|
||
import remoteException.ProtocolRemoteError;
|
||
import remoteException.VersionRemoteError;
|
||
import remoteException.NotATracker;
|
||
import tools.ServeErrors;
|
||
import tools.HostItem;
|
||
import tools.Logger;
|
||
import tools.LogLevel;
|
||
|
||
/** Implementation of P2P-JAVA-PROJECT CLIENT
|
||
* @author Louis Royer
|
||
* @author Flavien Haas
|
||
* @author JS Auge
|
||
* @version 1.0
|
||
*/
|
||
public abstract class ClientManagement extends ServeErrors implements Runnable {
|
||
protected String baseDirectory;
|
||
protected String partsSubdir;
|
||
protected List<HostItem> hostList;
|
||
protected HostItem tracker;
|
||
protected Logger logger;
|
||
protected Scanner scanner;
|
||
protected ClientDownload downLoader;
|
||
|
||
/** Constructor with baseDirectory, tracker, partsSubdir, logger, and scanner parameters.
|
||
* @param baseDirectory the root directory where files are stored
|
||
* @param tracker Tracker hostItem
|
||
* @param partsSubdir subdirectory to store file parts
|
||
* @param logger Loggger
|
||
* @param scanner Scanner used to read input
|
||
*/
|
||
public ClientManagement(String baseDirectory, HostItem tracker, String partsSubdir, Logger logger, Scanner scanner) {
|
||
this.scanner = scanner;
|
||
this.baseDirectory = baseDirectory;
|
||
this.tracker = tracker;
|
||
this.partsSubdir = partsSubdir;
|
||
this.logger = logger;
|
||
try {
|
||
initHostList();
|
||
} catch (InternalError e) {
|
||
System.exit(-1);
|
||
} catch (ProtocolError e) {
|
||
System.exit(-2);
|
||
}
|
||
}
|
||
|
||
/** Getter for tracker socket
|
||
*/
|
||
protected abstract Object getTrackerSocket();
|
||
|
||
|
||
/** Initialize hostList from tracker
|
||
* @throws ProtocolError
|
||
* @throws InternalError
|
||
*/
|
||
private void initHostList() throws ProtocolError, InternalError {
|
||
ProtocolP2PPacket<?> d = createProtocolP2PPacket(new DiscoverRequest(null));
|
||
try {
|
||
d.sendRequest(getTrackerSocket());
|
||
Payload p = d.receiveResponse().getPayload();
|
||
assert p instanceof DiscoverResponse : "This payload must be instance of Filelist";
|
||
if (!(p instanceof DiscoverResponse)) {
|
||
throw new InternalError();
|
||
} else {
|
||
hostList = ((DiscoverResponse)p).getHostList();
|
||
}
|
||
} catch (SocketClosed e){
|
||
writeLog("listDirectory : SocketClosed", LogLevel.Error);
|
||
throw new ProtocolError();
|
||
} catch (NotATracker e) {
|
||
writeLog(e, LogLevel.Error);
|
||
throw new ProtocolError();
|
||
} catch (Exception e) {
|
||
writeLog(e, LogLevel.Error);
|
||
throw new ProtocolError();
|
||
}
|
||
}
|
||
|
||
/** Compute Hashsum of a file.
|
||
* @param filename
|
||
* @return hashsum
|
||
*/
|
||
protected byte[] computeHashsum(String filename, HashAlgorithm h) {
|
||
try {
|
||
MessageDigest md = MessageDigest.getInstance(HashAlgorithm.SHA512.getName());
|
||
return md.digest(Files.readAllBytes(Paths.get(baseDirectory + filename)));
|
||
} catch (NoSuchAlgorithmException e) {
|
||
writeLog(h.getName() + " not supported", LogLevel.Error);
|
||
} catch (IOException e) {
|
||
writeLog("cannot read " + filename, LogLevel.Error);
|
||
}
|
||
return new byte[0];
|
||
}
|
||
|
||
/** Getter for HostItem socket
|
||
* @param hostItem HostItem
|
||
*/
|
||
protected abstract Object getHostItemSocket(HostItem hostItem);
|
||
|
||
/** list server’s directory content
|
||
* @return list of files
|
||
* @throws InternalError
|
||
* @throws UnknowHostException
|
||
* @throws IOException
|
||
* @throws TransmissionError
|
||
* @throws ProtocolError
|
||
* @throws VersionError
|
||
* @throws SizeError
|
||
* @throws EmptyDirectory
|
||
* @throws InternalRemoteError
|
||
* @throws ProtocolRemoteError
|
||
* @throws VersionRemoteError
|
||
*/
|
||
protected String[] listDirectory() throws EmptyDirectory, InternalError, UnknownHostException, IOException, TransmissionError, ProtocolError, VersionError, SizeError, InternalRemoteError, ProtocolRemoteError, VersionRemoteError {
|
||
ProtocolP2PPacket<?> d = createProtocolP2PPacket(new Payload(RequestResponseCode.LIST_REQUEST));
|
||
try {
|
||
d.sendRequest(getHostItemSocket(hostList.get(0)));
|
||
Payload p = d.receiveResponse().getPayload();
|
||
assert p instanceof FileList : "This payload must be instance of Filelist";
|
||
if (!(p instanceof FileList)) {
|
||
throw new InternalError();
|
||
} else {
|
||
return ((FileList)p).getFileList();
|
||
}
|
||
} catch (NotFound e) {
|
||
writeLog(e, LogLevel.Error);
|
||
throw new ProtocolError();
|
||
} catch (EmptyFile e) {
|
||
writeLog(e, LogLevel.Error);
|
||
throw new ProtocolError();
|
||
} catch (SocketClosed e){
|
||
writeLog("listDirectory : SocketClosed", LogLevel.Error);
|
||
throw new ProtocolError();
|
||
} catch (NotATracker e) {
|
||
writeLog(e, LogLevel.Error);
|
||
throw new ProtocolError();
|
||
}
|
||
}
|
||
|
||
/** Initialize downloader
|
||
* @param filename Name of the file to download
|
||
*/
|
||
protected abstract void initDownloader(String filename);
|
||
|
||
/** Try to download a file
|
||
* @param filename name of the file to download
|
||
* @throws NotFound
|
||
* @throws InternalError
|
||
* @throws UnknownHostException
|
||
* @throws IOException
|
||
* @throws TransmissionError
|
||
* @throws ProtocolError
|
||
* @throws VersionError
|
||
* @throws SizeError
|
||
* @throws InternalRemoteError
|
||
* @throws ProtocolRemoteError
|
||
* @throws VersionRemoteError
|
||
* @throws EmptyFile
|
||
*/
|
||
private void download(String filename) throws EmptyFile, NotFound, InternalError, UnknownHostException, IOException, TransmissionError, ProtocolError, VersionError, SizeError, InternalRemoteError, ProtocolRemoteError, VersionRemoteError {
|
||
initDownloader(filename);
|
||
Thread t = new Thread(downLoader);
|
||
t.start();
|
||
try {
|
||
t.join();
|
||
if (downLoader.getSuccess()) {
|
||
byte[] hash512 = downLoader.getHashSum512();
|
||
if (!Arrays.equals(hash512, computeHashsum(filename, HashAlgorithm.SHA512))) {
|
||
writeLog("Hashsum does not match", LogLevel.Error);
|
||
String line = "Computed checksum:\n";
|
||
byte[] c = computeHashsum(filename, HashAlgorithm.SHA512);
|
||
for (byte b: c) {
|
||
line += String.format("%02X", b);
|
||
}
|
||
line += "\nReceived checksum:\n";
|
||
for (byte b: hash512) {
|
||
line += String.format("%02X", b);
|
||
}
|
||
line += "\n";
|
||
writeLog(line, LogLevel.Info);
|
||
throw new InternalError();
|
||
}
|
||
} else {
|
||
throw new InternalError();
|
||
}
|
||
} catch (InterruptedException e) {
|
||
throw new InternalError();
|
||
}
|
||
}
|
||
|
||
/** Implementation of Runnable
|
||
*/
|
||
public void run() {
|
||
try {
|
||
int i = 1;
|
||
String[] list = listDirectory();
|
||
System.out.println("Files present on the server:");
|
||
System.out.println("0 : Exit the program");
|
||
for(String listItem: list) {
|
||
System.out.println(i + " : " + listItem);
|
||
i++;
|
||
}
|
||
System.out.println("Type the number associated with the file to download:");
|
||
String f = scanner.nextLine();
|
||
if(f.equals("0")){
|
||
System.out.println("on ferme tout");
|
||
}
|
||
else{
|
||
int j = Integer.parseInt(f);
|
||
if(j <= list.length){
|
||
j--;
|
||
download(list[j]);
|
||
System.out.println("File " + f + " sucessfully downloaded");
|
||
writeLog("File " + f + " sucessfully downloaded", LogLevel.Info);
|
||
}
|
||
else{
|
||
System.out.println("File " + f + " unsucessfully downloaded, wrong number");
|
||
writeLog("File " + f + " unsucessfully downloaded, wrong number", LogLevel.Info);
|
||
}
|
||
}
|
||
} catch (EmptyDirectory e) {
|
||
writeLog("Server has no file in directory", LogLevel.Error);
|
||
} catch (InternalError e) {
|
||
writeLog("Client internal error", LogLevel.Error);
|
||
} catch (UnknownHostException e) {
|
||
writeLog("Server host is unknown", LogLevel.Error);
|
||
} catch (IOException e) {
|
||
writeLog("Request cannot be send or response cannot be received", LogLevel.Error);
|
||
} catch (TransmissionError e) {
|
||
writeLog("Message received is too big", LogLevel.Error);
|
||
} catch (ProtocolError e) {
|
||
writeLog("Cannot decode server’s response", LogLevel.Error);
|
||
} catch (VersionError e) {
|
||
writeLog("Server’s response use bad version of the protocol", LogLevel.Error);
|
||
} catch (SizeError e) {
|
||
writeLog("Cannot handle this packets because of internal representation limitations of numbers on the client", LogLevel.Error);
|
||
} catch (InternalRemoteError e) {
|
||
writeLog("Server internal error", LogLevel.Error);
|
||
} catch (ProtocolRemoteError e) {
|
||
writeLog("Server cannot decode client’s request", LogLevel.Error);
|
||
} catch (VersionRemoteError e) {
|
||
writeLog("Server cannot decode this version of the protocol", LogLevel.Error);
|
||
} catch (NotFound e) {
|
||
writeLog("Server has not this file in directory", LogLevel.Error);
|
||
} catch (EmptyFile e) {
|
||
writeLog("File is empty", LogLevel.Error);
|
||
}
|
||
}
|
||
|
||
}
|