/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redPandaLib.core;
import java.nio.ByteBuffer;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.redPandaLib.Main;
import org.redPandaLib.NewMessageListener;
import static org.redPandaLib.core.Test.messageStore;
import org.redPandaLib.core.messages.BlockMsg;
import org.redPandaLib.core.messages.TextMessageContent;
import org.redPandaLib.core.messages.TextMsg;
import org.redPandaLib.crypt.Sha256Hash;
import org.redPandaLib.database.DirectMessageStore;
import org.redPandaLib.services.MessageDownloader;
/**
*
* @author rflohr
*/
public class Blocks {
public static void generate(Channel channel) {
if (!channel.isWriteable()) {
return;
}
//get id from chanel in database
int pubkeyId = Test.messageStore.getPubkeyId(channel.getKey());
long currentTime = System.currentTimeMillis() - BlockMsg.BLOCK_SYNC_TO_TIME; // have to go back some time to overcome the problem with new messages
try {
//get Key Id
//String query = "SELECT pubkey_id,message_id,content,public_type,timestamp,nonce from message WHERE timestamp > ? and verified = true AND pubkey_id = ?";
String query = "SELECT message_id,message_type,timestamp,decryptedContent,identity,fromMe,nonce,public_type from channelmessage WHERE pubkey_id =? AND timestamp > ? AND timestamp < ? ORDER BY timestamp ASC";
PreparedStatement pstmt = Test.messageStore.getConnection().prepareStatement(query);
pstmt.setInt(1, pubkeyId);
long asd = currentTime - BlockMsg.TIME_TO_SYNC_BACK;
System.out.println("time: " + asd);
pstmt.setLong(2, asd);
pstmt.setLong(3, currentTime);
ResultSet executeQuery = pstmt.executeQuery();
int msgcount = 0;
boolean breaked = false;
byte[] dataArray = new byte[1024 * 200]; //max size of a message!! should be regulated later!
ByteBuffer buffer = ByteBuffer.wrap(dataArray);
byte[] dataArrayHash = new byte[1024 * 200];
ByteBuffer bufferHash = ByteBuffer.wrap(dataArrayHash);
//ToDo: add hash from all data and count of messages to get an easier sync!
//System.out.println("dwzdzwd " + executeQuery.next());
while (executeQuery.next()) {
int message_id = executeQuery.getInt("message_id");
int message_type = executeQuery.getInt("message_type");
byte[] decryptedContent = executeQuery.getBytes("decryptedContent");
long timestamp = executeQuery.getLong("timestamp");
long identity = executeQuery.getLong("identity");
boolean fromMe = executeQuery.getBoolean("fromMe");
byte public_type = executeQuery.getByte("public_type");
int nonce = executeQuery.getInt("nonce");
if (decryptedContent == null) {
decryptedContent = "".getBytes();
}
//only pack a message into a block if the public_type is 20!
if (public_type == 20) {
//skip content which will be generated regulary, image messages should not have public_type 20! (with new version, old imgs will be deleted)
if (message_type != TextMsg.BYTE) {
continue;
}
if (buffer.remaining() < 8 + 4 + 4 + 8 + 4 + decryptedContent.length) {
System.out.println("buffer full, exit routine, dont know what to do atm");
breaked = true;
break;
}
//System.out.println("Data: msgtyp: " + message_type + " pubtyp: " + public_type + " " + new String(decryptedContent));
System.out.println("len: " + decryptedContent.length);
buffer.putLong(timestamp);
buffer.putInt(nonce);
buffer.putInt(message_type);
buffer.putLong(identity);
buffer.putInt(decryptedContent.length);
buffer.put(decryptedContent);
msgcount++;
//add data to hash bytes:b (dont use all data because when syncing we only need to get these data types)
bufferHash.putLong(timestamp);
bufferHash.putInt(message_type);
bufferHash.putInt(public_type);
}
}
executeQuery.close();
pstmt.close();
if (breaked) {
System.out.println("abort...");
return;
}
//System.out.println("Found - messages: " + msgCnt + " with " + textBytes / 1024. + " kb text and " + imageBytes / 1024. + " kb images");
//System.out.format("%30s %10s %10s %20s %10s %20s %10s %20s %10s %20s\n", "Channel", "pubkeyId", "rawCount", "textbytes", "imageCount", "imageBytes", "infoCount", "infoBytes", "deliveredCount", "deliveredBytes");
//System.out.format("%30s %10d %10d %20f %10d %20f %10d %20f %10d %20f\n", chan.getName(), pubkeyId, rawMessageCount, textBytes / 1024., imageMessageCount, imageBytes / 1024., infoMessageCount, infoBytes / 1024., deliveredMessageCount, deliveredBytes / 1024.);
ByteBuffer finalBuffer = ByteBuffer.allocate(buffer.position() + 1 + 8 + 4 + 4);
System.out.println("size: " + buffer.position());
ByteBuffer lel = ByteBuffer.allocate(buffer.position());
lel.put(dataArray, 0, buffer.position());
dataArray = lel.array();//shrinked to actual size
finalBuffer.put(BlockMsg.BYTE); //cmd for block
finalBuffer.putLong(Test.localSettings.identity);//mark that i was the generator of the block
finalBuffer.putInt(msgcount);
finalBuffer.putInt(Sha256Hash.create(dataArrayHash).hashCode());
finalBuffer.put(dataArray);
double kbs = finalBuffer.position() / 1024.;
System.out.println("content block size: " + kbs + " in " + msgcount + " messags.");
MessageDownloader.channelIdToLatestBlockTimeLock.lock();
MessageDownloader.channelIdToLatestBlockTime.put(pubkeyId, currentTime);
MessageDownloader.channelIdToLatestBlockTimeLock.unlock();
// System.out.println("hex: " + Utils.bytesToHexString(finalBuffer.array()));
BlockMsg build = BlockMsg.build(channel, currentTime, 45678, finalBuffer.array());
BlockMsg addMessage = (BlockMsg) MessageHolder.addMessage(build);
Test.broadcastMsg(addMessage);
String text = "Generated Block: " + msgcount + " msgs (" + kbs + " kb).";
Test.messageStore.addDecryptedContent(addMessage.getKey().database_id, (int) addMessage.database_Id, BlockMsg.BYTE, addMessage.timestamp, text.getBytes(), ((BlockMsg) addMessage).getIdentity(), true, addMessage.nonce, addMessage.public_type);
TextMessageContent textMessageContent = new TextMessageContent(addMessage.database_Id, addMessage.key.database_id, addMessage.public_type, TextMsg.BYTE, addMessage.timestamp, addMessage.decryptedContent, addMessage.channel, addMessage.getIdentity(), text, true);
textMessageContent.read = true;
for (NewMessageListener listener : Main.listeners) {
listener.newMessage(textMessageContent);
}
System.out.println("New block saved and send, doing cleanup...");
//remove old block:
int removeMessagesFromChannel = messageStore.removeMessagesFromChannel(pubkeyId, BlockMsg.PUBLIC_TYPE, currentTime);
System.out.println("removed old blocks: " + removeMessagesFromChannel);
//remove old messages which are encrypted and now saved in the new block (only necessary data)...
removeMessagesFromChannel = messageStore.removeMessagesFromChannel(pubkeyId, (byte) 20, currentTime);
System.out.println("removed old encrypted messages: " + removeMessagesFromChannel);
} catch (SQLException ex) {
Logger.getLogger(DirectMessageStore.class.getName()).log(Level.SEVERE, null, ex);
}
}
}