Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 57 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>ru.spbau.aastarkova</groupId>
<artifactId>homeworks</artifactId>
<version>1.0-SNAPSHOT</version>

<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>19.0</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<compilerArgs>
<arg>-Xlint:all</arg>
</compilerArgs>
</configuration>
</plugin>

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<compilerArgs>
<arg>-Xlint:all</arg>
</compilerArgs>
</configuration>
</plugin>
</plugins>
</build>
</project>
58 changes: 58 additions & 0 deletions src/main/java/ru/spbau/mit/Client.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package ru.spbau.mit;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;

public class Client extends ClientBase {
public Client(ClientInfo info) {
super(info);
}

public List<FileDescriptor> list() throws IOException {
try (TrackerConnection connection = connectToTracker()) {
connection.sendListRequest();
return connection.readListResponse();
}
}

public boolean get(int id) throws Exception {
try (MyLock myLock = MyLock.lock(info.lock.readLock())) {
if (info.files.containsKey(id)) {
return false;
}
}
FileDescriptor serverDescriptor = list().stream()
.filter(descriptor -> descriptor.getFileId() == id)
.findAny().orElse(null);
if (serverDescriptor == null) {
return false;
}
try (MyLock myLock = MyLock.lock(info.lock.writeLock())) {
info.files.put(id, new ClientInfo.FileInfo(serverDescriptor, null, info.workingDirectory));
}
return true;
}

public FileDescriptor newFile(Path path) throws IOException {
if (!Files.isRegularFile(path)) {
throw new IllegalArgumentException("File not exists or is not a regular file.");
}

FileDescriptor newDescriptor = new FileDescriptor(Files.size(path), path.getFileName().toString());
try (TrackerConnection connection = connectToTracker()) {
connection.sendUploadRequest(newDescriptor);
int newId = connection.readUploadResponse();
newDescriptor = newDescriptor.setId(newId);
}
ClientInfo.FileInfo newInfo = new ClientInfo.FileInfo(newDescriptor, path, null);
try (MyLock myLock = MyLock.lock(info.lock.writeLock())) {
info.files.put(newDescriptor.getFileId(), newInfo);
} catch (Exception e) {
e.printStackTrace();
}
return newDescriptor;
}

}
16 changes: 16 additions & 0 deletions src/main/java/ru/spbau/mit/ClientBase.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package ru.spbau.mit;

import java.io.IOException;
import java.net.Socket;

public abstract class ClientBase {
protected ClientInfo info;

public ClientBase(ClientInfo info) {
this.info = info;
}

protected TrackerConnection connectToTracker() throws IOException {
return new TrackerConnection(new Socket(info.host, TrackerConnection.PORT));
}
}
45 changes: 45 additions & 0 deletions src/main/java/ru/spbau/mit/ClientDescriptor.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package ru.spbau.mit;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.List;

/**
* Created by Анастасия on 10.04.2016.
*/
public final class ClientDescriptor {
private final InetSocketAddress address;
private final List<Integer> idList;

public ClientDescriptor(InetSocketAddress address, List<Integer> idList) {
this.address = address;
this.idList = idList;
}

public InetSocketAddress getAddress() {
return address;
}

public List<Integer> getIdList() {
return idList;
}

public void writeInfoToOutputStream(DataOutputStream outputStream) throws IOException {
//Write address to output stream
ReadWriteHelper.writeAddress(outputStream, address);
//Write idList to output stream
ReadWriteHelper.writeCollection(outputStream, idList, DataOutputStream::writeInt);
}

public static ClientDescriptor readInfoFromInputStream(DataInputStream inputStream) throws IOException {
return new ClientDescriptor(
//Read address from input stream
ReadWriteHelper.readAddress(inputStream),
//Read idList from input stream
ReadWriteHelper.readCollection(inputStream, new ArrayList<>(), DataInputStream::readInt));
}

}
130 changes: 130 additions & 0 deletions src/main/java/ru/spbau/mit/ClientInfo.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
package ru.spbau.mit;

import com.sun.xml.internal.ws.policy.privateutil.PolicyUtils;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.function.Function;
import java.util.stream.Collectors;

public class ClientInfo implements AutoCloseable {
private static final String INFO_FILE = "client-info.dat";
private static final String DOWNLOADS_DIR = "downloads";

Path workingDirectory;
ReadWriteLock lock = new ReentrantReadWriteLock();
Map<Integer, FileInfo> files;
String host;

public ClientInfo(String host, Path workingDirectory) throws IOException {
this(workingDirectory);
this.host = host;
}

public ClientInfo(Path workingDirectory) throws IOException {
this.workingDirectory = workingDirectory;
load();
}

public static void removeInfo(Path workingDirectory) {
Path info = workingDirectory.resolve(INFO_FILE);
if (Files.exists(info)) {
try {
Files.delete(info);
} catch (IOException e) {
e.printStackTrace();
}
}
}

@Override
public void close() throws Exception {
store();
}

static final class FileInfo {
ReadWriteLock fileLock = new ReentrantReadWriteLock();
FileDescriptor descriptor;
PartsBitset parts;
Path localPath;

FileInfo(FileDescriptor descriptor, Path localPath, Path workingDirectory) throws IOException {
this(descriptor, new PartsBitset(descriptor.getNumberOfTheParts(), localPath != null),
localPath, workingDirectory);
}

FileInfo(FileDescriptor descriptor, PartsBitset parts, Path localPath,
Path workingDirectory) throws IOException {
this.descriptor = descriptor;
this.parts = parts;
if (localPath == null) {
this.localPath = workingDirectory.resolve(Paths.get(
DOWNLOADS_DIR,
Integer.toString(descriptor.getFileId()),
descriptor.getFileName()
));
Files.createDirectories(this.localPath.getParent());
try (RandomAccessFile file = new RandomAccessFile(this.localPath.toString(), "rw")) {
file.setLength(descriptor.getFileSize());
}
} else {
this.localPath = localPath;
}
}

private void writeDataToOutputStream(DataOutputStream outputStream) throws IOException {
descriptor.writeInfoToOutputStream(outputStream);
parts.writeDataToOutputStream(outputStream);
outputStream.writeUTF(localPath.toString());
}

private static FileInfo readDataFromInputStream(DataInputStream inputStream) throws IOException {
FileDescriptor fileDescriptor = FileDescriptor.readInfoFromInputStream(inputStream, true);
PartsBitset parts = PartsBitset.readDataFromInputStream(inputStream, fileDescriptor.getNumberOfTheParts());
String localPath = inputStream.readUTF();
return new FileInfo(fileDescriptor, parts, Paths.get(localPath), null);
}
}

private void store() throws IOException {
Path info = workingDirectory.resolve(INFO_FILE);
if (!Files.exists(info)) {
Files.createDirectories(workingDirectory);
Files.createFile(info);
}
try (DataOutputStream outputStream = new DataOutputStream(Files.newOutputStream(info))) {
outputStream.writeUTF(host);
ReadWriteHelper.writeCollection(outputStream, files.values(),
(outputStream1, w) -> w.writeDataToOutputStream(outputStream1));
}
}

private void load() throws IOException {
Path info = workingDirectory.resolve(INFO_FILE);
if (Files.exists(info)) {
try (DataInputStream inputStream = new DataInputStream(Files.newInputStream(info))) {
host = inputStream.readUTF();
files = ReadWriteHelper.readCollection(inputStream, new HashSet<>(), FileInfo::readDataFromInputStream)
.stream()
.collect(Collectors.toMap(
fileInfo -> fileInfo.descriptor.getFileId(),
Function.identity()

));
}
} else {
host = "";
files = new HashMap<>();
}
}
}
67 changes: 67 additions & 0 deletions src/main/java/ru/spbau/mit/Connection.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package ru.spbau.mit;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.Collection;

/**
* Created by Анастасия on 10.04.2016.
*/
public abstract class Connection implements AutoCloseable {
private Socket socket;
private DataInputStream inputStream;
private DataOutputStream outputStream;

//Constructor for our abstract class
protected Connection(Socket socket) throws IOException {
this.socket = socket;
//Creating new input and output streams using socket
inputStream = new DataInputStream(socket.getInputStream());
outputStream = new DataOutputStream(socket.getOutputStream());
}

@Override
public void close() {
try {
socket.close();
} catch (IOException ignoredException) {
}
}

public DataOutputStream getOutputStream() {
return outputStream;
}

public DataInputStream getInputStream() {
return inputStream;
}

//We need this function in Tracker class in update() method
public String getHost() {
return ((InetSocketAddress) socket.getRemoteSocketAddress()).getHostName();
}

/*
* writeCollection function for the connection, using ReadWriteHelper writeConnection function
* we need it in methods of class TrackerConnection
*/
protected <T> void writeCollection(Collection<T> collection,
ReadWriteHelper.Writer<? super T> writer) throws IOException {
ReadWriteHelper.writeCollection(outputStream, collection, writer);
}

//readCollection function for the connection, using ReadWriteHelper readConnection function
protected <T, R extends Collection<T>> R readCollection(R collection,
ReadWriteHelper.Reader<? extends T> reader)
throws IOException {
return ReadWriteHelper.readCollection(inputStream, collection, reader);
}

//We need this function in listenConnection function in class Tracker
public int readRequest() throws IOException {
return inputStream.readUnsignedByte();
}
}
Loading