├── .gitignore
├── LICENSE
├── build.gradle
├── docs
├── CODE_OF_CONDUCT.md
├── ISSUE_TEMPLATE.md
├── PULL_REQUEST_TEMPLATE.md
└── README.md
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── settings.gradle
└── src
├── main
└── java
│ └── com
│ └── clusterws
│ ├── Channel.java
│ ├── ClusterWS.java
│ ├── Emitter.java
│ ├── IClusterWSListener.java
│ ├── IEmitterListener.java
│ ├── ISocketEvents.java
│ ├── MessageHandler.java
│ ├── PingHandler.java
│ ├── ReconnectionParams.java
│ └── Socket.java
└── test
└── java
└── com
└── clusterws
├── ChannelServerTest.java
├── ChannelTest.java
├── ClusterWSStatesBool.java
├── ClusterWSTest.java
├── EmitterTest.java
├── MessageHandlerTest.java
└── PingHandlerTest.java
/.gitignore:
--------------------------------------------------------------------------------
1 | /.idea
2 | /build
3 | *.iml
4 | /.gradle
5 | /out
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 ClusterWS
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'java'
2 | apply plugin: 'idea'
3 | apply plugin: 'maven'
4 |
5 | group 'com.github.clusterws'
6 | version '1.5'
7 | sourceCompatibility = 1.8
8 | targetCompatibility = 1.8
9 |
10 | repositories {
11 | mavenCentral()
12 | jcenter()
13 | }
14 |
15 | configurations {
16 | deployerJars
17 | }
18 |
19 | dependencies {
20 | testCompile 'junit:junit:4.12'
21 | testCompile 'org.mockito:mockito-core:2.7.22'
22 | compile "org.java-websocket:Java-WebSocket:1.3.6"
23 | compile 'com.alibaba:fastjson:1.2.44'
24 | }
25 |
26 | task sourcesJar(type: Jar, dependsOn: classes) {
27 | classifier = 'sources'
28 | from sourceSets.main.allJava
29 | }
30 |
31 | task javadocJar(type: Jar, dependsOn: javadoc) {
32 | classifier = 'javadoc'
33 | from javadoc.destinationDir
34 | }
35 |
36 | artifacts {
37 | archives sourcesJar
38 | archives javadocJar
39 | }
40 |
--------------------------------------------------------------------------------
/docs/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
6 |
7 | ## Our Standards
8 |
9 | Examples of behavior that contributes to creating a positive environment include:
10 |
11 | * Using welcoming and inclusive language
12 | * Being respectful of differing viewpoints and experiences
13 | * Gracefully accepting constructive criticism
14 | * Focusing on what is best for the community
15 | * Showing empathy towards other community members
16 |
17 | Examples of unacceptable behavior by participants include:
18 |
19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances
20 | * Trolling, insulting/derogatory comments, and personal or political attacks
21 | * Public or private harassment
22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission
23 | * Other conduct which could reasonably be considered inappropriate in a professional setting
24 |
25 | ## Our Responsibilities
26 |
27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
28 |
29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
30 |
31 | ## Scope
32 |
33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
34 |
35 | ## Enforcement
36 |
37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team . The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
38 |
39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
40 |
41 | ## Attribution
42 |
43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
44 |
45 | [homepage]: http://contributor-covenant.org
46 | [version]: http://contributor-covenant.org/version/1/4/
--------------------------------------------------------------------------------
/docs/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | ### Submitting
2 |
3 | - [ ] Bug
4 | - [ ] Question
5 | - [ ] Suggetion
6 | - [ ] Other
7 |
8 | ### Details
9 |
--------------------------------------------------------------------------------
/docs/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | ### Submitting
2 |
3 | - [ ] Bug fix
4 | - [ ] Feature
5 | - [ ] Other
6 |
7 | ### Details
8 |
--------------------------------------------------------------------------------
/docs/README.md:
--------------------------------------------------------------------------------
1 |
ClusterWS Java Client
2 | Build Scalable Node.js WebSocket Applications
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | Official Java Client library for ClusterWS - lightweight, fast and powerful framework for building horizontally & vertically scalable WebSocket applications in Node.js
16 |
17 |
18 |
19 |
20 | Find more about ClusterWS Java Client in Wiki Documentation
21 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ClusterWS/ClusterWS-Client-Java/50deb4992b414aad001fc47744aad801cabd5662/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Sun Dec 10 10:00:07 NZDT 2017
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-3.5-rc-2-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn ( ) {
37 | echo "$*"
38 | }
39 |
40 | die ( ) {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save ( ) {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'clusterws-client-java'
2 |
3 |
--------------------------------------------------------------------------------
/src/main/java/com/clusterws/Channel.java:
--------------------------------------------------------------------------------
1 | package com.clusterws;
2 |
3 | import java.util.List;
4 |
5 | public class Channel {
6 | public interface IChannelListener {
7 | void onDataReceived(String channelName, Object data);
8 | }
9 |
10 | private IChannelListener mChannelListener;
11 | private String mChannelName;
12 | private ClusterWS mClusterWS;
13 |
14 | public Channel(String channelName, ClusterWS clusterWS) {
15 | mChannelName = channelName;
16 | mClusterWS = clusterWS;
17 | }
18 |
19 | public Channel watch(IChannelListener listener) {
20 | mChannelListener = listener;
21 | return this;
22 | }
23 |
24 | public Channel publish(Object data) {
25 | mClusterWS.send(mChannelName, data, "publish");
26 | return this;
27 | }
28 |
29 | public void unsubscribe() {
30 | mClusterWS.send("unsubscribe", mChannelName, "system");
31 | List channelArrayList = mClusterWS.getChannels();
32 | channelArrayList.remove(this);
33 | }
34 |
35 | String getChannelName() {
36 | return mChannelName;
37 | }
38 |
39 | void onMessage(Object data) {
40 | if (mChannelListener != null) {
41 | mChannelListener.onDataReceived(mChannelName, data);
42 | }
43 | }
44 |
45 | void subscribe() {
46 | mClusterWS.send("subscribe", mChannelName, "system");
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/main/java/com/clusterws/ClusterWS.java:
--------------------------------------------------------------------------------
1 | package com.clusterws;
2 |
3 | import org.java_websocket.WebSocket;
4 |
5 | import java.net.URI;
6 | import java.nio.ByteBuffer;
7 | import java.nio.charset.StandardCharsets;
8 | import java.util.ArrayList;
9 | import java.util.List;
10 | import java.util.Timer;
11 | import java.util.TimerTask;
12 | import java.util.concurrent.ThreadLocalRandom;
13 |
14 | public class ClusterWS {
15 | private Socket mSocket;
16 | private String mUrl;
17 | private Emitter mEmitter;
18 | private boolean mUseBinary;
19 | private IClusterWSListener mClusterWSListener;
20 | private MessageHandler mMessageHandler;
21 | private PingHandler mPingHandler;
22 | private List mChannels;
23 | private ReconnectionParams mReconnectionParams;
24 | private static final byte[] PONG = "A".getBytes();
25 |
26 | public ClusterWS(String url) {
27 | if (url == null) {
28 | throw new NullPointerException("Url must be provided");
29 | }
30 | mUrl = url;
31 | mChannels = new ArrayList<>();
32 | mReconnectionParams = new ReconnectionParams(
33 | false,
34 | null,
35 | null,
36 | null);
37 | createSocket();
38 | }
39 |
40 | public ClusterWS setReconnection(Boolean autoReconnect,
41 | Integer reconnectionIntervalMin,
42 | Integer reconnectionIntervalMax,
43 | Integer reconnectionAttempts) {
44 | mReconnectionParams = new ReconnectionParams(autoReconnect,
45 | reconnectionIntervalMin,
46 | reconnectionIntervalMax,
47 | reconnectionAttempts);
48 | return this;
49 | }
50 |
51 | public ClusterWS setClusterWSListener(IClusterWSListener clusterWSListener) {
52 | mClusterWSListener = clusterWSListener;
53 | return this;
54 | }
55 |
56 | public void connect() {
57 | mSocket.connect();
58 | }
59 |
60 | public void disconnect(Integer closeCode, String reason) {
61 | mSocket.close(closeCode == null ? 1000 : closeCode, reason);
62 | }
63 |
64 | public void on(String event, IEmitterListener listener) {
65 | mEmitter.addEventListener(event, listener);
66 | }
67 |
68 | public void send(String event, Object data) {
69 | send(event, data, "emit");
70 | }
71 |
72 | public WebSocket.READYSTATE getState() {
73 | return mSocket.getReadyState();
74 | }
75 |
76 | public Channel getChannelByName(String channelName) {
77 | for (Channel channel :
78 | mChannels) {
79 | if (channel.getChannelName().equals(channelName)) {
80 | return channel;
81 | }
82 | }
83 | return null;
84 | }
85 |
86 | public Channel subscribe(String channelName) {
87 | for (Channel channel :
88 | mChannels) {
89 | if (channel.getChannelName().equals(channelName)) {
90 | return channel;
91 | }
92 | }
93 | Channel newChannel = new Channel(channelName, this);
94 | newChannel.subscribe();
95 | mChannels.add(newChannel);
96 | return newChannel;
97 | }
98 |
99 | public List getChannels() {
100 | return mChannels;
101 | }
102 |
103 | IClusterWSListener getClusterWSListener() {
104 | return mClusterWSListener;
105 | }
106 |
107 | Emitter getEmitter() {
108 | return mEmitter;
109 | }
110 |
111 | void setUseBinary(boolean useBinary) {
112 | mUseBinary = useBinary;
113 | }
114 |
115 |
116 | void send(String event, Object data, String type) {
117 | if (mUseBinary) {
118 | mSocket.send(mMessageHandler.messageEncode(event, data, type).getBytes());
119 | } else {
120 | mSocket.send(mMessageHandler.messageEncode(event, data, type));
121 |
122 | }
123 | }
124 |
125 | PingHandler getPingHandler() {
126 | return mPingHandler;
127 | }
128 |
129 | private void createSocket() {
130 | mSocket = new Socket(URI.create(mUrl), new ISocketEvents() {
131 | @Override
132 | public void onOpen() {
133 | for (Channel channel :
134 | mChannels) {
135 | channel.subscribe();
136 | }
137 | }
138 |
139 | @Override
140 | public void onError(Exception exception) {
141 | if (mClusterWSListener != null) {
142 | mClusterWSListener.onError(exception);
143 | }
144 | }
145 |
146 | @Override
147 | public void onClose(int code, String reason) {
148 | if (mPingHandler.getPingTimer() != null) {
149 | mPingHandler.getPingTimer().cancel();
150 | }
151 | if (mReconnectionParams.isAutoReconnect()
152 | && code != 1000
153 | && (mReconnectionParams.getReconnectionAttempts() == 0 || mReconnectionParams.getReconnectionsAttempted() < mReconnectionParams.getReconnectionAttempts())) {
154 | if (mSocket.getReadyState() == WebSocket.READYSTATE.CLOSED || mSocket.getReadyState() == WebSocket.READYSTATE.NOT_YET_CONNECTED || mSocket.getReadyState() == WebSocket.READYSTATE.CLOSING) {
155 | mReconnectionParams.incrementReconnectionsAttempted();
156 | int randomDelay = ThreadLocalRandom.current().nextInt(1,
157 | mReconnectionParams.getReconnectionIntervalMax() -
158 | mReconnectionParams.getReconnectionIntervalMin() +
159 | 1);
160 | new Timer().schedule(new TimerTask() {
161 | @Override
162 | public void run() {
163 | connect();
164 | }
165 | }, randomDelay);
166 | }
167 | }
168 | mClusterWSListener.onDisconnected(code, reason);
169 | }
170 |
171 | @Override
172 | public void onBinaryMessage(ByteBuffer bytes) {
173 | byte[] arr = new byte[bytes.remaining()];
174 | bytes.get(arr);
175 | if (arr.length == 1 && arr[0] == 57) {
176 | mPingHandler.setMissedPingToZero();
177 | mSocket.send(PONG);
178 | } else {
179 | String message = new String(arr, StandardCharsets.UTF_8);
180 | onMessageReceived(message);
181 | }
182 |
183 | }
184 |
185 | @Override
186 | public void onMessage(String message) {
187 | onMessageReceived(message);
188 | }
189 | });
190 | mUseBinary = false;
191 | mEmitter = new Emitter();
192 | mMessageHandler = new MessageHandler();
193 | mPingHandler = new PingHandler();
194 | }
195 |
196 | private void onMessageReceived(String message) {
197 | mMessageHandler.messageDecode(ClusterWS.this, message);
198 | }
199 | }
200 |
--------------------------------------------------------------------------------
/src/main/java/com/clusterws/Emitter.java:
--------------------------------------------------------------------------------
1 | package com.clusterws;
2 |
3 | import java.util.concurrent.ConcurrentHashMap;
4 |
5 | class Emitter {
6 | private ConcurrentHashMap mEvents;
7 |
8 | Emitter() {
9 | mEvents = new ConcurrentHashMap<>();
10 | }
11 |
12 | void addEventListener(String event, IEmitterListener listener) {
13 | if (mEvents.containsKey(event)) {
14 | mEvents.replace(event, listener);
15 | } else {
16 | mEvents.put(event, listener);
17 | }
18 | }
19 |
20 | void emit(String event, Object object) {
21 | IEmitterListener listener = mEvents.get(event);
22 | if (listener != null) {
23 | listener.onDataReceived(object);
24 | }
25 | }
26 |
27 | void removeAllEvents() {
28 | mEvents = new ConcurrentHashMap<>();
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/main/java/com/clusterws/IClusterWSListener.java:
--------------------------------------------------------------------------------
1 | package com.clusterws;
2 |
3 | public interface IClusterWSListener {
4 | void onConnected();
5 |
6 | void onError(Exception exception);
7 |
8 | void onDisconnected(int code, String reason);
9 | }
10 |
--------------------------------------------------------------------------------
/src/main/java/com/clusterws/IEmitterListener.java:
--------------------------------------------------------------------------------
1 | package com.clusterws;
2 |
3 | public interface IEmitterListener {
4 | void onDataReceived(Object data);
5 | }
6 |
--------------------------------------------------------------------------------
/src/main/java/com/clusterws/ISocketEvents.java:
--------------------------------------------------------------------------------
1 | package com.clusterws;
2 |
3 | import java.nio.ByteBuffer;
4 |
5 | public interface ISocketEvents {
6 | void onOpen();
7 |
8 | void onError(Exception exception);
9 |
10 | void onClose(int code, String reason);
11 |
12 | void onBinaryMessage(ByteBuffer bytes);
13 |
14 | void onMessage(String message);
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/src/main/java/com/clusterws/MessageHandler.java:
--------------------------------------------------------------------------------
1 | package com.clusterws;
2 |
3 | import com.alibaba.fastjson.JSON;
4 | import com.alibaba.fastjson.JSONArray;
5 | import com.alibaba.fastjson.JSONObject;
6 |
7 | import java.util.List;
8 | import java.util.TimerTask;
9 |
10 |
11 | class MessageHandler {
12 | String messageEncode(String event, Object data, String type) {
13 | JSONObject jsonObject = new JSONObject();
14 | JSONArray jsonArray = new JSONArray();
15 | switch (type) {
16 | case "publish":
17 | jsonArray.add("p");
18 | jsonArray.add(event);
19 | jsonArray.add(data);
20 | jsonObject.put("#", jsonArray);
21 | return jsonObject.toJSONString();
22 | case "emit":
23 | jsonArray.add("e");
24 | jsonArray.add(event);
25 | jsonArray.add(data);
26 | jsonObject.put("#", jsonArray);
27 | return jsonObject.toJSONString();
28 | case "system":
29 | switch (event) {
30 | case "subscribe":
31 | jsonArray.add("s");
32 | jsonArray.add("s");
33 | jsonArray.add(data);
34 | jsonObject.put("#", jsonArray);
35 | return jsonObject.toJSONString();
36 | case "unsubscribe":
37 | jsonArray.add("s");
38 | jsonArray.add("u");
39 | jsonArray.add(data);
40 | jsonObject.put("#", jsonArray);
41 | return jsonObject.toJSONString();
42 | }
43 | case "ping":
44 | return event;
45 | default:
46 | return event;
47 | }
48 | }
49 |
50 | void messageDecode(final ClusterWS socket, String message) {
51 | JSONArray jsonArray = JSON.parseObject(message).getJSONArray("#");
52 | switch (jsonArray.getString(0)) {
53 | case "p":
54 | //
55 | List channelArrayList = socket.getChannels();
56 | String channelName = jsonArray.getString(1);
57 | for (Channel channel :
58 | channelArrayList) {
59 | if (channel.getChannelName().equals(channelName)) {
60 | channel.onMessage(jsonArray.get(2));
61 | break;
62 | }
63 | }
64 | break;
65 | case "e":
66 | socket.getEmitter().emit(jsonArray.getString(1), jsonArray.get(2));
67 | break;
68 | case "s":
69 | if (jsonArray.getString(1).equals("c")) {
70 | socket.getPingHandler().getPingTimer().scheduleAtFixedRate(new TimerTask() {
71 | @Override
72 | public void run() {
73 | if (socket.getPingHandler().getMissedPing() < 3) {
74 | socket.getPingHandler().incrementMissedPing();
75 | } else {
76 | socket.disconnect(4001, "No pings");
77 | cancel();
78 | }
79 | }
80 | }, 0, jsonArray.getJSONObject(2).getInteger("ping"));
81 | boolean useBinary = jsonArray.getJSONObject(2).getBoolean("binary");
82 | socket.setUseBinary(useBinary);
83 | if (socket.getClusterWSListener() != null) {
84 | socket.getClusterWSListener().onConnected();
85 | }
86 | }
87 | break;
88 | }
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/src/main/java/com/clusterws/PingHandler.java:
--------------------------------------------------------------------------------
1 | package com.clusterws;
2 |
3 | import java.util.Timer;
4 |
5 | class PingHandler {
6 | private Timer mPingTimer;
7 | private int mMissedPing;
8 |
9 | PingHandler() {
10 | mPingTimer = new Timer();
11 | mMissedPing = 0;
12 | }
13 |
14 | void incrementMissedPing() {
15 | mMissedPing++;
16 | }
17 |
18 | void setMissedPingToZero() {
19 | mMissedPing = 0;
20 | }
21 |
22 | Timer getPingTimer() {
23 | return mPingTimer;
24 | }
25 |
26 | int getMissedPing() {
27 | return mMissedPing;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/com/clusterws/ReconnectionParams.java:
--------------------------------------------------------------------------------
1 | package com.clusterws;
2 |
3 | public class ReconnectionParams {
4 | private Boolean mAutoReconnect;
5 | private Integer mReconnectionIntervalMin;
6 | private Integer mReconnectionIntervalMax;
7 | private Integer mReconnectionAttempts;
8 | private Integer mReconnectionsAttempted;
9 |
10 | public ReconnectionParams(Boolean autoReconnect,
11 | Integer reconnectionIntervalMin,
12 | Integer reconnectionIntervalMax,
13 | Integer reconnectionAttempts) {
14 | mAutoReconnect = autoReconnect != null ? autoReconnect : false;
15 | mReconnectionIntervalMin = reconnectionIntervalMin != null ? reconnectionIntervalMin : 1000;
16 | mReconnectionIntervalMax = reconnectionIntervalMax != null ? reconnectionIntervalMax : 5000;
17 | mReconnectionAttempts = reconnectionAttempts != null ? reconnectionAttempts : 0;
18 | mReconnectionsAttempted = 0;
19 | }
20 |
21 | public boolean isAutoReconnect() {
22 | return mAutoReconnect;
23 | }
24 |
25 | public Integer getReconnectionIntervalMin() {
26 | return mReconnectionIntervalMin;
27 | }
28 |
29 | public Integer getReconnectionIntervalMax() {
30 | return mReconnectionIntervalMax;
31 | }
32 |
33 | public Integer getReconnectionAttempts() {
34 | return mReconnectionAttempts;
35 | }
36 |
37 | public void incrementReconnectionsAttempted() {
38 | mReconnectionsAttempted++;
39 | }
40 |
41 | public void resetReconnectionsAttempted() {
42 | mReconnectionsAttempted = 0;
43 | }
44 |
45 | public Integer getReconnectionsAttempted() {
46 | return mReconnectionsAttempted;
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/main/java/com/clusterws/Socket.java:
--------------------------------------------------------------------------------
1 | package com.clusterws;
2 |
3 | import org.java_websocket.client.WebSocketClient;
4 | import org.java_websocket.handshake.ServerHandshake;
5 |
6 | import java.net.URI;
7 | import java.nio.ByteBuffer;
8 |
9 | class Socket extends WebSocketClient {
10 | private ISocketEvents mSocketEvents;
11 |
12 | Socket(URI serverUri, ISocketEvents socketEvents) {
13 | super(serverUri);
14 | mSocketEvents = socketEvents;
15 | }
16 |
17 |
18 | @Override
19 | public void onOpen(ServerHandshake handshakedata) {
20 | mSocketEvents.onOpen();
21 | }
22 |
23 | @Override
24 | public void onMessage(String message) {
25 | mSocketEvents.onMessage(message);
26 | }
27 |
28 | @Override
29 | public void onClose(int code, String reason, boolean remote) {
30 | mSocketEvents.onClose(code, reason);
31 | }
32 |
33 | @Override
34 | public void onError(Exception ex) {
35 | mSocketEvents.onError(ex);
36 | }
37 |
38 | @Override
39 | public void onMessage(ByteBuffer bytes) {
40 | mSocketEvents.onBinaryMessage(bytes);
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/test/java/com/clusterws/ChannelServerTest.java:
--------------------------------------------------------------------------------
1 | package com.clusterws;
2 |
3 | import com.alibaba.fastjson.JSONArray;
4 | import com.alibaba.fastjson.JSONObject;
5 | import org.junit.Before;
6 | import org.junit.Test;
7 |
8 | import java.util.ArrayList;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | public class ChannelServerTest {
13 | private ClusterWS mClusterWS;
14 | private boolean mGotTheData;
15 | private Object mReceivedData;
16 |
17 | @Before
18 | public void init() throws Exception {
19 | mClusterWS = new ClusterWS("ws://localhost:3000");
20 | mGotTheData = false;
21 | mReceivedData = null;
22 | }
23 |
24 | @Test
25 | public void testChannelPublishAndWatchInt() throws Exception {
26 | mClusterWS.connect();
27 | Thread.sleep(1000);
28 | mClusterWS.subscribe("testChannel")
29 | .watch(new Channel.IChannelListener() {
30 | @Override
31 | public void onDataReceived(String channelName, Object data) {
32 | mGotTheData = true;
33 | mReceivedData = data;
34 | }
35 | })
36 | .publish(24);
37 | Thread.sleep(1000);
38 |
39 | assertTrue("Did not get the data", mGotTheData);
40 | assertEquals("Data send and data received are not the same", 24, mReceivedData);
41 | }
42 |
43 | @Test
44 | public void testChannelPublishAndWatchString() throws Exception {
45 | mClusterWS.connect();
46 | Thread.sleep(1000);
47 | mClusterWS.subscribe("testChannel")
48 | .watch(new Channel.IChannelListener() {
49 | @Override
50 | public void onDataReceived(String channelName, Object data) {
51 | mGotTheData = true;
52 | mReceivedData = data;
53 | }
54 | })
55 | .publish("test string");
56 | Thread.sleep(1000);
57 |
58 | assertTrue("Did not get the data", mGotTheData);
59 | assertEquals("Data send and data received are not the same", "test string", mReceivedData);
60 | }
61 |
62 | @Test
63 | public void testChannelPublishAndWatchObject() throws Exception {
64 | JSONObject jsonObject = new JSONObject();
65 | jsonObject.put("int", 30);
66 | jsonObject.put("bool", true);
67 | jsonObject.put("string", "CHLEN");
68 | JSONArray jsonArray = new JSONArray();
69 | jsonArray.add(30);
70 | jsonArray.add(true);
71 | jsonArray.add("CHLEN");
72 | jsonObject.put("array", jsonArray);
73 |
74 | mClusterWS.connect();
75 | Thread.sleep(1000);
76 | mClusterWS.subscribe("testChannel")
77 | .watch(new Channel.IChannelListener() {
78 | @Override
79 | public void onDataReceived(String channelName, Object data) {
80 | mGotTheData = true;
81 | mReceivedData = data;
82 | }
83 | })
84 | .publish(jsonObject);
85 | Thread.sleep(1000);
86 |
87 | assertTrue("Did not get the data", mGotTheData);
88 | assertEquals("Data send and data received are not the same", jsonObject, mReceivedData);
89 | }
90 |
91 | @Test
92 | public void testChannelPublishAndWatchNull() throws Exception {
93 | mClusterWS.connect();
94 | Thread.sleep(1000);
95 | mClusterWS.subscribe("testChannel")
96 | .watch(new Channel.IChannelListener() {
97 | @Override
98 | public void onDataReceived(String channelName, Object data) {
99 | mGotTheData = true;
100 | mReceivedData = data;
101 | }
102 | })
103 | .publish(null);
104 | Thread.sleep(1000);
105 |
106 | assertTrue("Did not get the data", mGotTheData);
107 | assertEquals("Data send and data received are not the same", null, mReceivedData);
108 | }
109 |
110 | @Test
111 | public void testChannelPublishAndWatchArray() throws Exception {
112 | ArrayList mObjectArrayList;
113 | mObjectArrayList = new ArrayList<>();
114 | mObjectArrayList.add(30);
115 | mObjectArrayList.add(false);
116 | mObjectArrayList.add("Test message");
117 |
118 | JSONObject jsonObject = new JSONObject();
119 | jsonObject.put("int", 30);
120 | jsonObject.put("bool", true);
121 | jsonObject.put("string", "CHLEN");
122 | JSONArray jsonArray = new JSONArray();
123 | jsonArray.add(30);
124 | jsonArray.add(true);
125 | jsonArray.add("CHLEN");
126 | jsonObject.put("array", jsonArray);
127 |
128 | mObjectArrayList.add(jsonObject);
129 |
130 | mClusterWS.connect();
131 | Thread.sleep(1000);
132 | mClusterWS.subscribe("testChannel")
133 | .watch(new Channel.IChannelListener() {
134 | @Override
135 | public void onDataReceived(String channelName, Object data) {
136 | mGotTheData = true;
137 | mReceivedData = data;
138 | }
139 | })
140 | .publish(mObjectArrayList);
141 | Thread.sleep(1000);
142 |
143 | assertTrue("Did not get the data", mGotTheData);
144 | assertEquals("Data send and data received are not the same", mObjectArrayList, mReceivedData);
145 | }
146 |
147 | @Test
148 | public void testGetChannelByName() throws Exception {
149 | mClusterWS.connect();
150 | Thread.sleep(1000);
151 | mClusterWS.subscribe("testChannel");
152 | assertNotNull(mClusterWS.getChannelByName("testChannel"));
153 | }
154 |
155 | @Test
156 | public void testGetChannelList() throws Exception {
157 | mClusterWS.connect();
158 | Thread.sleep(1000);
159 | mClusterWS.subscribe("testChannel1");
160 | mClusterWS.subscribe("testChannel2");
161 | mClusterWS.subscribe("testChannel3");
162 |
163 | assertEquals(mClusterWS.getChannels().size(), 3);
164 | assertEquals(mClusterWS.getChannels().get(0).getChannelName(), "testChannel1");
165 | assertEquals(mClusterWS.getChannels().get(1).getChannelName(), "testChannel2");
166 | assertEquals(mClusterWS.getChannels().get(2).getChannelName(), "testChannel3");
167 | }
168 |
169 | @Test
170 | public void testTryGetChannelByNameAfterUnsubscribing() throws Exception {
171 | mClusterWS.connect();
172 | Thread.sleep(1000);
173 | Channel channel = mClusterWS.subscribe("testChannel1");
174 | channel.unsubscribe();
175 | assertNull(mClusterWS.getChannelByName("testChannel1"));
176 | }
177 |
178 | @Test
179 | public void testResubscribeOnAllChannelsAfterReconnection() throws Exception {
180 | mClusterWS.setReconnection(true, 1000, 2000, null);
181 | mClusterWS.connect();
182 | Thread.sleep(1000);
183 | Channel channel = mClusterWS.subscribe("testChannel")
184 | .watch(new Channel.IChannelListener() {
185 | @Override
186 | public void onDataReceived(String channelName, Object data) {
187 | mGotTheData = true;
188 | mReceivedData = data;
189 | }
190 | });
191 | mClusterWS.disconnect(4001, "hui");
192 | Thread.sleep(3000);
193 | channel.publish("testData");
194 | Thread.sleep(1000);
195 | assertTrue("Did not get the data", mGotTheData);
196 | assertEquals("Data send and data received are not the same", "testData", mReceivedData);
197 | }
198 |
199 | }
--------------------------------------------------------------------------------
/src/test/java/com/clusterws/ChannelTest.java:
--------------------------------------------------------------------------------
1 | package com.clusterws;
2 |
3 | import org.junit.Before;
4 | import org.junit.Rule;
5 | import org.junit.Test;
6 | import org.mockito.Mock;
7 | import org.mockito.junit.MockitoJUnit;
8 | import org.mockito.junit.MockitoRule;
9 |
10 | import java.util.ArrayList;
11 |
12 | import static org.junit.Assert.*;
13 | import static org.mockito.Mockito.when;
14 |
15 | public class ChannelTest {
16 | private Channel mChannel;
17 | private static final String CHANNEL_NAME = "testChannel";
18 | private static final String TEST_STRING_DATA = "testData";
19 |
20 | @Mock
21 | private ClusterWS mClusterWS;
22 |
23 | @Rule
24 | public MockitoRule mockitoRule = MockitoJUnit.rule();
25 |
26 | @Before
27 | public void init(){
28 | mChannel = new Channel(CHANNEL_NAME,mClusterWS);
29 | }
30 |
31 | @Test
32 | public void watchAndOnMessage() throws Exception {
33 | mChannel.watch(new Channel.IChannelListener() {
34 | @Override
35 | public void onDataReceived(String channelName, Object data) {
36 | assertEquals("Data is not the same",TEST_STRING_DATA,data);
37 | }
38 | });
39 | mChannel.onMessage(TEST_STRING_DATA);
40 | }
41 |
42 |
43 | @Test
44 | public void unsubscribe() throws Exception {
45 | ArrayList channelArrayList = new ArrayList<>();
46 | channelArrayList.add(mChannel);
47 | channelArrayList.add(new Channel("GAY",mClusterWS));
48 | channelArrayList.add(new Channel("SHIT",mClusterWS));
49 | when(mClusterWS.getChannels()).thenReturn(channelArrayList);
50 | mChannel.unsubscribe();
51 | assertNotEquals("There is an old channel",CHANNEL_NAME,channelArrayList.get(0).getChannelName());
52 | }
53 |
54 | @Test
55 | public void getChannelName() throws Exception {
56 | assertEquals(mChannel.getChannelName(),CHANNEL_NAME);
57 | }
58 |
59 |
60 | }
--------------------------------------------------------------------------------
/src/test/java/com/clusterws/ClusterWSStatesBool.java:
--------------------------------------------------------------------------------
1 | package com.clusterws;
2 |
3 | public class ClusterWSStatesBool {
4 | private boolean mClosed;
5 | private boolean mClosing;
6 | private boolean mNotYetConnected;
7 | private boolean mConnecting;
8 | private boolean mOpen;
9 |
10 | public ClusterWSStatesBool() {
11 | mClosed = false;
12 | mClosing = false;
13 | mNotYetConnected = false;
14 | mConnecting = false;
15 | mOpen = false;
16 | }
17 |
18 | public boolean isClosed() {
19 | return mClosed;
20 | }
21 |
22 | public void setClosed(boolean closed) {
23 | mClosed = closed;
24 | }
25 |
26 | public boolean isClosing() {
27 | return mClosing;
28 | }
29 |
30 | public void setClosing(boolean closing) {
31 | mClosing = closing;
32 | }
33 |
34 | public boolean isNotYetConnected() {
35 | return mNotYetConnected;
36 | }
37 |
38 | public void setNotYetConnected(boolean notYetConnected) {
39 | mNotYetConnected = notYetConnected;
40 | }
41 |
42 | public boolean isConnecting() {
43 | return mConnecting;
44 | }
45 |
46 | public void setConnecting(boolean connecting) {
47 | mConnecting = connecting;
48 | }
49 |
50 | public boolean isOpen() {
51 | return mOpen;
52 | }
53 |
54 | public void setOpen(boolean open) {
55 | mOpen = open;
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/test/java/com/clusterws/ClusterWSTest.java:
--------------------------------------------------------------------------------
1 | package com.clusterws;
2 |
3 | import com.alibaba.fastjson.JSONArray;
4 | import com.alibaba.fastjson.JSONObject;
5 | import org.java_websocket.WebSocket;
6 | import org.junit.After;
7 | import org.junit.Before;
8 | import org.junit.Test;
9 | import org.mockito.internal.matchers.Null;
10 |
11 | import java.util.ArrayList;
12 |
13 | import static org.junit.Assert.*;
14 |
15 | public class ClusterWSTest {
16 |
17 | private ClusterWS mClusterWS;
18 | private Object receivedData;
19 | private boolean gotTheData;
20 |
21 | @Before
22 | public void init() {
23 | mClusterWS = new ClusterWS("ws://localhost:3000");
24 | receivedData = null;
25 | gotTheData = false;
26 | }
27 |
28 | @After
29 | public void clearSocket() {
30 | mClusterWS.disconnect(null, null);
31 | mClusterWS = null;
32 | }
33 |
34 | @Test
35 | public void connect() throws Exception {
36 | mClusterWS.connect();
37 | Thread.sleep(1000);
38 |
39 | assertEquals("Socket did not connect", WebSocket.READYSTATE.OPEN, mClusterWS.getState());
40 | }
41 |
42 | @Test
43 | public void testOnAndSendString() throws Exception {
44 | mClusterWS.connect();
45 | mClusterWS.on("String", new IEmitterListener() {
46 | @Override
47 | public void onDataReceived(Object data) {
48 | gotTheData = true;
49 | receivedData = data;
50 | }
51 | });
52 | Thread.sleep(1000);
53 | mClusterWS.send("String", "test message");
54 | Thread.sleep(1000);
55 |
56 | assertTrue("Did not get the data", gotTheData);
57 | assertEquals("Data send and data received are not the same", "test message", receivedData);
58 | }
59 |
60 | @Test
61 | public void testSendAndOnBoolean() throws Exception {
62 | mClusterWS.connect();
63 | mClusterWS.on("String", new IEmitterListener() {
64 | @Override
65 | public void onDataReceived(Object data) {
66 | gotTheData = true;
67 | receivedData = data;
68 | }
69 | });
70 | Thread.sleep(1000);
71 | mClusterWS.send("String", true);
72 | Thread.sleep(1000);
73 |
74 | assertTrue("Did not get the data", gotTheData);
75 | assertTrue("Data send and data received are not the same", (Boolean) receivedData);
76 | }
77 |
78 | @Test
79 | public void testSendAndOnInteger() throws Exception {
80 | mClusterWS.connect();
81 | mClusterWS.on("String", new IEmitterListener() {
82 | @Override
83 | public void onDataReceived(Object data) {
84 | gotTheData = true;
85 | receivedData = data;
86 | }
87 | });
88 | Thread.sleep(1000);
89 | mClusterWS.send("String", 30);
90 | Thread.sleep(1000);
91 |
92 | assertTrue("Did not get the data", gotTheData);
93 | assertEquals("Data send and data received are not the same", 30, (int) receivedData);
94 | }
95 |
96 | @Test
97 | public void testSendAndOnNull() throws Exception {
98 | mClusterWS.connect();
99 | mClusterWS.on("String", new IEmitterListener() {
100 | @Override
101 | public void onDataReceived(Object data) {
102 | gotTheData = true;
103 | if (data.equals(null)) {
104 | receivedData = null;
105 | }
106 | }
107 | });
108 | Thread.sleep(1000);
109 | mClusterWS.send("String", null);
110 | Thread.sleep(1000);
111 |
112 | assertTrue("Did not get the data", gotTheData);
113 | assertNull("Data send and data received are not the same", receivedData);
114 | }
115 |
116 | @Test
117 | public void testSendAndOnObject() throws Exception {
118 | mClusterWS.connect();
119 | mClusterWS.on("String", new IEmitterListener() {
120 | @Override
121 | public void onDataReceived(Object data) {
122 | gotTheData = true;
123 | receivedData = data;
124 | }
125 | });
126 | JSONObject jsonObject = new JSONObject();
127 | jsonObject.put("int", 30);
128 | jsonObject.put("bool", true);
129 | jsonObject.put("string", "CHLEN");
130 | JSONArray jsonArray = new JSONArray();
131 | jsonArray.add(30);
132 | jsonArray.add(true);
133 | jsonArray.add("CHLEN");
134 | jsonObject.put("array", jsonArray);
135 | Thread.sleep(1000);
136 | mClusterWS.send("String", jsonObject);
137 | Thread.sleep(1000);
138 |
139 | assertTrue("Did not get the data", gotTheData);
140 | assertEquals("Data send and data received are not the same", jsonObject.toString(), receivedData.toString());
141 | }
142 |
143 | @Test
144 | public void testSendAndOnArray() throws Exception {
145 | mClusterWS.connect();
146 | mClusterWS.on("String", new IEmitterListener() {
147 | @Override
148 | public void onDataReceived(Object data) {
149 | gotTheData = true;
150 | receivedData = data;
151 | }
152 | });
153 | ArrayList mObjectArrayList;
154 | mObjectArrayList = new ArrayList<>();
155 | mObjectArrayList.add(30);
156 | mObjectArrayList.add(false);
157 | mObjectArrayList.add("Test message");
158 |
159 | JSONObject jsonObject = new JSONObject();
160 | jsonObject.put("int", 30);
161 | jsonObject.put("bool", true);
162 | jsonObject.put("string", "CHLEN");
163 | JSONArray jsonArray = new JSONArray();
164 | jsonArray.add(30);
165 | jsonArray.add(true);
166 | jsonArray.add("CHLEN");
167 | jsonObject.put("array", jsonArray);
168 |
169 | mObjectArrayList.add(jsonObject);
170 | Thread.sleep(1000);
171 | mClusterWS.send("String", mObjectArrayList.toString());
172 | Thread.sleep(1000);
173 |
174 | assertTrue("Did not get the data", gotTheData);
175 | assertEquals("Data send and data received are not the same", mObjectArrayList.toString(), receivedData.toString());
176 | }
177 |
178 | @Test
179 | public void testDisconnect() throws Exception {
180 | mClusterWS.connect();
181 | Thread.sleep(1000);
182 | mClusterWS.disconnect(null, null);
183 | Thread.sleep(1000);
184 | assertEquals(WebSocket.READYSTATE.CLOSED, mClusterWS.getState());
185 | }
186 |
187 | @Test
188 | public void testAllGetStates() throws Exception {
189 | final com.clusterws.ClusterWSStatesBool clusterWSStatesBool = new com.clusterws.ClusterWSStatesBool();
190 | if (mClusterWS.getState() == WebSocket.READYSTATE.NOT_YET_CONNECTED) {
191 | clusterWSStatesBool.setNotYetConnected(true);
192 | }
193 |
194 | mClusterWS.setClusterWSListener(new IClusterWSListener() {
195 | @Override
196 | public void onConnected() {
197 | if (mClusterWS.getState() == WebSocket.READYSTATE.OPEN) {
198 | clusterWSStatesBool.setOpen(true);
199 | }
200 | }
201 |
202 | @Override
203 | public void onError(Exception exception) {
204 |
205 | }
206 |
207 | @Override
208 | public void onDisconnected(int code, String reason) {
209 |
210 | }
211 | });
212 |
213 | mClusterWS.connect();
214 | if (mClusterWS.getState() == WebSocket.READYSTATE.CONNECTING) {
215 | clusterWSStatesBool.setConnecting(true);
216 | }
217 | Thread.sleep(1000);
218 | mClusterWS.disconnect(1000, "Test");
219 | if (mClusterWS.getState() == WebSocket.READYSTATE.CLOSING) {
220 | clusterWSStatesBool.setClosing(true);
221 | }
222 | Thread.sleep(1000);
223 | if (mClusterWS.getState() == WebSocket.READYSTATE.CLOSED) {
224 | clusterWSStatesBool.setClosed(true);
225 | }
226 |
227 | assertTrue("State CREATED not working", clusterWSStatesBool.isNotYetConnected());
228 | //TODO Сложно поймать этот state
229 | // assertTrue("State CONNECTING not working",clusterWSStatesBool.isConnecting());
230 | assertTrue("State OPEN not working", clusterWSStatesBool.isOpen());
231 | assertTrue("State CLOSING not working", clusterWSStatesBool.isClosing());
232 | assertTrue("State CLOSED not working", clusterWSStatesBool.isClosed());
233 | }
234 |
235 | @Test
236 | public void testReconnection() throws Exception {
237 | mClusterWS.setReconnection(true, 1000, 2000, null);
238 | mClusterWS.connect();
239 | Thread.sleep(1000);
240 | mClusterWS.disconnect(3002, "test");
241 | Thread.sleep(4000);
242 | assertEquals("Did not reconnect", WebSocket.READYSTATE.OPEN, mClusterWS.getState());
243 | }
244 |
245 | @Test
246 | public void testPingPong() throws Exception {
247 | mClusterWS.connect();
248 | Thread.sleep(1900);
249 | assertEquals("Websocket disconnected", WebSocket.READYSTATE.OPEN, mClusterWS.getState());
250 | }
251 |
252 | @Test(expected = NullPointerException.class)
253 | public void testNullUrl() throws Exception {
254 | mClusterWS = new ClusterWS(null);
255 | }
256 |
257 | }
--------------------------------------------------------------------------------
/src/test/java/com/clusterws/EmitterTest.java:
--------------------------------------------------------------------------------
1 | package com.clusterws;
2 |
3 | import org.junit.After;
4 | import org.junit.Before;
5 | import org.junit.Test;
6 |
7 | import static org.junit.Assert.*;
8 |
9 | public class EmitterTest {
10 | private boolean gotMessage;
11 | private Emitter mEmitter;
12 |
13 | @Before
14 | public void init(){
15 | mEmitter = new Emitter();
16 | gotMessage = false;
17 | }
18 |
19 | @After
20 | public void deleteEmitter(){
21 | mEmitter = null;
22 | }
23 |
24 | @Test
25 | public void addEventListenerAndEmit() throws Exception {
26 | mEmitter.addEventListener("test", new IEmitterListener() {
27 | @Override
28 | public void onDataReceived(Object data) {
29 | gotMessage = true;
30 | }
31 | });
32 | mEmitter.emit("test","HUI");
33 | assertTrue(gotMessage);
34 | }
35 |
36 | @Test
37 | public void addDifferentEventListenersWithTheSameEventName() throws Exception{
38 | mEmitter.addEventListener("test", new IEmitterListener() {
39 | @Override
40 | public void onDataReceived(Object data) {
41 | gotMessage = false;
42 | }
43 | });
44 | mEmitter.addEventListener("test", new IEmitterListener() {
45 | @Override
46 | public void onDataReceived(Object data) {
47 | gotMessage = true;
48 | }
49 | });
50 | mEmitter.emit("test","HUI");
51 | assertTrue(gotMessage);
52 | }
53 |
54 | @Test
55 | public void removeAllEvents() throws Exception {
56 | mEmitter.addEventListener("test", new IEmitterListener() {
57 | @Override
58 | public void onDataReceived(Object data) {
59 | gotMessage = true;
60 | }
61 | });
62 | mEmitter.removeAllEvents();
63 | mEmitter.emit("test","HUI");
64 | assertFalse(gotMessage);
65 | }
66 |
67 | }
--------------------------------------------------------------------------------
/src/test/java/com/clusterws/MessageHandlerTest.java:
--------------------------------------------------------------------------------
1 | package com.clusterws;
2 |
3 | import com.alibaba.fastjson.JSONArray;
4 | import com.alibaba.fastjson.JSONObject;
5 | import org.junit.Before;
6 | import org.junit.Test;
7 |
8 | import java.util.ArrayList;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | public class MessageHandlerTest {
13 | private MessageHandler mMessageHandler;
14 | private String mResult;
15 |
16 | @Before
17 | public void init() {
18 | mMessageHandler = new MessageHandler();
19 | mResult = null;
20 | }
21 |
22 | @Test
23 | public void messageEncodeEmitString() throws Exception {
24 | mResult = mMessageHandler.messageEncode("test", "testString", "emit");
25 | assertEquals("{\"#\":[\"e\",\"test\",\"testString\"]}", mResult);
26 | }
27 |
28 | @Test
29 | public void messageEncodeEmitInt() throws Exception {
30 | mResult = mMessageHandler.messageEncode("test", 20, "emit");
31 | assertEquals("{\"#\":[\"e\",\"test\",20]}", mResult);
32 | }
33 |
34 | @Test
35 | public void messageEncodeEmitBoolean() throws Exception {
36 | mResult = mMessageHandler.messageEncode("test", true, "emit");
37 | assertEquals("{\"#\":[\"e\",\"test\",true]}", mResult);
38 | }
39 |
40 | @Test
41 | public void messageEncodeEmitNull() throws Exception {
42 | mResult = mMessageHandler.messageEncode("test", null, "emit");
43 | assertEquals("{\"#\":[\"e\",\"test\",null]}", mResult);
44 | }
45 |
46 | @Test
47 | public void messageEncodeEmitObject() throws Exception {
48 | JSONObject jsonObject = new JSONObject();
49 | jsonObject.put("int", 30);
50 | jsonObject.put("bool", true);
51 | jsonObject.put("string", "CHLEN");
52 | JSONArray jsonArray = new JSONArray();
53 | jsonArray.add(30);
54 | jsonArray.add(true);
55 | jsonArray.add("CHLEN");
56 | jsonObject.put("array", jsonArray);
57 | mResult = mMessageHandler.messageEncode("test", jsonObject, "emit");
58 | assertEquals("{\"#\":[\"e\",\"test\",{\"bool\":true,\"string\":\"CHLEN\",\"array\":[30,true,\"CHLEN\"],\"int\":30}]}", mResult);
59 | }
60 |
61 |
62 | @Test
63 | public void messageEncodeEmitArray() throws Exception {
64 | JSONObject jsonObject = new JSONObject();
65 | jsonObject.put("int", 30);
66 | jsonObject.put("bool", true);
67 | jsonObject.put("string", "CHLEN");
68 | JSONArray jsonArray = new JSONArray();
69 | jsonArray.add(30);
70 | jsonArray.add(true);
71 | jsonArray.add("CHLEN");
72 | jsonObject.put("array", jsonArray);
73 |
74 | ArrayList arrayList = new ArrayList<>();
75 | arrayList.add(30);
76 | arrayList.add(false);
77 | arrayList.add("Test message");
78 | arrayList.add(jsonObject);
79 | mResult = mMessageHandler.messageEncode("test", arrayList, "emit");
80 | assertEquals("{\"#\":[\"e\",\"test\",[30,false,\"Test message\",{\"bool\":true,\"string\":\"CHLEN\",\"array\":[30,true,\"CHLEN\"],\"int\":30}]]}", mResult);
81 | }
82 |
83 | @Test
84 | public void messageEncodeSystemSubscribe() throws Exception{
85 | mResult = mMessageHandler.messageEncode("subscribe","channelName","system");
86 | assertEquals("{\"#\":[\"s\",\"s\",\"channelName\"]}",mResult);
87 | }
88 |
89 | @Test
90 | public void messageEncodeSystemUnsubscribe() throws Exception{
91 | mResult = mMessageHandler.messageEncode("unsubscribe","channelName","system");
92 | assertEquals("{\"#\":[\"s\",\"u\",\"channelName\"]}",mResult);
93 | }
94 | @Test
95 | public void messageEncodePing() throws Exception{
96 | mResult = mMessageHandler.messageEncode("#1",null,"ping");
97 | assertEquals("#1",mResult);
98 | }
99 |
100 | @Test
101 | public void messageEncodePublishString(){
102 | mResult = mMessageHandler.messageEncode("channelname", "testData", "publish");
103 | assertEquals("{\"#\":[\"p\",\"channelname\",\"testData\"]}", mResult);
104 | }
105 |
106 | @Test
107 | public void messageEncodePublishInt() throws Exception {
108 | mResult = mMessageHandler.messageEncode("channelname", 20, "publish");
109 | assertEquals("{\"#\":[\"p\",\"channelname\",20]}", mResult);
110 |
111 | }
112 |
113 | @Test
114 | public void messageEncodePublishBoolean() throws Exception {
115 | mResult = mMessageHandler.messageEncode("channelname", true, "publish");
116 | assertEquals("{\"#\":[\"p\",\"channelname\",true]}", mResult);
117 |
118 | }
119 |
120 | @Test
121 | public void messageEncodePublishNull() throws Exception {
122 | mResult = mMessageHandler.messageEncode("channelname", null, "publish");
123 | assertEquals("{\"#\":[\"p\",\"channelname\",null]}", mResult);
124 |
125 | }
126 |
127 | @Test
128 | public void messageEncodePublishObject() throws Exception {
129 | JSONObject jsonObject = new JSONObject();
130 | jsonObject.put("int", 30);
131 | jsonObject.put("bool", true);
132 | jsonObject.put("string", "CHLEN");
133 | JSONArray jsonArray = new JSONArray();
134 | jsonArray.add(30);
135 | jsonArray.add(true);
136 | jsonArray.add("CHLEN");
137 | jsonObject.put("array", jsonArray);
138 | mResult = mMessageHandler.messageEncode("channelname", jsonObject, "publish");
139 | assertEquals("{\"#\":[\"p\",\"channelname\",{\"bool\":true,\"string\":\"CHLEN\",\"array\":[30,true,\"CHLEN\"],\"int\":30}]}", mResult);
140 | }
141 |
142 |
143 | @Test
144 | public void messageEncodePublishArray() throws Exception {
145 | JSONObject jsonObject = new JSONObject();
146 | jsonObject.put("int", 30);
147 | jsonObject.put("bool", true);
148 | jsonObject.put("string", "CHLEN");
149 | JSONArray jsonArray = new JSONArray();
150 | jsonArray.add(30);
151 | jsonArray.add(true);
152 | jsonArray.add("CHLEN");
153 | jsonObject.put("array", jsonArray);
154 |
155 | ArrayList arrayList = new ArrayList<>();
156 | arrayList.add(30);
157 | arrayList.add(false);
158 | arrayList.add("Test message");
159 | arrayList.add(jsonObject);
160 | mResult = mMessageHandler.messageEncode("channelname", arrayList, "publish");
161 | assertEquals("{\"#\":[\"p\",\"channelname\",[30,false,\"Test message\",{\"bool\":true,\"string\":\"CHLEN\",\"array\":[30,true,\"CHLEN\"],\"int\":30}]]}", mResult);
162 | }
163 | }
--------------------------------------------------------------------------------
/src/test/java/com/clusterws/PingHandlerTest.java:
--------------------------------------------------------------------------------
1 | package com.clusterws;
2 |
3 | import org.junit.Before;
4 | import org.junit.Test;
5 |
6 | import static org.junit.Assert.*;
7 |
8 | public class PingHandlerTest {
9 |
10 | private PingHandler mPingHandler;
11 |
12 | @Before
13 | public void init(){
14 | mPingHandler = new PingHandler();
15 | }
16 |
17 | @Test
18 | public void incrementMissedPing() throws Exception {
19 | mPingHandler.incrementMissedPing();
20 | assertEquals(1,mPingHandler.getMissedPing());
21 | }
22 |
23 | @Test
24 | public void setMissedPingToZero() throws Exception {
25 | mPingHandler.incrementMissedPing();
26 | mPingHandler.setMissedPingToZero();
27 | assertEquals(0,mPingHandler.getMissedPing());
28 | }
29 |
30 |
31 | @Test
32 | public void getMissedPing() throws Exception {
33 | assertEquals(0,mPingHandler.getMissedPing());
34 | }
35 |
36 | }
--------------------------------------------------------------------------------