Forum Sharing Client backend

This commit replaces the old ForumSharingManagerImpl with a new one
which is based on state machines and the ProtocolEngine.

There is a SharerEngine and a InviteeEngine that take care of state
transitions, messages, events and trigger actions to be carried out by
the ForumSharingManagerImpl. This is all very similar to the
Introduction Client.

The general sharing paradigm has been changed from sharing as a state to
sharing as an action. Now the UI can allow users to invite contacts to
forums. The contacts can accept or decline the invitiation. Also, the
Forum Sharing Manger is notified when users leave a forum.

Closes #322
This commit is contained in:
Torsten Grote
2016-04-26 20:26:46 -03:00
parent db3226794d
commit 9bef114c35
23 changed files with 1713 additions and 338 deletions

View File

@@ -0,0 +1,24 @@
package org.briarproject.api.event;
import org.briarproject.api.contact.ContactId;
import org.briarproject.api.forum.Forum;
import org.briarproject.api.introduction.IntroductionRequest;
public class ForumInvitationReceivedEvent extends Event {
private final Forum forum;
private final ContactId contactId;
public ForumInvitationReceivedEvent(Forum forum, ContactId contactId) {
this.forum = forum;
this.contactId = contactId;
}
public Forum getForum() {
return forum;
}
public ContactId getContactId() {
return contactId;
}
}

View File

@@ -0,0 +1,24 @@
package org.briarproject.api.event;
import org.briarproject.api.contact.ContactId;
public class ForumInvitationResponseReceivedEvent extends Event {
private final String forumName;
private final ContactId contactId;
public ForumInvitationResponseReceivedEvent(String forumName,
ContactId contactId) {
this.forumName = forumName;
this.contactId = contactId;
}
public String getForumName() {
return forumName;
}
public ContactId getContactId() {
return contactId;
}
}

View File

@@ -15,4 +15,38 @@ public interface ForumConstants {
/** The maximum length of a forum post's body in bytes. */
int MAX_FORUM_POST_BODY_LENGTH = MAX_MESSAGE_BODY_LENGTH - 1024;
/* Forum Sharing Constants */
String CONTACT_ID = "contactId";
String GROUP_ID = "groupId";
String TO_BE_SHARED_BY_US = "toBeSharedByUs";
String SHARED_BY_US = "sharedByUs";
String SHARED_WITH_US = "sharedWithUs";
String TYPE = "type";
String SESSION_ID = "sessionId";
String STORAGE_ID = "storageId";
String STATE = "state";
String LOCAL = "local";
String TIME = "time";
String READ = "read";
String IS_SHARER = "isSharer";
String FORUM_ID = "forumId";
String FORUM_NAME = "forumName";
String FORUM_SALT = "forumSalt";
String INVITATION_MSG = "invitationMsg";
int SHARE_MSG_TYPE_INVITATION = 1;
int SHARE_MSG_TYPE_ACCEPT = 2;
int SHARE_MSG_TYPE_DECLINE = 3;
int SHARE_MSG_TYPE_LEAVE = 4;
int SHARE_MSG_TYPE_ABORT = 5;
String TASK = "task";
int TASK_ADD_FORUM_TO_LIST_SHARED_WITH_US = 0;
int TASK_REMOVE_FORUM_FROM_LIST_SHARED_WITH_US = 1;
int TASK_ADD_SHARED_FORUM = 2;
int TASK_ADD_FORUM_TO_LIST_TO_BE_SHARED_BY_US = 3;
int TASK_REMOVE_FORUM_FROM_LIST_TO_BE_SHARED_BY_US = 4;
int TASK_SHARE_FORUM = 5;
int TASK_UNSHARE_FORUM_SHARED_BY_US = 6;
int TASK_UNSHARE_FORUM_SHARED_WITH_US = 7;
}

View File

@@ -0,0 +1,48 @@
package org.briarproject.api.forum;
import org.briarproject.api.clients.SessionId;
import org.briarproject.api.contact.ContactId;
import org.briarproject.api.messaging.BaseMessage;
import org.briarproject.api.sync.MessageId;
public class ForumInvitationMessage extends BaseMessage {
private final SessionId sessionId;
private final ContactId contactId;
private final String forumName, message;
private final boolean available;
public ForumInvitationMessage(MessageId id, SessionId sessionId,
ContactId contactId, String forumName, String message,
boolean available, long time, boolean local, boolean sent,
boolean seen, boolean read) {
super(id, time, local, read, sent, seen);
this.sessionId = sessionId;
this.contactId = contactId;
this.forumName = forumName;
this.message = message;
this.available = available;
}
public SessionId getSessionId() {
return sessionId;
}
public ContactId getContactId() {
return contactId;
}
public String getForumName() {
return forumName;
}
public String getMessage() {
return message;
}
public boolean isAvailable() {
return available;
}
}

View File

@@ -1,5 +1,6 @@
package org.briarproject.api.forum;
import org.briarproject.api.clients.SessionId;
import org.briarproject.api.contact.Contact;
import org.briarproject.api.contact.ContactId;
import org.briarproject.api.db.DbException;
@@ -13,20 +14,35 @@ public interface ForumSharingManager {
/** Returns the unique ID of the forum sharing client. */
ClientId getClientId();
/**
* Sends an invitation to share the given forum with the given contact
* and sends an optional message along with it.
*/
void sendForumInvitation(GroupId groupId, ContactId contactId,
String message) throws DbException;
/**
* Responds to a pending forum invitation
*/
void respondToInvitation(Forum f, boolean accept) throws DbException;
/**
* Returns all forum sharing messages sent by the Contact
* identified by contactId.
*/
Collection<ForumInvitationMessage> getForumInvitationMessages(
ContactId contactId) throws DbException;
/** Returns all forums to which the user could subscribe. */
Collection<Forum> getAvailableForums() throws DbException;
/** Returns all contacts who are sharing the given forum with the user. */
/** Returns all contacts who are sharing the given forum with us. */
Collection<Contact> getSharedBy(GroupId g) throws DbException;
/** Returns the IDs of all contacts with whom the given forum is shared. */
Collection<ContactId> getSharedWith(GroupId g) throws DbException;
/**
* Shares a forum with the given contacts and unshares it with any other
* contacts.
*/
void setSharedWith(GroupId g, Collection<ContactId> shared)
throws DbException;
/** Returns true if the forum not already shared and no invitation is open */
boolean canBeShared(GroupId g, Contact c) throws DbException;
}

View File

@@ -0,0 +1,34 @@
package org.briarproject.api.forum;
import static org.briarproject.api.forum.ForumConstants.SHARE_MSG_TYPE_ABORT;
import static org.briarproject.api.forum.ForumConstants.SHARE_MSG_TYPE_ACCEPT;
import static org.briarproject.api.forum.ForumConstants.SHARE_MSG_TYPE_DECLINE;
import static org.briarproject.api.forum.ForumConstants.SHARE_MSG_TYPE_INVITATION;
import static org.briarproject.api.forum.ForumConstants.SHARE_MSG_TYPE_LEAVE;
public enum InviteeAction {
LOCAL_ACCEPT,
LOCAL_DECLINE,
LOCAL_LEAVE,
LOCAL_ABORT,
REMOTE_INVITATION,
REMOTE_LEAVE,
REMOTE_ABORT;
public static InviteeAction getLocal(long type) {
if (type == SHARE_MSG_TYPE_ACCEPT) return LOCAL_ACCEPT;
if (type == SHARE_MSG_TYPE_DECLINE) return LOCAL_DECLINE;
if (type == SHARE_MSG_TYPE_LEAVE) return LOCAL_LEAVE;
if (type == SHARE_MSG_TYPE_ABORT) return LOCAL_ABORT;
return null;
}
public static InviteeAction getRemote(long type) {
if (type == SHARE_MSG_TYPE_INVITATION) return REMOTE_INVITATION;
if (type == SHARE_MSG_TYPE_LEAVE) return REMOTE_LEAVE;
if (type == SHARE_MSG_TYPE_ABORT) return REMOTE_ABORT;
return null;
}
}

View File

@@ -0,0 +1,62 @@
package org.briarproject.api.forum;
import static org.briarproject.api.forum.InviteeAction.LOCAL_ACCEPT;
import static org.briarproject.api.forum.InviteeAction.LOCAL_DECLINE;
import static org.briarproject.api.forum.InviteeAction.LOCAL_LEAVE;
import static org.briarproject.api.forum.InviteeAction.REMOTE_INVITATION;
import static org.briarproject.api.forum.InviteeAction.REMOTE_LEAVE;
public enum InviteeProtocolState {
ERROR(0),
AWAIT_INVITATION(1) {
@Override
public InviteeProtocolState next(InviteeAction a) {
if (a == REMOTE_INVITATION) return AWAIT_LOCAL_RESPONSE;
return ERROR;
}
},
AWAIT_LOCAL_RESPONSE(2) {
@Override
public InviteeProtocolState next(InviteeAction a) {
if (a == LOCAL_ACCEPT || a == LOCAL_DECLINE) return FINISHED;
if (a == REMOTE_LEAVE) return LEFT;
return ERROR;
}
},
FINISHED(3) {
@Override
public InviteeProtocolState next(InviteeAction a) {
if (a == LOCAL_LEAVE || a == REMOTE_LEAVE) return LEFT;
return FINISHED;
}
},
LEFT(4) {
@Override
public InviteeProtocolState next(InviteeAction a) {
if (a == LOCAL_LEAVE) return ERROR;
return LEFT;
}
};
private final int value;
InviteeProtocolState(int value) {
this.value = value;
}
public int getValue() {
return value;
}
public static InviteeProtocolState fromValue(int value) {
for (InviteeProtocolState s : values()) {
if (s.value == value) return s;
}
throw new IllegalArgumentException();
}
public InviteeProtocolState next(InviteeAction a) {
return this;
}
}

View File

@@ -0,0 +1,34 @@
package org.briarproject.api.forum;
import static org.briarproject.api.forum.ForumConstants.SHARE_MSG_TYPE_ABORT;
import static org.briarproject.api.forum.ForumConstants.SHARE_MSG_TYPE_ACCEPT;
import static org.briarproject.api.forum.ForumConstants.SHARE_MSG_TYPE_DECLINE;
import static org.briarproject.api.forum.ForumConstants.SHARE_MSG_TYPE_INVITATION;
import static org.briarproject.api.forum.ForumConstants.SHARE_MSG_TYPE_LEAVE;
public enum SharerAction {
LOCAL_INVITATION,
LOCAL_LEAVE,
LOCAL_ABORT,
REMOTE_ACCEPT,
REMOTE_DECLINE,
REMOTE_LEAVE,
REMOTE_ABORT;
public static SharerAction getLocal(long type) {
if (type == SHARE_MSG_TYPE_INVITATION) return LOCAL_INVITATION;
if (type == SHARE_MSG_TYPE_LEAVE) return LOCAL_LEAVE;
if (type == SHARE_MSG_TYPE_ABORT) return LOCAL_ABORT;
return null;
}
public static SharerAction getRemote(long type) {
if (type == SHARE_MSG_TYPE_ACCEPT) return REMOTE_ACCEPT;
if (type == SHARE_MSG_TYPE_DECLINE) return REMOTE_DECLINE;
if (type == SHARE_MSG_TYPE_LEAVE) return REMOTE_LEAVE;
if (type == SHARE_MSG_TYPE_ABORT) return REMOTE_ABORT;
return null;
}
}

View File

@@ -0,0 +1,62 @@
package org.briarproject.api.forum;
import static org.briarproject.api.forum.SharerAction.LOCAL_INVITATION;
import static org.briarproject.api.forum.SharerAction.LOCAL_LEAVE;
import static org.briarproject.api.forum.SharerAction.REMOTE_ACCEPT;
import static org.briarproject.api.forum.SharerAction.REMOTE_DECLINE;
import static org.briarproject.api.forum.SharerAction.REMOTE_LEAVE;
public enum SharerProtocolState {
ERROR(0),
PREPARE_INVITATION(1) {
@Override
public SharerProtocolState next(SharerAction a) {
if (a == LOCAL_INVITATION) return AWAIT_RESPONSE;
return ERROR;
}
},
AWAIT_RESPONSE(2) {
@Override
public SharerProtocolState next(SharerAction a) {
if (a == REMOTE_ACCEPT || a == REMOTE_DECLINE) return FINISHED;
if (a == LOCAL_LEAVE) return LEFT;
return ERROR;
}
},
FINISHED(3) {
@Override
public SharerProtocolState next(SharerAction a) {
if (a == LOCAL_LEAVE || a == REMOTE_LEAVE) return LEFT;
return FINISHED;
}
},
LEFT(4) {
@Override
public SharerProtocolState next(SharerAction a) {
if (a == LOCAL_LEAVE) return ERROR;
return LEFT;
}
};
private final int value;
SharerProtocolState(int value) {
this.value = value;
}
public int getValue() {
return value;
}
public static SharerProtocolState fromValue(int value) {
for (SharerProtocolState s : values()) {
if (s.value == value) return s;
}
throw new IllegalArgumentException();
}
public SharerProtocolState next(SharerAction a) {
return this;
}
}

View File

@@ -1,61 +1,36 @@
package org.briarproject.api.introduction;
import org.briarproject.api.clients.SessionId;
import org.briarproject.api.messaging.BaseMessage;
import org.briarproject.api.sync.MessageId;
import static org.briarproject.api.introduction.IntroductionConstants.ROLE_INTRODUCEE;
import static org.briarproject.api.introduction.IntroductionConstants.ROLE_INTRODUCER;
abstract public class IntroductionMessage {
public class IntroductionMessage extends BaseMessage {
private final SessionId sessionId;
private final MessageId messageId;
private final int role;
private final long time;
private final boolean local, sent, seen, read;
public IntroductionMessage(SessionId sessionId, MessageId messageId,
int role, long time, boolean local, boolean sent, boolean seen,
boolean read) {
super(messageId, time, local, read, sent, seen);
this.sessionId = sessionId;
this.messageId = messageId;
this.role = role;
this.time = time;
this.local = local;
this.sent = sent;
this.seen = seen;
this.read = read;
}
public SessionId getSessionId() {
return sessionId;
}
public long getTime() {
return time;
}
public MessageId getMessageId() {
return messageId;
}
public boolean isLocal() {
return local;
}
public boolean isSent() {
return sent;
}
public boolean isSeen() {
return seen;
}
public boolean isRead() {
return read;
}
public boolean isIntroducer() {
return role == ROLE_INTRODUCER;
}

View File

@@ -0,0 +1,45 @@
package org.briarproject.api.messaging;
import org.briarproject.api.sync.MessageId;
public abstract class BaseMessage {
private final MessageId id;
private final long timestamp;
private final boolean local, read, sent, seen;
public BaseMessage(MessageId id, long timestamp, boolean local,
boolean read, boolean sent, boolean seen) {
this.id = id;
this.timestamp = timestamp;
this.local = local;
this.read = read;
this.sent = sent;
this.seen = seen;
}
public MessageId getId() {
return id;
}
public long getTimestamp() {
return timestamp;
}
public boolean isLocal() {
return local;
}
public boolean isRead() {
return read;
}
public boolean isSent() {
return sent;
}
public boolean isSeen() {
return seen;
}
}

View File

@@ -2,50 +2,19 @@ package org.briarproject.api.messaging;
import org.briarproject.api.sync.MessageId;
public class PrivateMessageHeader {
public class PrivateMessageHeader extends BaseMessage {
private final MessageId id;
private final long timestamp;
private final String contentType;
private final boolean local, read, sent, seen;
public PrivateMessageHeader(MessageId id, long timestamp,
String contentType, boolean local, boolean read, boolean sent,
boolean seen) {
this.id = id;
this.timestamp = timestamp;
this.contentType = contentType;
this.local = local;
this.read = read;
this.sent = sent;
this.seen = seen;
}
public MessageId getId() {
return id;
super(id, timestamp, local, read, sent, seen);
this.contentType = contentType;
}
public String getContentType() {
return contentType;
}
public long getTimestamp() {
return timestamp;
}
public boolean isLocal() {
return local;
}
public boolean isRead() {
return read;
}
public boolean isSent() {
return sent;
}
public boolean isSeen() {
return seen;
}
}