mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-12 10:49:06 +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.ForumManager;
|
||||
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.Group;
|
||||
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 org.briarproject.api.clients.ProtocolEngine.StateUpdate;
|
||||
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.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.LOCAL;
|
||||
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_INVITATION;
|
||||
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_TO_BE_SHARED_BY_US;
|
||||
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_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.TYPE;
|
||||
import static org.briarproject.api.forum.ForumManager.RemoveForumHook;
|
||||
import static org.briarproject.api.forum.InviteeProtocolState.AWAIT_INVITATION;
|
||||
import static org.briarproject.api.forum.InviteeProtocolState.AWAIT_LOCAL_RESPONSE;
|
||||
import static org.briarproject.api.forum.SharerProtocolState.PREPARE_INVITATION;
|
||||
import static org.briarproject.api.forum.ForumSharingMessage.BaseMessage;
|
||||
import static org.briarproject.api.forum.ForumSharingMessage.Invitation;
|
||||
import static org.briarproject.forum.ForumSharingSessionState.fromBdfDictionary;
|
||||
import static org.briarproject.forum.SharerSessionState.Action;
|
||||
|
||||
class ForumSharingManagerImpl extends BdfIncomingMessageHook
|
||||
implements ForumSharingManager, Client, RemoveForumHook,
|
||||
@@ -187,11 +176,12 @@ class ForumSharingManagerImpl extends BdfIncomingMessageHook
|
||||
|
||||
@Override
|
||||
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));
|
||||
long type = msg.getLong(TYPE);
|
||||
if (type == SHARE_MSG_TYPE_INVITATION) {
|
||||
BaseMessage msg = BaseMessage.from(m.getGroupId(), d);
|
||||
SessionId sessionId = msg.getSessionId();
|
||||
|
||||
if (msg.getType() == SHARE_MSG_TYPE_INVITATION) {
|
||||
// we are an invitee who just received a new invitation
|
||||
boolean stateExists = true;
|
||||
try {
|
||||
@@ -206,43 +196,46 @@ class ForumSharingManagerImpl extends BdfIncomingMessageHook
|
||||
if (stateExists) throw new FormatException();
|
||||
|
||||
// check if forum can be shared
|
||||
Forum f = forumFactory.createForum(msg.getString(FORUM_NAME),
|
||||
msg.getRaw(FORUM_SALT));
|
||||
Invitation invitation = (Invitation) msg;
|
||||
Forum f = forumFactory.createForum(invitation.getForumName(),
|
||||
invitation.getForumSalt());
|
||||
ContactId contactId = getContactId(txn, m.getGroupId());
|
||||
Contact contact = db.getContact(txn, contactId);
|
||||
if (!canBeShared(txn, f.getId(), contact))
|
||||
throw new FormatException();
|
||||
|
||||
// initialize state and process invitation
|
||||
BdfDictionary state =
|
||||
initializeInviteeState(txn, contactId, msg);
|
||||
InviteeSessionState state =
|
||||
initializeInviteeState(txn, contactId, invitation);
|
||||
InviteeEngine engine = new InviteeEngine(forumFactory);
|
||||
processStateUpdate(txn, m.getId(),
|
||||
processInviteeStateUpdate(txn, m.getId(),
|
||||
engine.onMessageReceived(state, msg));
|
||||
} catch (FormatException e) {
|
||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||
deleteMessage(txn, m.getId());
|
||||
}
|
||||
} else if (type == SHARE_MSG_TYPE_ACCEPT ||
|
||||
type == SHARE_MSG_TYPE_DECLINE) {
|
||||
} else if (msg.getType() == SHARE_MSG_TYPE_ACCEPT ||
|
||||
msg.getType() == SHARE_MSG_TYPE_DECLINE) {
|
||||
// we are a sharer who just received a response
|
||||
BdfDictionary state = getSessionState(txn, sessionId, true);
|
||||
SharerSessionState state = getSessionStateForSharer(txn, sessionId);
|
||||
SharerEngine engine = new SharerEngine();
|
||||
processStateUpdate(txn, m.getId(),
|
||||
processSharerStateUpdate(txn, m.getId(),
|
||||
engine.onMessageReceived(state, msg));
|
||||
} else if (type == SHARE_MSG_TYPE_LEAVE ||
|
||||
type == SHARE_MSG_TYPE_ABORT) {
|
||||
} else if (msg.getType() == SHARE_MSG_TYPE_LEAVE ||
|
||||
msg.getType() == SHARE_MSG_TYPE_ABORT) {
|
||||
// we don't know who we are, so figure it out
|
||||
BdfDictionary state = getSessionState(txn, sessionId, true);
|
||||
if (state.getBoolean(IS_SHARER)) {
|
||||
ForumSharingSessionState s = getSessionState(txn, sessionId, true);
|
||||
if (s instanceof SharerSessionState) {
|
||||
// we are a sharer and the invitee wants to leave or abort
|
||||
SharerSessionState state = (SharerSessionState) s;
|
||||
SharerEngine engine = new SharerEngine();
|
||||
processStateUpdate(txn, m.getId(),
|
||||
processSharerStateUpdate(txn, m.getId(),
|
||||
engine.onMessageReceived(state, msg));
|
||||
} else {
|
||||
// we are an invitee and the sharer wants to leave or abort
|
||||
InviteeSessionState state = (InviteeSessionState) s;
|
||||
InviteeEngine engine = new InviteeEngine(forumFactory);
|
||||
processStateUpdate(txn, m.getId(),
|
||||
processInviteeStateUpdate(txn, m.getId(),
|
||||
engine.onMessageReceived(state, msg));
|
||||
}
|
||||
} else {
|
||||
@@ -264,19 +257,18 @@ class ForumSharingManagerImpl extends BdfIncomingMessageHook
|
||||
try {
|
||||
// initialize local state for sharer
|
||||
Forum f = forumManager.getForum(txn, groupId);
|
||||
BdfDictionary localState = initializeSharerState(txn, f, contactId);
|
||||
SharerSessionState localState =
|
||||
initializeSharerState(txn, f, contactId);
|
||||
|
||||
// define action
|
||||
BdfDictionary localAction = new BdfDictionary();
|
||||
localAction.put(TYPE, SHARE_MSG_TYPE_INVITATION);
|
||||
// add invitation message to local state to be available for engine
|
||||
if (!StringUtils.isNullOrEmpty(msg)) {
|
||||
localAction.put(INVITATION_MSG, msg);
|
||||
localState.setMessage(msg);
|
||||
}
|
||||
|
||||
// start engine and process its state update
|
||||
SharerEngine engine = new SharerEngine();
|
||||
processStateUpdate(txn, null,
|
||||
engine.onLocalAction(localState, localAction));
|
||||
processSharerStateUpdate(txn, null,
|
||||
engine.onLocalAction(localState, Action.LOCAL_INVITATION));
|
||||
|
||||
txn.setComplete();
|
||||
} catch (FormatException e) {
|
||||
@@ -293,19 +285,19 @@ class ForumSharingManagerImpl extends BdfIncomingMessageHook
|
||||
Transaction txn = db.startTransaction(false);
|
||||
try {
|
||||
// find session state based on forum
|
||||
BdfDictionary localState = getSessionStateForResponse(txn, f);
|
||||
InviteeSessionState localState = getSessionStateForResponse(txn, f);
|
||||
|
||||
// define action
|
||||
BdfDictionary localAction = new BdfDictionary();
|
||||
InviteeSessionState.Action localAction;
|
||||
if (accept) {
|
||||
localAction.put(TYPE, SHARE_MSG_TYPE_ACCEPT);
|
||||
localAction = InviteeSessionState.Action.LOCAL_ACCEPT;
|
||||
} else {
|
||||
localAction.put(TYPE, SHARE_MSG_TYPE_DECLINE);
|
||||
localAction = InviteeSessionState.Action.LOCAL_DECLINE;
|
||||
}
|
||||
|
||||
// start engine and process its state update
|
||||
InviteeEngine engine = new InviteeEngine(forumFactory);
|
||||
processStateUpdate(txn, null,
|
||||
processInviteeStateUpdate(txn, null,
|
||||
engine.onLocalAction(localState, localAction));
|
||||
|
||||
txn.setComplete();
|
||||
@@ -330,34 +322,33 @@ class ForumSharingManagerImpl extends BdfIncomingMessageHook
|
||||
Map<MessageId, BdfDictionary> map = clientHelper
|
||||
.getMessageMetadataAsDictionary(txn, group.getId());
|
||||
for (Map.Entry<MessageId, BdfDictionary> m : map.entrySet()) {
|
||||
BdfDictionary msg = m.getValue();
|
||||
BdfDictionary d = m.getValue();
|
||||
try {
|
||||
if (msg.getLong(TYPE) != SHARE_MSG_TYPE_INVITATION)
|
||||
if (d.getLong(TYPE) != SHARE_MSG_TYPE_INVITATION)
|
||||
continue;
|
||||
|
||||
Invitation msg = Invitation.from(group.getId(), d);
|
||||
MessageStatus status =
|
||||
db.getMessageStatus(txn, contactId, m.getKey());
|
||||
SessionId sessionId = new SessionId(msg.getRaw(SESSION_ID));
|
||||
String name = msg.getString(FORUM_NAME);
|
||||
String message = msg.getOptionalString(INVITATION_MSG);
|
||||
long time = msg.getLong(TIME);
|
||||
boolean local = msg.getBoolean(LOCAL);
|
||||
boolean read = msg.getBoolean(READ, false);
|
||||
long time = d.getLong(TIME);
|
||||
boolean local = d.getBoolean(LOCAL);
|
||||
boolean read = d.getBoolean(READ, false);
|
||||
boolean available = false;
|
||||
if (!local) {
|
||||
// figure out whether the forum is still available
|
||||
BdfDictionary sessionState =
|
||||
getSessionState(txn, sessionId, true);
|
||||
InviteeProtocolState state = InviteeProtocolState
|
||||
.fromValue(
|
||||
sessionState.getLong(STATE).intValue());
|
||||
available = state == AWAIT_LOCAL_RESPONSE;
|
||||
ForumSharingSessionState s =
|
||||
getSessionState(txn, msg.getSessionId(), true);
|
||||
if (!(s instanceof InviteeSessionState))
|
||||
continue;
|
||||
available = ((InviteeSessionState) s).getState() ==
|
||||
InviteeSessionState.State.AWAIT_LOCAL_RESPONSE;
|
||||
}
|
||||
ForumInvitationMessage im =
|
||||
new ForumInvitationMessage(m.getKey(), sessionId,
|
||||
contactId, name, message, available, time,
|
||||
local, status.isSent(), status.isSeen(),
|
||||
read);
|
||||
new ForumInvitationMessage(m.getKey(),
|
||||
msg.getSessionId(), contactId,
|
||||
msg.getForumName(), msg.getMessage(),
|
||||
available, time, local, status.isSent(),
|
||||
status.isSeen(), read);
|
||||
list.add(im);
|
||||
} catch (FormatException e) {
|
||||
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 {
|
||||
|
||||
Contact c = db.getContact(txn, contactId);
|
||||
@@ -502,33 +493,27 @@ class ForumSharingManagerImpl extends BdfIncomingMessageHook
|
||||
random.nextBytes(salt.getBytes());
|
||||
Message m = clientHelper.createMessage(localGroup.getId(), now,
|
||||
BdfList.of(salt));
|
||||
MessageId sessionId = m.getId();
|
||||
SessionId sessionId = new SessionId(m.getId().getBytes());
|
||||
|
||||
BdfDictionary d = new BdfDictionary();
|
||||
d.put(SESSION_ID, sessionId);
|
||||
d.put(STORAGE_ID, sessionId);
|
||||
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());
|
||||
SharerSessionState s = new SharerSessionState(sessionId, sessionId,
|
||||
group.getId(), SharerSessionState.State.PREPARE_INVITATION,
|
||||
contactId, f.getId(), f.getName(), f.getSalt());
|
||||
|
||||
// save local state to database
|
||||
BdfDictionary d = s.toBdfDictionary();
|
||||
clientHelper.addLocalMessage(txn, m, getClientId(), d, false);
|
||||
|
||||
return d;
|
||||
return s;
|
||||
}
|
||||
|
||||
private BdfDictionary initializeInviteeState(Transaction txn,
|
||||
ContactId contactId, BdfDictionary msg)
|
||||
private InviteeSessionState initializeInviteeState(Transaction txn,
|
||||
ContactId contactId, Invitation msg)
|
||||
throws FormatException, DbException {
|
||||
|
||||
Contact c = db.getContact(txn, contactId);
|
||||
Group group = getContactGroup(c);
|
||||
String name = msg.getString(FORUM_NAME);
|
||||
byte[] salt = msg.getRaw(FORUM_SALT);
|
||||
String name = msg.getForumName();
|
||||
byte[] salt = msg.getForumSalt();
|
||||
Forum f = forumFactory.createForum(name, salt);
|
||||
|
||||
// create local message to keep engine state
|
||||
@@ -538,29 +523,24 @@ class ForumSharingManagerImpl extends BdfIncomingMessageHook
|
||||
Message m = clientHelper.createMessage(localGroup.getId(), now,
|
||||
BdfList.of(mSalt));
|
||||
|
||||
BdfDictionary d = new BdfDictionary();
|
||||
d.put(SESSION_ID, msg.getRaw(SESSION_ID));
|
||||
d.put(STORAGE_ID, m.getId());
|
||||
d.put(GROUP_ID, group.getId());
|
||||
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);
|
||||
InviteeSessionState s = new InviteeSessionState(msg.getSessionId(),
|
||||
m.getId(), group.getId(),
|
||||
InviteeSessionState.State.AWAIT_INVITATION, contactId,
|
||||
f.getId(), f.getName(), f.getSalt());
|
||||
|
||||
// save local state to database
|
||||
BdfDictionary d = s.toBdfDictionary();
|
||||
clientHelper.addLocalMessage(txn, m, getClientId(), d, false);
|
||||
|
||||
return d;
|
||||
return s;
|
||||
}
|
||||
|
||||
private BdfDictionary getSessionState(Transaction txn, SessionId sessionId,
|
||||
boolean warn) throws DbException, FormatException {
|
||||
private ForumSharingSessionState getSessionState(Transaction txn,
|
||||
SessionId sessionId, boolean warn)
|
||||
throws DbException, FormatException {
|
||||
|
||||
try {
|
||||
// we should be able to get the sharer state directly from sessionId
|
||||
return clientHelper.getMessageMetadataAsDictionary(txn, sessionId);
|
||||
return getSessionStateForSharer(txn, sessionId);
|
||||
} catch (NoSuchMessageException e) {
|
||||
// State not found directly, so iterate over all states
|
||||
// to find state for invitee
|
||||
@@ -570,7 +550,7 @@ class ForumSharingManagerImpl extends BdfIncomingMessageHook
|
||||
BdfDictionary state = m.getValue();
|
||||
if (Arrays.equals(state.getRaw(SESSION_ID),
|
||||
sessionId.getBytes())) {
|
||||
return state;
|
||||
return fromBdfDictionary(state);
|
||||
}
|
||||
}
|
||||
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 {
|
||||
|
||||
// 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
|
||||
.getMessageMetadataAsDictionary(txn, localGroup.getId());
|
||||
for (Map.Entry<MessageId, BdfDictionary> m : map.entrySet()) {
|
||||
BdfDictionary d = m.getValue();
|
||||
try {
|
||||
InviteeProtocolState state = InviteeProtocolState
|
||||
.fromValue(d.getLong(STATE).intValue());
|
||||
if (state == AWAIT_LOCAL_RESPONSE) {
|
||||
byte[] id = d.getRaw(FORUM_ID);
|
||||
if (Arrays.equals(f.getId().getBytes(), id)) {
|
||||
// Note that there should always be only one session
|
||||
// in this state for the same forum
|
||||
return d;
|
||||
}
|
||||
ForumSharingSessionState s = fromBdfDictionary(d);
|
||||
if (!(s instanceof InviteeSessionState)) continue;
|
||||
if (!f.getId().equals(s.getForumId())) continue;
|
||||
|
||||
InviteeSessionState state = (InviteeSessionState) s;
|
||||
if (state.getState() ==
|
||||
InviteeSessionState.State.AWAIT_LOCAL_RESPONSE) {
|
||||
// Note that there should always be only one session
|
||||
// in this state for the same forum
|
||||
return state;
|
||||
}
|
||||
} catch (FormatException e) {
|
||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||
@@ -607,36 +601,40 @@ class ForumSharingManagerImpl extends BdfIncomingMessageHook
|
||||
throw new DbException();
|
||||
}
|
||||
|
||||
private BdfDictionary getSessionStateForLeaving(Transaction txn, Forum f,
|
||||
ContactId c) throws DbException, FormatException {
|
||||
private ForumSharingSessionState getSessionStateForLeaving(Transaction txn,
|
||||
Forum f, ContactId c) throws DbException, FormatException {
|
||||
|
||||
Map<MessageId, BdfDictionary> map = clientHelper
|
||||
.getMessageMetadataAsDictionary(txn, localGroup.getId());
|
||||
for (Map.Entry<MessageId, BdfDictionary> m : map.entrySet()) {
|
||||
BdfDictionary d = m.getValue();
|
||||
try {
|
||||
ForumSharingSessionState s = fromBdfDictionary(d);
|
||||
|
||||
// check that this session is with the right contact
|
||||
if (c.getInt() != d.getLong(CONTACT_ID)) 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;
|
||||
}
|
||||
if (!c.equals(s.getContactId())) continue;
|
||||
|
||||
// check that this state actually concerns this forum
|
||||
String name = d.getString(FORUM_NAME);
|
||||
byte[] salt = d.getRaw(FORUM_SALT);
|
||||
if (name.equals(f.getName()) &&
|
||||
Arrays.equals(salt, f.getSalt())) {
|
||||
// TODO what happens when there is more than one invitation?
|
||||
return d;
|
||||
if (!s.getForumName().equals(f.getName()) ||
|
||||
!Arrays.equals(s.getForumSalt(), f.getSalt())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 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) {
|
||||
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,
|
||||
StateUpdate<BdfDictionary, BdfDictionary> result)
|
||||
StateUpdate<ForumSharingSessionState, BaseMessage> result)
|
||||
throws DbException, FormatException {
|
||||
|
||||
// perform actions based on new local state
|
||||
performTasks(txn, result.localState);
|
||||
|
||||
// save new local state
|
||||
MessageId storageId =
|
||||
new MessageId(result.localState.getRaw(STORAGE_ID));
|
||||
clientHelper.mergeMessageMetadata(txn, storageId, result.localState);
|
||||
MessageId storageId = result.localState.getStorageId();
|
||||
clientHelper.mergeMessageMetadata(txn, storageId,
|
||||
result.localState.toBdfDictionary());
|
||||
|
||||
// send messages
|
||||
for (BdfDictionary d : result.toSend) {
|
||||
sendMessage(txn, d);
|
||||
for (BaseMessage msg : result.toSend) {
|
||||
sendMessage(txn, msg);
|
||||
}
|
||||
|
||||
// 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 {
|
||||
|
||||
if (!localState.containsKey(TASK)) return;
|
||||
if (localState.getTask() == -1) return;
|
||||
|
||||
// remember task and remove it from localState
|
||||
long task = localState.getLong(TASK);
|
||||
localState.put(TASK, BdfDictionary.NULL_VALUE);
|
||||
long task = localState.getTask();
|
||||
localState.setTask(-1);
|
||||
|
||||
// get group ID for later
|
||||
GroupId groupId = new GroupId(localState.getRaw(GROUP_ID));
|
||||
GroupId groupId = localState.getGroupId();
|
||||
// get contact ID for later
|
||||
ContactId contactId =
|
||||
new ContactId(localState.getLong(CONTACT_ID).intValue());
|
||||
ContactId contactId = localState.getContactId();
|
||||
|
||||
// get forum for later
|
||||
String name = localState.getString(FORUM_NAME);
|
||||
byte[] salt = localState.getRaw(FORUM_SALT);
|
||||
String name = localState.getForumName();
|
||||
byte[] salt = localState.getForumSalt();
|
||||
Forum f = forumFactory.createForum(name, salt);
|
||||
|
||||
// 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 {
|
||||
|
||||
BdfList list = encodeMessage(m);
|
||||
byte[] body = clientHelper.toByteArray(list);
|
||||
GroupId groupId = new GroupId(m.getRaw(GROUP_ID));
|
||||
Group group = db.getGroup(txn, groupId);
|
||||
byte[] body = clientHelper.toByteArray(m.toBdfList());
|
||||
Group group = db.getGroup(txn, m.getGroupId());
|
||||
long timestamp = clock.currentTimeMillis();
|
||||
|
||||
// add message itself as metadata
|
||||
m.put(LOCAL, true);
|
||||
m.put(TIME, timestamp);
|
||||
Metadata meta = metadataEncoder.encode(m);
|
||||
BdfDictionary d = m.toBdfDictionary();
|
||||
d.put(LOCAL, true);
|
||||
d.put(TIME, timestamp);
|
||||
Metadata meta = metadataEncoder.encode(d);
|
||||
|
||||
messageQueueManager
|
||||
.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) {
|
||||
return privateGroupFactory.createPrivateGroup(CLIENT_ID, c);
|
||||
}
|
||||
@@ -786,17 +780,18 @@ class ForumSharingManagerImpl extends BdfIncomingMessageHook
|
||||
private void leaveForum(Transaction txn, ContactId c, Forum f)
|
||||
throws DbException, FormatException {
|
||||
|
||||
BdfDictionary state = getSessionStateForLeaving(txn, f, c);
|
||||
BdfDictionary action = new BdfDictionary();
|
||||
action.put(TYPE, SHARE_MSG_TYPE_LEAVE);
|
||||
if (state.getBoolean(IS_SHARER)) {
|
||||
ForumSharingSessionState state = getSessionStateForLeaving(txn, f, c);
|
||||
if (state instanceof SharerSessionState) {
|
||||
Action action = Action.LOCAL_LEAVE;
|
||||
SharerEngine engine = new SharerEngine();
|
||||
processStateUpdate(txn, null,
|
||||
engine.onLocalAction(state, action));
|
||||
processSharerStateUpdate(txn, null,
|
||||
engine.onLocalAction((SharerSessionState) state, action));
|
||||
} else {
|
||||
InviteeSessionState.Action action =
|
||||
InviteeSessionState.Action.LOCAL_LEAVE;
|
||||
InviteeEngine engine = new InviteeEngine(forumFactory);
|
||||
processStateUpdate(txn, null,
|
||||
engine.onLocalAction(state, action));
|
||||
processInviteeStateUpdate(txn, null,
|
||||
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
|
||||
d.put(TYPE, type);
|
||||
d.put(SESSION_ID, id);
|
||||
d.put(GROUP_ID, m.getGroupId());
|
||||
d.put(LOCAL, false);
|
||||
d.put(TIME, m.getTimestamp());
|
||||
return d;
|
||||
|
||||
@@ -3,51 +3,42 @@ package org.briarproject.forum;
|
||||
import org.briarproject.api.FormatException;
|
||||
import org.briarproject.api.clients.ProtocolEngine;
|
||||
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.ForumInvitationReceivedEvent;
|
||||
import org.briarproject.api.forum.Forum;
|
||||
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.List;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import static java.util.logging.Level.INFO;
|
||||
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_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.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_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_UNSHARE_FORUM_SHARED_WITH_US;
|
||||
import static org.briarproject.api.forum.ForumConstants.TYPE;
|
||||
import static org.briarproject.api.forum.InviteeAction.LOCAL_ABORT;
|
||||
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;
|
||||
import static org.briarproject.api.forum.InviteeProtocolState.ERROR;
|
||||
import static org.briarproject.api.forum.InviteeProtocolState.FINISHED;
|
||||
import static org.briarproject.api.forum.InviteeProtocolState.LEFT;
|
||||
import static org.briarproject.api.forum.ForumSharingMessage.SimpleMessage;
|
||||
import static org.briarproject.api.forum.ForumSharingMessage.BaseMessage;
|
||||
import static org.briarproject.forum.InviteeSessionState.Action;
|
||||
import static org.briarproject.forum.InviteeSessionState.Action.LOCAL_ABORT;
|
||||
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;
|
||||
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
|
||||
implements ProtocolEngine<BdfDictionary, BdfDictionary, BdfDictionary> {
|
||||
implements ProtocolEngine<Action, InviteeSessionState, BaseMessage> {
|
||||
|
||||
private final ForumFactory forumFactory;
|
||||
private static final Logger LOG =
|
||||
@@ -58,16 +49,13 @@ public class InviteeEngine
|
||||
}
|
||||
|
||||
@Override
|
||||
public StateUpdate<BdfDictionary, BdfDictionary> onLocalAction(
|
||||
BdfDictionary localState, BdfDictionary localAction) {
|
||||
public StateUpdate<InviteeSessionState, BaseMessage> onLocalAction(
|
||||
InviteeSessionState localState, Action action) {
|
||||
|
||||
try {
|
||||
InviteeProtocolState currentState =
|
||||
getState(localState.getLong(STATE));
|
||||
long type = localAction.getLong(TYPE);
|
||||
InviteeAction action = InviteeAction.getLocal(type);
|
||||
InviteeProtocolState nextState = currentState.next(action);
|
||||
localState.put(STATE, nextState.getValue());
|
||||
State currentState = localState.getState();
|
||||
State nextState = currentState.next(action);
|
||||
localState.setState(nextState);
|
||||
|
||||
if (action == LOCAL_ABORT && currentState != ERROR) {
|
||||
return abortSession(currentState, localState);
|
||||
@@ -80,37 +68,34 @@ public class InviteeEngine
|
||||
}
|
||||
return noUpdate(localState, true);
|
||||
}
|
||||
List<BdfDictionary> messages;
|
||||
List<BaseMessage> messages;
|
||||
List<Event> events = Collections.emptyList();
|
||||
|
||||
if (action == LOCAL_ACCEPT || action == LOCAL_DECLINE) {
|
||||
BdfDictionary msg = BdfDictionary.of(
|
||||
new BdfEntry(SESSION_ID, localState.getRaw(SESSION_ID)),
|
||||
new BdfEntry(GROUP_ID, localState.getRaw(GROUP_ID))
|
||||
);
|
||||
BaseMessage msg;
|
||||
if (action == LOCAL_ACCEPT) {
|
||||
localState.put(TASK, TASK_ADD_SHARED_FORUM);
|
||||
msg.put(TYPE, SHARE_MSG_TYPE_ACCEPT);
|
||||
localState.setTask(TASK_ADD_SHARED_FORUM);
|
||||
msg = new SimpleMessage(SHARE_MSG_TYPE_ACCEPT,
|
||||
localState.getGroupId(), localState.getSessionId());
|
||||
} else {
|
||||
localState.put(TASK,
|
||||
localState.setTask(
|
||||
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);
|
||||
logLocalAction(currentState, localState, msg);
|
||||
}
|
||||
else if (action == LOCAL_LEAVE) {
|
||||
BdfDictionary msg = new BdfDictionary();
|
||||
msg.put(TYPE, SHARE_MSG_TYPE_LEAVE);
|
||||
msg.put(SESSION_ID, localState.getRaw(SESSION_ID));
|
||||
msg.put(GROUP_ID, localState.getRaw(GROUP_ID));
|
||||
BaseMessage msg = new SimpleMessage(SHARE_MSG_TYPE_LEAVE,
|
||||
localState.getGroupId(), localState.getSessionId());
|
||||
messages = Collections.singletonList(msg);
|
||||
logLocalAction(currentState, localState, msg);
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException("Unknown Local Action");
|
||||
}
|
||||
return new StateUpdate<BdfDictionary, BdfDictionary>(false,
|
||||
return new StateUpdate<InviteeSessionState, BaseMessage>(false,
|
||||
false, localState, messages, events);
|
||||
} catch (FormatException e) {
|
||||
throw new IllegalArgumentException(e);
|
||||
@@ -118,18 +103,16 @@ public class InviteeEngine
|
||||
}
|
||||
|
||||
@Override
|
||||
public StateUpdate<BdfDictionary, BdfDictionary> onMessageReceived(
|
||||
BdfDictionary localState, BdfDictionary msg) {
|
||||
public StateUpdate<InviteeSessionState, BaseMessage> onMessageReceived(
|
||||
InviteeSessionState localState, BaseMessage msg) {
|
||||
|
||||
try {
|
||||
InviteeProtocolState currentState =
|
||||
getState(localState.getLong(STATE));
|
||||
long type = msg.getLong(TYPE);
|
||||
InviteeAction action = InviteeAction.getRemote(type);
|
||||
InviteeProtocolState nextState = currentState.next(action);
|
||||
localState.put(STATE, nextState.getValue());
|
||||
State currentState = localState.getState();
|
||||
Action action = Action.getRemote(msg.getType());
|
||||
State nextState = currentState.next(action);
|
||||
localState.setState(nextState);
|
||||
|
||||
logMessageReceived(currentState, nextState, type, msg);
|
||||
logMessageReceived(currentState, nextState, msg.getType(), msg);
|
||||
|
||||
if (nextState == 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();
|
||||
boolean deleteMsg = false;
|
||||
|
||||
@@ -149,7 +132,7 @@ public class InviteeEngine
|
||||
}
|
||||
// the sharer left the forum she had shared with us
|
||||
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) {
|
||||
// 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
|
||||
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
|
||||
else if (action == REMOTE_INVITATION) {
|
||||
localState.put(TASK, TASK_ADD_FORUM_TO_LIST_SHARED_WITH_US);
|
||||
Forum forum = forumFactory
|
||||
.createForum(localState.getString(FORUM_NAME),
|
||||
localState.getRaw(FORUM_SALT));
|
||||
ContactId contactId = new ContactId(
|
||||
localState.getLong(CONTACT_ID).intValue());
|
||||
.createForum(localState.getForumName(),
|
||||
localState.getForumSalt());
|
||||
localState.setTask(TASK_ADD_FORUM_TO_LIST_SHARED_WITH_US);
|
||||
ContactId contactId = localState.getContactId();
|
||||
Event event = new ForumInvitationReceivedEvent(forum, contactId);
|
||||
events = Collections.singletonList(event);
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException("Bad state");
|
||||
}
|
||||
return new StateUpdate<BdfDictionary, BdfDictionary>(deleteMsg,
|
||||
return new StateUpdate<InviteeSessionState, BaseMessage>(deleteMsg,
|
||||
false, localState, messages, events);
|
||||
} catch (FormatException e) {
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void logLocalAction(InviteeProtocolState state,
|
||||
BdfDictionary localState, BdfDictionary msg) {
|
||||
private void logLocalAction(State state,
|
||||
InviteeSessionState localState, BaseMessage msg) {
|
||||
|
||||
if (!LOG.isLoggable(INFO)) return;
|
||||
|
||||
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() +
|
||||
" with session ID " +
|
||||
Arrays.hashCode(msg.getRaw(SESSION_ID)) + " in group " +
|
||||
Arrays.hashCode(msg.getRaw(GROUP_ID)) + ". " +
|
||||
"Moving on to state " +
|
||||
getState(localState.getLong(STATE)).name()
|
||||
);
|
||||
} catch (FormatException e) {
|
||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||
}
|
||||
LOG.info("Sending " + a + " in state " + state.name() +
|
||||
" with session ID " +
|
||||
msg.getSessionId().hashCode() + " in group " +
|
||||
msg.getGroupId().hashCode() + ". " +
|
||||
"Moving on to state " + localState.getState().name()
|
||||
);
|
||||
}
|
||||
|
||||
private void logMessageReceived(InviteeProtocolState currentState,
|
||||
InviteeProtocolState nextState, long type, BdfDictionary msg) {
|
||||
private void logMessageReceived(State currentState, State nextState,
|
||||
long type, BaseMessage msg) {
|
||||
|
||||
if (!LOG.isLoggable(INFO)) return;
|
||||
|
||||
try {
|
||||
String t = "unknown";
|
||||
if (type == SHARE_MSG_TYPE_INVITATION) t = "INVITE";
|
||||
else if (type == SHARE_MSG_TYPE_LEAVE) t = "LEAVE";
|
||||
else if (type == SHARE_MSG_TYPE_ABORT) t = "ABORT";
|
||||
String t = "unknown";
|
||||
if (type == SHARE_MSG_TYPE_INVITATION) t = "INVITE";
|
||||
else if (type == SHARE_MSG_TYPE_LEAVE) t = "LEAVE";
|
||||
else if (type == SHARE_MSG_TYPE_ABORT) t = "ABORT";
|
||||
|
||||
LOG.info("Received " + t + " in state " + currentState.name() +
|
||||
" with session ID " +
|
||||
Arrays.hashCode(msg.getRaw(SESSION_ID)) + " in group " +
|
||||
Arrays.hashCode(msg.getRaw(GROUP_ID)) + ". " +
|
||||
"Moving on to state " + nextState.name()
|
||||
);
|
||||
} catch (FormatException e) {
|
||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||
}
|
||||
LOG.info("Received " + t + " in state " + currentState.name() +
|
||||
" with session ID " +
|
||||
msg.getSessionId().hashCode() + " in group " +
|
||||
msg.getGroupId().hashCode() + ". " +
|
||||
"Moving on to state " + nextState.name()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StateUpdate<BdfDictionary, BdfDictionary> onMessageDelivered(
|
||||
BdfDictionary localState, BdfDictionary delivered) {
|
||||
public StateUpdate<InviteeSessionState, BaseMessage> onMessageDelivered(
|
||||
InviteeSessionState localState, BaseMessage delivered) {
|
||||
try {
|
||||
return noUpdate(localState, false);
|
||||
} catch (FormatException e) {
|
||||
@@ -234,38 +208,32 @@ public class InviteeEngine
|
||||
}
|
||||
}
|
||||
|
||||
private InviteeProtocolState getState(Long state) {
|
||||
return InviteeProtocolState.fromValue(state.intValue());
|
||||
}
|
||||
|
||||
private StateUpdate<BdfDictionary, BdfDictionary> abortSession(
|
||||
InviteeProtocolState currentState, BdfDictionary localState)
|
||||
private StateUpdate<InviteeSessionState, BaseMessage> abortSession(
|
||||
State currentState, InviteeSessionState localState)
|
||||
throws FormatException {
|
||||
|
||||
if (LOG.isLoggable(WARNING)) {
|
||||
LOG.warning("Aborting protocol session " +
|
||||
Arrays.hashCode(localState.getRaw(SESSION_ID)) +
|
||||
localState.getSessionId().hashCode() +
|
||||
" in state " + currentState.name());
|
||||
}
|
||||
|
||||
localState.put(STATE, ERROR.getValue());
|
||||
BdfDictionary msg = new BdfDictionary();
|
||||
msg.put(TYPE, SHARE_MSG_TYPE_ABORT);
|
||||
msg.put(SESSION_ID, localState.getRaw(SESSION_ID));
|
||||
msg.put(GROUP_ID, localState.getRaw(GROUP_ID));
|
||||
List<BdfDictionary> messages = Collections.singletonList(msg);
|
||||
localState.setState(ERROR);
|
||||
BaseMessage msg =
|
||||
new SimpleMessage(SHARE_MSG_TYPE_ABORT, localState.getGroupId(),
|
||||
localState.getSessionId());
|
||||
List<BaseMessage> messages = Collections.singletonList(msg);
|
||||
|
||||
List<Event> events = Collections.emptyList();
|
||||
|
||||
return new StateUpdate<BdfDictionary, BdfDictionary>(false, false,
|
||||
return new StateUpdate<InviteeSessionState, BaseMessage>(false, false,
|
||||
localState, messages, events);
|
||||
}
|
||||
|
||||
private StateUpdate<BdfDictionary, BdfDictionary> noUpdate(
|
||||
BdfDictionary localState, boolean delete) throws FormatException {
|
||||
private StateUpdate<InviteeSessionState, BaseMessage> noUpdate(
|
||||
InviteeSessionState localState, boolean delete) throws FormatException {
|
||||
|
||||
return new StateUpdate<BdfDictionary, BdfDictionary>(delete, false,
|
||||
localState, Collections.<BdfDictionary>emptyList(),
|
||||
return new StateUpdate<InviteeSessionState, BaseMessage>(delete, false,
|
||||
localState, Collections.<BaseMessage>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.clients.ProtocolEngine;
|
||||
import org.briarproject.api.contact.ContactId;
|
||||
import org.briarproject.api.data.BdfDictionary;
|
||||
import org.briarproject.api.event.Event;
|
||||
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.List;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import static java.util.logging.Level.INFO;
|
||||
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_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.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_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_UNSHARE_FORUM_SHARED_BY_US;
|
||||
import static org.briarproject.api.forum.ForumConstants.TYPE;
|
||||
import static org.briarproject.api.forum.SharerAction.LOCAL_ABORT;
|
||||
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;
|
||||
import static org.briarproject.api.forum.SharerProtocolState.ERROR;
|
||||
import static org.briarproject.api.forum.SharerProtocolState.FINISHED;
|
||||
import static org.briarproject.api.forum.SharerProtocolState.LEFT;
|
||||
import static org.briarproject.api.forum.ForumSharingMessage.BaseMessage;
|
||||
import static org.briarproject.api.forum.ForumSharingMessage.Invitation;
|
||||
import static org.briarproject.api.forum.ForumSharingMessage.SimpleMessage;
|
||||
import static org.briarproject.forum.SharerSessionState.Action;
|
||||
import static org.briarproject.forum.SharerSessionState.Action.LOCAL_ABORT;
|
||||
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;
|
||||
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
|
||||
implements ProtocolEngine<BdfDictionary, BdfDictionary, BdfDictionary> {
|
||||
implements ProtocolEngine<Action, SharerSessionState, BaseMessage> {
|
||||
|
||||
private static final Logger LOG =
|
||||
Logger.getLogger(SharerEngine.class.getName());
|
||||
|
||||
@Override
|
||||
public StateUpdate<BdfDictionary, BdfDictionary> onLocalAction(
|
||||
BdfDictionary localState, BdfDictionary localAction) {
|
||||
public StateUpdate<SharerSessionState, BaseMessage> onLocalAction(
|
||||
SharerSessionState localState, Action action) {
|
||||
|
||||
try {
|
||||
SharerProtocolState currentState =
|
||||
getState(localState.getLong(STATE));
|
||||
long type = localAction.getLong(TYPE);
|
||||
SharerAction action = SharerAction.getLocal(type);
|
||||
SharerProtocolState nextState = currentState.next(action);
|
||||
localState.put(STATE, nextState.getValue());
|
||||
State currentState = localState.getState();
|
||||
State nextState = currentState.next(action);
|
||||
localState.setState(nextState);
|
||||
|
||||
if (action == LOCAL_ABORT && currentState != ERROR) {
|
||||
return abortSession(currentState, localState);
|
||||
@@ -73,38 +61,29 @@ public class SharerEngine
|
||||
}
|
||||
return noUpdate(localState, true);
|
||||
}
|
||||
List<BdfDictionary> messages;
|
||||
List<BaseMessage> messages;
|
||||
List<Event> events = Collections.emptyList();
|
||||
|
||||
if (action == LOCAL_INVITATION) {
|
||||
BdfDictionary msg = new BdfDictionary();
|
||||
msg.put(TYPE, SHARE_MSG_TYPE_INVITATION);
|
||||
msg.put(SESSION_ID, localState.getRaw(SESSION_ID));
|
||||
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));
|
||||
}
|
||||
BaseMessage msg = new Invitation(localState.getGroupId(),
|
||||
localState.getSessionId(), localState.getForumName(),
|
||||
localState.getForumSalt(), localState.getMessage());
|
||||
messages = Collections.singletonList(msg);
|
||||
logLocalAction(currentState, localState, msg);
|
||||
logLocalAction(currentState, nextState, msg);
|
||||
|
||||
// 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) {
|
||||
BdfDictionary msg = new BdfDictionary();
|
||||
msg.put(TYPE, SHARE_MSG_TYPE_LEAVE);
|
||||
msg.put(SESSION_ID, localState.getRaw(SESSION_ID));
|
||||
msg.put(GROUP_ID, localState.getRaw(GROUP_ID));
|
||||
BaseMessage msg = new SimpleMessage(SHARE_MSG_TYPE_LEAVE,
|
||||
localState.getGroupId(), localState.getSessionId());
|
||||
messages = Collections.singletonList(msg);
|
||||
logLocalAction(currentState, localState, msg);
|
||||
logLocalAction(currentState, nextState, msg);
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException("Unknown Local Action");
|
||||
}
|
||||
return new StateUpdate<BdfDictionary, BdfDictionary>(false,
|
||||
return new StateUpdate<SharerSessionState, BaseMessage>(false,
|
||||
false, localState, messages, events);
|
||||
} catch (FormatException e) {
|
||||
throw new IllegalArgumentException(e);
|
||||
@@ -112,18 +91,16 @@ public class SharerEngine
|
||||
}
|
||||
|
||||
@Override
|
||||
public StateUpdate<BdfDictionary, BdfDictionary> onMessageReceived(
|
||||
BdfDictionary localState, BdfDictionary msg) {
|
||||
public StateUpdate<SharerSessionState, BaseMessage> onMessageReceived(
|
||||
SharerSessionState localState, BaseMessage msg) {
|
||||
|
||||
try {
|
||||
SharerProtocolState currentState =
|
||||
getState(localState.getLong(STATE));
|
||||
long type = msg.getLong(TYPE);
|
||||
SharerAction action = SharerAction.getRemote(type);
|
||||
SharerProtocolState nextState = currentState.next(action);
|
||||
localState.put(STATE, nextState.getValue());
|
||||
State currentState = localState.getState();
|
||||
Action action = Action.getRemote(msg.getType());
|
||||
State nextState = currentState.next(action);
|
||||
localState.setState(nextState);
|
||||
|
||||
logMessageReceived(currentState, nextState, type, msg);
|
||||
logMessageReceived(currentState, nextState, msg.getType(), msg);
|
||||
|
||||
if (nextState == ERROR) {
|
||||
if (currentState != ERROR) {
|
||||
@@ -132,7 +109,7 @@ public class SharerEngine
|
||||
return noUpdate(localState, true);
|
||||
}
|
||||
}
|
||||
List<BdfDictionary> messages = Collections.emptyList();
|
||||
List<BaseMessage> messages = Collections.emptyList();
|
||||
List<Event> events = Collections.emptyList();
|
||||
boolean deleteMsg = false;
|
||||
|
||||
@@ -141,7 +118,7 @@ public class SharerEngine
|
||||
deleteMsg = true;
|
||||
}
|
||||
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) {
|
||||
// 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
|
||||
else if (action == REMOTE_ACCEPT || action == REMOTE_DECLINE) {
|
||||
if (action == REMOTE_ACCEPT) {
|
||||
localState.put(TASK, TASK_SHARE_FORUM);
|
||||
localState.setTask(TASK_SHARE_FORUM);
|
||||
} else {
|
||||
// this ensures that the forum can be shared again
|
||||
localState.put(TASK,
|
||||
localState.setTask(
|
||||
TASK_REMOVE_FORUM_FROM_LIST_TO_BE_SHARED_BY_US);
|
||||
}
|
||||
String name = localState.getString(FORUM_NAME);
|
||||
ContactId c = new ContactId(
|
||||
localState.getLong(CONTACT_ID).intValue());
|
||||
String name = localState.getForumName();
|
||||
ContactId c = localState.getContactId();
|
||||
Event event = new ForumInvitationResponseReceivedEvent(name, c);
|
||||
events = Collections.singletonList(event);
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException("Bad state");
|
||||
}
|
||||
return new StateUpdate<BdfDictionary, BdfDictionary>(deleteMsg,
|
||||
return new StateUpdate<SharerSessionState, BaseMessage>(deleteMsg,
|
||||
false, localState, messages, events);
|
||||
} catch (FormatException e) {
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void logLocalAction(SharerProtocolState state,
|
||||
BdfDictionary localState, BdfDictionary msg) {
|
||||
private void logLocalAction(State currentState, State nextState,
|
||||
BaseMessage msg) {
|
||||
|
||||
if (!LOG.isLoggable(INFO)) return;
|
||||
|
||||
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 " + state.name() +
|
||||
" with session ID " +
|
||||
Arrays.hashCode(msg.getRaw(SESSION_ID)) + " in group " +
|
||||
Arrays.hashCode(msg.getRaw(GROUP_ID)) + ". " +
|
||||
"Moving on to state " +
|
||||
getState(localState.getLong(STATE)).name()
|
||||
);
|
||||
} catch (FormatException e) {
|
||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||
}
|
||||
LOG.info("Sending " + a + " in state " + currentState.name() +
|
||||
" with session ID " +
|
||||
msg.getSessionId().hashCode() + " in group " +
|
||||
msg.getGroupId().hashCode() + ". " +
|
||||
"Moving on to state " + nextState.name()
|
||||
);
|
||||
}
|
||||
|
||||
private void logMessageReceived(SharerProtocolState currentState,
|
||||
SharerProtocolState nextState, long type, BdfDictionary msg) {
|
||||
private void logMessageReceived(State currentState, State nextState,
|
||||
long type, BaseMessage msg) {
|
||||
|
||||
if (!LOG.isLoggable(INFO)) return;
|
||||
|
||||
try {
|
||||
String t = "unknown";
|
||||
if (type == SHARE_MSG_TYPE_ACCEPT) t = "ACCEPT";
|
||||
else if (type == SHARE_MSG_TYPE_DECLINE) t = "DECLINE";
|
||||
else if (type == SHARE_MSG_TYPE_LEAVE) t = "LEAVE";
|
||||
else if (type == SHARE_MSG_TYPE_ABORT) t = "ABORT";
|
||||
String t = "unknown";
|
||||
if (type == SHARE_MSG_TYPE_ACCEPT) t = "ACCEPT";
|
||||
else if (type == SHARE_MSG_TYPE_DECLINE) t = "DECLINE";
|
||||
else if (type == SHARE_MSG_TYPE_LEAVE) t = "LEAVE";
|
||||
else if (type == SHARE_MSG_TYPE_ABORT) t = "ABORT";
|
||||
|
||||
LOG.info("Received " + t + " in state " + currentState.name() +
|
||||
" with session ID " +
|
||||
Arrays.hashCode(msg.getRaw(SESSION_ID)) + " in group " +
|
||||
Arrays.hashCode(msg.getRaw(GROUP_ID)) + ". " +
|
||||
"Moving on to state " + nextState.name()
|
||||
);
|
||||
} catch (FormatException e) {
|
||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||
}
|
||||
LOG.info("Received " + t + " in state " + currentState.name() +
|
||||
" with session ID " +
|
||||
msg.getSessionId().hashCode() + " in group " +
|
||||
msg.getGroupId().hashCode() + ". " +
|
||||
"Moving on to state " + nextState.name()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StateUpdate<BdfDictionary, BdfDictionary> onMessageDelivered(
|
||||
BdfDictionary localState, BdfDictionary delivered) {
|
||||
public StateUpdate<SharerSessionState, BaseMessage> onMessageDelivered(
|
||||
SharerSessionState localState, BaseMessage delivered) {
|
||||
try {
|
||||
return noUpdate(localState, false);
|
||||
} catch (FormatException e) {
|
||||
@@ -227,38 +195,34 @@ public class SharerEngine
|
||||
}
|
||||
}
|
||||
|
||||
private SharerProtocolState getState(Long state) {
|
||||
return SharerProtocolState.fromValue(state.intValue());
|
||||
}
|
||||
|
||||
private StateUpdate<BdfDictionary, BdfDictionary> abortSession(
|
||||
SharerProtocolState currentState, BdfDictionary localState)
|
||||
private StateUpdate<SharerSessionState, BaseMessage> abortSession(
|
||||
State currentState, SharerSessionState localState)
|
||||
throws FormatException {
|
||||
|
||||
if (LOG.isLoggable(WARNING)) {
|
||||
LOG.warning("Aborting protocol session " +
|
||||
Arrays.hashCode(localState.getRaw(SESSION_ID)) +
|
||||
localState.getSessionId().hashCode() +
|
||||
" in state " + currentState.name());
|
||||
}
|
||||
|
||||
localState.put(STATE, ERROR.getValue());
|
||||
BdfDictionary msg = new BdfDictionary();
|
||||
msg.put(TYPE, SHARE_MSG_TYPE_ABORT);
|
||||
msg.put(SESSION_ID, localState.getRaw(SESSION_ID));
|
||||
msg.put(GROUP_ID, localState.getRaw(GROUP_ID));
|
||||
List<BdfDictionary> messages = Collections.singletonList(msg);
|
||||
localState.setState(ERROR);
|
||||
BaseMessage msg = new SimpleMessage(SHARE_MSG_TYPE_ABORT,
|
||||
localState.getGroupId(), localState.getSessionId());
|
||||
List<BaseMessage> messages = Collections.singletonList(msg);
|
||||
|
||||
List<Event> events = Collections.emptyList();
|
||||
|
||||
return new StateUpdate<BdfDictionary, BdfDictionary>(false, false,
|
||||
return new StateUpdate<SharerSessionState, BaseMessage>(false, false,
|
||||
localState, messages, events);
|
||||
}
|
||||
|
||||
private StateUpdate<BdfDictionary, BdfDictionary> noUpdate(
|
||||
BdfDictionary localState, boolean delete) throws FormatException {
|
||||
private StateUpdate<SharerSessionState, BaseMessage> noUpdate(
|
||||
SharerSessionState localState, boolean delete)
|
||||
throws FormatException {
|
||||
|
||||
return new StateUpdate<BdfDictionary, BdfDictionary>(delete, false,
|
||||
localState, Collections.<BdfDictionary>emptyList(),
|
||||
return new StateUpdate<SharerSessionState, BaseMessage>(delete, false,
|
||||
localState, Collections.<BaseMessage>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