package qora;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
import qora.block.Block;
import settings.Settings;
import network.Peer;
import network.message.BlockMessage;
import network.message.Message;
import network.message.MessageFactory;
public class BlockBuffer extends Thread
{
private static final int BUFFER_SIZE = 20;
private List<byte[]> signatures;
private Peer peer;
private int counter;
private boolean error;
private Map<byte[], BlockingQueue<Block>> blocks;
private boolean run = true;
public BlockBuffer(List<byte[]> signatures, Peer peer)
{
this.signatures = signatures;
this.peer = peer;
this.counter = 0;
this.error = false;
this.blocks = new HashMap<byte[], BlockingQueue<Block>>();
this.start();
}
public void run()
{
while(this.run)
{
for(int i=0; i<this.signatures.size() && i<this.counter + BUFFER_SIZE; i++)
{
byte[] signature = this.signatures.get(i);
//CHECK IF WE HAVE ALREADY LOADED THIS BLOCK
if(!this.blocks.containsKey(signature))
{
//LOAD BLOCK
this.loadBlock(signature);
}
}
try
{
Thread.sleep(10);
}
catch (InterruptedException e)
{
//ERROR SLEEPING
}
}
}
private void loadBlock(final byte[] signature)
{
//CREATE QUEUE
final BlockingQueue<Block> blockingQueue = new ArrayBlockingQueue<Block>(1);
this.blocks.put(signature, blockingQueue);
//LOAD BLOCK IN THREAD
new Thread(){
public void run()
{
//CREATE MESSAGE
Message message = MessageFactory.getInstance().createGetBlockMessage(signature);
//SEND MESSAGE TO PEER
BlockMessage response = (BlockMessage) peer.getResponse(message);
//CHECK IF WE GOT RESPONSE
if(response == null)
{
//ERROR
error = true;
return;
}
//CHECK BLOCK SIGNATURE
if(!response.getBlock().isSignatureValid())
{
error = true;
return;
}
//ADD TO LIST
blockingQueue.add(response.getBlock());
}
}.start();
}
public Block getBlock(byte[] signature) throws Exception
{
//CHECK ERROR
if(this.error)
{
throw new Exception("Block buffer error");
}
//UPDATE COUNTER
this.counter = this.signatures.indexOf(signature);
//CHECK IF ALREADY LOADED BLOCK
if(!this.blocks.containsKey(signature))
{
//LOAD BLOCK
this.loadBlock(signature);
}
//GET BLOCK
return this.blocks.get(signature).poll(Settings.getInstance().getConnectionTimeout(), TimeUnit.MILLISECONDS);
}
public void stopThread()
{
try
{
this.run = false;
this.join();
}
catch (InterruptedException e)
{
//INTERRUPTED
}
}
}