diff options
author | Andrew Comminos <andrew@comminos.com> | 2017-03-02 08:19:00 +0300 |
---|---|---|
committer | Andrew Comminos <andrew@comminos.com> | 2017-03-02 08:21:00 +0300 |
commit | 4a44ab69bdf4bd2c755f694dbac95fcc06373078 (patch) | |
tree | 6c9cf6e2855e4a9a975134159f56d95d05cf93e3 /src/main/java/com/morlunk/jumble | |
parent | dfdd83dee1707ddc90776e0483ad1b5f9c9db296 (diff) |
Migrate client API to a session-based approach, requiring usage of IJumbleService.getSession() to interact with the protocol.
This is intended to make it safer for clients to know what methods can
be accessed when connectivity is uncertain.
Diffstat (limited to 'src/main/java/com/morlunk/jumble')
5 files changed, 282 insertions, 229 deletions
diff --git a/src/main/java/com/morlunk/jumble/IJumbleService.java b/src/main/java/com/morlunk/jumble/IJumbleService.java index 90b5d23..2080546 100644 --- a/src/main/java/com/morlunk/jumble/IJumbleService.java +++ b/src/main/java/com/morlunk/jumble/IJumbleService.java @@ -24,6 +24,7 @@ import com.morlunk.jumble.model.Server; import com.morlunk.jumble.model.WhisperTarget; import com.morlunk.jumble.net.JumbleUDPMessageType; import com.morlunk.jumble.util.IJumbleObserver; +import com.morlunk.jumble.util.JumbleDisconnectedException; import com.morlunk.jumble.util.JumbleException; import com.morlunk.jumble.util.VoiceTargetMode; @@ -42,6 +43,20 @@ import java.util.List; * will throw IllegalStateException if disconnected or not synchronized. */ public interface IJumbleService { + void registerObserver(IJumbleObserver observer); + + void unregisterObserver(IJumbleObserver observer); + + /** + * @return true if handshaking with the server has completed. + */ + boolean isConnected(); + + /** + * Disconnects from the active connection, or does nothing if no connection is active. + */ + void disconnect(); + /** * Returns the current connection state of the service. * @return one of {@link JumbleService.ConnectionState}. @@ -67,219 +82,15 @@ public interface IJumbleService { void cancelReconnect(); /** - * @return the latency in milliseconds for the TCP connection. - * @throws IllegalStateException if not connected. - */ - long getTCPLatency(); - - /** - * @return the latency in milliseconds for the UDP connection. - * @throws IllegalStateException if not connected. - */ - long getUDPLatency(); - - /** - * @return the maximum bandwidth in bps for audio allowed by the server, or -1 if not set. - * @throws IllegalStateException if not synchronized. - */ - int getMaxBandwidth(); - - /** - * @return the current bandwidth in bps for audio sent to the server, or a negative integer - * if unknown (prior to connection or after disconnection). - * @throws IllegalStateException if not synchronized. - */ - int getCurrentBandwidth(); - - /** - * Returns the protocol version returned by the server in the format 0xAABBCC, where AA - * indicates the major version, BB indicates the minor version, and CC indicates the patch - * version. This is the same formatting used by the Mumble protocol in big-endian format. - * @return the current bandwidth in bps for audio sent to the server, or a negative integer - * if unknown (prior to connection or after disconnection). - * @throws IllegalStateException if not synchronized. - */ - int getServerVersion(); - - /** - * @return a user-readable string with the server's Mumble release info. - * @throws IllegalStateException if not synchronized. - */ - String getServerRelease(); - - /** - * @return a user-readable string with the server's OS name. - * @throws IllegalStateException if not connected. - */ - String getServerOSName(); - - /** - * @return a user-readable string with the server's OS version. - * @throws IllegalStateException if not synchronized. - */ - String getServerOSVersion(); - - /** - * Returns the current user's session. Set during server synchronization. - * @return an integer identifying the current user's connection. - * @throws IllegalStateException if not synchronized. - */ - int getSession(); - - /** - * Returns the current user. Set during server synchronization. - * @return the {@link IUser} representing the current user. - * @throws IllegalStateException if not synchronized. - */ - IUser getSessionUser(); - - /** - * Returns the user's current channel. - * @return the {@link IChannel} representing the user's current channel. - * @throws IllegalStateException if not synchronized. - */ - IChannel getSessionChannel(); - - /** - * @return the server that Jumble is currently connected to (or attempted connection to). - */ - Server getConnectedServer(); - - /** - * Retrieves the user with the given session ID. - * @param session An integer ID identifying a user's session. See {@link IUser#getSession()}. - * @return A user with the given session, or null if not found. - * @throws IllegalStateException if not synchronized. - */ - IUser getUser(int session); - - /** - * Retrieves the channel with the given ID. - * @param id An integer ID identifying a channel. See {@link IChannel#getId()}. - * @return A channel with the given session, or null if not found. - * @throws IllegalStateException if not synchronized. - */ - IChannel getChannel(int id); - - /** - * @return the root channel of the server. - * @throws IllegalStateException if not synchronized. - */ - IChannel getRootChannel(); - - int getPermissions(); - - int getTransmitMode(); - - JumbleUDPMessageType getCodec(); - - boolean usingBluetoothSco(); - - void enableBluetoothSco(); - - void disableBluetoothSco(); - - boolean isTalking(); - - void setTalkingState(boolean talking); - - void joinChannel(int channel); - - void moveUserToChannel(int session, int channel); - - void createChannel(int parent, String name, String description, int position, boolean temporary); - - void sendAccessTokens(List<String> tokens); - - void requestBanList(); - - void requestUserList(); - - void requestPermissions(int channel); - - void requestComment(int session); - - void requestAvatar(int session); - - void requestChannelDescription(int channel); - - void registerUser(int session); - - void kickBanUser(int session, String reason, boolean ban); - - Message sendUserTextMessage(int session, String message); - - Message sendChannelTextMessage(int channel, String message, boolean tree); - - void setUserComment(int session, String comment); - - void setPrioritySpeaker(int session, boolean priority); - - void removeChannel(int channel); - - void setMuteDeafState(int session, boolean mute, boolean deaf); - - void setSelfMuteDeafState(boolean mute, boolean deaf); - - void registerObserver(IJumbleObserver observer); - - void unregisterObserver(IJumbleObserver observer); - - /** - * Links the provided two channels together. - */ - void linkChannels(IChannel channelA, IChannel channelB); - - /** - * Unlinks the two provided channels. - */ - void unlinkChannels(IChannel channelA, IChannel channelB); - - /** - * Unlinks all channels from the provided channel. - * @param channel The channel to be unlinked. - */ - void unlinkAllChannels(IChannel channel); - - /** - * Registers a whisper target to be used as a voice target on the server. - * Note that Mumble only supports a maximum of 30 active voice targets at once. - * @param target The target to register. - * @return A voice target ID in the range [1, 30], or a negative value if all slots are full. - */ - byte registerWhisperTarget(final WhisperTarget target); - - /** - * Unregisters a whisper target from the server. - * Note that Mumble only supports a maximum of 30 active voice targets at once. - * @param target The target ID to unregister. - */ - void unregisterWhisperTarget(byte targetId); - - /** - * Sets the active voice target to the provided ID.<br> - * 0: Normal speech<br> - * 1-30: Whisper targets<br> - * 31: Server loopback - * @param targetId A voice target ID in the range [0, 31]. - */ - void setVoiceTargetId(byte targetId); - - /** - * Gets the current voice target ID in use, in the range [0, 31]. - * @return The active voice target ID. - */ - byte getVoiceTargetId(); - - /** - * Gets the current voice target mode. - * @return The active voice target mode. + * @return the server that Jumble is currently connected to, was connected to, or will attempt connection to. */ - VoiceTargetMode getVoiceTargetMode(); + Server getTargetServer(); /** - * Returns the current whisper target. - * @return the set whisper target, or null if the user is not whispering. + * Returns the active session with the remote, or throws an exception if no session is currently + * active. This can be checked using {@link IJumbleService#isConnected()}. + * @return the active session. + * @throws JumbleDisconnectedException if the connection state is not CONNECTED. */ - WhisperTarget getWhisperTarget(); + IJumbleSession getSession() throws JumbleDisconnectedException; } diff --git a/src/main/java/com/morlunk/jumble/IJumbleSession.java b/src/main/java/com/morlunk/jumble/IJumbleSession.java new file mode 100644 index 0000000..a501f3e --- /dev/null +++ b/src/main/java/com/morlunk/jumble/IJumbleSession.java @@ -0,0 +1,213 @@ +package com.morlunk.jumble; + +import com.morlunk.jumble.model.IChannel; +import com.morlunk.jumble.model.IUser; +import com.morlunk.jumble.model.Message; +import com.morlunk.jumble.model.Server; +import com.morlunk.jumble.model.WhisperTarget; +import com.morlunk.jumble.net.JumbleUDPMessageType; +import com.morlunk.jumble.util.IJumbleObserver; +import com.morlunk.jumble.util.VoiceTargetMode; + +import java.util.List; + +/** + * An interface representing a live connection to the server. + * Created by andrew on 28/02/17. + */ + +public interface IJumbleSession { + /** + * @return the latency in milliseconds for the TCP connection. + */ + long getTCPLatency(); + + /** + * @return the latency in milliseconds for the UDP connection. + */ + long getUDPLatency(); + + /** + * @return the maximum bandwidth in bps for audio allowed by the server, or -1 if not set. + */ + int getMaxBandwidth(); + + /** + * @return the current bandwidth in bps for audio sent to the server, or a negative integer + * if unknown (prior to connection or after disconnection). + */ + int getCurrentBandwidth(); + + /** + * Returns the protocol version returned by the server in the format 0xAABBCC, where AA + * indicates the major version, BB indicates the minor version, and CC indicates the patch + * version. This is the same formatting used by the Mumble protocol in big-endian format. + * @return the current bandwidth in bps for audio sent to the server, or a negative integer + * if unknown (prior to connection or after disconnection). + */ + int getServerVersion(); + + /** + * @return a user-readable string with the server's Mumble release info. + */ + String getServerRelease(); + + /** + * @return a user-readable string with the server's OS name. + */ + String getServerOSName(); + + /** + * @return a user-readable string with the server's OS version. + */ + String getServerOSVersion(); + + /** + * Returns the current user's session. Set during server synchronization. + * @return an integer identifying the current user's connection. + */ + int getSessionId(); + + /** + * Returns the current user. Set during server synchronization. + * @return the {@link IUser} representing the current user. + */ + IUser getSessionUser(); + + /** + * Returns the user's current channel. + * @return the {@link IChannel} representing the user's current channel. + */ + IChannel getSessionChannel(); + + /** + * Retrieves the user with the given session ID. + * @param session An integer ID identifying a user's session. See {@link IUser#getSession()}. + * @return A user with the given session, or null if not found. + */ + IUser getUser(int session); + + /** + * Retrieves the channel with the given ID. + * @param id An integer ID identifying a channel. See {@link IChannel#getId()}. + * @return A channel with the given session, or null if not found. + */ + IChannel getChannel(int id); + + /** + * @return the root channel of the server. + */ + IChannel getRootChannel(); + + int getPermissions(); + + int getTransmitMode(); + + JumbleUDPMessageType getCodec(); + + boolean usingBluetoothSco(); + + void enableBluetoothSco(); + + void disableBluetoothSco(); + + boolean isTalking(); + + void setTalkingState(boolean talking); + + void joinChannel(int channel); + + void moveUserToChannel(int session, int channel); + + void createChannel(int parent, String name, String description, int position, boolean temporary); + + void sendAccessTokens(List<String> tokens); + + void requestBanList(); + + void requestUserList(); + + void requestPermissions(int channel); + + void requestComment(int session); + + void requestAvatar(int session); + + void requestChannelDescription(int channel); + + void registerUser(int session); + + void kickBanUser(int session, String reason, boolean ban); + + Message sendUserTextMessage(int session, String message); + + Message sendChannelTextMessage(int channel, String message, boolean tree); + + void setUserComment(int session, String comment); + + void setPrioritySpeaker(int session, boolean priority); + + void removeChannel(int channel); + + void setMuteDeafState(int session, boolean mute, boolean deaf); + + void setSelfMuteDeafState(boolean mute, boolean deaf); + + /** + * Links the provided two channels together. + */ + void linkChannels(IChannel channelA, IChannel channelB); + + /** + * Unlinks the two provided channels. + */ + void unlinkChannels(IChannel channelA, IChannel channelB); + + /** + * Unlinks all channels from the provided channel. + * @param channel The channel to be unlinked. + */ + void unlinkAllChannels(IChannel channel); + + /** + * Registers a whisper target to be used as a voice target on the server. + * Note that Mumble only supports a maximum of 30 active voice targets at once. + * @param target The target to register. + * @return A voice target ID in the range [1, 30], or a negative value if all slots are full. + */ + byte registerWhisperTarget(final WhisperTarget target); + + /** + * Unregisters a whisper target from the server. + * Note that Mumble only supports a maximum of 30 active voice targets at once. + * @param target The target ID to unregister. + */ + void unregisterWhisperTarget(byte targetId); + + /** + * Sets the active voice target to the provided ID.<br> + * 0: Normal speech<br> + * 1-30: Whisper targets<br> + * 31: Server loopback + * @param targetId A voice target ID in the range [0, 31]. + */ + void setVoiceTargetId(byte targetId); + + /** + * Gets the current voice target ID in use, in the range [0, 31]. + * @return The active voice target ID. + */ + byte getVoiceTargetId(); + + /** + * Gets the current voice target mode. + * @return The active voice target mode. + */ + VoiceTargetMode getVoiceTargetMode(); + + /** + * Returns the current whisper target. + * @return the set whisper target, or null if the user is not whispering. + */ + WhisperTarget getWhisperTarget(); +} diff --git a/src/main/java/com/morlunk/jumble/JumbleService.java b/src/main/java/com/morlunk/jumble/JumbleService.java index 65b5fd5..acbda30 100644 --- a/src/main/java/com/morlunk/jumble/JumbleService.java +++ b/src/main/java/com/morlunk/jumble/JumbleService.java @@ -55,6 +55,7 @@ import com.morlunk.jumble.model.WhisperTargetList; import com.morlunk.jumble.net.JumbleConnection; import com.morlunk.jumble.net.JumbleUDPMessageType; import com.morlunk.jumble.util.IJumbleObserver; +import com.morlunk.jumble.util.JumbleDisconnectedException; import com.morlunk.jumble.util.JumbleException; import com.morlunk.jumble.net.JumbleTCPMessageType; import com.morlunk.jumble.protobuf.Mumble; @@ -67,11 +68,9 @@ import com.morlunk.jumble.util.VoiceTargetMode; import java.security.Security; import java.security.cert.X509Certificate; import java.util.ArrayList; -import java.util.Hashtable; import java.util.List; -import java.util.Queue; -public class JumbleService extends Service implements IJumbleService, JumbleConnection.JumbleConnectionListener, JumbleLogger, BluetoothScoReceiver.Listener { +public class JumbleService extends Service implements IJumbleService, IJumbleSession, JumbleConnection.JumbleConnectionListener, JumbleLogger, BluetoothScoReceiver.Listener { static { // Use Spongy Castle for crypto implementation so we can create and manage PKCS #12 (.p12) certificates. @@ -303,7 +302,9 @@ public class JumbleService extends Service implements IJumbleService, JumbleConn } public void disconnect() { - mConnection.disconnect(); + if (mConnection != null) { + mConnection.disconnect(); + } } public boolean isConnectionEstablished() { @@ -709,6 +710,18 @@ public class JumbleService extends Service implements IJumbleService, JumbleConn } @Override + public Server getTargetServer() { + return mServer; + } + + @Override + public IJumbleSession getSession() throws JumbleDisconnectedException { + if (mConnectionState != ConnectionState.CONNECTED) + throw new JumbleDisconnectedException(); + return this; + } + + @Override public long getTCPLatency() { try { return getConnection().getTCPLatency(); @@ -781,7 +794,7 @@ public class JumbleService extends Service implements IJumbleService, JumbleConn } @Override - public int getSession() { + public int getSessionId() { try { return getConnection().getSession(); } catch (NotSynchronizedException e) { @@ -792,7 +805,7 @@ public class JumbleService extends Service implements IJumbleService, JumbleConn @Override public IUser getSessionUser() { try { - return getModelHandler().getUser(getSession()); + return getModelHandler().getUser(getSessionId()); } catch (NotSynchronizedException e) { throw new IllegalStateException(e); } @@ -807,11 +820,6 @@ public class JumbleService extends Service implements IJumbleService, JumbleConn } @Override - public Server getConnectedServer() { - return mServer; - } - - @Override public IUser getUser(int session) { try { return getModelHandler().getUser(session); @@ -896,7 +904,7 @@ public class JumbleService extends Service implements IJumbleService, JumbleConn @Override public void joinChannel(int channel) { - moveUserToChannel(getSession(), channel); + moveUserToChannel(getSessionId(), channel); } @Override @@ -989,11 +997,11 @@ public class JumbleService extends Service implements IJumbleService, JumbleConn tmb.setMessage(message); getConnection().sendTCPMessage(tmb.build(), JumbleTCPMessageType.TextMessage); - User self = getModelHandler().getUser(getSession()); + User self = getModelHandler().getUser(getSessionId()); User user = getModelHandler().getUser(session); List<User> users = new ArrayList<User>(1); users.add(user); - return new Message(getSession(), self.getName(), new ArrayList<Channel>(0), new ArrayList<Channel>(0), users, message); + return new Message(getSessionId(), self.getName(), new ArrayList<Channel>(0), new ArrayList<Channel>(0), users, message); } catch (NotSynchronizedException e) { throw new IllegalStateException(e); } @@ -1011,11 +1019,11 @@ public class JumbleService extends Service implements IJumbleService, JumbleConn tmb.setMessage(message); getConnection().sendTCPMessage(tmb.build(), JumbleTCPMessageType.TextMessage); - User self = getModelHandler().getUser(getSession()); + User self = getModelHandler().getUser(getSessionId()); Channel targetChannel = getModelHandler().getChannel(channel); List<Channel> targetChannels = new ArrayList<Channel>(); targetChannels.add(targetChannel); - return new Message(getSession(), self.getName(), targetChannels, tree ? targetChannels : new ArrayList<Channel>(0), new ArrayList<User>(0), message); + return new Message(getSessionId(), self.getName(), targetChannels, tree ? targetChannels : new ArrayList<Channel>(0), new ArrayList<User>(0), message); } catch (NotSynchronizedException e) { throw new IllegalStateException(e); } @@ -1071,6 +1079,11 @@ public class JumbleService extends Service implements IJumbleService, JumbleConn } @Override + public boolean isConnected() { + return mConnectionState == ConnectionState.CONNECTED; + } + + @Override public void linkChannels(IChannel channelA, IChannel channelB) { Mumble.ChannelState.Builder csb = Mumble.ChannelState.newBuilder(); csb.setChannelId(channelA.getId()); diff --git a/src/main/java/com/morlunk/jumble/protocol/ModelHandler.java b/src/main/java/com/morlunk/jumble/protocol/ModelHandler.java index 02789f6..f1917e4 100644 --- a/src/main/java/com/morlunk/jumble/protocol/ModelHandler.java +++ b/src/main/java/com/morlunk/jumble/protocol/ModelHandler.java @@ -315,8 +315,8 @@ public class ModelHandler extends JumbleTCPMessageListener.Stub { if(msg.hasPrioritySpeaker()) user.setPrioritySpeaker(msg.getPrioritySpeaker()); -// if(self != null && ((user.getChannelId() == self.getChannelId()) || (actor.getSession() == self.getSession()))) { -// if(user.getSession() == self.getSession()) { +// if(self != null && ((user.getChannelId() == self.getChannelId()) || (actor.getSessionId() == self.getSessionId()))) { +// if(user.getSessionId() == self.getSessionId()) { // if(msg.hasMute() && msg.hasDeaf() && user.isMuted() && user.isDeafened()) { // mLogger.logInfo(); // } diff --git a/src/main/java/com/morlunk/jumble/util/JumbleDisconnectedException.java b/src/main/java/com/morlunk/jumble/util/JumbleDisconnectedException.java new file mode 100644 index 0000000..2b51e6c --- /dev/null +++ b/src/main/java/com/morlunk/jumble/util/JumbleDisconnectedException.java @@ -0,0 +1,16 @@ +package com.morlunk.jumble.util; + +/** + * Called when a + * Created by andrew on 01/03/17. + */ + +public class JumbleDisconnectedException extends RuntimeException { + public JumbleDisconnectedException() { + super("Caller attempted to use the protocol while disconnected."); + } + + public JumbleDisconnectedException(String reason) { + super(reason); + } +} |