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..74e977ac34b505e49438ec2c1491aecf28908b1d 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,7 +55,6 @@ 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; @@ -76,11 +71,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 +83,8 @@ 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.forum.ForumSharingSessionState.fromBdfDictionary; +import static org.briarproject.forum.SharerSessionState.Action; class ForumSharingManagerImpl extends BdfIncomingMessageHook implements ForumSharingManager, Client, RemoveForumHook, @@ -214,10 +205,10 @@ class ForumSharingManagerImpl extends BdfIncomingMessageHook throw new FormatException(); // initialize state and process invitation - BdfDictionary state = + InviteeSessionState state = initializeInviteeState(txn, contactId, msg); 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); @@ -226,23 +217,25 @@ class ForumSharingManagerImpl extends BdfIncomingMessageHook } else if (type == SHARE_MSG_TYPE_ACCEPT || type == 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) { // 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,7 +257,8 @@ 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(); @@ -275,7 +269,7 @@ class ForumSharingManagerImpl extends BdfIncomingMessageHook // start engine and process its state update SharerEngine engine = new SharerEngine(); - processStateUpdate(txn, null, + processSharerStateUpdate(txn, null, engine.onLocalAction(localState, localAction)); txn.setComplete(); @@ -293,7 +287,7 @@ 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(); @@ -305,7 +299,7 @@ class ForumSharingManagerImpl extends BdfIncomingMessageHook // start engine and process its state update InviteeEngine engine = new InviteeEngine(forumFactory); - processStateUpdate(txn, null, + processInviteeStateUpdate(txn, null, engine.onLocalAction(localState, localAction)); txn.setComplete(); @@ -346,12 +340,12 @@ class ForumSharingManagerImpl extends BdfIncomingMessageHook boolean available = false; if (!local) { // figure out whether the forum is still available - BdfDictionary sessionState = + ForumSharingSessionState s = getSessionState(txn, sessionId, true); - InviteeProtocolState state = InviteeProtocolState - .fromValue( - sessionState.getLong(STATE).intValue()); - available = state == AWAIT_LOCAL_RESPONSE; + if (!(s instanceof InviteeSessionState)) + continue; + available = ((InviteeSessionState) s).getState() == + InviteeSessionState.State.AWAIT_LOCAL_RESPONSE; } ForumInvitationMessage im = new ForumInvitationMessage(m.getKey(), sessionId, @@ -490,7 +484,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,26 +496,20 @@ 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, + private InviteeSessionState initializeInviteeState(Transaction txn, ContactId contactId, BdfDictionary msg) throws FormatException, DbException { @@ -538,29 +526,25 @@ 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); + SessionId sessionId = new SessionId(msg.getRaw(SESSION_ID)); + + InviteeSessionState s = new InviteeSessionState(sessionId, 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 +554,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 +566,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 +605,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,16 +648,16 @@ class ForumSharingManagerImpl extends BdfIncomingMessageHook } private void processStateUpdate(Transaction txn, MessageId messageId, - StateUpdate<BdfDictionary, BdfDictionary> result) + StateUpdate<ForumSharingSessionState, BdfDictionary> 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) { @@ -677,24 +679,47 @@ class ForumSharingManagerImpl extends BdfIncomingMessageHook } } - private void performTasks(Transaction txn, BdfDictionary localState) + private void processSharerStateUpdate(Transaction txn, MessageId messageId, + StateUpdate<SharerSessionState, BdfDictionary> result) + throws DbException, FormatException { + + StateUpdate<ForumSharingSessionState, BdfDictionary> r = + new StateUpdate<ForumSharingSessionState, BdfDictionary>( + result.deleteMessage, result.deleteState, + result.localState, result.toSend, result.toBroadcast); + + processStateUpdate(txn, messageId, r); + } + + private void processInviteeStateUpdate(Transaction txn, MessageId messageId, + StateUpdate<InviteeSessionState, BdfDictionary> result) + throws DbException, FormatException { + + StateUpdate<ForumSharingSessionState, BdfDictionary> r = + new StateUpdate<ForumSharingSessionState, BdfDictionary>( + 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 @@ -786,17 +811,17 @@ class ForumSharingManagerImpl extends BdfIncomingMessageHook private void leaveForum(Transaction txn, ContactId c, Forum f) throws DbException, FormatException { - BdfDictionary state = getSessionStateForLeaving(txn, f, c); + ForumSharingSessionState state = getSessionStateForLeaving(txn, f, c); BdfDictionary action = new BdfDictionary(); action.put(TYPE, SHARE_MSG_TYPE_LEAVE); - if (state.getBoolean(IS_SHARER)) { + if (state instanceof SharerSessionState) { SharerEngine engine = new SharerEngine(); - processStateUpdate(txn, null, - engine.onLocalAction(state, action)); + processSharerStateUpdate(txn, null, + engine.onLocalAction((SharerSessionState) state, action)); } else { 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/InviteeEngine.java b/briar-core/src/org/briarproject/forum/InviteeEngine.java index 70e9a24cb4edaeccf2ae96336d905bbc55d0d139..81d4cf766025797813049005487e0e14072e4b5a 100644 --- a/briar-core/src/org/briarproject/forum/InviteeEngine.java +++ b/briar-core/src/org/briarproject/forum/InviteeEngine.java @@ -9,8 +9,6 @@ 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; @@ -19,9 +17,6 @@ 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; @@ -29,25 +24,25 @@ 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.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<BdfDictionary, InviteeSessionState, BdfDictionary> { private final ForumFactory forumFactory; private static final Logger LOG = @@ -58,16 +53,15 @@ public class InviteeEngine } @Override - public StateUpdate<BdfDictionary, BdfDictionary> onLocalAction( - BdfDictionary localState, BdfDictionary localAction) { + public StateUpdate<InviteeSessionState, BdfDictionary> onLocalAction( + InviteeSessionState localState, BdfDictionary localAction) { try { - InviteeProtocolState currentState = - getState(localState.getLong(STATE)); + State currentState = localState.getState(); long type = localAction.getLong(TYPE); - InviteeAction action = InviteeAction.getLocal(type); - InviteeProtocolState nextState = currentState.next(action); - localState.put(STATE, nextState.getValue()); + Action action = Action.getLocal(type); + State nextState = currentState.next(action); + localState.setState(nextState); if (action == LOCAL_ABORT && currentState != ERROR) { return abortSession(currentState, localState); @@ -85,14 +79,14 @@ public class InviteeEngine 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)) + new BdfEntry(SESSION_ID, localState.getSessionId()), + new BdfEntry(GROUP_ID, localState.getGroupId()) ); if (action == LOCAL_ACCEPT) { - localState.put(TASK, TASK_ADD_SHARED_FORUM); + localState.setTask(TASK_ADD_SHARED_FORUM); msg.put(TYPE, SHARE_MSG_TYPE_ACCEPT); } else { - localState.put(TASK, + localState.setTask( TASK_REMOVE_FORUM_FROM_LIST_SHARED_WITH_US); msg.put(TYPE, SHARE_MSG_TYPE_DECLINE); } @@ -102,15 +96,15 @@ public class InviteeEngine 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)); + msg.put(SESSION_ID, localState.getSessionId()); + msg.put(GROUP_ID, localState.getGroupId()); 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, BdfDictionary>(false, false, localState, messages, events); } catch (FormatException e) { throw new IllegalArgumentException(e); @@ -118,16 +112,15 @@ public class InviteeEngine } @Override - public StateUpdate<BdfDictionary, BdfDictionary> onMessageReceived( - BdfDictionary localState, BdfDictionary msg) { + public StateUpdate<InviteeSessionState, BdfDictionary> onMessageReceived( + InviteeSessionState localState, BdfDictionary msg) { try { - InviteeProtocolState currentState = - getState(localState.getLong(STATE)); + State currentState = localState.getState(); long type = msg.getLong(TYPE); - InviteeAction action = InviteeAction.getRemote(type); - InviteeProtocolState nextState = currentState.next(action); - localState.put(STATE, nextState.getValue()); + Action action = Action.getRemote(type); + State nextState = currentState.next(action); + localState.setState(nextState); logMessageReceived(currentState, nextState, type, msg); @@ -149,7 +142,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,31 +151,30 @@ 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, BdfDictionary>(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, BdfDictionary msg) { if (!LOG.isLoggable(INFO)) return; @@ -194,16 +186,16 @@ public class InviteeEngine " 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() + "Moving on to state " + localState.getState().name() ); } catch (FormatException e) { if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); } } - private void logMessageReceived(InviteeProtocolState currentState, - InviteeProtocolState nextState, long type, BdfDictionary msg) { + private void logMessageReceived(State currentState, State nextState, + long type, BdfDictionary msg) { + if (!LOG.isLoggable(INFO)) return; try { @@ -224,8 +216,8 @@ public class InviteeEngine } @Override - public StateUpdate<BdfDictionary, BdfDictionary> onMessageDelivered( - BdfDictionary localState, BdfDictionary delivered) { + public StateUpdate<InviteeSessionState, BdfDictionary> onMessageDelivered( + InviteeSessionState localState, BdfDictionary delivered) { try { return noUpdate(localState, false); } catch (FormatException e) { @@ -234,37 +226,33 @@ 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, BdfDictionary> 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()); + localState.setState(ERROR); 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)); + msg.put(SESSION_ID, localState.getSessionId()); + msg.put(GROUP_ID, localState.getGroupId()); List<BdfDictionary> messages = Collections.singletonList(msg); List<Event> events = Collections.emptyList(); - return new StateUpdate<BdfDictionary, BdfDictionary>(false, false, + return new StateUpdate<InviteeSessionState, BdfDictionary>(false, false, localState, messages, events); } - private StateUpdate<BdfDictionary, BdfDictionary> noUpdate( - BdfDictionary localState, boolean delete) throws FormatException { + private StateUpdate<InviteeSessionState, BdfDictionary> noUpdate( + InviteeSessionState localState, boolean delete) throws FormatException { - return new StateUpdate<BdfDictionary, BdfDictionary>(delete, false, + return new StateUpdate<InviteeSessionState, BdfDictionary>(delete, false, localState, Collections.<BdfDictionary>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..cc4e1c40401b6970add1231e57be46f4067188af --- /dev/null +++ b/briar-core/src/org/briarproject/forum/InviteeSessionState.java @@ -0,0 +1,130 @@ +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_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 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 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..3e81470ae4812b2956bf31cbb8d91072023ae179 100644 --- a/briar-core/src/org/briarproject/forum/SharerEngine.java +++ b/briar-core/src/org/briarproject/forum/SharerEngine.java @@ -6,8 +6,7 @@ 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 static org.briarproject.forum.SharerSessionState.Action; import java.util.Arrays; import java.util.Collections; @@ -16,7 +15,6 @@ 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; @@ -27,40 +25,38 @@ 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.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<BdfDictionary, SharerSessionState, BdfDictionary> { private static final Logger LOG = Logger.getLogger(SharerEngine.class.getName()); @Override - public StateUpdate<BdfDictionary, BdfDictionary> onLocalAction( - BdfDictionary localState, BdfDictionary localAction) { + public StateUpdate<SharerSessionState, BdfDictionary> onLocalAction( + SharerSessionState localState, BdfDictionary localAction) { try { - SharerProtocolState currentState = - getState(localState.getLong(STATE)); + State currentState = localState.getState(); long type = localAction.getLong(TYPE); - SharerAction action = SharerAction.getLocal(type); - SharerProtocolState nextState = currentState.next(action); - localState.put(STATE, nextState.getValue()); + Action action = Action.getLocal(type); + State nextState = currentState.next(action); + localState.setState(nextState); if (action == LOCAL_ABORT && currentState != ERROR) { return abortSession(currentState, localState); @@ -79,32 +75,32 @@ public class SharerEngine 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)); + msg.put(SESSION_ID, localState.getSessionId()); + msg.put(GROUP_ID, localState.getGroupId()); + msg.put(FORUM_NAME, localState.getForumName()); + msg.put(FORUM_SALT, localState.getForumSalt()); if (localAction.containsKey(INVITATION_MSG)) { msg.put(INVITATION_MSG, localAction.getString(INVITATION_MSG)); } 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)); + msg.put(SESSION_ID, localState.getSessionId()); + msg.put(GROUP_ID, localState.getGroupId()); 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, BdfDictionary>(false, false, localState, messages, events); } catch (FormatException e) { throw new IllegalArgumentException(e); @@ -112,16 +108,15 @@ public class SharerEngine } @Override - public StateUpdate<BdfDictionary, BdfDictionary> onMessageReceived( - BdfDictionary localState, BdfDictionary msg) { + public StateUpdate<SharerSessionState, BdfDictionary> onMessageReceived( + SharerSessionState localState, BdfDictionary msg) { try { - SharerProtocolState currentState = - getState(localState.getLong(STATE)); + State currentState = localState.getState(); long type = msg.getLong(TYPE); - SharerAction action = SharerAction.getRemote(type); - SharerProtocolState nextState = currentState.next(action); - localState.put(STATE, nextState.getValue()); + Action action = Action.getRemote(type); + State nextState = currentState.next(action); + localState.setState(nextState); logMessageReceived(currentState, nextState, type, msg); @@ -141,7 +136,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,30 +146,29 @@ 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, BdfDictionary>(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, + BdfDictionary msg) { if (!LOG.isLoggable(INFO)) return; @@ -182,20 +176,20 @@ public class SharerEngine if (msg.getLong(TYPE, -1L) == SHARE_MSG_TYPE_LEAVE) a = "leave"; try { - LOG.info("Sending " + a + " in state " + state.name() + + LOG.info("Sending " + a + " 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 " + - getState(localState.getLong(STATE)).name() + "Moving on to state " + nextState.name() ); } catch (FormatException e) { if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); } } - private void logMessageReceived(SharerProtocolState currentState, - SharerProtocolState nextState, long type, BdfDictionary msg) { + private void logMessageReceived(State currentState, State nextState, + long type, BdfDictionary msg) { + if (!LOG.isLoggable(INFO)) return; try { @@ -217,8 +211,8 @@ public class SharerEngine } @Override - public StateUpdate<BdfDictionary, BdfDictionary> onMessageDelivered( - BdfDictionary localState, BdfDictionary delivered) { + public StateUpdate<SharerSessionState, BdfDictionary> onMessageDelivered( + SharerSessionState localState, BdfDictionary delivered) { try { return noUpdate(localState, false); } catch (FormatException e) { @@ -227,38 +221,36 @@ 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, BdfDictionary> 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()); + localState.setState(ERROR); 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)); + msg.put(SESSION_ID, localState.getSessionId()); + msg.put(GROUP_ID, localState.getGroupId()); List<BdfDictionary> messages = Collections.singletonList(msg); List<Event> events = Collections.emptyList(); - return new StateUpdate<BdfDictionary, BdfDictionary>(false, false, + return new StateUpdate<SharerSessionState, BdfDictionary>(false, false, localState, messages, events); } - private StateUpdate<BdfDictionary, BdfDictionary> noUpdate( - BdfDictionary localState, boolean delete) throws FormatException { + private StateUpdate<SharerSessionState, BdfDictionary> noUpdate( + SharerSessionState localState, boolean delete) + throws FormatException { - return new StateUpdate<BdfDictionary, BdfDictionary>(delete, false, + return new StateUpdate<SharerSessionState, BdfDictionary>(delete, false, localState, Collections.<BdfDictionary>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..b438c673459d05ef7ebd602ff4a44fc924742c69 --- /dev/null +++ b/briar-core/src/org/briarproject/forum/SharerSessionState.java @@ -0,0 +1,130 @@ +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_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.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; + + 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 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 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 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