package p2pp;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.klomp.snark.Peer;
import org.klomp.snark.PeerCoordinator;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
public class FileDownloadProgressListener implements DownloadProgressListener {
private Gson gson;
private JsonWriter jsonOut;
private long started;
private Map<Integer, FileDownloadProgressListener.Piece> pieces;
private PeerCoordinator coord;
private boolean firstReceived = false;
public FileDownloadProgressListener(String desc) throws IOException {
this("log", desc);
}
public FileDownloadProgressListener(String path, String description)
throws IOException {
this.started = System.currentTimeMillis();
this.gson = new Gson();
this.pieces = new HashMap<Integer, FileDownloadProgressListener.Piece>();
String name = description + "-" + System.currentTimeMillis() + ".log";
FileWriter writer = new FileWriter(new File(path, name));
this.jsonOut = new JsonWriter(writer);
this.jsonOut.setIndent(" ");
}
@Override
public void pieceDownloaded(Peer peer, int piece) {
synchronized(pieces) {
long time = System.currentTimeMillis() - started;
if(!firstReceived) {
firstReceived = true;
try {
jsonOut.beginArray();
} catch (IOException e) {
e.printStackTrace();
}
}
FileDownloadProgressListener.Piece p = pieces.get(piece);
String from = peer == null ? "web seed" : peer.toString();
p.received(from, time);
gson.toJson(p, FileDownloadProgressListener.Piece.class, jsonOut);
pieces.remove(piece);
}
}
@Override
public void downloadComplete() {
coord.halt();
try {
jsonOut.endArray();
jsonOut.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void pieceRequested(Peer peer, int piece) {
synchronized(pieces) {
long time = System.currentTimeMillis() - started;
FileDownloadProgressListener.Piece p = pieces.get(piece);
if(p == null) {
p = new FileDownloadProgressListener.Piece(piece);
pieces.put(piece, p);
}
String from = peer == null ? WebSeed.description : peer.toString();
p.requested(from, time);
}
}
@Override
public void setPeerCoordinator(PeerCoordinator coord) {
this.coord = coord;
}
static class LogReader {
private JsonReader jsonIn;
private Gson gson = new Gson();
public LogReader(String file) throws FileNotFoundException {
FileReader reader = new FileReader(file);
this.jsonIn = new JsonReader(reader);
}
public List<Piece> read() throws IOException {
return read(false);
}
public List<Piece> read(boolean filter) throws IOException {
Type list = new TypeToken<List<
FileDownloadProgressListener.Piece>>() {}.getType();
List<Piece> pieces = gson.fromJson(jsonIn, list);
if(filter) {
for(Piece piece : pieces) {
List<Request> requests = piece.requests;
Request finished = null;
for(Request request : requests)
if(request.received != -1 &&
(finished == null ||
finished.received > request.received))
finished = request;
requests.clear();
requests.add(finished);
}
}
return pieces;
}
}
static class Piece {
private int id;
private List<FileDownloadProgressListener.Request> requests;
public Piece() {}
public Piece(int id) {
this.id = id;
this.requests = new ArrayList<FileDownloadProgressListener.Request>();
}
public void requested(String from, long when) {
this.requests.add(
new FileDownloadProgressListener.Request(from, when));
}
public void received(String from, long when) {
for(int i = requests.size() - 1; i >= 0; i--) {
FileDownloadProgressListener.Request request = requests.get(i);
if(request.from.equals(from)) {
request.setReceived(when);
break;
}
}
}
public int getId() {
return id;
}
public List<Request> getRequests() {
return requests;
}
@Override
public String toString() {
return id + ":" + requests.toString();
}
}
static class Request {
private String from;
private long requested;
private long received = -1;
public Request() {}
public Request(String from, long when) {
this.requested = when;
this.from = from;
}
public void setReceived(long rec) {
this.received = rec;
}
public String getFrom() {
return from;
}
public long getRequested() {
return requested;
}
public long getReceived() {
return received;
}
@Override
public String toString() {
return "{from=" + from + ", requested=" + requested +
", received=" + received + "}";
}
}
}