diff --git a/briar-api/src/org/briarproject/api/forum/ForumSharingMessage.java b/briar-api/src/org/briarproject/api/forum/ForumSharingMessage.java new file mode 100644 index 0000000000000000000000000000000000000000..79a43ad6649010bdea912efbe12026f525f43203 --- /dev/null +++ b/briar-api/src/org/briarproject/api/forum/ForumSharingMessage.java @@ -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); + } + } + +} diff --git a/briar-api/src/org/briarproject/api/forum/InviteeAction.java b/briar-api/src/org/briarproject/api/forum/InviteeAction.java deleted file mode 100644 index 212f0861ce661de2e69b18adeb8a52ba9aa14af5..0000000000000000000000000000000000000000 --- a/briar-api/src/org/briarproject/api/forum/InviteeAction.java +++ /dev/null @@ -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; - } - -} diff --git a/briar-api/src/org/briarproject/api/forum/InviteeProtocolState.java b/briar-api/src/org/briarproject/api/forum/InviteeProtocolState.java deleted file mode 100644 index 35d6a880af0b9bbb41c3ffd2ede3122d9b7fb297..0000000000000000000000000000000000000000 --- a/briar-api/src/org/briarproject/api/forum/InviteeProtocolState.java +++ /dev/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; - } -} diff --git a/briar-api/src/org/briarproject/api/forum/SharerAction.java b/briar-api/src/org/briarproject/api/forum/SharerAction.java deleted file mode 100644 index 39796f2c828c10f01bcd6ae3a05f7d258792e11e..0000000000000000000000000000000000000000 --- a/briar-api/src/org/briarproject/api/forum/SharerAction.java +++ /dev/null @@ -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; - } - -} diff --git a/briar-api/src/org/briarproject/api/forum/SharerProtocolState.java b/briar-api/src/org/briarproject/api/forum/SharerProtocolState.java deleted file mode 100644 index b948a9483d980d1cd9a0eeed91d81a6edcdf5511..0000000000000000000000000000000000000000 --- a/briar-api/src/org/briarproject/api/forum/SharerProtocolState.java +++ /dev/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; - } -} diff --git a/briar-core/src/org/briarproject/forum/ForumSharingManagerImpl.java b/briar-core/src/org/briarproject/forum/ForumSharingManagerImpl.java index a157dbe8abd7c5287a0e267ae7bebc6a92614976..cbeb56d60f2ecf2c14000f897ef145c849bea0c8 100644 --- a/briar-core/src/org/briarproject/forum/ForumSharingManagerImpl.java +++ b/briar-core/src/org/briarproject/forum/ForumSharingManagerImpl.java @@ -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 { + + BaseMessage msg = BaseMessage.from(m.getGroupId(), d); + SessionId sessionId = msg.getSessionId(); - SessionId sessionId = new SessionId(msg.getRaw(SESSION_ID)); - long type = msg.getLong(TYPE); - if (type == SHARE_MSG_TYPE_INVITATION) { + 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(); - - 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()); + SessionId sessionId = new SessionId(m.getId().getBytes()); + + 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; + if (!c.equals(s.getContactId())) continue; + + // check that this state actually concerns this forum + if (!s.getForumName().equals(f.getName()) || + !Arrays.equals(s.getForumSalt(), f.getSalt())) { + 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; + 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 { - InviteeProtocolState state = InviteeProtocolState - .fromValue(intState); - if (state.next(InviteeAction.LOCAL_LEAVE) == - InviteeProtocolState.ERROR) 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; + 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)); } } diff --git a/briar-core/src/org/briarproject/forum/ForumSharingSessionState.java b/briar-core/src/org/briarproject/forum/ForumSharingSessionState.java new file mode 100644 index 0000000000000000000000000000000000000000..dc2e69bfb38ecbc5ec72f1d83080c1618207f3ad --- /dev/null +++ b/briar-core/src/org/briarproject/forum/ForumSharingSessionState.java @@ -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; + } + +} \ No newline at end of file diff --git a/briar-core/src/org/briarproject/forum/ForumSharingValidator.java b/briar-core/src/org/briarproject/forum/ForumSharingValidator.java index c204623a27dee2dc193befcaaad12ec915a12cba..b162579433ad180719d24bd25b628dc3b32ea9da 100644 --- a/briar-core/src/org/briarproject/forum/ForumSharingValidator.java +++ b/briar-core/src/org/briarproject/forum/ForumSharingValidator.java @@ -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; diff --git a/briar-core/src/org/briarproject/forum/InviteeEngine.java b/briar-core/src/org/briarproject/forum/InviteeEngine.java index 70e9a24cb4edaeccf2ae96336d905bbc55d0d139..c7c9ff6223c159fb163d6e6504d81c5600cc4246 100644 --- a/briar-core/src/org/briarproject/forum/InviteeEngine.java +++ b/briar-core/src/org/briarproject/forum/InviteeEngine.java @@ -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"; - - 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); - } + if (msg.getType() == SHARE_MSG_TYPE_LEAVE) a = "leave"; + + 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"; - - 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); - } + 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 " + + 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()); } } diff --git a/briar-core/src/org/briarproject/forum/InviteeSessionState.java b/briar-core/src/org/briarproject/forum/InviteeSessionState.java new file mode 100644 index 0000000000000000000000000000000000000000..68b397bc726767ecc15b52f72526425470908725 --- /dev/null +++ b/briar-core/src/org/briarproject/forum/InviteeSessionState.java @@ -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; + } + } + +} \ No newline at end of file diff --git a/briar-core/src/org/briarproject/forum/SharerEngine.java b/briar-core/src/org/briarproject/forum/SharerEngine.java index 05db965b80fb8f78aaa7b86c3f67cae3a838759f..4a142c039523413f5e18d982f51c55e62d3fbf0e 100644 --- a/briar-core/src/org/briarproject/forum/SharerEngine.java +++ b/briar-core/src/org/briarproject/forum/SharerEngine.java @@ -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"; - - 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); - } + if (msg.getType() == SHARE_MSG_TYPE_LEAVE) a = "leave"; + + 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"; - - 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); - } + 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 " + + 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()); } + } diff --git a/briar-core/src/org/briarproject/forum/SharerSessionState.java b/briar-core/src/org/briarproject/forum/SharerSessionState.java new file mode 100644 index 0000000000000000000000000000000000000000..6653648530e7e07a830ec50e5381f75e5a9c6e84 --- /dev/null +++ b/briar-core/src/org/briarproject/forum/SharerSessionState.java @@ -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; + } + } + +} \ No newline at end of file