added max history age (default 1w). automatically sort newly added mam messages

This commit is contained in:
iNPUTmice 2014-12-08 21:59:14 +01:00
parent 4a94389f05
commit 0ab530932a
9 changed files with 103 additions and 42 deletions

View file

@ -22,6 +22,8 @@ public final class Config {
public static final boolean NO_PROXY_LOOKUP = false; //useful to debug ibb public static final boolean NO_PROXY_LOOKUP = false; //useful to debug ibb
public static final long MAX_HISTORY_AGE = 7 * 24 * 60 * 60 * 1000;
private Config() { private Config() {
} }

View file

@ -17,5 +17,4 @@ public abstract class AbstractEntity {
public boolean equals(AbstractEntity entity) { public boolean equals(AbstractEntity entity) {
return this.getUuid().equals(entity.getUuid()); return this.getUuid().equals(entity.getUuid());
} }
} }

View file

@ -16,6 +16,8 @@ import org.json.JSONObject;
import java.security.interfaces.DSAPublicKey; import java.security.interfaces.DSAPublicKey;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List; import java.util.List;
import eu.siacs.conversations.xmpp.jid.InvalidJidException; import eu.siacs.conversations.xmpp.jid.InvalidJidException;
@ -471,12 +473,25 @@ public class Conversation extends AbstractEntity {
} }
} }
public void setLastMessageReceived(long value) { public boolean setLastMessageReceived(long value) {
long before = getLastMessageReceived();
this.setAttribute(ATTRIBUTE_LAST_MESSAGE_RECEIVED, String.valueOf(value)); this.setAttribute(ATTRIBUTE_LAST_MESSAGE_RECEIVED, String.valueOf(value));
return (value - before > 1000);
} }
public long getLastMessageReceived() { public long getLastMessageReceived() {
return getLongAttribute(ATTRIBUTE_LAST_MESSAGE_RECEIVED,0); long timestamp = getLongAttribute(ATTRIBUTE_LAST_MESSAGE_RECEIVED,0);
if (timestamp == 0) {
synchronized (this.messages) {
for(int i = this.messages.size() - 1; i >= 0; --i) {
Message message = this.messages.get(i);
if (message.getStatus() == Message.STATUS_RECEIVED) {
return message.getTimeSent();
}
}
}
}
return timestamp;
} }
public void setMutedTill(long value) { public void setMutedTill(long value) {
@ -544,6 +559,26 @@ public class Conversation extends AbstractEntity {
} }
} }
public void sort() {
synchronized (this.messages) {
for(Message message : this.messages) {
message.untie();
}
Collections.sort(this.messages,new Comparator<Message>() {
@Override
public int compare(Message left, Message right) {
if (left.getTimeSent() < right.getTimeSent()) {
return -1;
} else if (left.getTimeSent() > right.getTimeSent()) {
return 1;
} else {
return 0;
}
}
});
}
}
public class Smp { public class Smp {
public static final int STATUS_NONE = 0; public static final int STATUS_NONE = 0;
public static final int STATUS_CONTACT_REQUESTED = 1; public static final int STATUS_CONTACT_REQUESTED = 1;

View file

@ -493,6 +493,11 @@ public class Message extends AbstractEntity {
} }
} }
public void untie() {
this.mNextMessage = null;
this.mPreviousMessage = null;
}
public class ImageParams { public class ImageParams {
public URL url; public URL url;
public long size = 0; public long size = 0;

View file

@ -549,8 +549,11 @@ public class MessageParser extends AbstractParser implements
} }
Conversation conversation = message.getConversation(); Conversation conversation = message.getConversation();
conversation.add(message); conversation.add(message);
conversation.setLastMessageReceived(System.currentTimeMillis()); if (account.getXmppConnection() != null && account.getXmppConnection().getFeatures().advancedStreamFeaturesLoaded()) {
mXmppConnectionService.updateConversation(conversation); if (conversation.setLastMessageReceived(System.currentTimeMillis())) {
mXmppConnectionService.updateConversation(conversation);
}
}
if (message.getStatus() == Message.STATUS_RECEIVED if (message.getStatus() == Message.STATUS_RECEIVED
&& conversation.getOtrSession() != null && conversation.getOtrSession() != null

View file

@ -4,16 +4,18 @@ import android.util.Log;
import java.math.BigInteger; import java.math.BigInteger;
import java.util.HashSet; import java.util.HashSet;
import java.util.List;
import eu.siacs.conversations.Config; import eu.siacs.conversations.Config;
import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Conversation; import eu.siacs.conversations.entities.Conversation;
import eu.siacs.conversations.xml.Element; import eu.siacs.conversations.xml.Element;
import eu.siacs.conversations.xmpp.OnAdvancedStreamFeaturesLoaded;
import eu.siacs.conversations.xmpp.OnIqPacketReceived; import eu.siacs.conversations.xmpp.OnIqPacketReceived;
import eu.siacs.conversations.xmpp.jid.Jid; import eu.siacs.conversations.xmpp.jid.Jid;
import eu.siacs.conversations.xmpp.stanzas.IqPacket; import eu.siacs.conversations.xmpp.stanzas.IqPacket;
public class MessageArchiveService { public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded {
private final XmppConnectionService mXmppConnectionService; private final XmppConnectionService mXmppConnectionService;
@ -28,18 +30,31 @@ public class MessageArchiveService {
final Account account = conversation.getAccount(); final Account account = conversation.getAccount();
long start = conversation.getLastMessageReceived(); long start = conversation.getLastMessageReceived();
long end = account.getXmppConnection().getLastSessionEstablished(); long end = account.getXmppConnection().getLastSessionEstablished();
if (end - start >= Config.MAX_HISTORY_AGE) {
start = end - Config.MAX_HISTORY_AGE;
}
final Query query = new Query(conversation, start, end); final Query query = new Query(conversation, start, end);
this.queries.add(query); this.queries.add(query);
IqPacket packet = this.mXmppConnectionService.getIqGenerator().queryMessageArchiveManagement(query); IqPacket packet = this.mXmppConnectionService.getIqGenerator().queryMessageArchiveManagement(query);
this.mXmppConnectionService.sendIqPacket(account, packet, new OnIqPacketReceived() { this.mXmppConnectionService.sendIqPacket(account, packet, new OnIqPacketReceived() {
@Override @Override
public void onIqPacketReceived(Account account, IqPacket packet) { public void onIqPacketReceived(Account account, IqPacket packet) {
Log.d(Config.LOGTAG, packet.toString()); if (packet.getType() == IqPacket.TYPE_ERROR) {
finalizeQuery(query);
}
} }
}); });
} }
} }
private void finalizeQuery(Query query) {
synchronized (this.queries) {
this.queries.remove(query);
}
query.getConversation().sort();
this.mXmppConnectionService.updateConversationUi();
}
public void processFin(Element fin) { public void processFin(Element fin) {
if (fin == null) { if (fin == null) {
return; return;
@ -48,27 +63,26 @@ public class MessageArchiveService {
if (query == null) { if (query == null) {
return; return;
} }
Log.d(Config.LOGTAG,"fin "+fin.toString());
boolean complete = fin.getAttributeAsBoolean("complete"); boolean complete = fin.getAttributeAsBoolean("complete");
Element set = fin.findChild("set","http://jabber.org/protocol/rsm"); Element set = fin.findChild("set","http://jabber.org/protocol/rsm");
Element last = set == null ? null : set.findChild("last"); Element last = set == null ? null : set.findChild("last");
if (complete || last == null) { if (complete || last == null) {
Log.d(Config.LOGTAG,"completed mam query for "+query.getWith().toString()); final Account account = query.getConversation().getAccount();
synchronized (this.queries) { Log.d(Config.LOGTAG,account.getJid().toBareJid().toString()+": completed mam query for "+query.getWith().toString());
this.queries.remove(query); this.finalizeQuery(query);
}
} else { } else {
Query nextQuery = query.next(last == null ? null : last.getContent()); final Query nextQuery = query.next(last == null ? null : last.getContent());
IqPacket packet = this.mXmppConnectionService.getIqGenerator().queryMessageArchiveManagement(nextQuery); IqPacket packet = this.mXmppConnectionService.getIqGenerator().queryMessageArchiveManagement(nextQuery);
synchronized (this.queries) { synchronized (this.queries) {
this.queries.remove(query); this.queries.remove(query);
this.queries.add(nextQuery); this.queries.add(nextQuery);
} }
Log.d(Config.LOGTAG,packet.toString());
this.mXmppConnectionService.sendIqPacket(query.getConversation().getAccount(),packet,new OnIqPacketReceived() { this.mXmppConnectionService.sendIqPacket(query.getConversation().getAccount(),packet,new OnIqPacketReceived() {
@Override @Override
public void onIqPacketReceived(Account account, IqPacket packet) { public void onIqPacketReceived(Account account, IqPacket packet) {
Log.d(Config.LOGTAG,packet.toString()); if (packet.getType() == IqPacket.TYPE_ERROR) {
finalizeQuery(nextQuery);
}
} }
}); });
} }
@ -88,6 +102,20 @@ public class MessageArchiveService {
} }
} }
@Override
public void onAdvancedStreamFeaturesAvailable(Account account) {
if (account.getXmppConnection() != null && account.getXmppConnection().getFeatures().mam()) {
List<Conversation> conversations = mXmppConnectionService.getConversations();
for (Conversation conversation : conversations) {
if (conversation.getMode() == Conversation.MODE_SINGLE && conversation.getAccount() == account) {
this.query(conversation);
}
}
} else {
Log.d(Config.LOGTAG,"no mam available");
}
}
public class Query { public class Query {
private long start; private long start;
private long end; private long end;

View file

@ -73,7 +73,7 @@ import eu.siacs.conversations.utils.OnPhoneContactsLoadedListener;
import eu.siacs.conversations.utils.PRNGFixes; import eu.siacs.conversations.utils.PRNGFixes;
import eu.siacs.conversations.utils.PhoneHelper; import eu.siacs.conversations.utils.PhoneHelper;
import eu.siacs.conversations.xml.Element; import eu.siacs.conversations.xml.Element;
import eu.siacs.conversations.xmpp.OnAdvancedStreamFeaturesAvailable; import eu.siacs.conversations.xmpp.OnAdvancedStreamFeaturesLoaded;
import eu.siacs.conversations.xmpp.OnBindListener; import eu.siacs.conversations.xmpp.OnBindListener;
import eu.siacs.conversations.xmpp.OnContactStatusChanged; import eu.siacs.conversations.xmpp.OnContactStatusChanged;
import eu.siacs.conversations.xmpp.OnIqPacketReceived; import eu.siacs.conversations.xmpp.OnIqPacketReceived;
@ -205,12 +205,7 @@ public class XmppConnectionService extends Service {
getNotificationService().updateErrorNotification(); getNotificationService().updateErrorNotification();
} }
}; };
private OnAdvancedStreamFeaturesAvailable onAdvancedStreamFeaturesAvailable = new OnAdvancedStreamFeaturesAvailable() {
@Override
public void onAdvancedStreamFeaturesAvailable(Account account) {
queryMessagesFromArchive(account);
}
};
private int accountChangedListenerCount = 0; private int accountChangedListenerCount = 0;
private OnRosterUpdate mOnRosterUpdate = null; private OnRosterUpdate mOnRosterUpdate = null;
private int rosterChangedListenerCount = 0; private int rosterChangedListenerCount = 0;
@ -592,7 +587,7 @@ public class XmppConnectionService extends Service {
connection.setOnJinglePacketReceivedListener(this.jingleListener); connection.setOnJinglePacketReceivedListener(this.jingleListener);
connection.setOnBindListener(this.mOnBindListener); connection.setOnBindListener(this.mOnBindListener);
connection.setOnMessageAcknowledgeListener(this.mOnMessageAcknowledgedListener); connection.setOnMessageAcknowledgeListener(this.mOnMessageAcknowledgedListener);
connection.setOnAdvancedStreamFeaturesAvailableListener(this.onAdvancedStreamFeaturesAvailable); connection.addOnAdvancedStreamFeaturesAvailableListener(this.mMessageArchiveService);
return connection; return connection;
} }
@ -1027,6 +1022,7 @@ public class XmppConnectionService extends Service {
} }
this.databaseBackend.createConversation(conversation); this.databaseBackend.createConversation(conversation);
} }
this.mMessageArchiveService.query(conversation);
this.conversations.add(conversation); this.conversations.add(conversation);
updateConversationUi(); updateConversationUi();
return conversation; return conversation;
@ -1239,19 +1235,6 @@ public class XmppConnectionService extends Service {
} }
} }
private void queryMessagesFromArchive(final Account account) {
if (account.getXmppConnection() != null && account.getXmppConnection().getFeatures().mam()) {
List<Conversation> conversations = getConversations();
for (Conversation conversation : conversations) {
if (conversation.getMode() == Conversation.MODE_SINGLE && conversation.getAccount() == account) {
this.mMessageArchiveService.query(conversation);
}
}
} else {
Log.d(Config.LOGTAG,"no mam available");
}
}
public void joinMuc(Conversation conversation) { public void joinMuc(Conversation conversation) {
Account account = conversation.getAccount(); Account account = conversation.getAccount();
account.pendingConferenceJoins.remove(conversation); account.pendingConferenceJoins.remove(conversation);

View file

@ -2,6 +2,6 @@ package eu.siacs.conversations.xmpp;
import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.Account;
public interface OnAdvancedStreamFeaturesAvailable { public interface OnAdvancedStreamFeaturesLoaded {
public void onAdvancedStreamFeaturesAvailable(final Account account); public void onAdvancedStreamFeaturesAvailable(final Account account);
} }

View file

@ -107,7 +107,7 @@ public class XmppConnection implements Runnable {
private OnMessagePacketReceived messageListener = null; private OnMessagePacketReceived messageListener = null;
private OnStatusChanged statusListener = null; private OnStatusChanged statusListener = null;
private OnBindListener bindListener = null; private OnBindListener bindListener = null;
private OnAdvancedStreamFeaturesAvailable advancedStreamFeaturesAvailableListener = null; private ArrayList<OnAdvancedStreamFeaturesLoaded> advancedStreamFeaturesLoadedListeners = new ArrayList<>();
private OnMessageAcknowledged acknowledgedListener = null; private OnMessageAcknowledged acknowledgedListener = null;
private XmppConnectionService mXmppConnectionService = null; private XmppConnectionService mXmppConnectionService = null;
@ -772,8 +772,8 @@ public class XmppConnection implements Runnable {
if (account.getServer().equals(server.toDomainJid())) { if (account.getServer().equals(server.toDomainJid())) {
enableAdvancedStreamFeatures(); enableAdvancedStreamFeatures();
if (advancedStreamFeaturesAvailableListener != null) { for(OnAdvancedStreamFeaturesLoaded listener : advancedStreamFeaturesLoadedListeners) {
advancedStreamFeaturesAvailableListener.onAdvancedStreamFeaturesAvailable(account); listener.onAdvancedStreamFeaturesAvailable(account);
} }
} }
} }
@ -947,8 +947,10 @@ public class XmppConnection implements Runnable {
this.acknowledgedListener = listener; this.acknowledgedListener = listener;
} }
public void setOnAdvancedStreamFeaturesAvailableListener(OnAdvancedStreamFeaturesAvailable listener) { public void addOnAdvancedStreamFeaturesAvailableListener(OnAdvancedStreamFeaturesLoaded listener) {
this.advancedStreamFeaturesAvailableListener = listener; if (!this.advancedStreamFeaturesLoadedListeners.contains(listener)) {
this.advancedStreamFeaturesLoadedListeners.add(listener);
}
} }
public void disconnect(boolean force) { public void disconnect(boolean force) {
@ -1095,6 +1097,10 @@ public class XmppConnection implements Runnable {
return hasDiscoFeature(account.getServer(), "urn:xmpp:mam:0"); return hasDiscoFeature(account.getServer(), "urn:xmpp:mam:0");
} }
public boolean advancedStreamFeaturesLoaded() {
return disco.containsKey(account.getServer().toString());
}
public boolean rosterVersioning() { public boolean rosterVersioning() {
return connection.streamFeatures != null && connection.streamFeatures.hasChild("ver"); return connection.streamFeatures != null && connection.streamFeatures.hasChild("ver");
} }