mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-18 21:59:54 +01:00
Merge branch '378-replace-bdf-with-classes-for-forum-sharing-client' into 'master'
Replace BDF data structures with classes in forum sharing client This introduces two new classes for protocol session states: One for the sharer and one for the invitee. The respective classes for protocol state machines and actions have been moved into these classes as inner classes. The two new classes replace the `BdfDictionary` that was used before to represent the local state information of a forum sharing session. A similar technique is used for local actions and protocol messages. Local actions are just represented by one Enum and protocol messages have their own classes now that also handle serialization into BdfDictionaries and BdfLists. Closes #378 See merge request !184
This commit is contained in:
@@ -0,0 +1,166 @@
|
|||||||
|
package org.briarproject.api.forum;
|
||||||
|
|
||||||
|
import org.briarproject.api.FormatException;
|
||||||
|
import org.briarproject.api.clients.SessionId;
|
||||||
|
import org.briarproject.api.data.BdfDictionary;
|
||||||
|
import org.briarproject.api.data.BdfEntry;
|
||||||
|
import org.briarproject.api.data.BdfList;
|
||||||
|
import org.briarproject.api.sync.GroupId;
|
||||||
|
|
||||||
|
import static org.briarproject.api.forum.ForumConstants.FORUM_NAME;
|
||||||
|
import static org.briarproject.api.forum.ForumConstants.FORUM_SALT;
|
||||||
|
import static org.briarproject.api.forum.ForumConstants.GROUP_ID;
|
||||||
|
import static org.briarproject.api.forum.ForumConstants.INVITATION_MSG;
|
||||||
|
import static org.briarproject.api.forum.ForumConstants.SESSION_ID;
|
||||||
|
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;
|
||||||
|
import static org.briarproject.api.forum.ForumConstants.TYPE;
|
||||||
|
|
||||||
|
public interface ForumSharingMessage {
|
||||||
|
|
||||||
|
abstract class BaseMessage {
|
||||||
|
private final GroupId groupId;
|
||||||
|
private final SessionId sessionId;
|
||||||
|
|
||||||
|
public BaseMessage(GroupId groupId, SessionId sessionId) {
|
||||||
|
|
||||||
|
this.groupId = groupId;
|
||||||
|
this.sessionId = sessionId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BdfList toBdfList() {
|
||||||
|
return BdfList.of(getType(), getSessionId());
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract BdfDictionary toBdfDictionary();
|
||||||
|
|
||||||
|
protected BdfDictionary toBdfDictionaryHelper() {
|
||||||
|
return BdfDictionary.of(
|
||||||
|
new BdfEntry(TYPE, getType()),
|
||||||
|
new BdfEntry(GROUP_ID, groupId),
|
||||||
|
new BdfEntry(SESSION_ID, sessionId)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BaseMessage from(GroupId groupId, BdfDictionary d)
|
||||||
|
throws FormatException {
|
||||||
|
|
||||||
|
long type = d.getLong(TYPE);
|
||||||
|
|
||||||
|
if (type == SHARE_MSG_TYPE_INVITATION)
|
||||||
|
return Invitation.from(groupId, d);
|
||||||
|
else
|
||||||
|
return SimpleMessage.from(type, groupId, d);
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract long getType();
|
||||||
|
|
||||||
|
public GroupId getGroupId() {
|
||||||
|
return groupId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SessionId getSessionId() {
|
||||||
|
return sessionId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Invitation extends BaseMessage {
|
||||||
|
|
||||||
|
private final String forumName;
|
||||||
|
private final byte[] forumSalt;
|
||||||
|
private final String message;
|
||||||
|
|
||||||
|
public Invitation(GroupId groupId, SessionId sessionId,
|
||||||
|
String forumName, byte[] forumSalt, String message) {
|
||||||
|
|
||||||
|
super(groupId, sessionId);
|
||||||
|
|
||||||
|
this.forumName = forumName;
|
||||||
|
this.forumSalt = forumSalt;
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getType() {
|
||||||
|
return SHARE_MSG_TYPE_INVITATION;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BdfList toBdfList() {
|
||||||
|
BdfList list = super.toBdfList();
|
||||||
|
list.add(forumName);
|
||||||
|
list.add(forumSalt);
|
||||||
|
if (message != null) list.add(message);
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BdfDictionary toBdfDictionary() {
|
||||||
|
BdfDictionary d = toBdfDictionaryHelper();
|
||||||
|
d.put(FORUM_NAME, forumName);
|
||||||
|
d.put(FORUM_SALT, forumSalt);
|
||||||
|
if (message != null) d.put(INVITATION_MSG, message);
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Invitation from(GroupId groupId, BdfDictionary d)
|
||||||
|
throws FormatException {
|
||||||
|
|
||||||
|
SessionId sessionId = new SessionId(d.getRaw(SESSION_ID));
|
||||||
|
String forumName = d.getString(FORUM_NAME);
|
||||||
|
byte[] forumSalt = d.getRaw(FORUM_SALT);
|
||||||
|
String message = d.getOptionalString(INVITATION_MSG);
|
||||||
|
|
||||||
|
return new Invitation(groupId, sessionId, forumName, forumSalt,
|
||||||
|
message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getForumName() {
|
||||||
|
return forumName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getForumSalt() {
|
||||||
|
return forumSalt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMessage() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SimpleMessage extends BaseMessage {
|
||||||
|
|
||||||
|
private final long type;
|
||||||
|
|
||||||
|
public SimpleMessage(long type, GroupId groupId, SessionId sessionId) {
|
||||||
|
super(groupId, sessionId);
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BdfDictionary toBdfDictionary() {
|
||||||
|
return toBdfDictionaryHelper();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SimpleMessage from(long type, GroupId groupId,
|
||||||
|
BdfDictionary d) throws FormatException {
|
||||||
|
|
||||||
|
if (type != SHARE_MSG_TYPE_ACCEPT &&
|
||||||
|
type != SHARE_MSG_TYPE_DECLINE &&
|
||||||
|
type != SHARE_MSG_TYPE_LEAVE &&
|
||||||
|
type != SHARE_MSG_TYPE_ABORT) throw new FormatException();
|
||||||
|
|
||||||
|
SessionId sessionId = new SessionId(d.getRaw(SESSION_ID));
|
||||||
|
return new SimpleMessage(type, groupId, sessionId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -27,10 +27,6 @@ import org.briarproject.api.forum.ForumFactory;
|
|||||||
import org.briarproject.api.forum.ForumInvitationMessage;
|
import org.briarproject.api.forum.ForumInvitationMessage;
|
||||||
import org.briarproject.api.forum.ForumManager;
|
import org.briarproject.api.forum.ForumManager;
|
||||||
import org.briarproject.api.forum.ForumSharingManager;
|
import org.briarproject.api.forum.ForumSharingManager;
|
||||||
import org.briarproject.api.forum.InviteeAction;
|
|
||||||
import org.briarproject.api.forum.InviteeProtocolState;
|
|
||||||
import org.briarproject.api.forum.SharerAction;
|
|
||||||
import org.briarproject.api.forum.SharerProtocolState;
|
|
||||||
import org.briarproject.api.sync.ClientId;
|
import org.briarproject.api.sync.ClientId;
|
||||||
import org.briarproject.api.sync.Group;
|
import org.briarproject.api.sync.Group;
|
||||||
import org.briarproject.api.sync.GroupId;
|
import org.briarproject.api.sync.GroupId;
|
||||||
@@ -59,12 +55,7 @@ import static java.util.logging.Level.INFO;
|
|||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
import static org.briarproject.api.clients.ProtocolEngine.StateUpdate;
|
import static org.briarproject.api.clients.ProtocolEngine.StateUpdate;
|
||||||
import static org.briarproject.api.forum.ForumConstants.CONTACT_ID;
|
import static org.briarproject.api.forum.ForumConstants.CONTACT_ID;
|
||||||
import static org.briarproject.api.forum.ForumConstants.FORUM_ID;
|
|
||||||
import static org.briarproject.api.forum.ForumConstants.FORUM_NAME;
|
|
||||||
import static org.briarproject.api.forum.ForumConstants.FORUM_SALT;
|
|
||||||
import static org.briarproject.api.forum.ForumConstants.FORUM_SALT_LENGTH;
|
import static org.briarproject.api.forum.ForumConstants.FORUM_SALT_LENGTH;
|
||||||
import static org.briarproject.api.forum.ForumConstants.GROUP_ID;
|
|
||||||
import static org.briarproject.api.forum.ForumConstants.INVITATION_MSG;
|
|
||||||
import static org.briarproject.api.forum.ForumConstants.IS_SHARER;
|
import static org.briarproject.api.forum.ForumConstants.IS_SHARER;
|
||||||
import static org.briarproject.api.forum.ForumConstants.LOCAL;
|
import static org.briarproject.api.forum.ForumConstants.LOCAL;
|
||||||
import static org.briarproject.api.forum.ForumConstants.READ;
|
import static org.briarproject.api.forum.ForumConstants.READ;
|
||||||
@@ -76,11 +67,8 @@ 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_DECLINE;
|
||||||
import static org.briarproject.api.forum.ForumConstants.SHARE_MSG_TYPE_INVITATION;
|
import static org.briarproject.api.forum.ForumConstants.SHARE_MSG_TYPE_INVITATION;
|
||||||
import static org.briarproject.api.forum.ForumConstants.SHARE_MSG_TYPE_LEAVE;
|
import static org.briarproject.api.forum.ForumConstants.SHARE_MSG_TYPE_LEAVE;
|
||||||
import static org.briarproject.api.forum.ForumConstants.STATE;
|
|
||||||
import static org.briarproject.api.forum.ForumConstants.STORAGE_ID;
|
|
||||||
import static org.briarproject.api.forum.ForumConstants.TASK;
|
|
||||||
import static org.briarproject.api.forum.ForumConstants.TASK_ADD_FORUM_TO_LIST_TO_BE_SHARED_BY_US;
|
|
||||||
import static org.briarproject.api.forum.ForumConstants.TASK_ADD_FORUM_TO_LIST_SHARED_WITH_US;
|
import static org.briarproject.api.forum.ForumConstants.TASK_ADD_FORUM_TO_LIST_SHARED_WITH_US;
|
||||||
|
import static org.briarproject.api.forum.ForumConstants.TASK_ADD_FORUM_TO_LIST_TO_BE_SHARED_BY_US;
|
||||||
import static org.briarproject.api.forum.ForumConstants.TASK_ADD_SHARED_FORUM;
|
import static org.briarproject.api.forum.ForumConstants.TASK_ADD_SHARED_FORUM;
|
||||||
import static org.briarproject.api.forum.ForumConstants.TASK_REMOVE_FORUM_FROM_LIST_SHARED_WITH_US;
|
import static org.briarproject.api.forum.ForumConstants.TASK_REMOVE_FORUM_FROM_LIST_SHARED_WITH_US;
|
||||||
import static org.briarproject.api.forum.ForumConstants.TASK_REMOVE_FORUM_FROM_LIST_TO_BE_SHARED_BY_US;
|
import static org.briarproject.api.forum.ForumConstants.TASK_REMOVE_FORUM_FROM_LIST_TO_BE_SHARED_BY_US;
|
||||||
@@ -91,9 +79,10 @@ import static org.briarproject.api.forum.ForumConstants.TIME;
|
|||||||
import static org.briarproject.api.forum.ForumConstants.TO_BE_SHARED_BY_US;
|
import static org.briarproject.api.forum.ForumConstants.TO_BE_SHARED_BY_US;
|
||||||
import static org.briarproject.api.forum.ForumConstants.TYPE;
|
import static org.briarproject.api.forum.ForumConstants.TYPE;
|
||||||
import static org.briarproject.api.forum.ForumManager.RemoveForumHook;
|
import static org.briarproject.api.forum.ForumManager.RemoveForumHook;
|
||||||
import static org.briarproject.api.forum.InviteeProtocolState.AWAIT_INVITATION;
|
import static org.briarproject.api.forum.ForumSharingMessage.BaseMessage;
|
||||||
import static org.briarproject.api.forum.InviteeProtocolState.AWAIT_LOCAL_RESPONSE;
|
import static org.briarproject.api.forum.ForumSharingMessage.Invitation;
|
||||||
import static org.briarproject.api.forum.SharerProtocolState.PREPARE_INVITATION;
|
import static org.briarproject.forum.ForumSharingSessionState.fromBdfDictionary;
|
||||||
|
import static org.briarproject.forum.SharerSessionState.Action;
|
||||||
|
|
||||||
class ForumSharingManagerImpl extends BdfIncomingMessageHook
|
class ForumSharingManagerImpl extends BdfIncomingMessageHook
|
||||||
implements ForumSharingManager, Client, RemoveForumHook,
|
implements ForumSharingManager, Client, RemoveForumHook,
|
||||||
@@ -187,11 +176,12 @@ class ForumSharingManagerImpl extends BdfIncomingMessageHook
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void incomingMessage(Transaction txn, Message m, BdfList body,
|
protected void incomingMessage(Transaction txn, Message m, BdfList body,
|
||||||
BdfDictionary msg) throws DbException, FormatException {
|
BdfDictionary d) throws DbException, FormatException {
|
||||||
|
|
||||||
SessionId sessionId = new SessionId(msg.getRaw(SESSION_ID));
|
BaseMessage msg = BaseMessage.from(m.getGroupId(), d);
|
||||||
long type = msg.getLong(TYPE);
|
SessionId sessionId = msg.getSessionId();
|
||||||
if (type == SHARE_MSG_TYPE_INVITATION) {
|
|
||||||
|
if (msg.getType() == SHARE_MSG_TYPE_INVITATION) {
|
||||||
// we are an invitee who just received a new invitation
|
// we are an invitee who just received a new invitation
|
||||||
boolean stateExists = true;
|
boolean stateExists = true;
|
||||||
try {
|
try {
|
||||||
@@ -206,43 +196,46 @@ class ForumSharingManagerImpl extends BdfIncomingMessageHook
|
|||||||
if (stateExists) throw new FormatException();
|
if (stateExists) throw new FormatException();
|
||||||
|
|
||||||
// check if forum can be shared
|
// check if forum can be shared
|
||||||
Forum f = forumFactory.createForum(msg.getString(FORUM_NAME),
|
Invitation invitation = (Invitation) msg;
|
||||||
msg.getRaw(FORUM_SALT));
|
Forum f = forumFactory.createForum(invitation.getForumName(),
|
||||||
|
invitation.getForumSalt());
|
||||||
ContactId contactId = getContactId(txn, m.getGroupId());
|
ContactId contactId = getContactId(txn, m.getGroupId());
|
||||||
Contact contact = db.getContact(txn, contactId);
|
Contact contact = db.getContact(txn, contactId);
|
||||||
if (!canBeShared(txn, f.getId(), contact))
|
if (!canBeShared(txn, f.getId(), contact))
|
||||||
throw new FormatException();
|
throw new FormatException();
|
||||||
|
|
||||||
// initialize state and process invitation
|
// initialize state and process invitation
|
||||||
BdfDictionary state =
|
InviteeSessionState state =
|
||||||
initializeInviteeState(txn, contactId, msg);
|
initializeInviteeState(txn, contactId, invitation);
|
||||||
InviteeEngine engine = new InviteeEngine(forumFactory);
|
InviteeEngine engine = new InviteeEngine(forumFactory);
|
||||||
processStateUpdate(txn, m.getId(),
|
processInviteeStateUpdate(txn, m.getId(),
|
||||||
engine.onMessageReceived(state, msg));
|
engine.onMessageReceived(state, msg));
|
||||||
} catch (FormatException e) {
|
} catch (FormatException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
deleteMessage(txn, m.getId());
|
deleteMessage(txn, m.getId());
|
||||||
}
|
}
|
||||||
} else if (type == SHARE_MSG_TYPE_ACCEPT ||
|
} else if (msg.getType() == SHARE_MSG_TYPE_ACCEPT ||
|
||||||
type == SHARE_MSG_TYPE_DECLINE) {
|
msg.getType() == SHARE_MSG_TYPE_DECLINE) {
|
||||||
// we are a sharer who just received a response
|
// we are a sharer who just received a response
|
||||||
BdfDictionary state = getSessionState(txn, sessionId, true);
|
SharerSessionState state = getSessionStateForSharer(txn, sessionId);
|
||||||
SharerEngine engine = new SharerEngine();
|
SharerEngine engine = new SharerEngine();
|
||||||
processStateUpdate(txn, m.getId(),
|
processSharerStateUpdate(txn, m.getId(),
|
||||||
engine.onMessageReceived(state, msg));
|
engine.onMessageReceived(state, msg));
|
||||||
} else if (type == SHARE_MSG_TYPE_LEAVE ||
|
} else if (msg.getType() == SHARE_MSG_TYPE_LEAVE ||
|
||||||
type == SHARE_MSG_TYPE_ABORT) {
|
msg.getType() == SHARE_MSG_TYPE_ABORT) {
|
||||||
// we don't know who we are, so figure it out
|
// we don't know who we are, so figure it out
|
||||||
BdfDictionary state = getSessionState(txn, sessionId, true);
|
ForumSharingSessionState s = getSessionState(txn, sessionId, true);
|
||||||
if (state.getBoolean(IS_SHARER)) {
|
if (s instanceof SharerSessionState) {
|
||||||
// we are a sharer and the invitee wants to leave or abort
|
// we are a sharer and the invitee wants to leave or abort
|
||||||
|
SharerSessionState state = (SharerSessionState) s;
|
||||||
SharerEngine engine = new SharerEngine();
|
SharerEngine engine = new SharerEngine();
|
||||||
processStateUpdate(txn, m.getId(),
|
processSharerStateUpdate(txn, m.getId(),
|
||||||
engine.onMessageReceived(state, msg));
|
engine.onMessageReceived(state, msg));
|
||||||
} else {
|
} else {
|
||||||
// we are an invitee and the sharer wants to leave or abort
|
// we are an invitee and the sharer wants to leave or abort
|
||||||
|
InviteeSessionState state = (InviteeSessionState) s;
|
||||||
InviteeEngine engine = new InviteeEngine(forumFactory);
|
InviteeEngine engine = new InviteeEngine(forumFactory);
|
||||||
processStateUpdate(txn, m.getId(),
|
processInviteeStateUpdate(txn, m.getId(),
|
||||||
engine.onMessageReceived(state, msg));
|
engine.onMessageReceived(state, msg));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -264,19 +257,18 @@ class ForumSharingManagerImpl extends BdfIncomingMessageHook
|
|||||||
try {
|
try {
|
||||||
// initialize local state for sharer
|
// initialize local state for sharer
|
||||||
Forum f = forumManager.getForum(txn, groupId);
|
Forum f = forumManager.getForum(txn, groupId);
|
||||||
BdfDictionary localState = initializeSharerState(txn, f, contactId);
|
SharerSessionState localState =
|
||||||
|
initializeSharerState(txn, f, contactId);
|
||||||
|
|
||||||
// define action
|
// add invitation message to local state to be available for engine
|
||||||
BdfDictionary localAction = new BdfDictionary();
|
|
||||||
localAction.put(TYPE, SHARE_MSG_TYPE_INVITATION);
|
|
||||||
if (!StringUtils.isNullOrEmpty(msg)) {
|
if (!StringUtils.isNullOrEmpty(msg)) {
|
||||||
localAction.put(INVITATION_MSG, msg);
|
localState.setMessage(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
// start engine and process its state update
|
// start engine and process its state update
|
||||||
SharerEngine engine = new SharerEngine();
|
SharerEngine engine = new SharerEngine();
|
||||||
processStateUpdate(txn, null,
|
processSharerStateUpdate(txn, null,
|
||||||
engine.onLocalAction(localState, localAction));
|
engine.onLocalAction(localState, Action.LOCAL_INVITATION));
|
||||||
|
|
||||||
txn.setComplete();
|
txn.setComplete();
|
||||||
} catch (FormatException e) {
|
} catch (FormatException e) {
|
||||||
@@ -293,19 +285,19 @@ class ForumSharingManagerImpl extends BdfIncomingMessageHook
|
|||||||
Transaction txn = db.startTransaction(false);
|
Transaction txn = db.startTransaction(false);
|
||||||
try {
|
try {
|
||||||
// find session state based on forum
|
// find session state based on forum
|
||||||
BdfDictionary localState = getSessionStateForResponse(txn, f);
|
InviteeSessionState localState = getSessionStateForResponse(txn, f);
|
||||||
|
|
||||||
// define action
|
// define action
|
||||||
BdfDictionary localAction = new BdfDictionary();
|
InviteeSessionState.Action localAction;
|
||||||
if (accept) {
|
if (accept) {
|
||||||
localAction.put(TYPE, SHARE_MSG_TYPE_ACCEPT);
|
localAction = InviteeSessionState.Action.LOCAL_ACCEPT;
|
||||||
} else {
|
} else {
|
||||||
localAction.put(TYPE, SHARE_MSG_TYPE_DECLINE);
|
localAction = InviteeSessionState.Action.LOCAL_DECLINE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// start engine and process its state update
|
// start engine and process its state update
|
||||||
InviteeEngine engine = new InviteeEngine(forumFactory);
|
InviteeEngine engine = new InviteeEngine(forumFactory);
|
||||||
processStateUpdate(txn, null,
|
processInviteeStateUpdate(txn, null,
|
||||||
engine.onLocalAction(localState, localAction));
|
engine.onLocalAction(localState, localAction));
|
||||||
|
|
||||||
txn.setComplete();
|
txn.setComplete();
|
||||||
@@ -330,34 +322,33 @@ class ForumSharingManagerImpl extends BdfIncomingMessageHook
|
|||||||
Map<MessageId, BdfDictionary> map = clientHelper
|
Map<MessageId, BdfDictionary> map = clientHelper
|
||||||
.getMessageMetadataAsDictionary(txn, group.getId());
|
.getMessageMetadataAsDictionary(txn, group.getId());
|
||||||
for (Map.Entry<MessageId, BdfDictionary> m : map.entrySet()) {
|
for (Map.Entry<MessageId, BdfDictionary> m : map.entrySet()) {
|
||||||
BdfDictionary msg = m.getValue();
|
BdfDictionary d = m.getValue();
|
||||||
try {
|
try {
|
||||||
if (msg.getLong(TYPE) != SHARE_MSG_TYPE_INVITATION)
|
if (d.getLong(TYPE) != SHARE_MSG_TYPE_INVITATION)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
Invitation msg = Invitation.from(group.getId(), d);
|
||||||
MessageStatus status =
|
MessageStatus status =
|
||||||
db.getMessageStatus(txn, contactId, m.getKey());
|
db.getMessageStatus(txn, contactId, m.getKey());
|
||||||
SessionId sessionId = new SessionId(msg.getRaw(SESSION_ID));
|
long time = d.getLong(TIME);
|
||||||
String name = msg.getString(FORUM_NAME);
|
boolean local = d.getBoolean(LOCAL);
|
||||||
String message = msg.getOptionalString(INVITATION_MSG);
|
boolean read = d.getBoolean(READ, false);
|
||||||
long time = msg.getLong(TIME);
|
|
||||||
boolean local = msg.getBoolean(LOCAL);
|
|
||||||
boolean read = msg.getBoolean(READ, false);
|
|
||||||
boolean available = false;
|
boolean available = false;
|
||||||
if (!local) {
|
if (!local) {
|
||||||
// figure out whether the forum is still available
|
// figure out whether the forum is still available
|
||||||
BdfDictionary sessionState =
|
ForumSharingSessionState s =
|
||||||
getSessionState(txn, sessionId, true);
|
getSessionState(txn, msg.getSessionId(), true);
|
||||||
InviteeProtocolState state = InviteeProtocolState
|
if (!(s instanceof InviteeSessionState))
|
||||||
.fromValue(
|
continue;
|
||||||
sessionState.getLong(STATE).intValue());
|
available = ((InviteeSessionState) s).getState() ==
|
||||||
available = state == AWAIT_LOCAL_RESPONSE;
|
InviteeSessionState.State.AWAIT_LOCAL_RESPONSE;
|
||||||
}
|
}
|
||||||
ForumInvitationMessage im =
|
ForumInvitationMessage im =
|
||||||
new ForumInvitationMessage(m.getKey(), sessionId,
|
new ForumInvitationMessage(m.getKey(),
|
||||||
contactId, name, message, available, time,
|
msg.getSessionId(), contactId,
|
||||||
local, status.isSent(), status.isSeen(),
|
msg.getForumName(), msg.getMessage(),
|
||||||
read);
|
available, time, local, status.isSent(),
|
||||||
|
status.isSeen(), read);
|
||||||
list.add(im);
|
list.add(im);
|
||||||
} catch (FormatException e) {
|
} catch (FormatException e) {
|
||||||
if (LOG.isLoggable(WARNING))
|
if (LOG.isLoggable(WARNING))
|
||||||
@@ -490,7 +481,7 @@ class ForumSharingManagerImpl extends BdfIncomingMessageHook
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private BdfDictionary initializeSharerState(Transaction txn, Forum f,
|
private SharerSessionState initializeSharerState(Transaction txn, Forum f,
|
||||||
ContactId contactId) throws FormatException, DbException {
|
ContactId contactId) throws FormatException, DbException {
|
||||||
|
|
||||||
Contact c = db.getContact(txn, contactId);
|
Contact c = db.getContact(txn, contactId);
|
||||||
@@ -502,33 +493,27 @@ class ForumSharingManagerImpl extends BdfIncomingMessageHook
|
|||||||
random.nextBytes(salt.getBytes());
|
random.nextBytes(salt.getBytes());
|
||||||
Message m = clientHelper.createMessage(localGroup.getId(), now,
|
Message m = clientHelper.createMessage(localGroup.getId(), now,
|
||||||
BdfList.of(salt));
|
BdfList.of(salt));
|
||||||
MessageId sessionId = m.getId();
|
SessionId sessionId = new SessionId(m.getId().getBytes());
|
||||||
|
|
||||||
BdfDictionary d = new BdfDictionary();
|
SharerSessionState s = new SharerSessionState(sessionId, sessionId,
|
||||||
d.put(SESSION_ID, sessionId);
|
group.getId(), SharerSessionState.State.PREPARE_INVITATION,
|
||||||
d.put(STORAGE_ID, sessionId);
|
contactId, f.getId(), f.getName(), f.getSalt());
|
||||||
d.put(GROUP_ID, group.getId());
|
|
||||||
d.put(IS_SHARER, true);
|
|
||||||
d.put(STATE, PREPARE_INVITATION.getValue());
|
|
||||||
d.put(CONTACT_ID, contactId.getInt());
|
|
||||||
d.put(FORUM_ID, f.getId());
|
|
||||||
d.put(FORUM_NAME, f.getName());
|
|
||||||
d.put(FORUM_SALT, f.getSalt());
|
|
||||||
|
|
||||||
// save local state to database
|
// save local state to database
|
||||||
|
BdfDictionary d = s.toBdfDictionary();
|
||||||
clientHelper.addLocalMessage(txn, m, getClientId(), d, false);
|
clientHelper.addLocalMessage(txn, m, getClientId(), d, false);
|
||||||
|
|
||||||
return d;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
private BdfDictionary initializeInviteeState(Transaction txn,
|
private InviteeSessionState initializeInviteeState(Transaction txn,
|
||||||
ContactId contactId, BdfDictionary msg)
|
ContactId contactId, Invitation msg)
|
||||||
throws FormatException, DbException {
|
throws FormatException, DbException {
|
||||||
|
|
||||||
Contact c = db.getContact(txn, contactId);
|
Contact c = db.getContact(txn, contactId);
|
||||||
Group group = getContactGroup(c);
|
Group group = getContactGroup(c);
|
||||||
String name = msg.getString(FORUM_NAME);
|
String name = msg.getForumName();
|
||||||
byte[] salt = msg.getRaw(FORUM_SALT);
|
byte[] salt = msg.getForumSalt();
|
||||||
Forum f = forumFactory.createForum(name, salt);
|
Forum f = forumFactory.createForum(name, salt);
|
||||||
|
|
||||||
// create local message to keep engine state
|
// create local message to keep engine state
|
||||||
@@ -538,29 +523,24 @@ class ForumSharingManagerImpl extends BdfIncomingMessageHook
|
|||||||
Message m = clientHelper.createMessage(localGroup.getId(), now,
|
Message m = clientHelper.createMessage(localGroup.getId(), now,
|
||||||
BdfList.of(mSalt));
|
BdfList.of(mSalt));
|
||||||
|
|
||||||
BdfDictionary d = new BdfDictionary();
|
InviteeSessionState s = new InviteeSessionState(msg.getSessionId(),
|
||||||
d.put(SESSION_ID, msg.getRaw(SESSION_ID));
|
m.getId(), group.getId(),
|
||||||
d.put(STORAGE_ID, m.getId());
|
InviteeSessionState.State.AWAIT_INVITATION, contactId,
|
||||||
d.put(GROUP_ID, group.getId());
|
f.getId(), f.getName(), f.getSalt());
|
||||||
d.put(IS_SHARER, false);
|
|
||||||
d.put(STATE, AWAIT_INVITATION.getValue());
|
|
||||||
d.put(CONTACT_ID, contactId.getInt());
|
|
||||||
d.put(FORUM_ID, f.getId());
|
|
||||||
d.put(FORUM_NAME, name);
|
|
||||||
d.put(FORUM_SALT, salt);
|
|
||||||
|
|
||||||
// save local state to database
|
// save local state to database
|
||||||
|
BdfDictionary d = s.toBdfDictionary();
|
||||||
clientHelper.addLocalMessage(txn, m, getClientId(), d, false);
|
clientHelper.addLocalMessage(txn, m, getClientId(), d, false);
|
||||||
|
|
||||||
return d;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
private BdfDictionary getSessionState(Transaction txn, SessionId sessionId,
|
private ForumSharingSessionState getSessionState(Transaction txn,
|
||||||
boolean warn) throws DbException, FormatException {
|
SessionId sessionId, boolean warn)
|
||||||
|
throws DbException, FormatException {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// we should be able to get the sharer state directly from sessionId
|
return getSessionStateForSharer(txn, sessionId);
|
||||||
return clientHelper.getMessageMetadataAsDictionary(txn, sessionId);
|
|
||||||
} catch (NoSuchMessageException e) {
|
} catch (NoSuchMessageException e) {
|
||||||
// State not found directly, so iterate over all states
|
// State not found directly, so iterate over all states
|
||||||
// to find state for invitee
|
// to find state for invitee
|
||||||
@@ -570,7 +550,7 @@ class ForumSharingManagerImpl extends BdfIncomingMessageHook
|
|||||||
BdfDictionary state = m.getValue();
|
BdfDictionary state = m.getValue();
|
||||||
if (Arrays.equals(state.getRaw(SESSION_ID),
|
if (Arrays.equals(state.getRaw(SESSION_ID),
|
||||||
sessionId.getBytes())) {
|
sessionId.getBytes())) {
|
||||||
return state;
|
return fromBdfDictionary(state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (warn && LOG.isLoggable(WARNING)) {
|
if (warn && LOG.isLoggable(WARNING)) {
|
||||||
@@ -582,23 +562,37 @@ class ForumSharingManagerImpl extends BdfIncomingMessageHook
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private BdfDictionary getSessionStateForResponse(Transaction txn, Forum f)
|
private SharerSessionState getSessionStateForSharer(Transaction txn,
|
||||||
|
SessionId sessionId)
|
||||||
throws DbException, FormatException {
|
throws DbException, FormatException {
|
||||||
|
|
||||||
|
// we should be able to get the sharer state directly from sessionId
|
||||||
|
BdfDictionary d =
|
||||||
|
clientHelper.getMessageMetadataAsDictionary(txn, sessionId);
|
||||||
|
|
||||||
|
if (!d.getBoolean(IS_SHARER)) throw new FormatException();
|
||||||
|
|
||||||
|
return (SharerSessionState) fromBdfDictionary(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
private InviteeSessionState getSessionStateForResponse(Transaction txn,
|
||||||
|
Forum f) throws DbException, FormatException {
|
||||||
|
|
||||||
Map<MessageId, BdfDictionary> map = clientHelper
|
Map<MessageId, BdfDictionary> map = clientHelper
|
||||||
.getMessageMetadataAsDictionary(txn, localGroup.getId());
|
.getMessageMetadataAsDictionary(txn, localGroup.getId());
|
||||||
for (Map.Entry<MessageId, BdfDictionary> m : map.entrySet()) {
|
for (Map.Entry<MessageId, BdfDictionary> m : map.entrySet()) {
|
||||||
BdfDictionary d = m.getValue();
|
BdfDictionary d = m.getValue();
|
||||||
try {
|
try {
|
||||||
InviteeProtocolState state = InviteeProtocolState
|
ForumSharingSessionState s = fromBdfDictionary(d);
|
||||||
.fromValue(d.getLong(STATE).intValue());
|
if (!(s instanceof InviteeSessionState)) continue;
|
||||||
if (state == AWAIT_LOCAL_RESPONSE) {
|
if (!f.getId().equals(s.getForumId())) continue;
|
||||||
byte[] id = d.getRaw(FORUM_ID);
|
|
||||||
if (Arrays.equals(f.getId().getBytes(), id)) {
|
InviteeSessionState state = (InviteeSessionState) s;
|
||||||
// Note that there should always be only one session
|
if (state.getState() ==
|
||||||
// in this state for the same forum
|
InviteeSessionState.State.AWAIT_LOCAL_RESPONSE) {
|
||||||
return d;
|
// Note that there should always be only one session
|
||||||
}
|
// in this state for the same forum
|
||||||
|
return state;
|
||||||
}
|
}
|
||||||
} catch (FormatException e) {
|
} catch (FormatException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
@@ -607,36 +601,40 @@ class ForumSharingManagerImpl extends BdfIncomingMessageHook
|
|||||||
throw new DbException();
|
throw new DbException();
|
||||||
}
|
}
|
||||||
|
|
||||||
private BdfDictionary getSessionStateForLeaving(Transaction txn, Forum f,
|
private ForumSharingSessionState getSessionStateForLeaving(Transaction txn,
|
||||||
ContactId c) throws DbException, FormatException {
|
Forum f, ContactId c) throws DbException, FormatException {
|
||||||
|
|
||||||
Map<MessageId, BdfDictionary> map = clientHelper
|
Map<MessageId, BdfDictionary> map = clientHelper
|
||||||
.getMessageMetadataAsDictionary(txn, localGroup.getId());
|
.getMessageMetadataAsDictionary(txn, localGroup.getId());
|
||||||
for (Map.Entry<MessageId, BdfDictionary> m : map.entrySet()) {
|
for (Map.Entry<MessageId, BdfDictionary> m : map.entrySet()) {
|
||||||
BdfDictionary d = m.getValue();
|
BdfDictionary d = m.getValue();
|
||||||
try {
|
try {
|
||||||
|
ForumSharingSessionState s = fromBdfDictionary(d);
|
||||||
|
|
||||||
// check that this session is with the right contact
|
// check that this session is with the right contact
|
||||||
if (c.getInt() != d.getLong(CONTACT_ID)) continue;
|
if (!c.equals(s.getContactId())) continue;
|
||||||
// check that a forum get be left in current session
|
|
||||||
int intState = d.getLong(STATE).intValue();
|
|
||||||
if (d.getBoolean(IS_SHARER)) {
|
|
||||||
SharerProtocolState state =
|
|
||||||
SharerProtocolState.fromValue(intState);
|
|
||||||
if (state.next(SharerAction.LOCAL_LEAVE) ==
|
|
||||||
SharerProtocolState.ERROR) continue;
|
|
||||||
} else {
|
|
||||||
InviteeProtocolState state = InviteeProtocolState
|
|
||||||
.fromValue(intState);
|
|
||||||
if (state.next(InviteeAction.LOCAL_LEAVE) ==
|
|
||||||
InviteeProtocolState.ERROR) continue;
|
|
||||||
}
|
|
||||||
// check that this state actually concerns this forum
|
// check that this state actually concerns this forum
|
||||||
String name = d.getString(FORUM_NAME);
|
if (!s.getForumName().equals(f.getName()) ||
|
||||||
byte[] salt = d.getRaw(FORUM_SALT);
|
!Arrays.equals(s.getForumSalt(), f.getSalt())) {
|
||||||
if (name.equals(f.getName()) &&
|
continue;
|
||||||
Arrays.equals(salt, f.getSalt())) {
|
}
|
||||||
// TODO what happens when there is more than one invitation?
|
|
||||||
return d;
|
// check that a forum get be left in current session
|
||||||
|
if (s instanceof SharerSessionState) {
|
||||||
|
SharerSessionState state = (SharerSessionState) s;
|
||||||
|
SharerSessionState.State nextState =
|
||||||
|
state.getState().next(Action.LOCAL_LEAVE);
|
||||||
|
if (nextState != SharerSessionState.State.ERROR) {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
InviteeSessionState state = (InviteeSessionState) s;
|
||||||
|
InviteeSessionState.State nextState = state.getState()
|
||||||
|
.next(InviteeSessionState.Action.LOCAL_LEAVE);
|
||||||
|
if (nextState != InviteeSessionState.State.ERROR) {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (FormatException e) {
|
} catch (FormatException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
@@ -646,20 +644,20 @@ class ForumSharingManagerImpl extends BdfIncomingMessageHook
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void processStateUpdate(Transaction txn, MessageId messageId,
|
private void processStateUpdate(Transaction txn, MessageId messageId,
|
||||||
StateUpdate<BdfDictionary, BdfDictionary> result)
|
StateUpdate<ForumSharingSessionState, BaseMessage> result)
|
||||||
throws DbException, FormatException {
|
throws DbException, FormatException {
|
||||||
|
|
||||||
// perform actions based on new local state
|
// perform actions based on new local state
|
||||||
performTasks(txn, result.localState);
|
performTasks(txn, result.localState);
|
||||||
|
|
||||||
// save new local state
|
// save new local state
|
||||||
MessageId storageId =
|
MessageId storageId = result.localState.getStorageId();
|
||||||
new MessageId(result.localState.getRaw(STORAGE_ID));
|
clientHelper.mergeMessageMetadata(txn, storageId,
|
||||||
clientHelper.mergeMessageMetadata(txn, storageId, result.localState);
|
result.localState.toBdfDictionary());
|
||||||
|
|
||||||
// send messages
|
// send messages
|
||||||
for (BdfDictionary d : result.toSend) {
|
for (BaseMessage msg : result.toSend) {
|
||||||
sendMessage(txn, d);
|
sendMessage(txn, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
// broadcast events
|
// broadcast events
|
||||||
@@ -677,24 +675,47 @@ class ForumSharingManagerImpl extends BdfIncomingMessageHook
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void performTasks(Transaction txn, BdfDictionary localState)
|
private void processSharerStateUpdate(Transaction txn, MessageId messageId,
|
||||||
|
StateUpdate<SharerSessionState, BaseMessage> result)
|
||||||
|
throws DbException, FormatException {
|
||||||
|
|
||||||
|
StateUpdate<ForumSharingSessionState, BaseMessage> r =
|
||||||
|
new StateUpdate<ForumSharingSessionState, BaseMessage>(
|
||||||
|
result.deleteMessage, result.deleteState,
|
||||||
|
result.localState, result.toSend, result.toBroadcast);
|
||||||
|
|
||||||
|
processStateUpdate(txn, messageId, r);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processInviteeStateUpdate(Transaction txn, MessageId messageId,
|
||||||
|
StateUpdate<InviteeSessionState, BaseMessage> result)
|
||||||
|
throws DbException, FormatException {
|
||||||
|
|
||||||
|
StateUpdate<ForumSharingSessionState, BaseMessage> r =
|
||||||
|
new StateUpdate<ForumSharingSessionState, BaseMessage>(
|
||||||
|
result.deleteMessage, result.deleteState,
|
||||||
|
result.localState, result.toSend, result.toBroadcast);
|
||||||
|
|
||||||
|
processStateUpdate(txn, messageId, r);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void performTasks(Transaction txn, ForumSharingSessionState localState)
|
||||||
throws FormatException, DbException {
|
throws FormatException, DbException {
|
||||||
|
|
||||||
if (!localState.containsKey(TASK)) return;
|
if (localState.getTask() == -1) return;
|
||||||
|
|
||||||
// remember task and remove it from localState
|
// remember task and remove it from localState
|
||||||
long task = localState.getLong(TASK);
|
long task = localState.getTask();
|
||||||
localState.put(TASK, BdfDictionary.NULL_VALUE);
|
localState.setTask(-1);
|
||||||
|
|
||||||
// get group ID for later
|
// get group ID for later
|
||||||
GroupId groupId = new GroupId(localState.getRaw(GROUP_ID));
|
GroupId groupId = localState.getGroupId();
|
||||||
// get contact ID for later
|
// get contact ID for later
|
||||||
ContactId contactId =
|
ContactId contactId = localState.getContactId();
|
||||||
new ContactId(localState.getLong(CONTACT_ID).intValue());
|
|
||||||
|
|
||||||
// get forum for later
|
// get forum for later
|
||||||
String name = localState.getString(FORUM_NAME);
|
String name = localState.getForumName();
|
||||||
byte[] salt = localState.getRaw(FORUM_SALT);
|
byte[] salt = localState.getForumSalt();
|
||||||
Forum f = forumFactory.createForum(name, salt);
|
Forum f = forumFactory.createForum(name, salt);
|
||||||
|
|
||||||
// perform tasks
|
// perform tasks
|
||||||
@@ -728,50 +749,23 @@ class ForumSharingManagerImpl extends BdfIncomingMessageHook
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendMessage(Transaction txn, BdfDictionary m)
|
private void sendMessage(Transaction txn, BaseMessage m)
|
||||||
throws FormatException, DbException {
|
throws FormatException, DbException {
|
||||||
|
|
||||||
BdfList list = encodeMessage(m);
|
byte[] body = clientHelper.toByteArray(m.toBdfList());
|
||||||
byte[] body = clientHelper.toByteArray(list);
|
Group group = db.getGroup(txn, m.getGroupId());
|
||||||
GroupId groupId = new GroupId(m.getRaw(GROUP_ID));
|
|
||||||
Group group = db.getGroup(txn, groupId);
|
|
||||||
long timestamp = clock.currentTimeMillis();
|
long timestamp = clock.currentTimeMillis();
|
||||||
|
|
||||||
// add message itself as metadata
|
// add message itself as metadata
|
||||||
m.put(LOCAL, true);
|
BdfDictionary d = m.toBdfDictionary();
|
||||||
m.put(TIME, timestamp);
|
d.put(LOCAL, true);
|
||||||
Metadata meta = metadataEncoder.encode(m);
|
d.put(TIME, timestamp);
|
||||||
|
Metadata meta = metadataEncoder.encode(d);
|
||||||
|
|
||||||
messageQueueManager
|
messageQueueManager
|
||||||
.sendMessage(txn, group, timestamp, body, meta);
|
.sendMessage(txn, group, timestamp, body, meta);
|
||||||
}
|
}
|
||||||
|
|
||||||
private BdfList encodeMessage(BdfDictionary m) throws FormatException {
|
|
||||||
long type = m.getLong(TYPE);
|
|
||||||
|
|
||||||
BdfList list;
|
|
||||||
if (type == SHARE_MSG_TYPE_INVITATION) {
|
|
||||||
list = BdfList.of(type,
|
|
||||||
m.getRaw(SESSION_ID),
|
|
||||||
m.getString(FORUM_NAME),
|
|
||||||
m.getRaw(FORUM_SALT)
|
|
||||||
);
|
|
||||||
String msg = m.getOptionalString(INVITATION_MSG);
|
|
||||||
if (msg != null) list.add(msg);
|
|
||||||
} else if (type == SHARE_MSG_TYPE_ACCEPT) {
|
|
||||||
list = BdfList.of(type, m.getRaw(SESSION_ID));
|
|
||||||
} else if (type == SHARE_MSG_TYPE_DECLINE) {
|
|
||||||
list = BdfList.of(type, m.getRaw(SESSION_ID));
|
|
||||||
} else if (type == SHARE_MSG_TYPE_LEAVE) {
|
|
||||||
list = BdfList.of(type, m.getRaw(SESSION_ID));
|
|
||||||
} else if (type == SHARE_MSG_TYPE_ABORT) {
|
|
||||||
list = BdfList.of(type, m.getRaw(SESSION_ID));
|
|
||||||
} else {
|
|
||||||
throw new FormatException();
|
|
||||||
}
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Group getContactGroup(Contact c) {
|
private Group getContactGroup(Contact c) {
|
||||||
return privateGroupFactory.createPrivateGroup(CLIENT_ID, c);
|
return privateGroupFactory.createPrivateGroup(CLIENT_ID, c);
|
||||||
}
|
}
|
||||||
@@ -786,17 +780,18 @@ class ForumSharingManagerImpl extends BdfIncomingMessageHook
|
|||||||
private void leaveForum(Transaction txn, ContactId c, Forum f)
|
private void leaveForum(Transaction txn, ContactId c, Forum f)
|
||||||
throws DbException, FormatException {
|
throws DbException, FormatException {
|
||||||
|
|
||||||
BdfDictionary state = getSessionStateForLeaving(txn, f, c);
|
ForumSharingSessionState state = getSessionStateForLeaving(txn, f, c);
|
||||||
BdfDictionary action = new BdfDictionary();
|
if (state instanceof SharerSessionState) {
|
||||||
action.put(TYPE, SHARE_MSG_TYPE_LEAVE);
|
Action action = Action.LOCAL_LEAVE;
|
||||||
if (state.getBoolean(IS_SHARER)) {
|
|
||||||
SharerEngine engine = new SharerEngine();
|
SharerEngine engine = new SharerEngine();
|
||||||
processStateUpdate(txn, null,
|
processSharerStateUpdate(txn, null,
|
||||||
engine.onLocalAction(state, action));
|
engine.onLocalAction((SharerSessionState) state, action));
|
||||||
} else {
|
} else {
|
||||||
|
InviteeSessionState.Action action =
|
||||||
|
InviteeSessionState.Action.LOCAL_LEAVE;
|
||||||
InviteeEngine engine = new InviteeEngine(forumFactory);
|
InviteeEngine engine = new InviteeEngine(forumFactory);
|
||||||
processStateUpdate(txn, null,
|
processInviteeStateUpdate(txn, null,
|
||||||
engine.onLocalAction(state, action));
|
engine.onLocalAction((InviteeSessionState) state, action));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,119 @@
|
|||||||
|
package org.briarproject.forum;
|
||||||
|
|
||||||
|
import org.briarproject.api.FormatException;
|
||||||
|
import org.briarproject.api.clients.SessionId;
|
||||||
|
import org.briarproject.api.contact.ContactId;
|
||||||
|
import org.briarproject.api.data.BdfDictionary;
|
||||||
|
import org.briarproject.api.sync.GroupId;
|
||||||
|
import org.briarproject.api.sync.MessageId;
|
||||||
|
|
||||||
|
import static org.briarproject.api.forum.ForumConstants.CONTACT_ID;
|
||||||
|
import static org.briarproject.api.forum.ForumConstants.FORUM_ID;
|
||||||
|
import static org.briarproject.api.forum.ForumConstants.FORUM_NAME;
|
||||||
|
import static org.briarproject.api.forum.ForumConstants.FORUM_SALT;
|
||||||
|
import static org.briarproject.api.forum.ForumConstants.GROUP_ID;
|
||||||
|
import static org.briarproject.api.forum.ForumConstants.IS_SHARER;
|
||||||
|
import static org.briarproject.api.forum.ForumConstants.SESSION_ID;
|
||||||
|
import static org.briarproject.api.forum.ForumConstants.STATE;
|
||||||
|
import static org.briarproject.api.forum.ForumConstants.STORAGE_ID;
|
||||||
|
|
||||||
|
// This class is not thread-safe
|
||||||
|
public abstract class ForumSharingSessionState {
|
||||||
|
|
||||||
|
private final SessionId sessionId;
|
||||||
|
private final MessageId storageId;
|
||||||
|
private final GroupId groupId;
|
||||||
|
private final ContactId contactId;
|
||||||
|
private final GroupId forumId;
|
||||||
|
private final String forumName;
|
||||||
|
private final byte[] forumSalt;
|
||||||
|
private int task = -1; // TODO get rid of task, see #376
|
||||||
|
|
||||||
|
public ForumSharingSessionState(SessionId sessionId, MessageId storageId,
|
||||||
|
GroupId groupId, ContactId contactId, GroupId forumId,
|
||||||
|
String forumName, byte[] forumSalt) {
|
||||||
|
|
||||||
|
this.sessionId = sessionId;
|
||||||
|
this.storageId = storageId;
|
||||||
|
this.groupId = groupId;
|
||||||
|
this.contactId = contactId;
|
||||||
|
this.forumId = forumId;
|
||||||
|
this.forumName = forumName;
|
||||||
|
this.forumSalt = forumSalt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ForumSharingSessionState fromBdfDictionary(BdfDictionary d)
|
||||||
|
throws FormatException{
|
||||||
|
|
||||||
|
SessionId sessionId = new SessionId(d.getRaw(SESSION_ID));
|
||||||
|
MessageId messageId = new MessageId(d.getRaw(STORAGE_ID));
|
||||||
|
GroupId groupId = new GroupId(d.getRaw(GROUP_ID));
|
||||||
|
ContactId contactId = new ContactId(d.getLong(CONTACT_ID).intValue());
|
||||||
|
GroupId forumId = new GroupId(d.getRaw(FORUM_ID));
|
||||||
|
String forumName = d.getString(FORUM_NAME);
|
||||||
|
byte[] forumSalt = d.getRaw(FORUM_SALT);
|
||||||
|
|
||||||
|
int intState = d.getLong(STATE).intValue();
|
||||||
|
if (d.getBoolean(IS_SHARER)) {
|
||||||
|
SharerSessionState.State state =
|
||||||
|
SharerSessionState.State.fromValue(intState);
|
||||||
|
return new SharerSessionState(sessionId, messageId, groupId, state,
|
||||||
|
contactId, forumId, forumName, forumSalt);
|
||||||
|
} else {
|
||||||
|
InviteeSessionState.State state =
|
||||||
|
InviteeSessionState.State.fromValue(intState);
|
||||||
|
return new InviteeSessionState(sessionId, messageId, groupId, state,
|
||||||
|
contactId, forumId, forumName, forumSalt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public BdfDictionary toBdfDictionary() {
|
||||||
|
BdfDictionary d = new BdfDictionary();
|
||||||
|
d.put(SESSION_ID, getSessionId());
|
||||||
|
d.put(STORAGE_ID, getStorageId());
|
||||||
|
d.put(GROUP_ID, getGroupId());
|
||||||
|
d.put(CONTACT_ID, getContactId().getInt());
|
||||||
|
d.put(FORUM_ID, getForumId());
|
||||||
|
d.put(FORUM_NAME, getForumName());
|
||||||
|
d.put(FORUM_SALT, getForumSalt());
|
||||||
|
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SessionId getSessionId() {
|
||||||
|
return sessionId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MessageId getStorageId() {
|
||||||
|
return storageId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GroupId getGroupId() {
|
||||||
|
return groupId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ContactId getContactId() {
|
||||||
|
return contactId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GroupId getForumId() {
|
||||||
|
return forumId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getForumName() {
|
||||||
|
return forumName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getForumSalt() {
|
||||||
|
return forumSalt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTask(int task) {
|
||||||
|
this.task = task;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getTask() {
|
||||||
|
return task;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -73,7 +73,6 @@ class ForumSharingValidator extends BdfMessageValidator {
|
|||||||
// Return the metadata
|
// Return the metadata
|
||||||
d.put(TYPE, type);
|
d.put(TYPE, type);
|
||||||
d.put(SESSION_ID, id);
|
d.put(SESSION_ID, id);
|
||||||
d.put(GROUP_ID, m.getGroupId());
|
|
||||||
d.put(LOCAL, false);
|
d.put(LOCAL, false);
|
||||||
d.put(TIME, m.getTimestamp());
|
d.put(TIME, m.getTimestamp());
|
||||||
return d;
|
return d;
|
||||||
|
|||||||
@@ -3,51 +3,42 @@ package org.briarproject.forum;
|
|||||||
import org.briarproject.api.FormatException;
|
import org.briarproject.api.FormatException;
|
||||||
import org.briarproject.api.clients.ProtocolEngine;
|
import org.briarproject.api.clients.ProtocolEngine;
|
||||||
import org.briarproject.api.contact.ContactId;
|
import org.briarproject.api.contact.ContactId;
|
||||||
import org.briarproject.api.data.BdfDictionary;
|
|
||||||
import org.briarproject.api.data.BdfEntry;
|
|
||||||
import org.briarproject.api.event.Event;
|
import org.briarproject.api.event.Event;
|
||||||
import org.briarproject.api.event.ForumInvitationReceivedEvent;
|
import org.briarproject.api.event.ForumInvitationReceivedEvent;
|
||||||
import org.briarproject.api.forum.Forum;
|
import org.briarproject.api.forum.Forum;
|
||||||
import org.briarproject.api.forum.ForumFactory;
|
import org.briarproject.api.forum.ForumFactory;
|
||||||
import org.briarproject.api.forum.InviteeAction;
|
|
||||||
import org.briarproject.api.forum.InviteeProtocolState;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
import static org.briarproject.api.forum.ForumConstants.CONTACT_ID;
|
|
||||||
import static org.briarproject.api.forum.ForumConstants.FORUM_NAME;
|
|
||||||
import static org.briarproject.api.forum.ForumConstants.FORUM_SALT;
|
|
||||||
import static org.briarproject.api.forum.ForumConstants.GROUP_ID;
|
|
||||||
import static org.briarproject.api.forum.ForumConstants.SESSION_ID;
|
|
||||||
import static org.briarproject.api.forum.ForumConstants.SHARE_MSG_TYPE_ABORT;
|
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_ACCEPT;
|
||||||
import static org.briarproject.api.forum.ForumConstants.SHARE_MSG_TYPE_DECLINE;
|
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_INVITATION;
|
||||||
import static org.briarproject.api.forum.ForumConstants.SHARE_MSG_TYPE_LEAVE;
|
import static org.briarproject.api.forum.ForumConstants.SHARE_MSG_TYPE_LEAVE;
|
||||||
import static org.briarproject.api.forum.ForumConstants.STATE;
|
|
||||||
import static org.briarproject.api.forum.ForumConstants.TASK;
|
|
||||||
import static org.briarproject.api.forum.ForumConstants.TASK_ADD_FORUM_TO_LIST_SHARED_WITH_US;
|
import static org.briarproject.api.forum.ForumConstants.TASK_ADD_FORUM_TO_LIST_SHARED_WITH_US;
|
||||||
import static org.briarproject.api.forum.ForumConstants.TASK_ADD_SHARED_FORUM;
|
import static org.briarproject.api.forum.ForumConstants.TASK_ADD_SHARED_FORUM;
|
||||||
import static org.briarproject.api.forum.ForumConstants.TASK_REMOVE_FORUM_FROM_LIST_SHARED_WITH_US;
|
import static org.briarproject.api.forum.ForumConstants.TASK_REMOVE_FORUM_FROM_LIST_SHARED_WITH_US;
|
||||||
import static org.briarproject.api.forum.ForumConstants.TASK_UNSHARE_FORUM_SHARED_WITH_US;
|
import static org.briarproject.api.forum.ForumConstants.TASK_UNSHARE_FORUM_SHARED_WITH_US;
|
||||||
import static org.briarproject.api.forum.ForumConstants.TYPE;
|
import static org.briarproject.api.forum.ForumSharingMessage.SimpleMessage;
|
||||||
import static org.briarproject.api.forum.InviteeAction.LOCAL_ABORT;
|
import static org.briarproject.api.forum.ForumSharingMessage.BaseMessage;
|
||||||
import static org.briarproject.api.forum.InviteeAction.LOCAL_ACCEPT;
|
import static org.briarproject.forum.InviteeSessionState.Action;
|
||||||
import static org.briarproject.api.forum.InviteeAction.LOCAL_DECLINE;
|
import static org.briarproject.forum.InviteeSessionState.Action.LOCAL_ABORT;
|
||||||
import static org.briarproject.api.forum.InviteeAction.LOCAL_LEAVE;
|
import static org.briarproject.forum.InviteeSessionState.Action.LOCAL_ACCEPT;
|
||||||
import static org.briarproject.api.forum.InviteeAction.REMOTE_INVITATION;
|
import static org.briarproject.forum.InviteeSessionState.Action.LOCAL_DECLINE;
|
||||||
import static org.briarproject.api.forum.InviteeAction.REMOTE_LEAVE;
|
import static org.briarproject.forum.InviteeSessionState.Action.LOCAL_LEAVE;
|
||||||
import static org.briarproject.api.forum.InviteeProtocolState.ERROR;
|
import static org.briarproject.forum.InviteeSessionState.Action.REMOTE_INVITATION;
|
||||||
import static org.briarproject.api.forum.InviteeProtocolState.FINISHED;
|
import static org.briarproject.forum.InviteeSessionState.Action.REMOTE_LEAVE;
|
||||||
import static org.briarproject.api.forum.InviteeProtocolState.LEFT;
|
import static org.briarproject.forum.InviteeSessionState.State;
|
||||||
|
import static org.briarproject.forum.InviteeSessionState.State.ERROR;
|
||||||
|
import static org.briarproject.forum.InviteeSessionState.State.FINISHED;
|
||||||
|
import static org.briarproject.forum.InviteeSessionState.State.LEFT;
|
||||||
|
|
||||||
public class InviteeEngine
|
public class InviteeEngine
|
||||||
implements ProtocolEngine<BdfDictionary, BdfDictionary, BdfDictionary> {
|
implements ProtocolEngine<Action, InviteeSessionState, BaseMessage> {
|
||||||
|
|
||||||
private final ForumFactory forumFactory;
|
private final ForumFactory forumFactory;
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
@@ -58,16 +49,13 @@ public class InviteeEngine
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public StateUpdate<BdfDictionary, BdfDictionary> onLocalAction(
|
public StateUpdate<InviteeSessionState, BaseMessage> onLocalAction(
|
||||||
BdfDictionary localState, BdfDictionary localAction) {
|
InviteeSessionState localState, Action action) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
InviteeProtocolState currentState =
|
State currentState = localState.getState();
|
||||||
getState(localState.getLong(STATE));
|
State nextState = currentState.next(action);
|
||||||
long type = localAction.getLong(TYPE);
|
localState.setState(nextState);
|
||||||
InviteeAction action = InviteeAction.getLocal(type);
|
|
||||||
InviteeProtocolState nextState = currentState.next(action);
|
|
||||||
localState.put(STATE, nextState.getValue());
|
|
||||||
|
|
||||||
if (action == LOCAL_ABORT && currentState != ERROR) {
|
if (action == LOCAL_ABORT && currentState != ERROR) {
|
||||||
return abortSession(currentState, localState);
|
return abortSession(currentState, localState);
|
||||||
@@ -80,37 +68,34 @@ public class InviteeEngine
|
|||||||
}
|
}
|
||||||
return noUpdate(localState, true);
|
return noUpdate(localState, true);
|
||||||
}
|
}
|
||||||
List<BdfDictionary> messages;
|
List<BaseMessage> messages;
|
||||||
List<Event> events = Collections.emptyList();
|
List<Event> events = Collections.emptyList();
|
||||||
|
|
||||||
if (action == LOCAL_ACCEPT || action == LOCAL_DECLINE) {
|
if (action == LOCAL_ACCEPT || action == LOCAL_DECLINE) {
|
||||||
BdfDictionary msg = BdfDictionary.of(
|
BaseMessage msg;
|
||||||
new BdfEntry(SESSION_ID, localState.getRaw(SESSION_ID)),
|
|
||||||
new BdfEntry(GROUP_ID, localState.getRaw(GROUP_ID))
|
|
||||||
);
|
|
||||||
if (action == LOCAL_ACCEPT) {
|
if (action == LOCAL_ACCEPT) {
|
||||||
localState.put(TASK, TASK_ADD_SHARED_FORUM);
|
localState.setTask(TASK_ADD_SHARED_FORUM);
|
||||||
msg.put(TYPE, SHARE_MSG_TYPE_ACCEPT);
|
msg = new SimpleMessage(SHARE_MSG_TYPE_ACCEPT,
|
||||||
|
localState.getGroupId(), localState.getSessionId());
|
||||||
} else {
|
} else {
|
||||||
localState.put(TASK,
|
localState.setTask(
|
||||||
TASK_REMOVE_FORUM_FROM_LIST_SHARED_WITH_US);
|
TASK_REMOVE_FORUM_FROM_LIST_SHARED_WITH_US);
|
||||||
msg.put(TYPE, SHARE_MSG_TYPE_DECLINE);
|
msg = new SimpleMessage(SHARE_MSG_TYPE_DECLINE,
|
||||||
|
localState.getGroupId(), localState.getSessionId());
|
||||||
}
|
}
|
||||||
messages = Collections.singletonList(msg);
|
messages = Collections.singletonList(msg);
|
||||||
logLocalAction(currentState, localState, msg);
|
logLocalAction(currentState, localState, msg);
|
||||||
}
|
}
|
||||||
else if (action == LOCAL_LEAVE) {
|
else if (action == LOCAL_LEAVE) {
|
||||||
BdfDictionary msg = new BdfDictionary();
|
BaseMessage msg = new SimpleMessage(SHARE_MSG_TYPE_LEAVE,
|
||||||
msg.put(TYPE, SHARE_MSG_TYPE_LEAVE);
|
localState.getGroupId(), localState.getSessionId());
|
||||||
msg.put(SESSION_ID, localState.getRaw(SESSION_ID));
|
|
||||||
msg.put(GROUP_ID, localState.getRaw(GROUP_ID));
|
|
||||||
messages = Collections.singletonList(msg);
|
messages = Collections.singletonList(msg);
|
||||||
logLocalAction(currentState, localState, msg);
|
logLocalAction(currentState, localState, msg);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
throw new IllegalArgumentException("Unknown Local Action");
|
throw new IllegalArgumentException("Unknown Local Action");
|
||||||
}
|
}
|
||||||
return new StateUpdate<BdfDictionary, BdfDictionary>(false,
|
return new StateUpdate<InviteeSessionState, BaseMessage>(false,
|
||||||
false, localState, messages, events);
|
false, localState, messages, events);
|
||||||
} catch (FormatException e) {
|
} catch (FormatException e) {
|
||||||
throw new IllegalArgumentException(e);
|
throw new IllegalArgumentException(e);
|
||||||
@@ -118,18 +103,16 @@ public class InviteeEngine
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public StateUpdate<BdfDictionary, BdfDictionary> onMessageReceived(
|
public StateUpdate<InviteeSessionState, BaseMessage> onMessageReceived(
|
||||||
BdfDictionary localState, BdfDictionary msg) {
|
InviteeSessionState localState, BaseMessage msg) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
InviteeProtocolState currentState =
|
State currentState = localState.getState();
|
||||||
getState(localState.getLong(STATE));
|
Action action = Action.getRemote(msg.getType());
|
||||||
long type = msg.getLong(TYPE);
|
State nextState = currentState.next(action);
|
||||||
InviteeAction action = InviteeAction.getRemote(type);
|
localState.setState(nextState);
|
||||||
InviteeProtocolState nextState = currentState.next(action);
|
|
||||||
localState.put(STATE, nextState.getValue());
|
|
||||||
|
|
||||||
logMessageReceived(currentState, nextState, type, msg);
|
logMessageReceived(currentState, nextState, msg.getType(), msg);
|
||||||
|
|
||||||
if (nextState == ERROR) {
|
if (nextState == ERROR) {
|
||||||
if (currentState != ERROR) {
|
if (currentState != ERROR) {
|
||||||
@@ -139,7 +122,7 @@ public class InviteeEngine
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
List<BdfDictionary> messages = Collections.emptyList();
|
List<BaseMessage> messages = Collections.emptyList();
|
||||||
List<Event> events = Collections.emptyList();
|
List<Event> events = Collections.emptyList();
|
||||||
boolean deleteMsg = false;
|
boolean deleteMsg = false;
|
||||||
|
|
||||||
@@ -149,7 +132,7 @@ public class InviteeEngine
|
|||||||
}
|
}
|
||||||
// the sharer left the forum she had shared with us
|
// the sharer left the forum she had shared with us
|
||||||
else if (action == REMOTE_LEAVE && currentState == FINISHED) {
|
else if (action == REMOTE_LEAVE && currentState == FINISHED) {
|
||||||
localState.put(TASK, TASK_UNSHARE_FORUM_SHARED_WITH_US);
|
localState.setTask(TASK_UNSHARE_FORUM_SHARED_WITH_US);
|
||||||
}
|
}
|
||||||
else if (currentState == FINISHED) {
|
else if (currentState == FINISHED) {
|
||||||
// ignore and delete messages coming in while in that state
|
// ignore and delete messages coming in while in that state
|
||||||
@@ -158,74 +141,65 @@ public class InviteeEngine
|
|||||||
}
|
}
|
||||||
// the sharer left the forum before we couldn't even respond
|
// the sharer left the forum before we couldn't even respond
|
||||||
else if (action == REMOTE_LEAVE) {
|
else if (action == REMOTE_LEAVE) {
|
||||||
localState.put(TASK, TASK_REMOVE_FORUM_FROM_LIST_SHARED_WITH_US);
|
localState.setTask(TASK_REMOVE_FORUM_FROM_LIST_SHARED_WITH_US);
|
||||||
}
|
}
|
||||||
// we have just received our invitation
|
// we have just received our invitation
|
||||||
else if (action == REMOTE_INVITATION) {
|
else if (action == REMOTE_INVITATION) {
|
||||||
localState.put(TASK, TASK_ADD_FORUM_TO_LIST_SHARED_WITH_US);
|
|
||||||
Forum forum = forumFactory
|
Forum forum = forumFactory
|
||||||
.createForum(localState.getString(FORUM_NAME),
|
.createForum(localState.getForumName(),
|
||||||
localState.getRaw(FORUM_SALT));
|
localState.getForumSalt());
|
||||||
ContactId contactId = new ContactId(
|
localState.setTask(TASK_ADD_FORUM_TO_LIST_SHARED_WITH_US);
|
||||||
localState.getLong(CONTACT_ID).intValue());
|
ContactId contactId = localState.getContactId();
|
||||||
Event event = new ForumInvitationReceivedEvent(forum, contactId);
|
Event event = new ForumInvitationReceivedEvent(forum, contactId);
|
||||||
events = Collections.singletonList(event);
|
events = Collections.singletonList(event);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
throw new IllegalArgumentException("Bad state");
|
throw new IllegalArgumentException("Bad state");
|
||||||
}
|
}
|
||||||
return new StateUpdate<BdfDictionary, BdfDictionary>(deleteMsg,
|
return new StateUpdate<InviteeSessionState, BaseMessage>(deleteMsg,
|
||||||
false, localState, messages, events);
|
false, localState, messages, events);
|
||||||
} catch (FormatException e) {
|
} catch (FormatException e) {
|
||||||
throw new IllegalArgumentException(e);
|
throw new IllegalArgumentException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void logLocalAction(InviteeProtocolState state,
|
private void logLocalAction(State state,
|
||||||
BdfDictionary localState, BdfDictionary msg) {
|
InviteeSessionState localState, BaseMessage msg) {
|
||||||
|
|
||||||
if (!LOG.isLoggable(INFO)) return;
|
if (!LOG.isLoggable(INFO)) return;
|
||||||
|
|
||||||
String a = "response";
|
String a = "response";
|
||||||
if (msg.getLong(TYPE, -1L) == SHARE_MSG_TYPE_LEAVE) a = "leave";
|
if (msg.getType() == SHARE_MSG_TYPE_LEAVE) a = "leave";
|
||||||
|
|
||||||
try {
|
LOG.info("Sending " + a + " in state " + state.name() +
|
||||||
LOG.info("Sending " + a + " in state " + state.name() +
|
" with session ID " +
|
||||||
" with session ID " +
|
msg.getSessionId().hashCode() + " in group " +
|
||||||
Arrays.hashCode(msg.getRaw(SESSION_ID)) + " in group " +
|
msg.getGroupId().hashCode() + ". " +
|
||||||
Arrays.hashCode(msg.getRaw(GROUP_ID)) + ". " +
|
"Moving on to state " + localState.getState().name()
|
||||||
"Moving on to state " +
|
);
|
||||||
getState(localState.getLong(STATE)).name()
|
|
||||||
);
|
|
||||||
} catch (FormatException e) {
|
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void logMessageReceived(InviteeProtocolState currentState,
|
private void logMessageReceived(State currentState, State nextState,
|
||||||
InviteeProtocolState nextState, long type, BdfDictionary msg) {
|
long type, BaseMessage msg) {
|
||||||
|
|
||||||
if (!LOG.isLoggable(INFO)) return;
|
if (!LOG.isLoggable(INFO)) return;
|
||||||
|
|
||||||
try {
|
String t = "unknown";
|
||||||
String t = "unknown";
|
if (type == SHARE_MSG_TYPE_INVITATION) t = "INVITE";
|
||||||
if (type == SHARE_MSG_TYPE_INVITATION) t = "INVITE";
|
else if (type == SHARE_MSG_TYPE_LEAVE) t = "LEAVE";
|
||||||
else if (type == SHARE_MSG_TYPE_LEAVE) t = "LEAVE";
|
else if (type == SHARE_MSG_TYPE_ABORT) t = "ABORT";
|
||||||
else if (type == SHARE_MSG_TYPE_ABORT) t = "ABORT";
|
|
||||||
|
|
||||||
LOG.info("Received " + t + " in state " + currentState.name() +
|
LOG.info("Received " + t + " in state " + currentState.name() +
|
||||||
" with session ID " +
|
" with session ID " +
|
||||||
Arrays.hashCode(msg.getRaw(SESSION_ID)) + " in group " +
|
msg.getSessionId().hashCode() + " in group " +
|
||||||
Arrays.hashCode(msg.getRaw(GROUP_ID)) + ". " +
|
msg.getGroupId().hashCode() + ". " +
|
||||||
"Moving on to state " + nextState.name()
|
"Moving on to state " + nextState.name()
|
||||||
);
|
);
|
||||||
} catch (FormatException e) {
|
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public StateUpdate<BdfDictionary, BdfDictionary> onMessageDelivered(
|
public StateUpdate<InviteeSessionState, BaseMessage> onMessageDelivered(
|
||||||
BdfDictionary localState, BdfDictionary delivered) {
|
InviteeSessionState localState, BaseMessage delivered) {
|
||||||
try {
|
try {
|
||||||
return noUpdate(localState, false);
|
return noUpdate(localState, false);
|
||||||
} catch (FormatException e) {
|
} catch (FormatException e) {
|
||||||
@@ -234,38 +208,32 @@ public class InviteeEngine
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private InviteeProtocolState getState(Long state) {
|
private StateUpdate<InviteeSessionState, BaseMessage> abortSession(
|
||||||
return InviteeProtocolState.fromValue(state.intValue());
|
State currentState, InviteeSessionState localState)
|
||||||
}
|
|
||||||
|
|
||||||
private StateUpdate<BdfDictionary, BdfDictionary> abortSession(
|
|
||||||
InviteeProtocolState currentState, BdfDictionary localState)
|
|
||||||
throws FormatException {
|
throws FormatException {
|
||||||
|
|
||||||
if (LOG.isLoggable(WARNING)) {
|
if (LOG.isLoggable(WARNING)) {
|
||||||
LOG.warning("Aborting protocol session " +
|
LOG.warning("Aborting protocol session " +
|
||||||
Arrays.hashCode(localState.getRaw(SESSION_ID)) +
|
localState.getSessionId().hashCode() +
|
||||||
" in state " + currentState.name());
|
" in state " + currentState.name());
|
||||||
}
|
}
|
||||||
|
localState.setState(ERROR);
|
||||||
localState.put(STATE, ERROR.getValue());
|
BaseMessage msg =
|
||||||
BdfDictionary msg = new BdfDictionary();
|
new SimpleMessage(SHARE_MSG_TYPE_ABORT, localState.getGroupId(),
|
||||||
msg.put(TYPE, SHARE_MSG_TYPE_ABORT);
|
localState.getSessionId());
|
||||||
msg.put(SESSION_ID, localState.getRaw(SESSION_ID));
|
List<BaseMessage> messages = Collections.singletonList(msg);
|
||||||
msg.put(GROUP_ID, localState.getRaw(GROUP_ID));
|
|
||||||
List<BdfDictionary> messages = Collections.singletonList(msg);
|
|
||||||
|
|
||||||
List<Event> events = Collections.emptyList();
|
List<Event> events = Collections.emptyList();
|
||||||
|
|
||||||
return new StateUpdate<BdfDictionary, BdfDictionary>(false, false,
|
return new StateUpdate<InviteeSessionState, BaseMessage>(false, false,
|
||||||
localState, messages, events);
|
localState, messages, events);
|
||||||
}
|
}
|
||||||
|
|
||||||
private StateUpdate<BdfDictionary, BdfDictionary> noUpdate(
|
private StateUpdate<InviteeSessionState, BaseMessage> noUpdate(
|
||||||
BdfDictionary localState, boolean delete) throws FormatException {
|
InviteeSessionState localState, boolean delete) throws FormatException {
|
||||||
|
|
||||||
return new StateUpdate<BdfDictionary, BdfDictionary>(delete, false,
|
return new StateUpdate<InviteeSessionState, BaseMessage>(delete, false,
|
||||||
localState, Collections.<BdfDictionary>emptyList(),
|
localState, Collections.<BaseMessage>emptyList(),
|
||||||
Collections.<Event>emptyList());
|
Collections.<Event>emptyList());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
120
briar-core/src/org/briarproject/forum/InviteeSessionState.java
Normal file
120
briar-core/src/org/briarproject/forum/InviteeSessionState.java
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
package org.briarproject.forum;
|
||||||
|
|
||||||
|
import org.briarproject.api.clients.SessionId;
|
||||||
|
import org.briarproject.api.contact.ContactId;
|
||||||
|
import org.briarproject.api.data.BdfDictionary;
|
||||||
|
import org.briarproject.api.sync.GroupId;
|
||||||
|
import org.briarproject.api.sync.MessageId;
|
||||||
|
|
||||||
|
import static org.briarproject.api.forum.ForumConstants.IS_SHARER;
|
||||||
|
import static org.briarproject.api.forum.ForumConstants.SHARE_MSG_TYPE_ABORT;
|
||||||
|
import static org.briarproject.api.forum.ForumConstants.SHARE_MSG_TYPE_INVITATION;
|
||||||
|
import static org.briarproject.api.forum.ForumConstants.SHARE_MSG_TYPE_LEAVE;
|
||||||
|
import static org.briarproject.api.forum.ForumConstants.STATE;
|
||||||
|
import static org.briarproject.forum.InviteeSessionState.Action.LOCAL_ACCEPT;
|
||||||
|
import static org.briarproject.forum.InviteeSessionState.Action.LOCAL_DECLINE;
|
||||||
|
import static org.briarproject.forum.InviteeSessionState.Action.LOCAL_LEAVE;
|
||||||
|
import static org.briarproject.forum.InviteeSessionState.Action.REMOTE_INVITATION;
|
||||||
|
import static org.briarproject.forum.InviteeSessionState.Action.REMOTE_LEAVE;
|
||||||
|
|
||||||
|
// This class is not thread-safe
|
||||||
|
public class InviteeSessionState extends ForumSharingSessionState {
|
||||||
|
|
||||||
|
private State state;
|
||||||
|
|
||||||
|
public InviteeSessionState(SessionId sessionId, MessageId storageId,
|
||||||
|
GroupId groupId, State state, ContactId contactId, GroupId forumId,
|
||||||
|
String forumName, byte[] forumSalt) {
|
||||||
|
|
||||||
|
super(sessionId, storageId, groupId, contactId, forumId, forumName,
|
||||||
|
forumSalt);
|
||||||
|
this.state = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BdfDictionary toBdfDictionary() {
|
||||||
|
BdfDictionary d = super.toBdfDictionary();
|
||||||
|
d.put(STATE, getState().getValue());
|
||||||
|
d.put(IS_SHARER, false);
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setState(State state) {
|
||||||
|
this.state = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
public State getState() {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum State {
|
||||||
|
ERROR(0),
|
||||||
|
AWAIT_INVITATION(1) {
|
||||||
|
@Override
|
||||||
|
public State next(Action a) {
|
||||||
|
if (a == REMOTE_INVITATION) return AWAIT_LOCAL_RESPONSE;
|
||||||
|
return ERROR;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
AWAIT_LOCAL_RESPONSE(2) {
|
||||||
|
@Override
|
||||||
|
public State next(Action a) {
|
||||||
|
if (a == LOCAL_ACCEPT || a == LOCAL_DECLINE) return FINISHED;
|
||||||
|
if (a == REMOTE_LEAVE) return LEFT;
|
||||||
|
return ERROR;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
FINISHED(3) {
|
||||||
|
@Override
|
||||||
|
public State next(Action a) {
|
||||||
|
if (a == LOCAL_LEAVE || a == REMOTE_LEAVE) return LEFT;
|
||||||
|
return FINISHED;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
LEFT(4) {
|
||||||
|
@Override
|
||||||
|
public State next(Action a) {
|
||||||
|
if (a == LOCAL_LEAVE) return ERROR;
|
||||||
|
return LEFT;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private final int value;
|
||||||
|
|
||||||
|
State(int value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static State fromValue(int value) {
|
||||||
|
for (State s : values()) {
|
||||||
|
if (s.value == value) return s;
|
||||||
|
}
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public State next(Action a) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum Action {
|
||||||
|
LOCAL_ACCEPT,
|
||||||
|
LOCAL_DECLINE,
|
||||||
|
LOCAL_LEAVE,
|
||||||
|
LOCAL_ABORT,
|
||||||
|
REMOTE_INVITATION,
|
||||||
|
REMOTE_LEAVE,
|
||||||
|
REMOTE_ABORT;
|
||||||
|
|
||||||
|
public static Action 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -3,64 +3,52 @@ package org.briarproject.forum;
|
|||||||
import org.briarproject.api.FormatException;
|
import org.briarproject.api.FormatException;
|
||||||
import org.briarproject.api.clients.ProtocolEngine;
|
import org.briarproject.api.clients.ProtocolEngine;
|
||||||
import org.briarproject.api.contact.ContactId;
|
import org.briarproject.api.contact.ContactId;
|
||||||
import org.briarproject.api.data.BdfDictionary;
|
|
||||||
import org.briarproject.api.event.Event;
|
import org.briarproject.api.event.Event;
|
||||||
import org.briarproject.api.event.ForumInvitationResponseReceivedEvent;
|
import org.briarproject.api.event.ForumInvitationResponseReceivedEvent;
|
||||||
import org.briarproject.api.forum.SharerAction;
|
|
||||||
import org.briarproject.api.forum.SharerProtocolState;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
import static org.briarproject.api.forum.ForumConstants.CONTACT_ID;
|
|
||||||
import static org.briarproject.api.forum.ForumConstants.FORUM_NAME;
|
|
||||||
import static org.briarproject.api.forum.ForumConstants.FORUM_SALT;
|
|
||||||
import static org.briarproject.api.forum.ForumConstants.GROUP_ID;
|
|
||||||
import static org.briarproject.api.forum.ForumConstants.INVITATION_MSG;
|
|
||||||
import static org.briarproject.api.forum.ForumConstants.SESSION_ID;
|
|
||||||
import static org.briarproject.api.forum.ForumConstants.SHARE_MSG_TYPE_ABORT;
|
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_ACCEPT;
|
||||||
import static org.briarproject.api.forum.ForumConstants.SHARE_MSG_TYPE_DECLINE;
|
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;
|
import static org.briarproject.api.forum.ForumConstants.SHARE_MSG_TYPE_LEAVE;
|
||||||
import static org.briarproject.api.forum.ForumConstants.STATE;
|
|
||||||
import static org.briarproject.api.forum.ForumConstants.TASK;
|
|
||||||
import static org.briarproject.api.forum.ForumConstants.TASK_ADD_FORUM_TO_LIST_TO_BE_SHARED_BY_US;
|
import static org.briarproject.api.forum.ForumConstants.TASK_ADD_FORUM_TO_LIST_TO_BE_SHARED_BY_US;
|
||||||
import static org.briarproject.api.forum.ForumConstants.TASK_REMOVE_FORUM_FROM_LIST_TO_BE_SHARED_BY_US;
|
import static org.briarproject.api.forum.ForumConstants.TASK_REMOVE_FORUM_FROM_LIST_TO_BE_SHARED_BY_US;
|
||||||
import static org.briarproject.api.forum.ForumConstants.TASK_SHARE_FORUM;
|
import static org.briarproject.api.forum.ForumConstants.TASK_SHARE_FORUM;
|
||||||
import static org.briarproject.api.forum.ForumConstants.TASK_UNSHARE_FORUM_SHARED_BY_US;
|
import static org.briarproject.api.forum.ForumConstants.TASK_UNSHARE_FORUM_SHARED_BY_US;
|
||||||
import static org.briarproject.api.forum.ForumConstants.TYPE;
|
import static org.briarproject.api.forum.ForumSharingMessage.BaseMessage;
|
||||||
import static org.briarproject.api.forum.SharerAction.LOCAL_ABORT;
|
import static org.briarproject.api.forum.ForumSharingMessage.Invitation;
|
||||||
import static org.briarproject.api.forum.SharerAction.LOCAL_INVITATION;
|
import static org.briarproject.api.forum.ForumSharingMessage.SimpleMessage;
|
||||||
import static org.briarproject.api.forum.SharerAction.LOCAL_LEAVE;
|
import static org.briarproject.forum.SharerSessionState.Action;
|
||||||
import static org.briarproject.api.forum.SharerAction.REMOTE_ACCEPT;
|
import static org.briarproject.forum.SharerSessionState.Action.LOCAL_ABORT;
|
||||||
import static org.briarproject.api.forum.SharerAction.REMOTE_DECLINE;
|
import static org.briarproject.forum.SharerSessionState.Action.LOCAL_INVITATION;
|
||||||
import static org.briarproject.api.forum.SharerAction.REMOTE_LEAVE;
|
import static org.briarproject.forum.SharerSessionState.Action.LOCAL_LEAVE;
|
||||||
import static org.briarproject.api.forum.SharerProtocolState.ERROR;
|
import static org.briarproject.forum.SharerSessionState.Action.REMOTE_ACCEPT;
|
||||||
import static org.briarproject.api.forum.SharerProtocolState.FINISHED;
|
import static org.briarproject.forum.SharerSessionState.Action.REMOTE_DECLINE;
|
||||||
import static org.briarproject.api.forum.SharerProtocolState.LEFT;
|
import static org.briarproject.forum.SharerSessionState.Action.REMOTE_LEAVE;
|
||||||
|
import static org.briarproject.forum.SharerSessionState.State;
|
||||||
|
import static org.briarproject.forum.SharerSessionState.State.ERROR;
|
||||||
|
import static org.briarproject.forum.SharerSessionState.State.FINISHED;
|
||||||
|
import static org.briarproject.forum.SharerSessionState.State.LEFT;
|
||||||
|
|
||||||
public class SharerEngine
|
public class SharerEngine
|
||||||
implements ProtocolEngine<BdfDictionary, BdfDictionary, BdfDictionary> {
|
implements ProtocolEngine<Action, SharerSessionState, BaseMessage> {
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(SharerEngine.class.getName());
|
Logger.getLogger(SharerEngine.class.getName());
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public StateUpdate<BdfDictionary, BdfDictionary> onLocalAction(
|
public StateUpdate<SharerSessionState, BaseMessage> onLocalAction(
|
||||||
BdfDictionary localState, BdfDictionary localAction) {
|
SharerSessionState localState, Action action) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
SharerProtocolState currentState =
|
State currentState = localState.getState();
|
||||||
getState(localState.getLong(STATE));
|
State nextState = currentState.next(action);
|
||||||
long type = localAction.getLong(TYPE);
|
localState.setState(nextState);
|
||||||
SharerAction action = SharerAction.getLocal(type);
|
|
||||||
SharerProtocolState nextState = currentState.next(action);
|
|
||||||
localState.put(STATE, nextState.getValue());
|
|
||||||
|
|
||||||
if (action == LOCAL_ABORT && currentState != ERROR) {
|
if (action == LOCAL_ABORT && currentState != ERROR) {
|
||||||
return abortSession(currentState, localState);
|
return abortSession(currentState, localState);
|
||||||
@@ -73,38 +61,29 @@ public class SharerEngine
|
|||||||
}
|
}
|
||||||
return noUpdate(localState, true);
|
return noUpdate(localState, true);
|
||||||
}
|
}
|
||||||
List<BdfDictionary> messages;
|
List<BaseMessage> messages;
|
||||||
List<Event> events = Collections.emptyList();
|
List<Event> events = Collections.emptyList();
|
||||||
|
|
||||||
if (action == LOCAL_INVITATION) {
|
if (action == LOCAL_INVITATION) {
|
||||||
BdfDictionary msg = new BdfDictionary();
|
BaseMessage msg = new Invitation(localState.getGroupId(),
|
||||||
msg.put(TYPE, SHARE_MSG_TYPE_INVITATION);
|
localState.getSessionId(), localState.getForumName(),
|
||||||
msg.put(SESSION_ID, localState.getRaw(SESSION_ID));
|
localState.getForumSalt(), localState.getMessage());
|
||||||
msg.put(GROUP_ID, localState.getRaw(GROUP_ID));
|
|
||||||
msg.put(FORUM_NAME, localState.getString(FORUM_NAME));
|
|
||||||
msg.put(FORUM_SALT, localState.getRaw(FORUM_SALT));
|
|
||||||
if (localAction.containsKey(INVITATION_MSG)) {
|
|
||||||
msg.put(INVITATION_MSG,
|
|
||||||
localAction.getString(INVITATION_MSG));
|
|
||||||
}
|
|
||||||
messages = Collections.singletonList(msg);
|
messages = Collections.singletonList(msg);
|
||||||
logLocalAction(currentState, localState, msg);
|
logLocalAction(currentState, nextState, msg);
|
||||||
|
|
||||||
// remember that we offered to share this forum
|
// remember that we offered to share this forum
|
||||||
localState.put(TASK, TASK_ADD_FORUM_TO_LIST_TO_BE_SHARED_BY_US);
|
localState.setTask(TASK_ADD_FORUM_TO_LIST_TO_BE_SHARED_BY_US);
|
||||||
}
|
}
|
||||||
else if (action == LOCAL_LEAVE) {
|
else if (action == LOCAL_LEAVE) {
|
||||||
BdfDictionary msg = new BdfDictionary();
|
BaseMessage msg = new SimpleMessage(SHARE_MSG_TYPE_LEAVE,
|
||||||
msg.put(TYPE, SHARE_MSG_TYPE_LEAVE);
|
localState.getGroupId(), localState.getSessionId());
|
||||||
msg.put(SESSION_ID, localState.getRaw(SESSION_ID));
|
|
||||||
msg.put(GROUP_ID, localState.getRaw(GROUP_ID));
|
|
||||||
messages = Collections.singletonList(msg);
|
messages = Collections.singletonList(msg);
|
||||||
logLocalAction(currentState, localState, msg);
|
logLocalAction(currentState, nextState, msg);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
throw new IllegalArgumentException("Unknown Local Action");
|
throw new IllegalArgumentException("Unknown Local Action");
|
||||||
}
|
}
|
||||||
return new StateUpdate<BdfDictionary, BdfDictionary>(false,
|
return new StateUpdate<SharerSessionState, BaseMessage>(false,
|
||||||
false, localState, messages, events);
|
false, localState, messages, events);
|
||||||
} catch (FormatException e) {
|
} catch (FormatException e) {
|
||||||
throw new IllegalArgumentException(e);
|
throw new IllegalArgumentException(e);
|
||||||
@@ -112,18 +91,16 @@ public class SharerEngine
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public StateUpdate<BdfDictionary, BdfDictionary> onMessageReceived(
|
public StateUpdate<SharerSessionState, BaseMessage> onMessageReceived(
|
||||||
BdfDictionary localState, BdfDictionary msg) {
|
SharerSessionState localState, BaseMessage msg) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
SharerProtocolState currentState =
|
State currentState = localState.getState();
|
||||||
getState(localState.getLong(STATE));
|
Action action = Action.getRemote(msg.getType());
|
||||||
long type = msg.getLong(TYPE);
|
State nextState = currentState.next(action);
|
||||||
SharerAction action = SharerAction.getRemote(type);
|
localState.setState(nextState);
|
||||||
SharerProtocolState nextState = currentState.next(action);
|
|
||||||
localState.put(STATE, nextState.getValue());
|
|
||||||
|
|
||||||
logMessageReceived(currentState, nextState, type, msg);
|
logMessageReceived(currentState, nextState, msg.getType(), msg);
|
||||||
|
|
||||||
if (nextState == ERROR) {
|
if (nextState == ERROR) {
|
||||||
if (currentState != ERROR) {
|
if (currentState != ERROR) {
|
||||||
@@ -132,7 +109,7 @@ public class SharerEngine
|
|||||||
return noUpdate(localState, true);
|
return noUpdate(localState, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
List<BdfDictionary> messages = Collections.emptyList();
|
List<BaseMessage> messages = Collections.emptyList();
|
||||||
List<Event> events = Collections.emptyList();
|
List<Event> events = Collections.emptyList();
|
||||||
boolean deleteMsg = false;
|
boolean deleteMsg = false;
|
||||||
|
|
||||||
@@ -141,7 +118,7 @@ public class SharerEngine
|
|||||||
deleteMsg = true;
|
deleteMsg = true;
|
||||||
}
|
}
|
||||||
else if (action == REMOTE_LEAVE) {
|
else if (action == REMOTE_LEAVE) {
|
||||||
localState.put(TASK, TASK_UNSHARE_FORUM_SHARED_BY_US);
|
localState.setTask(TASK_UNSHARE_FORUM_SHARED_BY_US);
|
||||||
}
|
}
|
||||||
else if (currentState == FINISHED) {
|
else if (currentState == FINISHED) {
|
||||||
// ignore and delete messages coming in while in that state
|
// ignore and delete messages coming in while in that state
|
||||||
@@ -151,74 +128,65 @@ public class SharerEngine
|
|||||||
// we have sent our invitation and just got a response
|
// we have sent our invitation and just got a response
|
||||||
else if (action == REMOTE_ACCEPT || action == REMOTE_DECLINE) {
|
else if (action == REMOTE_ACCEPT || action == REMOTE_DECLINE) {
|
||||||
if (action == REMOTE_ACCEPT) {
|
if (action == REMOTE_ACCEPT) {
|
||||||
localState.put(TASK, TASK_SHARE_FORUM);
|
localState.setTask(TASK_SHARE_FORUM);
|
||||||
} else {
|
} else {
|
||||||
// this ensures that the forum can be shared again
|
// this ensures that the forum can be shared again
|
||||||
localState.put(TASK,
|
localState.setTask(
|
||||||
TASK_REMOVE_FORUM_FROM_LIST_TO_BE_SHARED_BY_US);
|
TASK_REMOVE_FORUM_FROM_LIST_TO_BE_SHARED_BY_US);
|
||||||
}
|
}
|
||||||
String name = localState.getString(FORUM_NAME);
|
String name = localState.getForumName();
|
||||||
ContactId c = new ContactId(
|
ContactId c = localState.getContactId();
|
||||||
localState.getLong(CONTACT_ID).intValue());
|
|
||||||
Event event = new ForumInvitationResponseReceivedEvent(name, c);
|
Event event = new ForumInvitationResponseReceivedEvent(name, c);
|
||||||
events = Collections.singletonList(event);
|
events = Collections.singletonList(event);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
throw new IllegalArgumentException("Bad state");
|
throw new IllegalArgumentException("Bad state");
|
||||||
}
|
}
|
||||||
return new StateUpdate<BdfDictionary, BdfDictionary>(deleteMsg,
|
return new StateUpdate<SharerSessionState, BaseMessage>(deleteMsg,
|
||||||
false, localState, messages, events);
|
false, localState, messages, events);
|
||||||
} catch (FormatException e) {
|
} catch (FormatException e) {
|
||||||
throw new IllegalArgumentException(e);
|
throw new IllegalArgumentException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void logLocalAction(SharerProtocolState state,
|
private void logLocalAction(State currentState, State nextState,
|
||||||
BdfDictionary localState, BdfDictionary msg) {
|
BaseMessage msg) {
|
||||||
|
|
||||||
if (!LOG.isLoggable(INFO)) return;
|
if (!LOG.isLoggable(INFO)) return;
|
||||||
|
|
||||||
String a = "invitation";
|
String a = "invitation";
|
||||||
if (msg.getLong(TYPE, -1L) == SHARE_MSG_TYPE_LEAVE) a = "leave";
|
if (msg.getType() == SHARE_MSG_TYPE_LEAVE) a = "leave";
|
||||||
|
|
||||||
try {
|
LOG.info("Sending " + a + " in state " + currentState.name() +
|
||||||
LOG.info("Sending " + a + " in state " + state.name() +
|
" with session ID " +
|
||||||
" with session ID " +
|
msg.getSessionId().hashCode() + " in group " +
|
||||||
Arrays.hashCode(msg.getRaw(SESSION_ID)) + " in group " +
|
msg.getGroupId().hashCode() + ". " +
|
||||||
Arrays.hashCode(msg.getRaw(GROUP_ID)) + ". " +
|
"Moving on to state " + nextState.name()
|
||||||
"Moving on to state " +
|
);
|
||||||
getState(localState.getLong(STATE)).name()
|
|
||||||
);
|
|
||||||
} catch (FormatException e) {
|
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void logMessageReceived(SharerProtocolState currentState,
|
private void logMessageReceived(State currentState, State nextState,
|
||||||
SharerProtocolState nextState, long type, BdfDictionary msg) {
|
long type, BaseMessage msg) {
|
||||||
|
|
||||||
if (!LOG.isLoggable(INFO)) return;
|
if (!LOG.isLoggable(INFO)) return;
|
||||||
|
|
||||||
try {
|
String t = "unknown";
|
||||||
String t = "unknown";
|
if (type == SHARE_MSG_TYPE_ACCEPT) t = "ACCEPT";
|
||||||
if (type == SHARE_MSG_TYPE_ACCEPT) t = "ACCEPT";
|
else if (type == SHARE_MSG_TYPE_DECLINE) t = "DECLINE";
|
||||||
else if (type == SHARE_MSG_TYPE_DECLINE) t = "DECLINE";
|
else if (type == SHARE_MSG_TYPE_LEAVE) t = "LEAVE";
|
||||||
else if (type == SHARE_MSG_TYPE_LEAVE) t = "LEAVE";
|
else if (type == SHARE_MSG_TYPE_ABORT) t = "ABORT";
|
||||||
else if (type == SHARE_MSG_TYPE_ABORT) t = "ABORT";
|
|
||||||
|
|
||||||
LOG.info("Received " + t + " in state " + currentState.name() +
|
LOG.info("Received " + t + " in state " + currentState.name() +
|
||||||
" with session ID " +
|
" with session ID " +
|
||||||
Arrays.hashCode(msg.getRaw(SESSION_ID)) + " in group " +
|
msg.getSessionId().hashCode() + " in group " +
|
||||||
Arrays.hashCode(msg.getRaw(GROUP_ID)) + ". " +
|
msg.getGroupId().hashCode() + ". " +
|
||||||
"Moving on to state " + nextState.name()
|
"Moving on to state " + nextState.name()
|
||||||
);
|
);
|
||||||
} catch (FormatException e) {
|
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public StateUpdate<BdfDictionary, BdfDictionary> onMessageDelivered(
|
public StateUpdate<SharerSessionState, BaseMessage> onMessageDelivered(
|
||||||
BdfDictionary localState, BdfDictionary delivered) {
|
SharerSessionState localState, BaseMessage delivered) {
|
||||||
try {
|
try {
|
||||||
return noUpdate(localState, false);
|
return noUpdate(localState, false);
|
||||||
} catch (FormatException e) {
|
} catch (FormatException e) {
|
||||||
@@ -227,38 +195,34 @@ public class SharerEngine
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private SharerProtocolState getState(Long state) {
|
private StateUpdate<SharerSessionState, BaseMessage> abortSession(
|
||||||
return SharerProtocolState.fromValue(state.intValue());
|
State currentState, SharerSessionState localState)
|
||||||
}
|
|
||||||
|
|
||||||
private StateUpdate<BdfDictionary, BdfDictionary> abortSession(
|
|
||||||
SharerProtocolState currentState, BdfDictionary localState)
|
|
||||||
throws FormatException {
|
throws FormatException {
|
||||||
|
|
||||||
if (LOG.isLoggable(WARNING)) {
|
if (LOG.isLoggable(WARNING)) {
|
||||||
LOG.warning("Aborting protocol session " +
|
LOG.warning("Aborting protocol session " +
|
||||||
Arrays.hashCode(localState.getRaw(SESSION_ID)) +
|
localState.getSessionId().hashCode() +
|
||||||
" in state " + currentState.name());
|
" in state " + currentState.name());
|
||||||
}
|
}
|
||||||
|
|
||||||
localState.put(STATE, ERROR.getValue());
|
localState.setState(ERROR);
|
||||||
BdfDictionary msg = new BdfDictionary();
|
BaseMessage msg = new SimpleMessage(SHARE_MSG_TYPE_ABORT,
|
||||||
msg.put(TYPE, SHARE_MSG_TYPE_ABORT);
|
localState.getGroupId(), localState.getSessionId());
|
||||||
msg.put(SESSION_ID, localState.getRaw(SESSION_ID));
|
List<BaseMessage> messages = Collections.singletonList(msg);
|
||||||
msg.put(GROUP_ID, localState.getRaw(GROUP_ID));
|
|
||||||
List<BdfDictionary> messages = Collections.singletonList(msg);
|
|
||||||
|
|
||||||
List<Event> events = Collections.emptyList();
|
List<Event> events = Collections.emptyList();
|
||||||
|
|
||||||
return new StateUpdate<BdfDictionary, BdfDictionary>(false, false,
|
return new StateUpdate<SharerSessionState, BaseMessage>(false, false,
|
||||||
localState, messages, events);
|
localState, messages, events);
|
||||||
}
|
}
|
||||||
|
|
||||||
private StateUpdate<BdfDictionary, BdfDictionary> noUpdate(
|
private StateUpdate<SharerSessionState, BaseMessage> noUpdate(
|
||||||
BdfDictionary localState, boolean delete) throws FormatException {
|
SharerSessionState localState, boolean delete)
|
||||||
|
throws FormatException {
|
||||||
|
|
||||||
return new StateUpdate<BdfDictionary, BdfDictionary>(delete, false,
|
return new StateUpdate<SharerSessionState, BaseMessage>(delete, false,
|
||||||
localState, Collections.<BdfDictionary>emptyList(),
|
localState, Collections.<BaseMessage>emptyList(),
|
||||||
Collections.<Event>emptyList());
|
Collections.<Event>emptyList());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
131
briar-core/src/org/briarproject/forum/SharerSessionState.java
Normal file
131
briar-core/src/org/briarproject/forum/SharerSessionState.java
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
package org.briarproject.forum;
|
||||||
|
|
||||||
|
import org.briarproject.api.clients.SessionId;
|
||||||
|
import org.briarproject.api.contact.ContactId;
|
||||||
|
import org.briarproject.api.data.BdfDictionary;
|
||||||
|
import org.briarproject.api.sync.GroupId;
|
||||||
|
import org.briarproject.api.sync.MessageId;
|
||||||
|
|
||||||
|
import static org.briarproject.api.forum.ForumConstants.IS_SHARER;
|
||||||
|
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_LEAVE;
|
||||||
|
import static org.briarproject.api.forum.ForumConstants.STATE;
|
||||||
|
import static org.briarproject.forum.SharerSessionState.Action.LOCAL_INVITATION;
|
||||||
|
import static org.briarproject.forum.SharerSessionState.Action.LOCAL_LEAVE;
|
||||||
|
import static org.briarproject.forum.SharerSessionState.Action.REMOTE_ACCEPT;
|
||||||
|
import static org.briarproject.forum.SharerSessionState.Action.REMOTE_DECLINE;
|
||||||
|
import static org.briarproject.forum.SharerSessionState.Action.REMOTE_LEAVE;
|
||||||
|
|
||||||
|
// This class is not thread-safe
|
||||||
|
public class SharerSessionState extends ForumSharingSessionState {
|
||||||
|
|
||||||
|
private State state;
|
||||||
|
private String msg = null;
|
||||||
|
|
||||||
|
public SharerSessionState(SessionId sessionId, MessageId storageId,
|
||||||
|
GroupId groupId, State state, ContactId contactId, GroupId forumId,
|
||||||
|
String forumName, byte[] forumSalt) {
|
||||||
|
|
||||||
|
super(sessionId, storageId, groupId, contactId, forumId, forumName,
|
||||||
|
forumSalt);
|
||||||
|
this.state = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BdfDictionary toBdfDictionary() {
|
||||||
|
BdfDictionary d = super.toBdfDictionary();
|
||||||
|
d.put(STATE, getState().getValue());
|
||||||
|
d.put(IS_SHARER, true);
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setState(State state) {
|
||||||
|
this.state = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
public State getState() {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMessage(String msg) {
|
||||||
|
this.msg = msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMessage() {
|
||||||
|
return this.msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum State {
|
||||||
|
ERROR(0),
|
||||||
|
PREPARE_INVITATION(1) {
|
||||||
|
@Override
|
||||||
|
public State next(Action a) {
|
||||||
|
if (a == LOCAL_INVITATION) return AWAIT_RESPONSE;
|
||||||
|
return ERROR;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
AWAIT_RESPONSE(2) {
|
||||||
|
@Override
|
||||||
|
public State next(Action a) {
|
||||||
|
if (a == REMOTE_ACCEPT || a == REMOTE_DECLINE) return FINISHED;
|
||||||
|
if (a == LOCAL_LEAVE) return LEFT;
|
||||||
|
return ERROR;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
FINISHED(3) {
|
||||||
|
@Override
|
||||||
|
public State next(Action a) {
|
||||||
|
if (a == LOCAL_LEAVE || a == REMOTE_LEAVE) return LEFT;
|
||||||
|
return FINISHED;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
LEFT(4) {
|
||||||
|
@Override
|
||||||
|
public State next(Action a) {
|
||||||
|
if (a == LOCAL_LEAVE) return ERROR;
|
||||||
|
return LEFT;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private final int value;
|
||||||
|
|
||||||
|
State(int value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static State fromValue(int value) {
|
||||||
|
for (State s : values()) {
|
||||||
|
if (s.value == value) return s;
|
||||||
|
}
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public State next(Action a) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum Action {
|
||||||
|
LOCAL_INVITATION,
|
||||||
|
LOCAL_LEAVE,
|
||||||
|
LOCAL_ABORT,
|
||||||
|
REMOTE_ACCEPT,
|
||||||
|
REMOTE_DECLINE,
|
||||||
|
REMOTE_LEAVE,
|
||||||
|
REMOTE_ABORT;
|
||||||
|
|
||||||
|
public static Action 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user