file = f;
break;
}
}
if (file == null)
throw new ProtocolException("DOWNLOAD_CHUNK specified invalid file handle " + downloadChunk.getHandle());
if (downloadChunk.getNumChunks() <= 0)
throw new ProtocolException("DOWNLOAD_CHUNK: num_chunks must be >= 1");
if (file.getPricePerChunk() > 0) {
// How many chunks can the client afford with their current balance?
PaymentChannelServerState state = payments == null ? null : payments.state();
if (state == null)
throw new ProtocolException("Payment channel not initiated but this file is not free");
long balance = state.getBestValueToMe().longValue();
long affordableChunks = balance / file.getPricePerChunk();
if (affordableChunks < downloadChunk.getNumChunks())
throw new ProtocolException("Insufficient payment received for requested amount of data: got " + balance);
balance -= downloadChunk.getNumChunks();
}
for (int i = 0; i < downloadChunk.getNumChunks(); i++) {
long chunkId = downloadChunk.getChunkId() + i;
if (chunkId == 0)
log.info("{}: Starting download of {}", peerName, file.getFileName());
// This is super inefficient.
File diskFile = new File(directoryToServe, file.getFileName());
FileInputStream fis = new FileInputStream(diskFile);
final long offset = chunkId * CHUNK_SIZE;
if (fis.skip(offset) != offset)
throw new IOException("Bogus seek");
byte[] chunk = new byte[CHUNK_SIZE];
final int bytesActuallyRead = fis.read(chunk);
if (bytesActuallyRead < 0) {
log.debug("Reached EOF");
} else if (bytesActuallyRead > 0 && bytesActuallyRead < chunk.length) {
chunk = Arrays.copyOf(chunk, bytesActuallyRead);
}
Payfile.PayFileMessage msg = Payfile.PayFileMessage.newBuilder()
.setType(Payfile.PayFileMessage.Type.DATA)
.setData(Payfile.Data.newBuilder()
.setChunkId(downloadChunk.getChunkId())
.setHandle(file.getHandle())
.setData(ByteString.copyFrom(chunk))
.build()
).build();
writeMessage(msg);
}
} catch (IOException e) {
throw new ProtocolException("Error reading from disk: " + e.getMessage());
}
}