package ru.denull.wire.model; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.HashMap; import ru.denull.mtproto.DataService; import tl.*; public class MessageManager { private static final String TAG = "MessageManager"; public static final String TABLE_NAME = "message"; public static final String _ID = "_id"; public static final String COLUMN_NAME_PEER = "peer"; // user_id or -chat_id, used for filtering public static final String COLUMN_NAME_BODY = "body"; public static final String COLUMN_NAME_OUTDATED = "outdated"; public static final String SQL_CREATE_ENTRIES = "CREATE TABLE " + TABLE_NAME + " (" + _ID + " INTEGER PRIMARY KEY," + COLUMN_NAME_PEER + " INTEGER," + COLUMN_NAME_BODY + " BLOB," + COLUMN_NAME_OUTDATED + " INTEGER" + " )"; public static final String SQL_DELETE_ENTRIES = "DROP TABLE IF EXISTS " + TABLE_NAME; DataService service; SQLiteDatabase db; public HashMap<Integer, TMessage> loaded = new HashMap<Integer, TMessage>(); public static final MessageEmpty empty = new MessageEmpty(0); public int nextMessageID = 0; public MessageManager(DataService service, SQLiteDatabase db) { this.service = service; this.db = db; } public void store(final TMessage[] data) { for (TMessage message : data) { loaded.put(message.id, message); nextMessageID = Math.max(nextMessageID, message.id + 1); } // postpone saving to db service.threadPool.submit(new Runnable() { public void run() { // check if the oldest message is already stored in db Cursor cursor = db.rawQuery("SELECT MAX(" + _ID + ") FROM " + TABLE_NAME, null); if (cursor.getCount() > 0) { cursor.moveToFirst(); int max_id = cursor.getInt(0); if (max_id < data[data.length - 1].id) { // mark the last stored message as outdated (there's gap after it) ContentValues values = new ContentValues(); values.put(COLUMN_NAME_OUTDATED, 1); db.updateWithOnConflict(TABLE_NAME, values, "_id = ?", new String[] { max_id + "" }, SQLiteDatabase.CONFLICT_IGNORE); } } cursor.close(); for (TMessage message : data) { store(message); } } }); } public void store(TMessage message) { if (message.id > 0) { // id = 0 => empty, id < 0 => local message (not sent yet) ContentValues values = new ContentValues(); values.put(_ID, message.id); values.put(COLUMN_NAME_PEER, message.to_id instanceof PeerUser ? (message.out ? ((PeerUser) message.to_id).user_id : message.from_id) : -((PeerChat) message.to_id).chat_id); //values.put(COLUMN_NAME_BODY, message.writeToByteArray()); values.put(COLUMN_NAME_OUTDATED, 0); db.insertWithOnConflict(TABLE_NAME, null, values, SQLiteDatabase.CONFLICT_REPLACE); } loaded.put(message.id, message); nextMessageID = Math.max(nextMessageID, message.id + 1); } public TMessage get(int id) { TMessage result = loaded.get(id); if (result == null) { Cursor cursor = db.query(TABLE_NAME, new String[]{ COLUMN_NAME_BODY }, "_id = ?", new String[]{ id + "" }, null, null, null, "1"); if (cursor.getCount() > 0) { cursor.moveToFirst(); try { result = (TMessage) TL.read(cursor.getBlob(0)); } catch (Exception e) { e.printStackTrace(); } loaded.put(result.id, result); } cursor.close(); } return (result == null) ? empty : result; } public TMessage[] getHistory(TInputPeer peer, int max_id, int limit) { int peer_id = peer instanceof InputPeerContact ? ((InputPeerContact) peer).user_id : peer instanceof InputPeerForeign ? ((InputPeerForeign) peer).user_id : peer instanceof InputPeerSelf ? service.me.id : peer instanceof InputPeerChat ? -((InputPeerChat) peer).chat_id : 0; if (peer_id == 0) return new TMessage[] { }; Cursor cursor; if (max_id > 0) { cursor = db.query(TABLE_NAME, new String[] { COLUMN_NAME_BODY, COLUMN_NAME_OUTDATED }, "_id < ? AND peer = ?", new String[] { max_id + "", peer_id + "" }, null, null, "_id DESC", limit + ""); } else { cursor = db.query(TABLE_NAME, new String[] { COLUMN_NAME_BODY, COLUMN_NAME_OUTDATED }, "peer = ?", new String[] { peer_id + "" }, null, null, "_id DESC", limit + ""); } ArrayList<TMessage> result = new ArrayList<TMessage>(); cursor.moveToFirst(); while (!cursor.isAfterLast()) { if (cursor.getInt(1) == 1) break; // outdated (gap ahead), stop returning results try { result.add((TMessage) TL.read(cursor.getBlob(0))); } catch (Exception e) { e.printStackTrace(); } cursor.moveToNext(); } cursor.close(); return result.toArray(new TMessage[] {}); } }