-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathClient.java
More file actions
155 lines (139 loc) · 6.6 KB
/
Client.java
File metadata and controls
155 lines (139 loc) · 6.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.nio.file.Files;
import java.nio.file.Path;
import networkMessages.EndOfFile;
import networkMessages.CreateFileMessage;
import networkMessages.ErrorMessage;
import networkMessages.GetMetadataMessage;
import networkMessages.MetadataResponse;
import networkMessages.OkMessage;
import networkMessages.ReadFile;
public class Client {
private final String nameServerIPAddress;
private final int nameServerPort;
// Client Class constructor
public Client(String nameServerIPAddress, int nameServerPort) {
this.nameServerIPAddress = nameServerIPAddress;
this.nameServerPort = nameServerPort;
}
private void checkForError(Object response, String operation) throws IOException {
/*
This function processes the potential error message sent by the server. If message error, than prints a
readable message indicating the file name or chunk ID.
*/
if (response instanceof ErrorMessage error) {
StringBuilder errorMsg = new StringBuilder(operation);
errorMsg.append(" failed: ").append(error.message);
if (error.fileName != null) {
errorMsg.append(" (fileName: ").append(error.fileName).append(")");
}
if (error.chunkID != null) {
errorMsg.append(" (chunkID: ").append(error.chunkID).append(")");
}
throw new IOException(errorMsg.toString());
}
}
// Upload files from Client to Distributed File System
public void putFile(String path) throws Exception {
// Initialization
String fileName = Path.of(path).getFileName().toString();
int chunkSize = (int) FileMetadata.ChunkSize;
int chunkIndex = 0;
//On cree les flux réseau oos et ois, et un flux pour le fichier a envoyer in
try (Socket socket = new Socket(nameServerIPAddress, nameServerPort);
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
InputStream in = Files.newInputStream(Path.of(path))) {
//On cree un fichier vide sur le serveur
oos.writeObject(new CreateFileMessage(fileName));
oos.flush();
Object ack = ois.readObject();
checkForError(ack, "CreateFile");
if (!(ack instanceof OkMessage)) {
throw new IOException("CreateFile not acknowledged by NameServer");
}
// Get file metadata
//We ask the file ID (that could have been returned automatically previously but that's not the case)
//Just to include it in the chunks we send
oos.writeObject(new GetMetadataMessage(fileName));
oos.flush();
Object metaObj = ois.readObject();
checkForError(metaObj, "GetMetadata");
if (!(metaObj instanceof MetadataResponse)) {
throw new IOException("GetMetadata did not return metadata");
}
MetadataResponse meta = (MetadataResponse) metaObj;
if (!meta.exists) {
throw new IOException("File metadata not found after creation");
}
long fileId = meta.fileId;
// Send file chunks to NameServer
byte[] buffer = new byte[chunkSize]; //Creation d'un buffer de la taille d'un chunk
int read; //the number of bytes read for this iteration
while ((read = in.read(buffer)) != -1) {//while we read something
byte[] data;
if (read == buffer.length) {
//If the buffer is full, just send it as is
data = buffer;
} else {
//Otherwise remove the trailing space to avoid sending these random datas (that would be handled as part of the file by the server)
data = new byte[read];
System.arraycopy(buffer, 0, data, 0, read);
}
//The chunk is sent and we wait for acknowledgement
Chunk chunk = new Chunk(fileId, fileName, chunkIndex, data);
oos.writeObject(chunk);
oos.flush();
Object chunkAck = ois.readObject();
checkForError(chunkAck, "Chunk " + chunkIndex);
if (!(chunkAck instanceof OkMessage)) {
throw new IOException("Chunk " + chunkIndex + " not acknowledged by NameServer");
}
chunkIndex++;
//TODO : check if the following if is useful
if (data == buffer) {
buffer = new byte[chunkSize];
}
}
//Send a closefile message that could be useful with a lock system but is currently unused.
oos.writeObject(new EndOfFile(fileName));
oos.flush();
Object closeAck = ois.readObject();
checkForError(closeAck, "CloseFile");
if (!(closeAck instanceof OkMessage)) {
throw new IOException("CloseFile not acknowledged by NameServer");
}
}
}
public void readFile(String pathName, long offset) throws IOException {
try (Socket socket = new Socket(nameServerIPAddress, nameServerPort);
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
FileOutputStream outFile = new FileOutputStream(pathName)) {
//Query the nameserver
oos.writeObject(new ReadFile(pathName, offset));
oos.flush();
while (true){
Object response = null;
try { //To handle the class not found exception.
response = ois.readObject();
System.out.print(".");
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
checkForError(response, "Read File");
if (response instanceof EndOfFile){
//No need to close the streams, they will be closed when exiting the try.
break;
}
assert response instanceof Chunk;
outFile.write(((Chunk) response).getData()); //The cast has been automatically added by the IDE depiste of the assertion, I trust it.
}
}
}
}