package network.message;
import java.io.DataInputStream;
import java.util.Arrays;
import java.util.List;
import qora.block.Block;
import qora.crypto.Crypto;
import qora.transaction.Transaction;
import com.google.common.primitives.Ints;
import network.Peer;
public class MessageFactory {
private static MessageFactory instance;
public static MessageFactory getInstance()
{
if(instance == null)
{
instance = new MessageFactory();
}
return instance;
}
public Message createPingMessage()
{
//CREATE A MESSAGE WITH ping ACTION
return new Message(Message.PING_TYPE);
}
public Message createGetPeersMessage()
{
//CREATE A MESSAGE WITH getPeers ACTION
return new Message(Message.GET_PEERS_TYPE);
}
public Message createPeersMessage(List<Peer> peers)
{
return new PeersMessage(peers);
}
public Message createVersionMessage(int height)
{
return new VersionMessage(height);
}
public Message createGetHeadersMessage(byte[] parent)
{
return new GetSignaturesMessage(parent);
}
public Message createHeadersMessage(List<byte[]> headers)
{
return new SignaturesMessage(headers);
}
public Message createGetBlockMessage(byte[] header)
{
return new GetBlockMessage(header);
}
public Message createBlockMessage(Block block)
{
return new BlockMessage(block);
}
public Message createTransactionMessage(Transaction transaction)
{
return new TransactionMessage(transaction);
}
public Message parse(Peer sender, DataInputStream inputStream) throws Exception
{
//READ MESSAGE TYPE
byte[] typeBytes = new byte[Message.TYPE_LENGTH];
inputStream.readFully(typeBytes);
int type = Ints.fromByteArray(typeBytes);
//READ HAS ID
int hasId = inputStream.read();
int id = -1;
if(hasId == 1)
{
//READ ID
byte[] idBytes = new byte[Message.ID_LENGTH];
inputStream.readFully(idBytes);
id = Ints.fromByteArray(idBytes);
}
//READ LENGTH
//byte[] lengthBytes = new byte[Message.MESSAGE_LENGTH];
//inputStream.readFully(lengthBytes);
int length = inputStream.readInt();//Ints.fromByteArray(lengthBytes);
//IF MESSAGE CONTAINS DATA READ DATA AND VALIDATE CHECKSUM
byte[] data = new byte[length];
if(length > 0)
{
//READ CHECKSUM
byte[] checksum = new byte[Message.CHECKSUM_LENGTH];
inputStream.readFully(checksum);
//READ DATA
inputStream.readFully(data);
/*int position = 0;
while(position < length)
{
//READ MULTIPLE TIMES BECAUSE OF MAX READ OF 65536 BYTES
//TODO CHECK THIS FIXES PROBLEM
//position += inputStream.read(data, position, length - position);
int temp = inputStream.read(data, position, length - position);
position += temp;
if(temp == -1)
{
boolean tempa = true;
tempa = false;
if(tempa);
}
}*/
//VALIDATE CHECKSUM
byte[] digest = Crypto.getInstance().digest(data);
//TAKE FOR FIRST BYTES
digest = Arrays.copyOfRange(digest, 0, Message.CHECKSUM_LENGTH);
//CHECK IF CHECKSUM MATCHES
if(!Arrays.equals(checksum, digest))
{
throw new Exception("Invalid data checksum length="+length);
}
}
Message message = null;
switch(type)
{
//PING
case Message.PING_TYPE:
message = new Message(type);
break;
//GETPEERS
case Message.GET_PEERS_TYPE:
message = new Message(type);
break;
//PEERS
case Message.PEERS_TYPE:
//CREATE MESSAGE FROM DATA
message = PeersMessage.parse(data);
break;
//VERSION
case Message.VERSION_TYPE:
//CREATE MESSAGE FROM DATA
message = VersionMessage.parse(data);
break;
//GETSIGNATURES
case Message.GET_SIGNATURES_TYPE:
//CREATE MESSAGE FROM DATA
message = GetSignaturesMessage.parse(data);
break;
//SIGNATURES
case Message.SIGNATURES_TYPE:
//CREATE MESSAGE FROM DATA
message = SignaturesMessage.parse(data);
break;
//GETBLOCK
case Message.GET_BLOCK_TYPE:
//CREATE MESSAGE FROM DATA
message = GetBlockMessage.parse(data);
break;
//BLOCK
case Message.BLOCK_TYPE:
//CREATE MESSAGE FROM DATA
message = BlockMessage.parse(data);
break;
//TRANSACTION
case Message.TRANSACTION_TYPE:
//CREATE MESSAGE FRO MDATA
message = TransactionMessage.parse(data);
break;
}
//SET SENDER
message.setSender(sender);
//SET ID
if(hasId == 1)
{
message.setId(id);
}
//RETURN
return message;
}
}