Move lookup of latest conversation timestamp to core.

This commit is contained in:
akwizgran
2020-12-01 15:55:37 +00:00
committed by Torsten Grote
parent 47db28a738
commit e72169ecee
12 changed files with 204 additions and 197 deletions

View File

@@ -736,18 +736,10 @@ public class ConversationActivity extends BriarActivity
List<AttachmentHeader> attachmentHeaders) { List<AttachmentHeader> attachmentHeaders) {
if (isNullOrEmpty(text) && attachmentHeaders.isEmpty()) if (isNullOrEmpty(text) && attachmentHeaders.isEmpty())
throw new AssertionError(); throw new AssertionError();
long timestamp = System.currentTimeMillis(); viewModel.sendMessage(text, attachmentHeaders);
timestamp = Math.max(timestamp, getMinTimestampForNewMessage());
viewModel.sendMessage(text, attachmentHeaders, timestamp);
textInputView.clearText(); textInputView.clearText();
} }
private long getMinTimestampForNewMessage() {
// Don't use an earlier timestamp than the newest message
ConversationItem item = adapter.getLastItem();
return item == null ? 0 : item.getTime() + 1;
}
private void onAddedPrivateMessage(@Nullable PrivateMessageHeader h) { private void onAddedPrivateMessage(@Nullable PrivateMessageHeader h) {
if (h == null) return; if (h == null) return;
addConversationItem(h.accept(visitor)); addConversationItem(h.accept(visitor));
@@ -955,13 +947,11 @@ public class ConversationActivity extends BriarActivity
adapter.notifyItemChanged(position, item); adapter.notifyItemChanged(position, item);
} }
runOnDbThread(() -> { runOnDbThread(() -> {
long timestamp = System.currentTimeMillis();
timestamp = Math.max(timestamp, getMinTimestampForNewMessage());
try { try {
switch (item.getRequestType()) { switch (item.getRequestType()) {
case INTRODUCTION: case INTRODUCTION:
respondToIntroductionRequest(item.getSessionId(), respondToIntroductionRequest(item.getSessionId(),
accept, timestamp); accept);
break; break;
case FORUM: case FORUM:
respondToForumRequest(item.getSessionId(), accept); respondToForumRequest(item.getSessionId(), accept);
@@ -1037,9 +1027,8 @@ public class ConversationActivity extends BriarActivity
@DatabaseExecutor @DatabaseExecutor
private void respondToIntroductionRequest(SessionId sessionId, private void respondToIntroductionRequest(SessionId sessionId,
boolean accept, long time) throws DbException { boolean accept) throws DbException {
introductionManager.respondToIntroduction(contactId, sessionId, time, introductionManager.respondToIntroduction(contactId, sessionId, accept);
accept);
} }
@DatabaseExecutor @DatabaseExecutor

View File

@@ -35,6 +35,7 @@ import org.briarproject.briar.android.viewmodel.MutableLiveEvent;
import org.briarproject.briar.api.attachment.AttachmentHeader; import org.briarproject.briar.api.attachment.AttachmentHeader;
import org.briarproject.briar.api.autodelete.AutoDeleteManager; import org.briarproject.briar.api.autodelete.AutoDeleteManager;
import org.briarproject.briar.api.avatar.event.AvatarUpdatedEvent; import org.briarproject.briar.api.avatar.event.AvatarUpdatedEvent;
import org.briarproject.briar.api.conversation.ConversationManager;
import org.briarproject.briar.api.identity.AuthorInfo; import org.briarproject.briar.api.identity.AuthorInfo;
import org.briarproject.briar.api.identity.AuthorManager; import org.briarproject.briar.api.identity.AuthorManager;
import org.briarproject.briar.api.messaging.MessagingManager; import org.briarproject.briar.api.messaging.MessagingManager;
@@ -90,6 +91,7 @@ public class ConversationViewModel extends DbViewModel
private final AttachmentRetriever attachmentRetriever; private final AttachmentRetriever attachmentRetriever;
private final AttachmentCreator attachmentCreator; private final AttachmentCreator attachmentCreator;
private final AutoDeleteManager autoDeleteManager; private final AutoDeleteManager autoDeleteManager;
private final ConversationManager conversationManager;
@Nullable @Nullable
private ContactId contactId = null; private ContactId contactId = null;
@@ -125,7 +127,8 @@ public class ConversationViewModel extends DbViewModel
PrivateMessageFactory privateMessageFactory, PrivateMessageFactory privateMessageFactory,
AttachmentRetriever attachmentRetriever, AttachmentRetriever attachmentRetriever,
AttachmentCreator attachmentCreator, AttachmentCreator attachmentCreator,
AutoDeleteManager autoDeleteManager) { AutoDeleteManager autoDeleteManager,
ConversationManager conversationManager) {
super(application, dbExecutor, lifecycleManager, db, androidExecutor); super(application, dbExecutor, lifecycleManager, db, androidExecutor);
this.db = db; this.db = db;
this.eventBus = eventBus; this.eventBus = eventBus;
@@ -137,6 +140,7 @@ public class ConversationViewModel extends DbViewModel
this.attachmentRetriever = attachmentRetriever; this.attachmentRetriever = attachmentRetriever;
this.attachmentCreator = attachmentCreator; this.attachmentCreator = attachmentCreator;
this.autoDeleteManager = autoDeleteManager; this.autoDeleteManager = autoDeleteManager;
this.conversationManager = conversationManager;
messagingGroupId = map(contactItem, c -> messagingGroupId = map(contactItem, c ->
messagingManager.getContactGroup(c.getContact()).getId()); messagingManager.getContactGroup(c.getContact()).getId());
contactDeleted.setValue(false); contactDeleted.setValue(false);
@@ -244,14 +248,13 @@ public class ConversationViewModel extends DbViewModel
} }
@UiThread @UiThread
void sendMessage(@Nullable String text, void sendMessage(@Nullable String text, List<AttachmentHeader> headers) {
List<AttachmentHeader> headers, long timestamp) {
// messagingGroupId is loaded with the contact // messagingGroupId is loaded with the contact
observeForeverOnce(messagingGroupId, groupId -> { observeForeverOnce(messagingGroupId, groupId -> {
requireNonNull(groupId); requireNonNull(groupId);
observeForeverOnce(privateMessageFormat, format -> observeForeverOnce(privateMessageFormat, format ->
storeMessage(requireNonNull(contactId), groupId, text, storeMessage(requireNonNull(contactId), groupId, text,
headers, timestamp, format)); headers, format));
}); });
} }
@@ -313,8 +316,10 @@ public class ConversationViewModel extends DbViewModel
private PrivateMessage createMessage(Transaction txn, ContactId c, private PrivateMessage createMessage(Transaction txn, ContactId c,
GroupId groupId, @Nullable String text, GroupId groupId, @Nullable String text,
List<AttachmentHeader> headers, long timestamp, List<AttachmentHeader> headers, PrivateMessageFormat format)
PrivateMessageFormat format) throws DbException { throws DbException {
long timestamp =
conversationManager.getTimestampForOutgoingMessage(txn, c);
try { try {
if (format == TEXT_ONLY) { if (format == TEXT_ONLY) {
return privateMessageFactory.createLegacyPrivateMessage( return privateMessageFactory.createLegacyPrivateMessage(
@@ -335,13 +340,13 @@ public class ConversationViewModel extends DbViewModel
@UiThread @UiThread
private void storeMessage(ContactId c, GroupId groupId, private void storeMessage(ContactId c, GroupId groupId,
@Nullable String text, List<AttachmentHeader> headers, @Nullable String text, List<AttachmentHeader> headers,
long timestamp, PrivateMessageFormat format) { PrivateMessageFormat format) {
runOnDbThread(() -> { runOnDbThread(() -> {
try { try {
db.transaction(false, txn -> { db.transaction(false, txn -> {
long start = now(); long start = now();
PrivateMessage m = createMessage(txn, c, groupId, text, PrivateMessage m = createMessage(txn, c, groupId, text,
headers, timestamp, format); headers, format);
messagingManager.addLocalMessage(txn, m); messagingManager.addLocalMessage(txn, m);
logDuration(LOG, "Storing message", start); logDuration(LOG, "Storing message", start);
Message message = m.getMessage(); Message message = m.getMessage();

View File

@@ -219,8 +219,7 @@ public class IntroductionMessageFragment extends BaseFragment
introductionActivity.runOnDbThread(() -> { introductionActivity.runOnDbThread(() -> {
// actually make the introduction // actually make the introduction
try { try {
long timestamp = System.currentTimeMillis(); introductionManager.makeIntroduction(c1, c2, text);
introductionManager.makeIntroduction(c1, c2, text, timestamp);
} catch (DbException e) { } catch (DbException e) {
logException(LOG, WARNING, e); logException(LOG, WARNING, e);
introductionError(); introductionError();

View File

@@ -48,6 +48,13 @@ public interface ConversationManager {
*/ */
GroupCount getGroupCount(Transaction txn, ContactId c) throws DbException; GroupCount getGroupCount(Transaction txn, ContactId c) throws DbException;
/**
* Returns a timestamp for an outgoing message, which is later than the
* timestamp of any visible message sent or received so far.
*/
long getTimestampForOutgoingMessage(Transaction txn, ContactId c)
throws DbException;
/** /**
* Deletes all messages exchanged with the given contact. * Deletes all messages exchanged with the given contact.
*/ */

View File

@@ -36,13 +36,13 @@ public interface IntroductionManager extends ConversationClient {
/** /**
* Sends two initial introduction messages. * Sends two initial introduction messages.
*/ */
void makeIntroduction(Contact c1, Contact c2, @Nullable String text, void makeIntroduction(Contact c1, Contact c2, @Nullable String text)
long timestamp) throws DbException; throws DbException;
/** /**
* Responds to an introduction. * Responds to an introduction.
*/ */
void respondToIntroduction(ContactId contactId, SessionId sessionId, void respondToIntroduction(ContactId contactId, SessionId sessionId,
long timestamp, boolean accept) throws DbException; boolean accept) throws DbException;
} }

View File

@@ -20,11 +20,11 @@ import org.briarproject.bramble.api.properties.TransportProperties;
import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.Message; import org.briarproject.bramble.api.sync.Message;
import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.versioning.ClientVersioningManager; import org.briarproject.bramble.api.versioning.ClientVersioningManager;
import org.briarproject.briar.api.autodelete.AutoDeleteManager; import org.briarproject.briar.api.autodelete.AutoDeleteManager;
import org.briarproject.briar.api.client.MessageTracker; import org.briarproject.briar.api.client.MessageTracker;
import org.briarproject.briar.api.client.SessionId; import org.briarproject.briar.api.client.SessionId;
import org.briarproject.briar.api.conversation.ConversationManager;
import org.briarproject.briar.api.identity.AuthorInfo; import org.briarproject.briar.api.identity.AuthorInfo;
import org.briarproject.briar.api.identity.AuthorManager; import org.briarproject.briar.api.identity.AuthorManager;
import org.briarproject.briar.api.introduction.IntroductionResponse; import org.briarproject.briar.api.introduction.IntroductionResponse;
@@ -61,7 +61,7 @@ abstract class AbstractProtocolEngine<S extends Session<?>>
protected final MessageEncoder messageEncoder; protected final MessageEncoder messageEncoder;
protected final ClientVersioningManager clientVersioningManager; protected final ClientVersioningManager clientVersioningManager;
protected final AutoDeleteManager autoDeleteManager; protected final AutoDeleteManager autoDeleteManager;
protected final Clock clock; protected final ConversationManager conversationManager;
AbstractProtocolEngine( AbstractProtocolEngine(
DatabaseComponent db, DatabaseComponent db,
@@ -75,7 +75,7 @@ abstract class AbstractProtocolEngine<S extends Session<?>>
MessageEncoder messageEncoder, MessageEncoder messageEncoder,
ClientVersioningManager clientVersioningManager, ClientVersioningManager clientVersioningManager,
AutoDeleteManager autoDeleteManager, AutoDeleteManager autoDeleteManager,
Clock clock) { ConversationManager conversationManager) {
this.db = db; this.db = db;
this.clientHelper = clientHelper; this.clientHelper = clientHelper;
this.contactManager = contactManager; this.contactManager = contactManager;
@@ -87,7 +87,7 @@ abstract class AbstractProtocolEngine<S extends Session<?>>
this.messageEncoder = messageEncoder; this.messageEncoder = messageEncoder;
this.clientVersioningManager = clientVersioningManager; this.clientVersioningManager = clientVersioningManager;
this.autoDeleteManager = autoDeleteManager; this.autoDeleteManager = autoDeleteManager;
this.clock = clock; this.conversationManager = conversationManager;
} }
Message sendRequestMessage(Transaction txn, PeerSession s, Message sendRequestMessage(Transaction txn, PeerSession s,
@@ -231,14 +231,10 @@ abstract class AbstractProtocolEngine<S extends Session<?>>
return !dependency.equals(lastRemoteMessageId); return !dependency.equals(lastRemoteMessageId);
} }
long getLocalTimestamp(long localTimestamp, long requestTimestamp) { long getTimestampForOutgoingMessage(Transaction txn, GroupId contactGroupId)
return Math.max( throws DbException {
clock.currentTimeMillis(), ContactId c = getContactId(txn, contactGroupId);
Math.max( return conversationManager.getTimestampForOutgoingMessage(txn, c);
localTimestamp,
requestTimestamp
) + 1
);
} }
private ContactId getContactId(Transaction txn, GroupId contactGroupId) private ContactId getContactId(Transaction txn, GroupId contactGroupId)

View File

@@ -22,7 +22,6 @@ import org.briarproject.bramble.api.properties.TransportProperties;
import org.briarproject.bramble.api.properties.TransportPropertyManager; import org.briarproject.bramble.api.properties.TransportPropertyManager;
import org.briarproject.bramble.api.sync.Message; import org.briarproject.bramble.api.sync.Message;
import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.transport.KeyManager; import org.briarproject.bramble.api.transport.KeyManager;
import org.briarproject.bramble.api.transport.KeySetId; import org.briarproject.bramble.api.transport.KeySetId;
import org.briarproject.bramble.api.versioning.ClientVersioningManager; import org.briarproject.bramble.api.versioning.ClientVersioningManager;
@@ -30,6 +29,7 @@ import org.briarproject.briar.api.autodelete.AutoDeleteManager;
import org.briarproject.briar.api.client.MessageTracker; import org.briarproject.briar.api.client.MessageTracker;
import org.briarproject.briar.api.client.ProtocolStateException; import org.briarproject.briar.api.client.ProtocolStateException;
import org.briarproject.briar.api.client.SessionId; import org.briarproject.briar.api.client.SessionId;
import org.briarproject.briar.api.conversation.ConversationManager;
import org.briarproject.briar.api.identity.AuthorInfo; import org.briarproject.briar.api.identity.AuthorInfo;
import org.briarproject.briar.api.identity.AuthorManager; import org.briarproject.briar.api.identity.AuthorManager;
import org.briarproject.briar.api.introduction.IntroductionRequest; import org.briarproject.briar.api.introduction.IntroductionRequest;
@@ -44,6 +44,7 @@ import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.Immutable;
import javax.inject.Inject; import javax.inject.Inject;
import static java.lang.Math.max;
import static java.util.logging.Level.WARNING; import static java.util.logging.Level.WARNING;
import static org.briarproject.bramble.util.LogUtils.logException; import static org.briarproject.bramble.util.LogUtils.logException;
import static org.briarproject.briar.introduction.IntroduceeState.AWAIT_AUTH; import static org.briarproject.briar.introduction.IntroduceeState.AWAIT_AUTH;
@@ -77,16 +78,16 @@ class IntroduceeProtocolEngine
AuthorManager authorManager, AuthorManager authorManager,
MessageParser messageParser, MessageParser messageParser,
MessageEncoder messageEncoder, MessageEncoder messageEncoder,
Clock clock,
IntroductionCrypto crypto, IntroductionCrypto crypto,
KeyManager keyManager, KeyManager keyManager,
TransportPropertyManager transportPropertyManager, TransportPropertyManager transportPropertyManager,
ClientVersioningManager clientVersioningManager, ClientVersioningManager clientVersioningManager,
AutoDeleteManager autoDeleteManager) { AutoDeleteManager autoDeleteManager,
ConversationManager conversationManager) {
super(db, clientHelper, contactManager, contactGroupFactory, super(db, clientHelper, contactManager, contactGroupFactory,
messageTracker, identityManager, authorManager, messageParser, messageTracker, identityManager, authorManager, messageParser,
messageEncoder, clientVersioningManager, autoDeleteManager, messageEncoder, clientVersioningManager, autoDeleteManager,
clock); conversationManager);
this.crypto = crypto; this.crypto = crypto;
this.keyManager = keyManager; this.keyManager = keyManager;
this.transportPropertyManager = transportPropertyManager; this.transportPropertyManager = transportPropertyManager;
@@ -94,18 +95,18 @@ class IntroduceeProtocolEngine
@Override @Override
public IntroduceeSession onRequestAction(Transaction txn, public IntroduceeSession onRequestAction(Transaction txn,
IntroduceeSession session, @Nullable String text, long timestamp) { IntroduceeSession session, @Nullable String text) {
throw new UnsupportedOperationException(); // Invalid in this role throw new UnsupportedOperationException(); // Invalid in this role
} }
@Override @Override
public IntroduceeSession onAcceptAction(Transaction txn, public IntroduceeSession onAcceptAction(Transaction txn,
IntroduceeSession session, long timestamp) throws DbException { IntroduceeSession session) throws DbException {
switch (session.getState()) { switch (session.getState()) {
case AWAIT_RESPONSES: case AWAIT_RESPONSES:
case REMOTE_DECLINED: case REMOTE_DECLINED:
case REMOTE_ACCEPTED: case REMOTE_ACCEPTED:
return onLocalAccept(txn, session, timestamp); return onLocalAccept(txn, session);
case START: case START:
case LOCAL_DECLINED: case LOCAL_DECLINED:
case LOCAL_ACCEPTED: case LOCAL_ACCEPTED:
@@ -119,12 +120,12 @@ class IntroduceeProtocolEngine
@Override @Override
public IntroduceeSession onDeclineAction(Transaction txn, public IntroduceeSession onDeclineAction(Transaction txn,
IntroduceeSession session, long timestamp) throws DbException { IntroduceeSession session) throws DbException {
switch (session.getState()) { switch (session.getState()) {
case AWAIT_RESPONSES: case AWAIT_RESPONSES:
case REMOTE_DECLINED: case REMOTE_DECLINED:
case REMOTE_ACCEPTED: case REMOTE_ACCEPTED:
return onLocalDecline(txn, session, timestamp); return onLocalDecline(txn, session);
case START: case START:
case LOCAL_DECLINED: case LOCAL_DECLINED:
case LOCAL_ACCEPTED: case LOCAL_ACCEPTED:
@@ -275,7 +276,7 @@ class IntroduceeProtocolEngine
} }
private IntroduceeSession onLocalAccept(Transaction txn, private IntroduceeSession onLocalAccept(Transaction txn,
IntroduceeSession s, long timestamp) throws DbException { IntroduceeSession s) throws DbException {
// Mark the request message unavailable to answer // Mark the request message unavailable to answer
markRequestsUnavailableToAnswer(txn, s); markRequestsUnavailableToAnswer(txn, s);
@@ -287,7 +288,7 @@ class IntroduceeProtocolEngine
transportPropertyManager.getLocalProperties(txn); transportPropertyManager.getLocalProperties(txn);
// Send a ACCEPT message // Send a ACCEPT message
long localTimestamp = Math.max(timestamp + 1, getLocalTimestamp(s)); long localTimestamp = getLocalTimestamp(txn, s);
Message sent = sendAcceptMessage(txn, s, localTimestamp, publicKey, Message sent = sendAcceptMessage(txn, s, localTimestamp, publicKey,
localTimestamp, transportProperties, true); localTimestamp, transportProperties, true);
// Track the message // Track the message
@@ -312,12 +313,12 @@ class IntroduceeProtocolEngine
} }
private IntroduceeSession onLocalDecline(Transaction txn, private IntroduceeSession onLocalDecline(Transaction txn,
IntroduceeSession s, long timestamp) throws DbException { IntroduceeSession s) throws DbException {
// Mark the request message unavailable to answer // Mark the request message unavailable to answer
markRequestsUnavailableToAnswer(txn, s); markRequestsUnavailableToAnswer(txn, s);
// Send a DECLINE message // Send a DECLINE message
long localTimestamp = Math.max(timestamp + 1, getLocalTimestamp(s)); long localTimestamp = getLocalTimestamp(txn, s);
Message sent = sendDeclineMessage(txn, s, localTimestamp, true); Message sent = sendDeclineMessage(txn, s, localTimestamp, true);
// Track the message // Track the message
@@ -415,8 +416,8 @@ class IntroduceeProtocolEngine
return abort(txn, s); return abort(txn, s);
} }
if (s.getState() != AWAIT_AUTH) throw new AssertionError(); if (s.getState() != AWAIT_AUTH) throw new AssertionError();
Message sent = sendAuthMessage(txn, s, getLocalTimestamp(s), mac, long localTimestamp = getLocalTimestamp(txn, s);
signature); Message sent = sendAuthMessage(txn, s, localTimestamp, mac, signature);
return IntroduceeSession.addLocalAuth(s, AWAIT_AUTH, sent, masterKey, return IntroduceeSession.addLocalAuth(s, AWAIT_AUTH, sent, masterKey,
aliceMacKey, bobMacKey); aliceMacKey, bobMacKey);
} }
@@ -465,7 +466,8 @@ class IntroduceeProtocolEngine
// send ACTIVATE message with a MAC // send ACTIVATE message with a MAC
byte[] mac = crypto.activateMac(s); byte[] mac = crypto.activateMac(s);
Message sent = sendActivateMessage(txn, s, getLocalTimestamp(s), mac); long localTimestamp = getLocalTimestamp(txn, s);
Message sent = sendActivateMessage(txn, s, localTimestamp, mac);
// Move to AWAIT_ACTIVATE state and clear key material from session // Move to AWAIT_ACTIVATE state and clear key material from session
return IntroduceeSession.awaitActivate(s, m, sent, keys); return IntroduceeSession.awaitActivate(s, m, sent, keys);
@@ -516,7 +518,8 @@ class IntroduceeProtocolEngine
markRequestsUnavailableToAnswer(txn, s); markRequestsUnavailableToAnswer(txn, s);
// Send an ABORT message // Send an ABORT message
Message sent = sendAbortMessage(txn, s, getLocalTimestamp(s)); long localTimestamp = getLocalTimestamp(txn, s);
Message sent = sendAbortMessage(txn, s, localTimestamp);
// Broadcast abort event for testing // Broadcast abort event for testing
txn.attach(new IntroductionAbortedEvent(s.getSessionId())); txn.attach(new IntroductionAbortedEvent(s.getSessionId()));
@@ -531,9 +534,18 @@ class IntroduceeProtocolEngine
return isInvalidDependency(s.getLastRemoteMessageId(), dependency); return isInvalidDependency(s.getLastRemoteMessageId(), dependency);
} }
private long getLocalTimestamp(IntroduceeSession s) { /**
return getLocalTimestamp(s.getLocalTimestamp(), * Returns a timestamp for an outgoing message, which is later than the
s.getRequestTimestamp()); * timestamp of any message sent or received so far in the conversation
* or the session.
*/
private long getLocalTimestamp(Transaction txn, IntroduceeSession s)
throws DbException {
long conversationTimestamp =
getTimestampForOutgoingMessage(txn, s.getContactGroupId());
long sessionTimestamp =
max(s.getLocalTimestamp(), s.getRequestTimestamp()) + 1;
return max(conversationTimestamp, sessionTimestamp);
} }
private void addSessionId(Transaction txn, MessageId m, SessionId sessionId) private void addSessionId(Transaction txn, MessageId m, SessionId sessionId)

View File

@@ -12,11 +12,11 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.Message; import org.briarproject.bramble.api.sync.Message;
import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.versioning.ClientVersioningManager; import org.briarproject.bramble.api.versioning.ClientVersioningManager;
import org.briarproject.briar.api.autodelete.AutoDeleteManager; import org.briarproject.briar.api.autodelete.AutoDeleteManager;
import org.briarproject.briar.api.client.MessageTracker; import org.briarproject.briar.api.client.MessageTracker;
import org.briarproject.briar.api.client.ProtocolStateException; import org.briarproject.briar.api.client.ProtocolStateException;
import org.briarproject.briar.api.conversation.ConversationManager;
import org.briarproject.briar.api.identity.AuthorManager; import org.briarproject.briar.api.identity.AuthorManager;
import org.briarproject.briar.api.introduction.event.IntroductionAbortedEvent; import org.briarproject.briar.api.introduction.event.IntroductionAbortedEvent;
import org.briarproject.briar.introduction.IntroducerSession.Introducee; import org.briarproject.briar.introduction.IntroducerSession.Introducee;
@@ -25,6 +25,7 @@ import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.Immutable;
import javax.inject.Inject; import javax.inject.Inject;
import static java.lang.Math.max;
import static org.briarproject.briar.introduction.IntroducerState.AWAIT_ACTIVATES; import static org.briarproject.briar.introduction.IntroducerState.AWAIT_ACTIVATES;
import static org.briarproject.briar.introduction.IntroducerState.AWAIT_ACTIVATE_A; import static org.briarproject.briar.introduction.IntroducerState.AWAIT_ACTIVATE_A;
import static org.briarproject.briar.introduction.IntroducerState.AWAIT_ACTIVATE_B; import static org.briarproject.briar.introduction.IntroducerState.AWAIT_ACTIVATE_B;
@@ -56,20 +57,20 @@ class IntroducerProtocolEngine
MessageEncoder messageEncoder, MessageEncoder messageEncoder,
ClientVersioningManager clientVersioningManager, ClientVersioningManager clientVersioningManager,
AutoDeleteManager autoDeleteManager, AutoDeleteManager autoDeleteManager,
Clock clock) { ConversationManager conversationManager) {
super(db, clientHelper, contactManager, contactGroupFactory, super(db, clientHelper, contactManager, contactGroupFactory,
messageTracker, identityManager, authorManager, messageParser, messageTracker, identityManager, authorManager, messageParser,
messageEncoder, clientVersioningManager, autoDeleteManager, messageEncoder, clientVersioningManager, autoDeleteManager,
clock); conversationManager);
} }
@Override @Override
public IntroducerSession onRequestAction(Transaction txn, public IntroducerSession onRequestAction(Transaction txn,
IntroducerSession s, @Nullable String text, long timestamp) IntroducerSession s, @Nullable String text)
throws DbException { throws DbException {
switch (s.getState()) { switch (s.getState()) {
case START: case START:
return onLocalRequest(txn, s, text, timestamp); return onLocalRequest(txn, s, text);
case AWAIT_RESPONSES: case AWAIT_RESPONSES:
case AWAIT_RESPONSE_A: case AWAIT_RESPONSE_A:
case AWAIT_RESPONSE_B: case AWAIT_RESPONSE_B:
@@ -89,37 +90,24 @@ class IntroducerProtocolEngine
@Override @Override
public IntroducerSession onAcceptAction(Transaction txn, public IntroducerSession onAcceptAction(Transaction txn,
IntroducerSession s, long timestamp) { IntroducerSession s) {
throw new UnsupportedOperationException(); // Invalid in this role throw new UnsupportedOperationException(); // Invalid in this role
} }
@Override @Override
public IntroducerSession onDeclineAction(Transaction txn, public IntroducerSession onDeclineAction(Transaction txn,
IntroducerSession s, long timestamp) { IntroducerSession s) {
throw new UnsupportedOperationException(); // Invalid in this role throw new UnsupportedOperationException(); // Invalid in this role
} }
IntroducerSession onIntroduceeRemoved(Transaction txn, IntroducerSession onIntroduceeRemoved(Transaction txn,
Introducee remainingIntroducee, IntroducerSession session) Introducee remainingIntroducee, IntroducerSession session)
throws DbException { throws DbException {
// abort session // abort session with remaining introducee
IntroducerSession s = abort(txn, session); IntroducerSession s = abort(txn, session, remainingIntroducee);
// reset information for introducee that was removed
Introducee introduceeA, introduceeB;
if (remainingIntroducee.author.equals(s.getIntroduceeA().author)) {
introduceeA = s.getIntroduceeA();
introduceeB =
new Introducee(s.getSessionId(), s.getIntroduceeB().groupId,
s.getIntroduceeB().author);
} else if (remainingIntroducee.author
.equals(s.getIntroduceeB().author)) {
introduceeA =
new Introducee(s.getSessionId(), s.getIntroduceeA().groupId,
s.getIntroduceeA().author);
introduceeB = s.getIntroduceeB();
} else throw new DbException();
return new IntroducerSession(s.getSessionId(), s.getState(), return new IntroducerSession(s.getSessionId(), s.getState(),
s.getRequestTimestamp(), introduceeA, introduceeB); s.getRequestTimestamp(), s.getIntroduceeA(),
s.getIntroduceeB());
} }
@Override @Override
@@ -229,13 +217,11 @@ class IntroducerProtocolEngine
} }
private IntroducerSession onLocalRequest(Transaction txn, private IntroducerSession onLocalRequest(Transaction txn,
IntroducerSession s, @Nullable String text, long timestamp) IntroducerSession s, @Nullable String text) throws DbException {
throws DbException {
// Send REQUEST messages // Send REQUEST messages
long maxIntroduceeTimestamp = long timestampA = getLocalTimestamp(txn, s, s.getIntroduceeA());
Math.max(getLocalTimestamp(s, s.getIntroduceeA()), long timestampB = getLocalTimestamp(txn, s, s.getIntroduceeB());
getLocalTimestamp(s, s.getIntroduceeB())); long localTimestamp = max(timestampA, timestampB);
long localTimestamp = Math.max(timestamp, maxIntroduceeTimestamp);
Message sentA = sendRequestMessage(txn, s.getIntroduceeA(), Message sentA = sendRequestMessage(txn, s.getIntroduceeA(),
localTimestamp, s.getIntroduceeB().author, text); localTimestamp, s.getIntroduceeB().author, text);
Message sentB = sendRequestMessage(txn, s.getIntroduceeB(), Message sentB = sendRequestMessage(txn, s.getIntroduceeB(),
@@ -275,11 +261,10 @@ class IntroducerProtocolEngine
// Forward ACCEPT message // Forward ACCEPT message
Introducee i = getOtherIntroducee(s, m.getGroupId()); Introducee i = getOtherIntroducee(s, m.getGroupId());
long timestamp = getLocalTimestamp(s, i); long localTimestamp = getLocalTimestamp(txn, s, i);
Message sent = Message sent = sendAcceptMessage(txn, i, localTimestamp,
sendAcceptMessage(txn, i, timestamp, m.getEphemeralPublicKey(), m.getEphemeralPublicKey(), m.getAcceptTimestamp(),
m.getAcceptTimestamp(), m.getTransportProperties(), m.getTransportProperties(), false);
false);
// Create the next state // Create the next state
IntroducerState state = AWAIT_AUTHS; IntroducerState state = AWAIT_AUTHS;
@@ -336,7 +321,8 @@ class IntroducerProtocolEngine
// Forward ACCEPT message // Forward ACCEPT message
Introducee i = getOtherIntroducee(s, m.getGroupId()); Introducee i = getOtherIntroducee(s, m.getGroupId());
Message sent = sendAcceptMessage(txn, i, getLocalTimestamp(s, i), long localTimestamp = getLocalTimestamp(txn, s, i);
Message sent = sendAcceptMessage(txn, i, localTimestamp,
m.getEphemeralPublicKey(), m.getAcceptTimestamp(), m.getEphemeralPublicKey(), m.getAcceptTimestamp(),
m.getTransportProperties(), false); m.getTransportProperties(), false);
@@ -387,8 +373,8 @@ class IntroducerProtocolEngine
// Forward DECLINE message // Forward DECLINE message
Introducee i = getOtherIntroducee(s, m.getGroupId()); Introducee i = getOtherIntroducee(s, m.getGroupId());
long timestamp = getLocalTimestamp(s, i); long localTimestamp = getLocalTimestamp(txn, s, i);
Message sent = sendDeclineMessage(txn, i, timestamp, false); Message sent = sendDeclineMessage(txn, i, localTimestamp, false);
// Create the next state // Create the next state
IntroducerState state = START; IntroducerState state = START;
@@ -439,8 +425,8 @@ class IntroducerProtocolEngine
// Forward DECLINE message // Forward DECLINE message
Introducee i = getOtherIntroducee(s, m.getGroupId()); Introducee i = getOtherIntroducee(s, m.getGroupId());
long timestamp = getLocalTimestamp(s, i); long localTimestamp = getLocalTimestamp(txn, s, i);
Message sent = sendDeclineMessage(txn, i, timestamp, false); Message sent = sendDeclineMessage(txn, i, localTimestamp, false);
Introducee introduceeA, introduceeB; Introducee introduceeA, introduceeB;
Author sender, other; Author sender, other;
@@ -480,8 +466,8 @@ class IntroducerProtocolEngine
// Forward AUTH message // Forward AUTH message
Introducee i = getOtherIntroducee(s, m.getGroupId()); Introducee i = getOtherIntroducee(s, m.getGroupId());
long timestamp = getLocalTimestamp(s, i); long localTimestamp = getLocalTimestamp(txn, s, i);
Message sent = sendAuthMessage(txn, i, timestamp, m.getMac(), Message sent = sendAuthMessage(txn, i, localTimestamp, m.getMac(),
m.getSignature()); m.getSignature());
// Move to the next state // Move to the next state
@@ -516,8 +502,8 @@ class IntroducerProtocolEngine
// Forward ACTIVATE message // Forward ACTIVATE message
Introducee i = getOtherIntroducee(s, m.getGroupId()); Introducee i = getOtherIntroducee(s, m.getGroupId());
long timestamp = getLocalTimestamp(s, i); long localTimestamp = getLocalTimestamp(txn, s, i);
Message sent = sendActivateMessage(txn, i, timestamp, m.getMac()); Message sent = sendActivateMessage(txn, i, localTimestamp, m.getMac());
// Move to the next state // Move to the next state
IntroducerState state = START; IntroducerState state = START;
@@ -539,8 +525,9 @@ class IntroducerProtocolEngine
IntroducerSession s, AbortMessage m) throws DbException { IntroducerSession s, AbortMessage m) throws DbException {
// Forward ABORT message // Forward ABORT message
Introducee i = getOtherIntroducee(s, m.getGroupId()); Introducee i = getOtherIntroducee(s, m.getGroupId());
long timestamp = getLocalTimestamp(s, i); long localTimestamp = max(i.getLocalTimestamp(),
Message sent = sendAbortMessage(txn, i, timestamp); s.getRequestTimestamp()) + 1;
Message sent = sendAbortMessage(txn, i, localTimestamp);
// Broadcast abort event for testing // Broadcast abort event for testing
txn.attach(new IntroductionAbortedEvent(s.getSessionId())); txn.attach(new IntroductionAbortedEvent(s.getSessionId()));
@@ -558,15 +545,42 @@ class IntroducerProtocolEngine
s.getRequestTimestamp(), introduceeA, introduceeB); s.getRequestTimestamp(), introduceeA, introduceeB);
} }
private IntroducerSession abort(Transaction txn, private IntroducerSession abort(Transaction txn, IntroducerSession s,
IntroducerSession s) throws DbException { Introducee remainingIntroducee) throws DbException {
// Broadcast abort event for testing
txn.attach(new IntroductionAbortedEvent(s.getSessionId()));
// Send an ABORT message to the remaining introducee
long localTimestamp = getLocalTimestamp(txn, s, remainingIntroducee);
Message sent =
sendAbortMessage(txn, remainingIntroducee, localTimestamp);
// Reset the session back to initial state
Introducee introduceeA = s.getIntroduceeA();
Introducee introduceeB = s.getIntroduceeB();
if (remainingIntroducee.author.equals(introduceeA.author)) {
introduceeA = new Introducee(introduceeA, sent);
introduceeB = new Introducee(s.getSessionId(), introduceeB.groupId,
introduceeB.author);
} else if (remainingIntroducee.author.equals(introduceeB.author)) {
introduceeA = new Introducee(s.getSessionId(), introduceeA.groupId,
introduceeA.author);
introduceeB = new Introducee(introduceeB, sent);
} else {
throw new DbException();
}
return new IntroducerSession(s.getSessionId(), START,
s.getRequestTimestamp(), introduceeA, introduceeB);
}
private IntroducerSession abort(Transaction txn, IntroducerSession s)
throws DbException {
// Broadcast abort event for testing // Broadcast abort event for testing
txn.attach(new IntroductionAbortedEvent(s.getSessionId())); txn.attach(new IntroductionAbortedEvent(s.getSessionId()));
// Send an ABORT message to both introducees // Send an ABORT message to both introducees
long timestampA = getLocalTimestamp(s, s.getIntroduceeA()); long timestampA = getLocalTimestamp(txn, s, s.getIntroduceeA());
Message sentA = sendAbortMessage(txn, s.getIntroduceeA(), timestampA); Message sentA = sendAbortMessage(txn, s.getIntroduceeA(), timestampA);
long timestampB = getLocalTimestamp(s, s.getIntroduceeB()); long timestampB = getLocalTimestamp(txn, s, s.getIntroduceeB());
Message sentB = sendAbortMessage(txn, s.getIntroduceeB(), timestampB); Message sentB = sendAbortMessage(txn, s.getIntroduceeB(), timestampB);
// Reset the session back to initial state // Reset the session back to initial state
Introducee introduceeA = new Introducee(s.getIntroduceeA(), sentA); Introducee introduceeA = new Introducee(s.getIntroduceeA(), sentA);
@@ -596,9 +610,17 @@ class IntroducerProtocolEngine
return isInvalidDependency(expected, dependency); return isInvalidDependency(expected, dependency);
} }
private long getLocalTimestamp(IntroducerSession s, PeerSession p) { /**
return getLocalTimestamp(p.getLocalTimestamp(), * Returns a timestamp for an outgoing message, which is later than the
s.getRequestTimestamp()); * timestamp of any message sent or received so far in the conversation
* or the session.
*/
private long getLocalTimestamp(Transaction txn, IntroducerSession s,
PeerSession p) throws DbException {
long conversationTimestamp =
getTimestampForOutgoingMessage(txn, p.getContactGroupId());
long sessionTimestamp =
max(p.getLocalTimestamp(), s.getRequestTimestamp()) + 1;
return max(conversationTimestamp, sessionTimestamp);
} }
} }

View File

@@ -315,8 +315,8 @@ class IntroductionManagerImpl extends ConversationClientImpl
} }
@Override @Override
public void makeIntroduction(Contact c1, Contact c2, @Nullable String text, public void makeIntroduction(Contact c1, Contact c2, @Nullable String text)
long timestamp) throws DbException { throws DbException {
Transaction txn = db.startTransaction(false); Transaction txn = db.startTransaction(false);
try { try {
// Look up the session, if there is one // Look up the session, if there is one
@@ -348,8 +348,7 @@ class IntroductionManagerImpl extends ConversationClientImpl
storageId = ss.storageId; storageId = ss.storageId;
} }
// Handle the request action // Handle the request action
session = introducerEngine session = introducerEngine.onRequestAction(txn, session, text);
.onRequestAction(txn, session, text, timestamp);
// Store the updated session // Store the updated session
storeSession(txn, storageId, session); storeSession(txn, storageId, session);
db.commitTransaction(txn); db.commitTransaction(txn);
@@ -362,7 +361,7 @@ class IntroductionManagerImpl extends ConversationClientImpl
@Override @Override
public void respondToIntroduction(ContactId contactId, SessionId sessionId, public void respondToIntroduction(ContactId contactId, SessionId sessionId,
long timestamp, boolean accept) throws DbException { boolean accept) throws DbException {
Transaction txn = db.startTransaction(false); Transaction txn = db.startTransaction(false);
try { try {
// Look up the session // Look up the session
@@ -380,11 +379,9 @@ class IntroductionManagerImpl extends ConversationClientImpl
.parseIntroduceeSession(contactGroupId, ss.bdfSession); .parseIntroduceeSession(contactGroupId, ss.bdfSession);
// Handle the join or leave action // Handle the join or leave action
if (accept) { if (accept) {
session = introduceeEngine session = introduceeEngine.onAcceptAction(txn, session);
.onAcceptAction(txn, session, timestamp);
} else { } else {
session = introduceeEngine session = introduceeEngine.onDeclineAction(txn, session);
.onDeclineAction(txn, session, timestamp);
} }
// Store the updated session // Store the updated session
storeSession(txn, ss.storageId, session); storeSession(txn, ss.storageId, session);

View File

@@ -8,16 +8,14 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@NotNullByDefault @NotNullByDefault
interface ProtocolEngine<S extends Session> { interface ProtocolEngine<S extends Session<?>> {
S onRequestAction(Transaction txn, S session, @Nullable String text, S onRequestAction(Transaction txn, S session, @Nullable String text)
long timestamp) throws DbException;
S onAcceptAction(Transaction txn, S session, long timestamp)
throws DbException; throws DbException;
S onDeclineAction(Transaction txn, S session, long timestamp) S onAcceptAction(Transaction txn, S session) throws DbException;
throws DbException;
S onDeclineAction(Transaction txn, S session) throws DbException;
S onRequestMessage(Transaction txn, S session, RequestMessage m) S onRequestMessage(Transaction txn, S session, RequestMessage m)
throws DbException, FormatException; throws DbException, FormatException;

View File

@@ -6,6 +6,7 @@ import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Transaction; import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.briar.api.client.MessageTracker.GroupCount; import org.briarproject.briar.api.client.MessageTracker.GroupCount;
import org.briarproject.briar.api.conversation.ConversationManager; import org.briarproject.briar.api.conversation.ConversationManager;
import org.briarproject.briar.api.conversation.ConversationMessageHeader; import org.briarproject.briar.api.conversation.ConversationMessageHeader;
@@ -20,16 +21,20 @@ import java.util.concurrent.CopyOnWriteArraySet;
import javax.annotation.concurrent.ThreadSafe; import javax.annotation.concurrent.ThreadSafe;
import javax.inject.Inject; import javax.inject.Inject;
import static java.lang.Math.max;
@ThreadSafe @ThreadSafe
@NotNullByDefault @NotNullByDefault
class ConversationManagerImpl implements ConversationManager { class ConversationManagerImpl implements ConversationManager {
private final DatabaseComponent db; private final DatabaseComponent db;
private final Clock clock;
private final Set<ConversationClient> clients; private final Set<ConversationClient> clients;
@Inject @Inject
ConversationManagerImpl(DatabaseComponent db) { ConversationManagerImpl(DatabaseComponent db, Clock clock) {
this.db = db; this.db = db;
this.clock = clock;
clients = new CopyOnWriteArraySet<>(); clients = new CopyOnWriteArraySet<>();
} }
@@ -76,6 +81,14 @@ class ConversationManagerImpl implements ConversationManager {
return new GroupCount(msgCount, unreadCount, latestTime); return new GroupCount(msgCount, unreadCount, latestTime);
} }
@Override
public long getTimestampForOutgoingMessage(Transaction txn, ContactId c)
throws DbException {
long now = clock.currentTimeMillis();
GroupCount gc = getGroupCount(txn, c);
return max(now, gc.getLatestMsgTime() + 1);
}
@Override @Override
public DeletionResult deleteAllMessages(ContactId c) throws DbException { public DeletionResult deleteAllMessages(ContactId c) throws DbException {
return db.transactionWithResult(false, txn -> { return db.transactionWithResult(false, txn -> {

View File

@@ -140,11 +140,9 @@ public class IntroductionIntegrationTest
addListeners(true, true); addListeners(true, true);
// make introduction // make introduction
long time = clock.currentTimeMillis();
Contact introducee1 = contact1From0; Contact introducee1 = contact1From0;
Contact introducee2 = contact2From0; Contact introducee2 = contact2From0;
introductionManager0 introductionManager0.makeIntroduction(introducee1, introducee2, "Hi!");
.makeIntroduction(introducee1, introducee2, "Hi!", time);
// check that messages are tracked properly // check that messages are tracked properly
Group g1 = introductionManager0.getContactGroup(introducee1); Group g1 = introductionManager0.getContactGroup(introducee1);
@@ -264,11 +262,9 @@ public class IntroductionIntegrationTest
addListeners(false, true); addListeners(false, true);
// make introduction // make introduction
long time = clock.currentTimeMillis();
Contact introducee1 = contact1From0; Contact introducee1 = contact1From0;
Contact introducee2 = contact2From0; Contact introducee2 = contact2From0;
introductionManager0 introductionManager0.makeIntroduction(introducee1, introducee2, null);
.makeIntroduction(introducee1, introducee2, null, time);
// sync request messages // sync request messages
sync0To1(1, true); sync0To1(1, true);
@@ -356,9 +352,8 @@ public class IntroductionIntegrationTest
addListeners(true, false); addListeners(true, false);
// make introduction // make introduction
long time = clock.currentTimeMillis();
introductionManager0 introductionManager0
.makeIntroduction(contact1From0, contact2From0, null, time); .makeIntroduction(contact1From0, contact2From0, null);
// sync request messages // sync request messages
sync0To1(1, true); sync0To1(1, true);
@@ -412,9 +407,8 @@ public class IntroductionIntegrationTest
addListeners(false, true); addListeners(false, true);
// make introduction // make introduction
long time = clock.currentTimeMillis();
introductionManager0 introductionManager0
.makeIntroduction(contact1From0, contact2From0, null, time); .makeIntroduction(contact1From0, contact2From0, null);
// sync request messages // sync request messages
sync0To1(1, true); sync0To1(1, true);
@@ -438,9 +432,8 @@ public class IntroductionIntegrationTest
assertFalse(listener1.aborted); assertFalse(listener1.aborted);
assertFalse(listener2.aborted); assertFalse(listener2.aborted);
time = clock.currentTimeMillis();
introductionManager0 introductionManager0
.makeIntroduction(contact1From0, contact2From0, null, time); .makeIntroduction(contact1From0, contact2From0, null);
// sync request messages // sync request messages
sync0To1(1, true); sync0To1(1, true);
@@ -457,9 +450,8 @@ public class IntroductionIntegrationTest
addListeners(true, true); addListeners(true, true);
// make introduction // make introduction
long time = clock.currentTimeMillis();
introductionManager0 introductionManager0
.makeIntroduction(contact1From0, contact2From0, "Hi!", time); .makeIntroduction(contact1From0, contact2From0, "Hi!");
// sync first request message // sync first request message
sync0To1(1, true); sync0To1(1, true);
@@ -482,7 +474,7 @@ public class IntroductionIntegrationTest
// answer request manually // answer request manually
introductionManager2.respondToIntroduction(contactId0From2, introductionManager2.respondToIntroduction(contactId0From2,
listener2.sessionId, time, true); listener2.sessionId, true);
// sync second response and AUTH // sync second response and AUTH
sync2To0(2, true); sync2To0(2, true);
@@ -518,11 +510,10 @@ public class IntroductionIntegrationTest
listener2.answerRequests = false; listener2.answerRequests = false;
// make introduction // make introduction
long time = clock.currentTimeMillis();
Contact introducee1 = contact1From0; Contact introducee1 = contact1From0;
Contact introducee2 = contact2From0; Contact introducee2 = contact2From0;
introductionManager0 introductionManager0
.makeIntroduction(introducee1, introducee2, null, time); .makeIntroduction(introducee1, introducee2, null);
// sync request messages // sync request messages
sync0To1(1, true); sync0To1(1, true);
@@ -564,7 +555,7 @@ public class IntroductionIntegrationTest
// answer request manually // answer request manually
introductionManager2.respondToIntroduction(contactId0From2, introductionManager2.respondToIntroduction(contactId0From2,
listener2.sessionId, time, false); listener2.sessionId, false);
// now introducee2 should have returned to the START state // now introducee2 should have returned to the START state
introduceeSession = getIntroduceeSession(c2); introduceeSession = getIntroduceeSession(c2);
@@ -611,9 +602,8 @@ public class IntroductionIntegrationTest
addListeners(true, false); addListeners(true, false);
// make introduction // make introduction
long time = clock.currentTimeMillis();
introductionManager0 introductionManager0
.makeIntroduction(contact1From0, contact1From0, null, time); .makeIntroduction(contact1From0, contact1From0, null);
// sync request messages // sync request messages
sync0To1(1, false); sync0To1(1, false);
@@ -637,9 +627,8 @@ public class IntroductionIntegrationTest
.canIntroduce(contact1From0, contact2From0)); .canIntroduce(contact1From0, contact2From0));
// make the introduction // make the introduction
long time = clock.currentTimeMillis();
introductionManager0 introductionManager0
.makeIntroduction(contact1From0, contact2From0, null, time); .makeIntroduction(contact1From0, contact2From0, null);
// no more introduction allowed while the existing one is in progress // no more introduction allowed while the existing one is in progress
assertFalse(introductionManager0 assertFalse(introductionManager0
@@ -647,7 +636,7 @@ public class IntroductionIntegrationTest
// try it anyway and fail // try it anyway and fail
introductionManager0 introductionManager0
.makeIntroduction(contact1From0, contact2From0, null, time); .makeIntroduction(contact1From0, contact2From0, null);
} }
@Test @Test
@@ -661,9 +650,8 @@ public class IntroductionIntegrationTest
addListeners(true, true); addListeners(true, true);
// make the introduction // make the introduction
long time = clock.currentTimeMillis();
introductionManager0 introductionManager0
.makeIntroduction(contact1From0, contact2From0, null, time); .makeIntroduction(contact1From0, contact2From0, null);
// sync REQUEST messages // sync REQUEST messages
sync0To1(1, true); sync0To1(1, true);
@@ -719,9 +707,8 @@ public class IntroductionIntegrationTest
addListeners(true, true); addListeners(true, true);
// make the introduction // make the introduction
long time = clock.currentTimeMillis();
introductionManager0 introductionManager0
.makeIntroduction(contact1From0, contact2From0, null, time); .makeIntroduction(contact1From0, contact2From0, null);
// sync REQUEST messages // sync REQUEST messages
sync0To1(1, true); sync0To1(1, true);
@@ -766,9 +753,8 @@ public class IntroductionIntegrationTest
addListeners(true, true); addListeners(true, true);
// make the introduction // make the introduction
long time = clock.currentTimeMillis();
introductionManager0 introductionManager0
.makeIntroduction(contact1From0, contact2From0, null, time); .makeIntroduction(contact1From0, contact2From0, null);
// sync REQUEST to introducee1 // sync REQUEST to introducee1
sync0To1(1, true); sync0To1(1, true);
@@ -803,9 +789,8 @@ public class IntroductionIntegrationTest
addListeners(true, true); addListeners(true, true);
// make the introduction // make the introduction
long time = clock.currentTimeMillis();
introductionManager0 introductionManager0
.makeIntroduction(contact1From0, contact2From0, null, time); .makeIntroduction(contact1From0, contact2From0, null);
// sync REQUEST to introducee1 // sync REQUEST to introducee1
sync0To1(1, true); sync0To1(1, true);
@@ -838,9 +823,8 @@ public class IntroductionIntegrationTest
addListeners(false, true); addListeners(false, true);
// make the introduction // make the introduction
long time = clock.currentTimeMillis();
introductionManager0 introductionManager0
.makeIntroduction(contact1From0, contact2From0, null, time); .makeIntroduction(contact1From0, contact2From0, null);
// sync REQUEST to introducee1 // sync REQUEST to introducee1
sync0To1(1, true); sync0To1(1, true);
@@ -873,9 +857,8 @@ public class IntroductionIntegrationTest
addListeners(true, true); addListeners(true, true);
// make the introduction // make the introduction
long time = clock.currentTimeMillis();
introductionManager0 introductionManager0
.makeIntroduction(contact1From0, contact2From0, null, time); .makeIntroduction(contact1From0, contact2From0, null);
// sync REQUEST messages // sync REQUEST messages
sync0To1(1, true); sync0To1(1, true);
@@ -914,9 +897,8 @@ public class IntroductionIntegrationTest
addListeners(true, true); addListeners(true, true);
// make introduction // make introduction
long time = clock.currentTimeMillis();
introductionManager0 introductionManager0
.makeIntroduction(contact1From0, contact2From0, "Hi!", time); .makeIntroduction(contact1From0, contact2From0, "Hi!");
// sync first request message // sync first request message
sync0To1(1, true); sync0To1(1, true);
@@ -943,9 +925,8 @@ public class IntroductionIntegrationTest
addListeners(true, true); addListeners(true, true);
// make introduction // make introduction
long time = clock.currentTimeMillis();
introductionManager0 introductionManager0
.makeIntroduction(contact1From0, contact2From0, "Hi!", time); .makeIntroduction(contact1From0, contact2From0, "Hi!");
// sync first request message // sync first request message
sync0To1(1, true); sync0To1(1, true);
@@ -987,9 +968,8 @@ public class IntroductionIntegrationTest
@Test @Test
public void testIntroductionAfterReAddingContacts() throws Exception { public void testIntroductionAfterReAddingContacts() throws Exception {
// make introduction // make introduction
long time = clock.currentTimeMillis();
introductionManager0 introductionManager0
.makeIntroduction(contact1From0, contact2From0, null, time); .makeIntroduction(contact1From0, contact2From0, null);
// 0 and 1 remove and re-add each other // 0 and 1 remove and re-add each other
contactManager0.removeContact(contactId1From0); contactManager0.removeContact(contactId1From0);
@@ -1016,9 +996,8 @@ public class IntroductionIntegrationTest
addListeners(true, true); addListeners(true, true);
// make new introduction // make new introduction
time = clock.currentTimeMillis();
introductionManager0 introductionManager0
.makeIntroduction(contact1From0, contact2From0, null, time); .makeIntroduction(contact1From0, contact2From0, null);
// introduction should sync and not be INVALID or PENDING // introduction should sync and not be INVALID or PENDING
sync0To1(1, true); sync0To1(1, true);
@@ -1032,9 +1011,8 @@ public class IntroductionIntegrationTest
addListeners(true, true); addListeners(true, true);
// make introduction // make introduction
long time = clock.currentTimeMillis();
introductionManager0 introductionManager0
.makeIntroduction(contact1From0, contact2From0, "Hi!", time); .makeIntroduction(contact1From0, contact2From0, "Hi!");
// sync request messages // sync request messages
sync0To1(1, true); sync0To1(1, true);
@@ -1147,9 +1125,8 @@ public class IntroductionIntegrationTest
addListeners(true, true); addListeners(true, true);
// make introduction // make introduction
long time = clock.currentTimeMillis();
introductionManager0 introductionManager0
.makeIntroduction(contact1From0, contact2From0, "Hi!", time); .makeIntroduction(contact1From0, contact2From0, "Hi!");
// sync first REQUEST message // sync first REQUEST message
sync0To1(1, true); sync0To1(1, true);
@@ -1292,7 +1269,7 @@ public class IntroductionIntegrationTest
assertTrue(introductionManager0 assertTrue(introductionManager0
.canIntroduce(contact1From0, contact2From0)); .canIntroduce(contact1From0, contact2From0));
introductionManager0 introductionManager0
.makeIntroduction(contact1From0, contact2From0, "Ho!", time); .makeIntroduction(contact1From0, contact2From0, "Ho!");
sync0To1(1, true); sync0To1(1, true);
sync0To2(1, true); sync0To2(1, true);
@@ -1332,9 +1309,8 @@ public class IntroductionIntegrationTest
addListeners(false, false); addListeners(false, false);
// make introduction // make introduction
long time = clock.currentTimeMillis();
introductionManager0 introductionManager0
.makeIntroduction(contact1From0, contact2From0, "Hi!", time); .makeIntroduction(contact1From0, contact2From0, "Hi!");
// sync REQUEST messages // sync REQUEST messages
sync0To1(1, true); sync0To1(1, true);
@@ -1399,9 +1375,8 @@ public class IntroductionIntegrationTest
// a new introduction is still possible // a new introduction is still possible
assertTrue(introductionManager0 assertTrue(introductionManager0
.canIntroduce(contact1From0, contact2From0)); .canIntroduce(contact1From0, contact2From0));
time = clock.currentTimeMillis();
introductionManager0 introductionManager0
.makeIntroduction(contact1From0, contact2From0, "Ho!", time); .makeIntroduction(contact1From0, contact2From0, "Ho!");
sync0To1(1, true); sync0To1(1, true);
sync0To2(1, true); sync0To2(1, true);
@@ -1428,9 +1403,8 @@ public class IntroductionIntegrationTest
addListeners(false, false); addListeners(false, false);
// make introduction // make introduction
long time = clock.currentTimeMillis();
introductionManager0 introductionManager0
.makeIntroduction(contact1From0, contact2From0, "Hi!", time); .makeIntroduction(contact1From0, contact2From0, "Hi!");
// sync REQUEST messages // sync REQUEST messages
sync0To1(1, true); sync0To1(1, true);
@@ -1458,9 +1432,8 @@ public class IntroductionIntegrationTest
// a new introduction is still possible // a new introduction is still possible
assertTrue(introductionManager0 assertTrue(introductionManager0
.canIntroduce(contact1From0, contact2From0)); .canIntroduce(contact1From0, contact2From0));
time = clock.currentTimeMillis();
introductionManager0 introductionManager0
.makeIntroduction(contact1From0, contact2From0, "Ho!", time); .makeIntroduction(contact1From0, contact2From0, "Ho!");
sync0To1(1, true); sync0To1(1, true);
sync0To2(1, true); sync0To2(1, true);
@@ -1496,9 +1469,8 @@ public class IntroductionIntegrationTest
addListeners(false, false); addListeners(false, false);
// make introduction // make introduction
long time = clock.currentTimeMillis(); introductionManager0
introductionManager0.makeIntroduction(contact1From0, contact2From0, .makeIntroduction(contact1From0, contact2From0, "Hi!");
"Hi!", time);
// deleting the introduction for introducee1 will fail // deleting the introduction for introducee1 will fail
Collection<ConversationMessageHeader> m1From0 = getMessages1From0(); Collection<ConversationMessageHeader> m1From0 = getMessages1From0();
@@ -1795,16 +1767,13 @@ public class IntroductionIntegrationTest
IntroductionRequest ir = introEvent.getMessageHeader(); IntroductionRequest ir = introEvent.getMessageHeader();
ContactId contactId = introEvent.getContactId(); ContactId contactId = introEvent.getContactId();
sessionId = ir.getSessionId(); sessionId = ir.getSessionId();
long time = clock.currentTimeMillis();
try { try {
if (introducee == 1 && answerRequests) { if (introducee == 1 && answerRequests) {
introductionManager1 introductionManager1.respondToIntroduction(contactId,
.respondToIntroduction(contactId, sessionId, sessionId, accept);
time, accept);
} else if (introducee == 2 && answerRequests) { } else if (introducee == 2 && answerRequests) {
introductionManager2 introductionManager2.respondToIntroduction(contactId,
.respondToIntroduction(contactId, sessionId, sessionId, accept);
time, accept);
} }
} catch (DbException exception) { } catch (DbException exception) {
eventWaiter.rethrow(exception); eventWaiter.rethrow(exception);