├── .codecov.yml
├── .gitignore
├── .travis.yml
├── LICENSE
├── README.md
├── codecov.yml
├── deploy-docs.sh
├── docs
├── .gitignore
├── Makefile
├── _static
│ └── .keep
├── _themes
│ └── sphinx_rtd_theme
│ │ ├── __init__.py
│ │ ├── breadcrumbs.html
│ │ ├── footer.html
│ │ ├── layout.html
│ │ ├── search.html
│ │ ├── searchbox.html
│ │ ├── static
│ │ ├── css
│ │ │ ├── badge_only.css
│ │ │ └── theme.css
│ │ ├── fonts
│ │ │ ├── FontAwesome.otf
│ │ │ ├── fontawesome-webfont.eot
│ │ │ ├── fontawesome-webfont.svg
│ │ │ ├── fontawesome-webfont.ttf
│ │ │ ├── fontawesome-webfont.woff
│ │ │ └── fontawesome-webfont.woff2
│ │ └── js
│ │ │ ├── modernizr.min.js
│ │ │ └── theme.js
│ │ ├── theme.conf
│ │ └── versions.html
├── api.rst
├── conf.py
├── index.rst
├── install.rst
├── javadocs
│ └── index.rst
├── requirements.txt
└── using.rst
├── pom.xml
├── pom.xml.versionsBackup
├── socket.io-server-test
├── pom.xml
├── pom.xml.versionsBackup
└── src
│ └── test
│ ├── java
│ └── io
│ │ └── socket
│ │ └── socketio
│ │ └── server
│ │ ├── JettyEngineIoWebSocketHandler.java
│ │ ├── ServerWrapper.java
│ │ ├── SocketIoTest.java
│ │ └── Utils.java
│ └── resources
│ ├── package-lock.json
│ ├── package.json
│ ├── test_broadcast_to_all_clients.js
│ ├── test_broadcast_to_all_clients_except_one.js
│ ├── test_broadcast_to_multiple_rooms.js
│ ├── test_broadcast_to_one_room.js
│ ├── test_connect.js
│ ├── test_connect_dynamic.js
│ ├── test_message_to_client_binary_noack.js
│ ├── test_message_to_client_nonbinary_ack.js
│ ├── test_message_to_client_nonbinary_noack.js
│ ├── test_message_to_server_binary_noack.js
│ ├── test_message_to_server_nonbinary_ack.js
│ └── test_message_to_server_nonbinary_noack.js
└── socket.io-server
├── pom.xml
├── pom.xml.versionsBackup
└── src
├── main
└── java
│ └── io
│ └── socket
│ └── socketio
│ └── server
│ ├── PacketUtils.java
│ ├── SocketIoAdapter.java
│ ├── SocketIoClient.java
│ ├── SocketIoMemoryAdapter.java
│ ├── SocketIoNamespace.java
│ ├── SocketIoNamespaceGroupImpl.java
│ ├── SocketIoNamespaceImpl.java
│ ├── SocketIoNamespaceProvider.java
│ ├── SocketIoServer.java
│ ├── SocketIoServerOptions.java
│ ├── SocketIoSocket.java
│ ├── parser
│ ├── Binary.java
│ ├── DecodingException.java
│ ├── IOParser.java
│ ├── Packet.java
│ └── Parser.java
│ └── utils
│ └── HasBinary.java
└── test
└── java
└── io
└── socket
└── socketio
└── server
├── SocketIoAdapterImpl.java
├── SocketIoAdapterTest.java
├── SocketIoClientTest.java
├── SocketIoMemoryAdapterTest.java
├── SocketIoNamespaceImplTest.java
├── SocketIoServerOptionsTest.java
├── SocketIoServerTest.java
├── SocketIoSocketTest.java
└── StubEngineIoWebSocket.java
/.codecov.yml:
--------------------------------------------------------------------------------
1 | codecov:
2 | notify:
3 | require_ci_to_pass: yes
4 |
5 | coverage:
6 | precision: 2
7 | round: down
8 |
9 | status:
10 | project: yes
11 | patch: yes
12 | changes: no
13 |
14 | parsers:
15 | gcov:
16 | branch_detection:
17 | conditional: yes
18 | loop: yes
19 | method: no
20 | macro: no
21 |
22 | comment:
23 | layout: "header, diff"
24 | behavior: default
25 | require_changes: no
26 |
27 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.class
2 |
3 | # Package Files #
4 | *.jar
5 | *.war
6 | *.ear
7 |
8 | # Intellij project files
9 | *.iml
10 | *.ipr
11 | *.iws
12 | .idea/
13 |
14 | .DS_Store
15 | target/
16 | node_modules/
17 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: java
2 | dist: xenial
3 | sudo: false
4 |
5 | branches:
6 | except:
7 | - gh-pages
8 |
9 | env:
10 | global:
11 | - secure: x8A+yQ3K/iN8maKtml5H9arQQxsjc6AgX7IfuwU8AiCxkoZKWZit25OHfVB4N6cTo16+BBF3lTgRBS4SnDhYjGrLbzlfNCyv+RN4BXIGt2p+6Vq2qgkhWP2yOeGbsySibkEG4Fd0UKzOPwkDSy0nXx8h4b9nSfRMLdE1XL6QwmJMVVOpTJxUg5eL948XWcFdqF6TRCFUijNbUoBvnCKHTMh6q9fVTRMNwKeoT0dzXxbDlxV9F82wI1XwkRSYsuuc8zy5jWoxI8kfFaIq0P+tMikYRKkEDaWIX8cQ5Cz1wXOLMuOYHKKwmTtXTw0vvKGowTDj3JO2tnZ4/qWiHSNlJyPK834VHVxN1cCamwIQ9sr72vm5TGoG9rflRCmKemJgLPswAP1KmWTvX6t1UhLCngkscxcKbJxMMgdqCmYWG/rjX8wtUk2QaPcr7d0xswc8Ozqy8MlBmkkghjj1Z9fS5aT/wH+mf59E12DlKZbtimqqrs4a2Tm1QN0u4sLsO1se1VBnW8+abB+z6WrmuIn6H3xj3NULrSm9a6Dgn20ytkDZyyzy0GMRazXr4hzjusS0ifNJ2PWljOSxsuIU8qZAqEh+vsf75+ERJ2hJ654r6NcmiHBxkpmAMcUkhsRinG11wN1n37fAiLGVybglPfDCygJozr9dBIMUk+Q1aa4Y9K4=
12 |
13 | addons:
14 | apt:
15 | update: true
16 |
17 | matrix:
18 | include:
19 | - name: "Java 8 Tests"
20 | jdk: openjdk8
21 | env: TESTENV=tests
22 | script: mvn test
23 | - name: "GitHub Pages"
24 | jdk: openjdk8
25 | env: TESTENV=cover FYI="this also builds documentation for tags"
26 | script: '[[ -n "$TRAVIS_TAG" ]] && ./deploy-docs.sh || true'
27 | addons:
28 | apt:
29 | packages:
30 | - python3
31 | - python3-pip
32 | - python-virtualenv
33 | - make
34 |
35 | after_success:
36 | - '[[ "$TESTENV" == "tests" ]] && bash <(curl -s https://codecov.io/bash) -f engine.io-server-coverage/target/site/jacoco-aggregate/jacoco.xml'
37 |
38 | cache:
39 | directories:
40 | - $HOME/.m2
41 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2022 Trinopoty Biswas
2 |
3 | Licensed under the Apache License, Version 2.0 (the "License");
4 | you may not use this file except in compliance with the License.
5 | You may obtain a copy of the License at
6 |
7 | http://www.apache.org/licenses/LICENSE-2.0
8 |
9 | Unless required by applicable law or agreed to in writing, software
10 | distributed under the License is distributed on an "AS IS" BASIS,
11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | See the License for the specific language governing permissions and
13 | limitations under the License.
14 |
15 |
16 | Apache License
17 | Version 2.0, January 2004
18 | http://www.apache.org/licenses/
19 |
20 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
21 |
22 | 1. Definitions.
23 |
24 | "License" shall mean the terms and conditions for use, reproduction,
25 | and distribution as defined by Sections 1 through 9 of this document.
26 |
27 | "Licensor" shall mean the copyright owner or entity authorized by
28 | the copyright owner that is granting the License.
29 |
30 | "Legal Entity" shall mean the union of the acting entity and all
31 | other entities that control, are controlled by, or are under common
32 | control with that entity. For the purposes of this definition,
33 | "control" means (i) the power, direct or indirect, to cause the
34 | direction or management of such entity, whether by contract or
35 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
36 | outstanding shares, or (iii) beneficial ownership of such entity.
37 |
38 | "You" (or "Your") shall mean an individual or Legal Entity
39 | exercising permissions granted by this License.
40 |
41 | "Source" form shall mean the preferred form for making modifications,
42 | including but not limited to software source code, documentation
43 | source, and configuration files.
44 |
45 | "Object" form shall mean any form resulting from mechanical
46 | transformation or translation of a Source form, including but
47 | not limited to compiled object code, generated documentation,
48 | and conversions to other media types.
49 |
50 | "Work" shall mean the work of authorship, whether in Source or
51 | Object form, made available under the License, as indicated by a
52 | copyright notice that is included in or attached to the work
53 | (an example is provided in the Appendix below).
54 |
55 | "Derivative Works" shall mean any work, whether in Source or Object
56 | form, that is based on (or derived from) the Work and for which the
57 | editorial revisions, annotations, elaborations, or other modifications
58 | represent, as a whole, an original work of authorship. For the purposes
59 | of this License, Derivative Works shall not include works that remain
60 | separable from, or merely link (or bind by name) to the interfaces of,
61 | the Work and Derivative Works thereof.
62 |
63 | "Contribution" shall mean any work of authorship, including
64 | the original version of the Work and any modifications or additions
65 | to that Work or Derivative Works thereof, that is intentionally
66 | submitted to Licensor for inclusion in the Work by the copyright owner
67 | or by an individual or Legal Entity authorized to submit on behalf of
68 | the copyright owner. For the purposes of this definition, "submitted"
69 | means any form of electronic, verbal, or written communication sent
70 | to the Licensor or its representatives, including but not limited to
71 | communication on electronic mailing lists, source code control systems,
72 | and issue tracking systems that are managed by, or on behalf of, the
73 | Licensor for the purpose of discussing and improving the Work, but
74 | excluding communication that is conspicuously marked or otherwise
75 | designated in writing by the copyright owner as "Not a Contribution."
76 |
77 | "Contributor" shall mean Licensor and any individual or Legal Entity
78 | on behalf of whom a Contribution has been received by Licensor and
79 | subsequently incorporated within the Work.
80 |
81 | 2. Grant of Copyright License. Subject to the terms and conditions of
82 | this License, each Contributor hereby grants to You a perpetual,
83 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
84 | copyright license to reproduce, prepare Derivative Works of,
85 | publicly display, publicly perform, sublicense, and distribute the
86 | Work and such Derivative Works in Source or Object form.
87 |
88 | 3. Grant of Patent License. Subject to the terms and conditions of
89 | this License, each Contributor hereby grants to You a perpetual,
90 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
91 | (except as stated in this section) patent license to make, have made,
92 | use, offer to sell, sell, import, and otherwise transfer the Work,
93 | where such license applies only to those patent claims licensable
94 | by such Contributor that are necessarily infringed by their
95 | Contribution(s) alone or by combination of their Contribution(s)
96 | with the Work to which such Contribution(s) was submitted. If You
97 | institute patent litigation against any entity (including a
98 | cross-claim or counterclaim in a lawsuit) alleging that the Work
99 | or a Contribution incorporated within the Work constitutes direct
100 | or contributory patent infringement, then any patent licenses
101 | granted to You under this License for that Work shall terminate
102 | as of the date such litigation is filed.
103 |
104 | 4. Redistribution. You may reproduce and distribute copies of the
105 | Work or Derivative Works thereof in any medium, with or without
106 | modifications, and in Source or Object form, provided that You
107 | meet the following conditions:
108 |
109 | (a) You must give any other recipients of the Work or
110 | Derivative Works a copy of this License; and
111 |
112 | (b) You must cause any modified files to carry prominent notices
113 | stating that You changed the files; and
114 |
115 | (c) You must retain, in the Source form of any Derivative Works
116 | that You distribute, all copyright, patent, trademark, and
117 | attribution notices from the Source form of the Work,
118 | excluding those notices that do not pertain to any part of
119 | the Derivative Works; and
120 |
121 | (d) If the Work includes a "NOTICE" text file as part of its
122 | distribution, then any Derivative Works that You distribute must
123 | include a readable copy of the attribution notices contained
124 | within such NOTICE file, excluding those notices that do not
125 | pertain to any part of the Derivative Works, in at least one
126 | of the following places: within a NOTICE text file distributed
127 | as part of the Derivative Works; within the Source form or
128 | documentation, if provided along with the Derivative Works; or,
129 | within a display generated by the Derivative Works, if and
130 | wherever such third-party notices normally appear. The contents
131 | of the NOTICE file are for informational purposes only and
132 | do not modify the License. You may add Your own attribution
133 | notices within Derivative Works that You distribute, alongside
134 | or as an addendum to the NOTICE text from the Work, provided
135 | that such additional attribution notices cannot be construed
136 | as modifying the License.
137 |
138 | You may add Your own copyright statement to Your modifications and
139 | may provide additional or different license terms and conditions
140 | for use, reproduction, or distribution of Your modifications, or
141 | for any such Derivative Works as a whole, provided Your use,
142 | reproduction, and distribution of the Work otherwise complies with
143 | the conditions stated in this License.
144 |
145 | 5. Submission of Contributions. Unless You explicitly state otherwise,
146 | any Contribution intentionally submitted for inclusion in the Work
147 | by You to the Licensor shall be under the terms and conditions of
148 | this License, without any additional terms or conditions.
149 | Notwithstanding the above, nothing herein shall supersede or modify
150 | the terms of any separate license agreement you may have executed
151 | with Licensor regarding such Contributions.
152 |
153 | 6. Trademarks. This License does not grant permission to use the trade
154 | names, trademarks, service marks, or product names of the Licensor,
155 | except as required for reasonable and customary use in describing the
156 | origin of the Work and reproducing the content of the NOTICE file.
157 |
158 | 7. Disclaimer of Warranty. Unless required by applicable law or
159 | agreed to in writing, Licensor provides the Work (and each
160 | Contributor provides its Contributions) on an "AS IS" BASIS,
161 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
162 | implied, including, without limitation, any warranties or conditions
163 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
164 | PARTICULAR PURPOSE. You are solely responsible for determining the
165 | appropriateness of using or redistributing the Work and assume any
166 | risks associated with Your exercise of permissions under this License.
167 |
168 | 8. Limitation of Liability. In no event and under no legal theory,
169 | whether in tort (including negligence), contract, or otherwise,
170 | unless required by applicable law (such as deliberate and grossly
171 | negligent acts) or agreed to in writing, shall any Contributor be
172 | liable to You for damages, including any direct, indirect, special,
173 | incidental, or consequential damages of any character arising as a
174 | result of this License or out of the use or inability to use the
175 | Work (including but not limited to damages for loss of goodwill,
176 | work stoppage, computer failure or malfunction, or any and all
177 | other commercial damages or losses), even if such Contributor
178 | has been advised of the possibility of such damages.
179 |
180 | 9. Accepting Warranty or Additional Liability. While redistributing
181 | the Work or Derivative Works thereof, You may choose to offer,
182 | and charge a fee for, acceptance of support, warranty, indemnity,
183 | or other liability obligations and/or rights consistent with this
184 | License. However, in accepting such obligations, You may act only
185 | on Your own behalf and on Your sole responsibility, not on behalf
186 | of any other Contributor, and only if You agree to indemnify,
187 | defend, and hold each Contributor harmless for any liability
188 | incurred by, or claims asserted against, such Contributor by reason
189 | of your accepting any such warranty or additional liability.
190 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Socket.IO Java
2 | [](https://travis-ci.org/trinopoty/socket.io-server-java) [](https://codecov.io/gh/trinopoty/socket.io-server-java)
3 |
4 | This is the Socket.IO Server Library for Java ported from the [JavaScript server](https://github.com/socketio/socket.io).
5 |
6 | **NOTE** This library will follow the major version of the JS library starting with version 3.
7 |
8 | See also: [Socket.IO-client Java](https://github.com/socketio/socket.io-client-java)
9 |
10 | ## Features
11 | This library supports all of the features the JS server does, including events, options and upgrading transport.
12 |
13 | ## Documentation
14 | Complete documentation can be found [here](https://trinopoty.github.io/socket.io-server-java/).
15 |
16 | ## Installation
17 | The latest artifact is available on Maven Central.
18 |
19 | ### Maven
20 | Add the following dependency to your `pom.xml`.
21 |
22 | ```xml
23 |
24 |
25 | io.socket
26 | socket.io-server
27 | 4.0.1
28 |
29 |
30 | ```
31 |
32 | ### Gradle
33 | Add it as a gradle dependency in `build.gradle`.
34 |
35 | ```groovy
36 | compile ('io.socket:socket.io-server:4.0.1')
37 | ```
38 |
39 | ## Demo project
40 | A basic demo project running on a Jetty server can be found at https://github.com/oddmario/socket.io-server-java-demo
41 |
42 | ## License
43 |
44 | Apache 2.0
45 |
--------------------------------------------------------------------------------
/codecov.yml:
--------------------------------------------------------------------------------
1 | codecov:
2 | notify:
3 | require_ci_to_pass: yes
4 |
5 | coverage:
6 | precision: 2
7 | round: down
8 |
9 | status:
10 | project: yes
11 | patch: yes
12 | changes: no
13 |
14 | parsers:
15 | gcov:
16 | branch_detection:
17 | conditional: yes
18 | loop: yes
19 | method: no
20 | macro: no
21 |
22 | comment:
23 | layout: "header, diff"
24 | behavior: default
25 | require_changes: no
26 |
27 |
--------------------------------------------------------------------------------
/deploy-docs.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # This script builds the documentation and pushes it to github
4 |
5 | GH_REPO_REF="github.com/$TRAVIS_REPO_SLUG"
6 |
7 | set -e
8 |
9 | JAVADOC_DIR=$(pwd)/target/site/apidocs
10 |
11 | # Build the javadocs
12 | mvn clean javadoc:aggregate
13 |
14 | # Activate virtualenv
15 | python3 -m venv venv3
16 | . venv3/bin/activate
17 |
18 | cd docs
19 | rm -rf ./_build
20 |
21 | # Install dependencies
22 | pip install -r requirements.txt
23 |
24 | # Build docs
25 | make html
26 |
27 | cd _build
28 |
29 | # Clone docs branch
30 | git clone -b gh-pages https://git@$GH_REPO_REF docs-upload
31 | cd docs-upload
32 |
33 | # Configure git
34 | git config push.default simple
35 | git config user.name "Travis CI"
36 | git config user.email "travis@travis-ci.org"
37 |
38 | # Remove existing docs
39 | rm -rf *
40 |
41 | # Copy docs from build to repo
42 | cp -r ../html/* ./
43 |
44 | # Copy javadocs
45 | rm -rf ./javadocs
46 | mv "$JAVADOC_DIR" ./javadocs
47 |
48 | echo "" > .nojekyll
49 |
50 | if [[ -f "index.html" ]]; then
51 | # Commit
52 | git add --all
53 | git commit -m "Deploy code docs to GitHub Pages Travis build"
54 |
55 | export GH_REPO_TOKEN="trinopoty@${GH_TOKEN}"
56 | git push --force "https://${GH_REPO_TOKEN}@${GH_REPO_REF}" > /dev/null 2>&1
57 | else
58 | echo 'ERROR: index.html not found'
59 | exit 1
60 | fi
61 |
--------------------------------------------------------------------------------
/docs/.gitignore:
--------------------------------------------------------------------------------
1 | /_build
2 |
--------------------------------------------------------------------------------
/docs/Makefile:
--------------------------------------------------------------------------------
1 | # Minimal makefile for Sphinx documentation
2 | #
3 |
4 | # You can set these variables from the command line.
5 | SPHINXOPTS =
6 | SPHINXBUILD = sphinx-build
7 | SPHINXPROJ = SocketIO
8 | SOURCEDIR = .
9 | BUILDDIR = _build
10 |
11 | # Put it first so that "make" without argument is like "make help".
12 | help:
13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
14 |
15 | .PHONY: help Makefile
16 |
17 | # Catch-all target: route all unknown targets to Sphinx using the new
18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
19 | %: Makefile
20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
--------------------------------------------------------------------------------
/docs/_static/.keep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/docs/_themes/sphinx_rtd_theme/__init__.py:
--------------------------------------------------------------------------------
1 | """Sphinx ReadTheDocs theme.
2 |
3 | From https://github.com/ryan-roemer/sphinx-bootstrap-theme.
4 |
5 | """
6 | from os import path
7 |
8 | __version__ = '0.4.1'
9 | __version_full__ = __version__
10 |
11 |
12 | def get_html_theme_path():
13 | """Return list of HTML theme paths."""
14 | cur_dir = path.abspath(path.dirname(path.dirname(__file__)))
15 | return cur_dir
16 |
17 | # See http://www.sphinx-doc.org/en/stable/theming.html#distribute-your-theme-as-a-python-package
18 | def setup(app):
19 | app.add_html_theme('sphinx_rtd_theme', path.abspath(path.dirname(__file__)))
20 |
--------------------------------------------------------------------------------
/docs/_themes/sphinx_rtd_theme/breadcrumbs.html:
--------------------------------------------------------------------------------
1 | {# Support for Sphinx 1.3+ page_source_suffix, but don't break old builds. #}
2 |
3 | {% if page_source_suffix %}
4 | {% set suffix = page_source_suffix %}
5 | {% else %}
6 | {% set suffix = source_suffix %}
7 | {% endif %}
8 |
9 | {% if meta is defined and meta is not none %}
10 | {% set check_meta = True %}
11 | {% else %}
12 | {% set check_meta = False %}
13 | {% endif %}
14 |
15 | {% if check_meta and 'github_url' in meta %}
16 | {% set display_github = True %}
17 | {% endif %}
18 |
19 | {% if check_meta and 'bitbucket_url' in meta %}
20 | {% set display_bitbucket = True %}
21 | {% endif %}
22 |
23 | {% if check_meta and 'gitlab_url' in meta %}
24 | {% set display_gitlab = True %}
25 | {% endif %}
26 |
27 |
28 |
29 |
70 |
71 | {% if (theme_prev_next_buttons_location == 'top' or theme_prev_next_buttons_location == 'both') and (next or prev) %}
72 |
80 | {% endif %}
81 |
82 |
83 |
--------------------------------------------------------------------------------
/docs/_themes/sphinx_rtd_theme/footer.html:
--------------------------------------------------------------------------------
1 |
52 |
53 |
--------------------------------------------------------------------------------
/docs/_themes/sphinx_rtd_theme/layout.html:
--------------------------------------------------------------------------------
1 | {# TEMPLATE VAR SETTINGS #}
2 | {%- set url_root = pathto('', 1) %}
3 | {%- if url_root == '#' %}{% set url_root = '' %}{% endif %}
4 | {%- if not embedded and docstitle %}
5 | {%- set titlesuffix = " — "|safe + docstitle|e %}
6 | {%- else %}
7 | {%- set titlesuffix = "" %}
8 | {%- endif %}
9 | {%- set lang_attr = 'en' if language == None else (language | replace('_', '-')) %}
10 |
11 |
12 |
13 |
14 |
15 |
16 | {{ metatags }}
17 |
18 | {% block htmltitle %}
19 | {{ title|striptags|e }}{{ titlesuffix }}
20 | {% endblock %}
21 |
22 | {# FAVICON #}
23 | {% if favicon %}
24 |
25 | {% endif %}
26 | {# CANONICAL URL #}
27 | {% if theme_canonical_url %}
28 |
29 | {% endif %}
30 |
31 | {# CSS #}
32 |
33 | {# OPENSEARCH #}
34 | {% if not embedded %}
35 | {% if use_opensearch %}
36 |
39 | {% endif %}
40 |
41 | {% endif %}
42 |
43 |
44 |
45 | {%- for css in css_files %}
46 | {%- if css|attr("rel") %}
47 |
48 | {%- else %}
49 |
50 | {%- endif %}
51 | {%- endfor %}
52 | {%- for cssfile in extra_css_files %}
53 |
54 | {%- endfor %}
55 |
56 | {%- block linktags %}
57 | {%- if hasdoc('about') %}
58 |
59 | {%- endif %}
60 | {%- if hasdoc('genindex') %}
61 |
62 | {%- endif %}
63 | {%- if hasdoc('search') %}
64 |
65 | {%- endif %}
66 | {%- if hasdoc('copyright') %}
67 |
68 | {%- endif %}
69 | {%- if next %}
70 |
71 | {%- endif %}
72 | {%- if prev %}
73 |
74 | {%- endif %}
75 | {%- endblock %}
76 | {%- block extrahead %} {% endblock %}
77 |
78 | {# Keep modernizr in head - http://modernizr.com/docs/#installing #}
79 |
80 |
81 |
82 |
83 |
84 |
85 | {% block extrabody %} {% endblock %}
86 |
87 |
88 | {# SIDE NAV, TOGGLES ON MOBILE #}
89 |
90 |
146 |
147 |
148 |
149 |
150 | {# MOBILE NAV, TRIGGLES SIDE NAV ON TOGGLE #}
151 |
152 | {% block mobile_nav %}
153 |
154 | {{ project }}
155 | {% endblock %}
156 |
157 |
158 |
159 |
160 | {%- block content %}
161 | {% if theme_style_external_links|tobool %}
162 |
163 | {% else %}
164 |
165 | {% endif %}
166 | {% include "breadcrumbs.html" %}
167 |
168 | {%- block document %}
169 |
170 | {% block body %}{% endblock %}
171 |
172 | {% if self.comments()|trim %}
173 |
174 | {% block comments %}{% endblock %}
175 |
176 | {% endif%}
177 |
178 | {%- endblock %}
179 | {% include "footer.html" %}
180 |
181 | {%- endblock %}
182 |
183 |
184 |
185 |
186 |
187 | {% include "versions.html" %}
188 |
189 | {% if not embedded %}
190 |
191 |
202 | {%- for scriptfile in script_files %}
203 |
204 | {%- endfor %}
205 |
206 | {% endif %}
207 |
208 |
209 |
210 |
215 |
216 | {%- block footer %} {% endblock %}
217 |
218 |
219 |
220 |
--------------------------------------------------------------------------------
/docs/_themes/sphinx_rtd_theme/search.html:
--------------------------------------------------------------------------------
1 | {#
2 | basic/search.html
3 | ~~~~~~~~~~~~~~~~~
4 |
5 | Template for the search page.
6 |
7 | :copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS.
8 | :license: BSD, see LICENSE for details.
9 | #}
10 | {%- extends "layout.html" %}
11 | {% set title = _('Search') %}
12 | {% set script_files = script_files + ['_static/searchtools.js'] %}
13 | {% block footer %}
14 |
17 | {# this is used when loading the search index using $.ajax fails,
18 | such as on Chrome for documents on localhost #}
19 |
20 | {{ super() }}
21 | {% endblock %}
22 | {% block body %}
23 |
24 |
25 |
26 | {% trans %}Please activate JavaScript to enable the search
27 | functionality.{% endtrans %}
28 |
29 |
30 |
31 |
32 | {% if search_performed %}
33 | {{ _('Search Results') }}
34 | {% if not search_results %}
35 | {{ _('Your search did not match any documents. Please make sure that all words are spelled correctly and that you\'ve selected enough categories.') }}
36 | {% endif %}
37 | {% endif %}
38 |
39 | {% if search_results %}
40 |
41 | {% for href, caption, context in search_results %}
42 |
43 | {{ caption }}
44 | {{ context|e }}
45 |
46 | {% endfor %}
47 |
48 | {% endif %}
49 |
50 | {% endblock %}
51 |
--------------------------------------------------------------------------------
/docs/_themes/sphinx_rtd_theme/searchbox.html:
--------------------------------------------------------------------------------
1 | {%- if builder != 'singlehtml' %}
2 |
3 |
8 |
9 | {%- endif %}
10 |
--------------------------------------------------------------------------------
/docs/_themes/sphinx_rtd_theme/static/css/badge_only.css:
--------------------------------------------------------------------------------
1 | .fa:before{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:""}.clearfix:after{clear:both}@font-face{font-family:FontAwesome;font-weight:normal;font-style:normal;src:url("../fonts/fontawesome-webfont.eot");src:url("../fonts/fontawesome-webfont.eot?#iefix") format("embedded-opentype"),url("../fonts/fontawesome-webfont.woff") format("woff"),url("../fonts/fontawesome-webfont.ttf") format("truetype"),url("../fonts/fontawesome-webfont.svg#FontAwesome") format("svg")}.fa:before{display:inline-block;font-family:FontAwesome;font-style:normal;font-weight:normal;line-height:1;text-decoration:inherit}a .fa{display:inline-block;text-decoration:inherit}li .fa{display:inline-block}li .fa-large:before,li .fa-large:before{width:1.875em}ul.fas{list-style-type:none;margin-left:2em;text-indent:-0.8em}ul.fas li .fa{width:.8em}ul.fas li .fa-large:before,ul.fas li .fa-large:before{vertical-align:baseline}.fa-book:before{content:""}.icon-book:before{content:""}.fa-caret-down:before{content:""}.icon-caret-down:before{content:""}.fa-caret-up:before{content:""}.icon-caret-up:before{content:""}.fa-caret-left:before{content:""}.icon-caret-left:before{content:""}.fa-caret-right:before{content:""}.icon-caret-right:before{content:""}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;z-index:400}.rst-versions a{color:#2980B9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27AE60;*zoom:1}.rst-versions .rst-current-version:before,.rst-versions .rst-current-version:after{display:table;content:""}.rst-versions .rst-current-version:after{clear:both}.rst-versions .rst-current-version .fa{color:#fcfcfc}.rst-versions .rst-current-version .fa-book{float:left}.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#E74C3C;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#F1C40F;color:#000}.rst-versions.shift-up{height:auto;max-height:100%}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:gray;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:solid 1px #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px}.rst-versions.rst-badge .icon-book{float:none}.rst-versions.rst-badge .fa-book{float:none}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book{float:left}.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge .rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width: 768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}}
2 |
--------------------------------------------------------------------------------
/docs/_themes/sphinx_rtd_theme/static/fonts/FontAwesome.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/socketio/socket.io-server-java/HEAD/docs/_themes/sphinx_rtd_theme/static/fonts/FontAwesome.otf
--------------------------------------------------------------------------------
/docs/_themes/sphinx_rtd_theme/static/fonts/fontawesome-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/socketio/socket.io-server-java/HEAD/docs/_themes/sphinx_rtd_theme/static/fonts/fontawesome-webfont.eot
--------------------------------------------------------------------------------
/docs/_themes/sphinx_rtd_theme/static/fonts/fontawesome-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/socketio/socket.io-server-java/HEAD/docs/_themes/sphinx_rtd_theme/static/fonts/fontawesome-webfont.ttf
--------------------------------------------------------------------------------
/docs/_themes/sphinx_rtd_theme/static/fonts/fontawesome-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/socketio/socket.io-server-java/HEAD/docs/_themes/sphinx_rtd_theme/static/fonts/fontawesome-webfont.woff
--------------------------------------------------------------------------------
/docs/_themes/sphinx_rtd_theme/static/fonts/fontawesome-webfont.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/socketio/socket.io-server-java/HEAD/docs/_themes/sphinx_rtd_theme/static/fonts/fontawesome-webfont.woff2
--------------------------------------------------------------------------------
/docs/_themes/sphinx_rtd_theme/static/js/theme.js:
--------------------------------------------------------------------------------
1 | /* sphinx_rtd_theme version 0.4.1 | MIT license */
2 | /* Built 20180727 10:07 */
3 | require=function n(e,i,t){function o(s,a){if(!i[s]){if(!e[s]){var l="function"==typeof require&&require;if(!a&&l)return l(s,!0);if(r)return r(s,!0);var c=new Error("Cannot find module '"+s+"'");throw c.code="MODULE_NOT_FOUND",c}var u=i[s]={exports:{}};e[s][0].call(u.exports,function(n){var i=e[s][1][n];return o(i||n)},u,u.exports,n,e,i,t)}return i[s].exports}for(var r="function"==typeof require&&require,s=0;s "),n("table.docutils.footnote").wrap(""),n("table.docutils.citation").wrap("
"),n(".wy-menu-vertical ul").not(".simple").siblings("a").each(function(){var i=n(this);expand=n(' '),expand.on("click",function(n){return e.toggleCurrent(i),n.stopPropagation(),!1}),i.prepend(expand)})},reset:function(){var n=encodeURI(window.location.hash)||"#";try{var e=$(".wy-menu-vertical"),i=e.find('[href="'+n+'"]');if(0===i.length){var t=$('.document [id="'+n.substring(1)+'"]').closest("div.section");0===(i=e.find('[href="#'+t.attr("id")+'"]')).length&&(i=e.find('[href="#"]'))}i.length>0&&($(".wy-menu-vertical .current").removeClass("current"),i.addClass("current"),i.closest("li.toctree-l1").addClass("current"),i.closest("li.toctree-l1").parent().addClass("current"),i.closest("li.toctree-l1").addClass("current"),i.closest("li.toctree-l2").addClass("current"),i.closest("li.toctree-l3").addClass("current"),i.closest("li.toctree-l4").addClass("current"))}catch(o){console.log("Error expanding nav for anchor",o)}},onScroll:function(){this.winScroll=!1;var n=this.win.scrollTop(),e=n+this.winHeight,i=this.navBar.scrollTop()+(n-this.winPosition);n<0||e>this.docHeight||(this.navBar.scrollTop(i),this.winPosition=n)},onResize:function(){this.winResize=!1,this.winHeight=this.win.height(),this.docHeight=$(document).height()},hashChange:function(){this.linkScroll=!0,this.win.one("hashchange",function(){this.linkScroll=!1})},toggleCurrent:function(n){var e=n.closest("li");e.siblings("li.current").removeClass("current"),e.siblings().find("li.current").removeClass("current"),e.find("> ul li.current").removeClass("current"),e.toggleClass("current")}},"undefined"!=typeof window&&(window.SphinxRtdTheme={Navigation:e.exports.ThemeNav,StickyNav:e.exports.ThemeNav}),function(){for(var n=0,e=["ms","moz","webkit","o"],i=0;i
4 |
5 | Read the Docs
6 | v: {{ current_version }}
7 |
8 |
9 |
10 |
11 | {{ _('Versions') }}
12 | {% for slug, url in versions %}
13 | {{ slug }}
14 | {% endfor %}
15 |
16 |
17 | {{ _('Downloads') }}
18 | {% for type, url in downloads %}
19 | {{ type }}
20 | {% endfor %}
21 |
22 |
23 | {{ _('On Read the Docs') }}
24 |
25 | {{ _('Project Home') }}
26 |
27 |
28 | {{ _('Builds') }}
29 |
30 |
31 |
32 | {% trans %}Free document hosting provided by
Read the Docs .{% endtrans %}
33 |
34 |
35 |
36 | {% endif %}
37 |
38 |
--------------------------------------------------------------------------------
/docs/api.rst:
--------------------------------------------------------------------------------
1 | ===
2 | API
3 | ===
4 |
5 | .. contents:: Table of Contents
6 | :local:
7 |
8 | SocketIoServer
9 | ==============
10 |
11 | This class contains logic for creating namespaces
12 | and handle raw Engine.IO connections.
13 |
14 | Methods
15 | -------
16 |
17 | hasNamespace
18 | ^^^^^^^^^^^^
19 |
20 | Call this method to check if namespace is registered with server.
21 |
22 | namespace
23 | ^^^^^^^^^
24 |
25 | Call this method to create or retrieve a namespace instance.
26 |
27 | Dynamic Namespaces
28 | ------------------
29 |
30 | Call the ``namespace`` method with either a ``Pattern`` instance or
31 | ``SocketIoNamespaceProvider`` instance to create a dynamic namespace.
32 |
33 | **Note** Make sure to account for the starting ``/``.
34 |
35 | SocketIoNamespace
36 | =================
37 |
38 | This class represents a Socket.IO namespace instance.
39 |
40 | Methods
41 | -------
42 |
43 | broadcast
44 | ^^^^^^^^^
45 |
46 | Call this method to broadcast an event to one or many rooms.
47 |
48 | Events
49 | ------
50 |
51 | connect
52 | ^^^^^^^
53 |
54 | This event is emitted when a new client connection is established.
55 |
56 | **Arguments**
57 |
58 | 0. ``SocketIoSocket`` instance of socket
59 |
60 | connection
61 | ^^^^^^^^^^
62 |
63 | Same as ``connect`` event.
64 |
65 | SocketIoSocket
66 | ==============
67 |
68 | This class represents a socket to connected client.
69 |
70 | **Note** A socket joins a room with it's own id by default.
71 |
72 | Methods
73 | -------
74 |
75 | send
76 | ^^^^
77 |
78 | Call this method to send an event to the client with optional acknowledge callback.
79 |
80 | broadcast
81 | ^^^^^^^^^
82 |
83 | Call this method to broadcast an event to all sockets in one or many rooms excluding this socket.
84 |
85 | disconnect
86 | ^^^^^^^^^^
87 |
88 | Call this method to disconnect the socket.
89 |
90 | joinRoom
91 | ^^^^^^^^
92 |
93 | Call this method to add this socket to one or more rooms.
94 |
95 | leaveRoom
96 | ^^^^^^^^^
97 |
98 | Call this method to remove this socket from one or more rooms.
99 |
100 | leaveAllRooms
101 | ^^^^^^^^^^^^^
102 |
103 | Call this method to remove this socket from all rooms.
104 |
105 | Events
106 | ------
107 |
108 | Any event sent from the client is emitted in addition to the events listed below.
109 |
110 | disconnecting
111 | ^^^^^^^^^^^^^
112 |
113 | This event is emitted before disconnecting from client.
114 |
115 | disconnect
116 | ^^^^^^^^^^
117 |
118 | This event is emitted after disconnecting from client.
119 |
120 | error
121 | ^^^^^
122 |
123 | This event is raised on error.
124 |
125 | **Arguments**
126 |
127 | 0. ``String`` error reason/description
--------------------------------------------------------------------------------
/docs/conf.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | #
3 | # Configuration file for the Sphinx documentation builder.
4 | #
5 | # This file does only contain a selection of the most common options. For a
6 | # full list see the documentation:
7 | # http://www.sphinx-doc.org/en/master/config
8 |
9 | # -- Path setup --------------------------------------------------------------
10 |
11 | # If extensions (or modules to document with autodoc) are in another directory,
12 | # add these directories to sys.path here. If the directory is relative to the
13 | # documentation root, use os.path.abspath to make it absolute, like shown here.
14 | #
15 | # import os
16 | # import sys
17 | # sys.path.insert(0, os.path.abspath('.'))
18 |
19 |
20 | # -- Project information -----------------------------------------------------
21 |
22 | project = u'Socket.IO Java Server'
23 | copyright = u'2018, Trinopoty Biswas'
24 | author = u'Trinopoty Biswas'
25 |
26 | # The short X.Y version
27 | version = u''
28 | # The full version, including alpha/beta/rc tags
29 | release = u''
30 |
31 |
32 | # -- General configuration ---------------------------------------------------
33 |
34 | # If your documentation needs a minimal Sphinx version, state it here.
35 | #
36 | # needs_sphinx = '1.0'
37 |
38 | # Add any Sphinx extension module names here, as strings. They can be
39 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
40 | # ones.
41 | extensions = [
42 | 'sphinx.ext.todo',
43 | 'sphinx.ext.githubpages',
44 | ]
45 |
46 | # Add any paths that contain templates here, relative to this directory.
47 | templates_path = ['_templates']
48 |
49 | # The suffix(es) of source filenames.
50 | # You can specify multiple suffix as a list of string:
51 | #
52 | # source_suffix = ['.rst', '.md']
53 | source_suffix = '.rst'
54 |
55 | # The master toctree document.
56 | master_doc = 'index'
57 |
58 | # The language for content autogenerated by Sphinx. Refer to documentation
59 | # for a list of supported languages.
60 | #
61 | # This is also used if you do content translation via gettext catalogs.
62 | # Usually you set "language" from the command line for these cases.
63 | language = None
64 |
65 | # List of patterns, relative to source directory, that match files and
66 | # directories to ignore when looking for source files.
67 | # This pattern also affects html_static_path and html_extra_path .
68 | exclude_patterns = [u'_build', 'Thumbs.db', '.DS_Store']
69 |
70 | # The name of the Pygments (syntax highlighting) style to use.
71 | pygments_style = 'sphinx'
72 |
73 |
74 | # -- Options for HTML output -------------------------------------------------
75 |
76 | # The theme to use for HTML and HTML Help pages. See the documentation for
77 | # a list of builtin themes.
78 | #
79 | html_theme = 'sphinx_rtd_theme'
80 | html_theme_path = ['_themes']
81 |
82 | # Theme options are theme-specific and customize the look and feel of a theme
83 | # further. For a list of options available for each theme, see the
84 | # documentation.
85 | #
86 | # html_theme_options = {}
87 |
88 | # Add any paths that contain custom static files (such as style sheets) here,
89 | # relative to this directory. They are copied after the builtin static files,
90 | # so a file named "default.css" will overwrite the builtin "default.css".
91 | html_static_path = ['_static']
92 |
93 | # Custom sidebar templates, must be a dictionary that maps document names
94 | # to template names.
95 | #
96 | # The default sidebars (for documents that don't match any pattern) are
97 | # defined by theme itself. Builtin themes are using these templates by
98 | # default: ``['localtoc.html', 'relations.html', 'sourcelink.html',
99 | # 'searchbox.html']``.
100 | #
101 | # html_sidebars = {}
102 |
103 |
104 | # -- Options for HTMLHelp output ---------------------------------------------
105 |
106 | # Output file base name for HTML help builder.
107 | htmlhelp_basename = 'SocketIOdoc'
108 |
109 |
110 | # -- Options for LaTeX output ------------------------------------------------
111 |
112 | latex_elements = {
113 | # The paper size ('letterpaper' or 'a4paper').
114 | #
115 | # 'papersize': 'letterpaper',
116 |
117 | # The font size ('10pt', '11pt' or '12pt').
118 | #
119 | # 'pointsize': '10pt',
120 |
121 | # Additional stuff for the LaTeX preamble.
122 | #
123 | # 'preamble': '',
124 |
125 | # Latex figure (float) alignment
126 | #
127 | # 'figure_align': 'htbp',
128 | }
129 |
130 | # Grouping the document tree into LaTeX files. List of tuples
131 | # (source start file, target name, title,
132 | # author, documentclass [howto, manual, or own class]).
133 | latex_documents = [
134 | (master_doc, 'SocketIO.tex', u'Socket.IO Documentation',
135 | u'Trinopoty Biswas', 'manual'),
136 | ]
137 |
138 |
139 | # -- Options for manual page output ------------------------------------------
140 |
141 | # One entry per manual page. List of tuples
142 | # (source start file, name, description, authors, manual section).
143 | man_pages = [
144 | (master_doc, 'socketio', u'Socket.IO Documentation',
145 | [author], 1)
146 | ]
147 |
148 |
149 | # -- Options for Texinfo output ----------------------------------------------
150 |
151 | # Grouping the document tree into Texinfo files. List of tuples
152 | # (source start file, target name, title, author,
153 | # dir menu entry, description, category)
154 | texinfo_documents = [
155 | (master_doc, 'SocketIO', u'Socket.IO Documentation',
156 | author, 'SocketIO', 'One line description of project.',
157 | 'Miscellaneous'),
158 | ]
159 |
160 |
161 | # -- Extension configuration -------------------------------------------------
162 |
163 | # -- Options for todo extension ----------------------------------------------
164 |
165 | # If true, `todo` and `todoList` produce output, else they produce nothing.
166 | todo_include_todos = True
167 |
--------------------------------------------------------------------------------
/docs/index.rst:
--------------------------------------------------------------------------------
1 | .. Socket.IO documentation master file, created by
2 | sphinx-quickstart on Thu Aug 9 18:55:12 2018.
3 | You can adapt this file completely to your liking, but it should at least
4 | contain the root `toctree` directive.
5 |
6 | Welcome to Socket.IO Java Server's documentation!
7 | =================================================
8 |
9 | .. toctree::
10 | :maxdepth: 1
11 | :caption: Contents:
12 |
13 | install
14 | using
15 | api
16 | javadocs/index
17 |
--------------------------------------------------------------------------------
/docs/install.rst:
--------------------------------------------------------------------------------
1 | ============
2 | Installation
3 | ============
4 |
5 | The latest artifact will be available on Maven Central soon.
6 |
7 | Socket.IO Java Server Library
8 | =============================
9 |
10 | Maven
11 | -----
12 |
13 | Add the following dependency to your ``pom.xml``.::
14 |
15 |
16 |
17 | io.socket
18 | socket.io-server
19 | 4.0.1
20 |
21 |
22 |
23 | Gradle
24 | ------
25 |
26 | Add it as a gradle dependency in ``build.gradle``.::
27 |
28 | compile ('io.socket:socket.io-server:4.0.1')
29 |
--------------------------------------------------------------------------------
/docs/javadocs/index.rst:
--------------------------------------------------------------------------------
1 | ========
2 | Javadocs
3 | ========
4 |
--------------------------------------------------------------------------------
/docs/requirements.txt:
--------------------------------------------------------------------------------
1 | sphinx
2 | sphinx-autobuild
3 |
--------------------------------------------------------------------------------
/docs/using.rst:
--------------------------------------------------------------------------------
1 | ===============
2 | Getting Started
3 | ===============
4 |
5 | Create a servlet for handling incoming HTTP connections and call
6 | ``EngineIoServer`` class's ``handleRequest`` method on receiving an HTTP
7 | request. Create a new instance of ``SocketIoServer`` using the ``EngineIoServer``
8 | instance.
9 |
10 | Example servlet
11 | ===============
12 | Example servlet class::
13 |
14 | @WebServlet("/socket.io/*")
15 | public class SocketIoServlet extends HttpServlet {
16 |
17 | private final EngineIoServer mEngineIoServer = new EngineIoServer();
18 | private final SocketIoServer mSocketIoServer = new SocketIoServer(mEngineIoServer);
19 |
20 | @Override
21 | protected void service(HttpServletRequest request, HttpServletResponse response) throws IOException {
22 | mEngineIoServer.handleRequest(request, response);
23 | }
24 | }
25 |
26 | In the example servlet above, a static instance of ``EngineIoServer`` is defined and
27 | the method ``service`` is overridden to call ``handleRequest``.
28 |
29 | Accept WebSocket Connection
30 | ===========================
31 |
32 | Please refer to `Engine.IO documentation `_ for accepting WebSocket connection.
33 |
34 | Create namesapce
35 | ================
36 |
37 | Call the ``namespace`` method on ``SocketIoServer`` to create or retrieve a namespace.
38 |
39 | Example::
40 |
41 | SocketIoNamespace namespace = server.namespace("/");
42 | // Do something with namespace
43 |
44 | Listening for connections
45 | =========================
46 |
47 | Attach a listener to the ``connection`` event of ``SocketIoNamespace`` to listen for
48 | new connections.
49 |
50 | Example::
51 |
52 | namespace.on("connection", new Emitter.Listener() {
53 | @Override
54 | public void call(Object... args) {
55 | SocketIoSocket socket = (SocketIoSocket) args[0];
56 | // Do something with socket
57 | }
58 | });
59 |
60 | Listening for message from client
61 | =================================
62 |
63 | Attach an event listener on ``SocketIoSocket`` to listen for events from client.
64 |
65 | Example::
66 |
67 | // Attaching to 'foo' event
68 | socket.on("foo", new Emitter.Listener() {
69 | @Override
70 | public void call(Object... args) {
71 | // Arugments from client available in 'args'
72 | }
73 | });
74 |
75 | Sending message to client
76 | =========================
77 |
78 | Call the ``send`` method on ``SocketIoSocket`` to send event to remote client.
79 |
80 | Example::
81 |
82 | // Sending event 'foo' with args 'bar arg', 1
83 | socket.send("foo", "bar arg", 1);
84 |
85 | Broadcasting message to room
86 | ============================
87 |
88 | Call the ``broadcast`` method on ``SocketIoNamespace`` to broadcast event to
89 | all remote clients.
90 |
91 | Example::
92 |
93 | // Broadcasting event 'foo' with args 'bar arg' to room 'room'
94 | namespace.broadcast("room", "foo", "bar arg");
95 |
96 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | io.socket
8 | socket.io-server-bom
9 | 4.1.2
10 | pom
11 | socket.io
12 | Socket.IO server library for Java
13 | https://github.com/trinopoty/socket.io-server-java
14 |
15 |
16 | socket.io-server
17 | socket.io-server-test
18 |
19 |
20 |
21 | github
22 | UTF-8
23 | 11
24 | 11
25 |
26 | 11.0.15
27 |
28 |
29 |
30 |
31 | Apache License Version 2.0, January 2004
32 | https://www.apache.org/licenses/LICENSE-2.0.txt
33 | repo
34 |
35 |
36 |
37 |
38 | https://github.com/trinopoty/socket.io-server-java
39 | scm:git:https://github.com/trinopoty/socket.io-server-java.git
40 | scm:git:https://github.com/trinopoty/socket.io-server-java.git
41 | HEAD
42 |
43 |
44 |
45 |
46 | trinopoty
47 | Trinopoty Biswas
48 | trinopoty@gmail.com
49 |
50 |
51 |
52 |
53 |
54 | ossrh
55 | https://oss.sonatype.org/content/repositories/snapshots
56 |
57 |
58 | ossrh
59 | https://oss.sonatype.org/service/local/staging/deploy/maven2/
60 |
61 |
62 |
63 |
64 |
65 |
66 | io.socket
67 | socket.io-server
68 | ${project.version}
69 |
70 |
71 |
72 |
73 |
74 |
75 | release-sign-artifacts
76 |
77 |
78 | performRelease
79 | true
80 |
81 |
82 |
83 |
84 |
85 | org.apache.maven.plugins
86 | maven-gpg-plugin
87 | 3.1.0
88 |
89 |
90 | sign-artifacts
91 | verify
92 |
93 | sign
94 |
95 |
96 | ${gpg.keyname}
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | org.apache.maven.plugins
110 | maven-javadoc-plugin
111 | 3.5.0
112 |
113 |
114 | aggregate
115 |
116 | aggregate
117 |
118 | site
119 |
120 |
121 |
122 |
123 |
124 |
125 | org.codehaus.mojo
126 | cobertura-maven-plugin
127 | 2.7
128 |
129 |
130 | xml
131 |
132 | true
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 | org.apache.maven.plugins
142 | maven-javadoc-plugin
143 | 3.0.1
144 |
145 |
146 | aggregate
147 |
148 | aggregate
149 |
150 |
151 |
152 |
153 |
154 | org.codehaus.mojo
155 | cobertura-maven-plugin
156 | 2.7
157 |
158 |
159 |
160 |
161 |
--------------------------------------------------------------------------------
/pom.xml.versionsBackup:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | io.socket
8 | socket.io-server-bom
9 | 4.1.1
10 | pom
11 | socket.io
12 | Socket.IO server library for Java
13 | https://github.com/trinopoty/socket.io-server-java
14 |
15 |
16 | socket.io-server
17 | socket.io-server-test
18 |
19 |
20 |
21 | github
22 | UTF-8
23 | 11
24 | 11
25 |
26 | 11.0.15
27 |
28 |
29 |
30 |
31 | Apache License Version 2.0, January 2004
32 | https://www.apache.org/licenses/LICENSE-2.0.txt
33 | repo
34 |
35 |
36 |
37 |
38 | https://github.com/trinopoty/socket.io-server-java
39 | scm:git:https://github.com/trinopoty/socket.io-server-java.git
40 | scm:git:https://github.com/trinopoty/socket.io-server-java.git
41 | HEAD
42 |
43 |
44 |
45 |
46 | trinopoty
47 | Trinopoty Biswas
48 | trinopoty@gmail.com
49 |
50 |
51 |
52 |
53 |
54 | ossrh
55 | https://oss.sonatype.org/content/repositories/snapshots
56 |
57 |
58 | ossrh
59 | https://oss.sonatype.org/service/local/staging/deploy/maven2/
60 |
61 |
62 |
63 |
64 |
65 |
66 | io.socket
67 | socket.io-server
68 | ${project.version}
69 |
70 |
71 |
72 |
73 |
74 |
75 | release-sign-artifacts
76 |
77 |
78 | performRelease
79 | true
80 |
81 |
82 |
83 |
84 |
85 | org.apache.maven.plugins
86 | maven-gpg-plugin
87 | 3.1.0
88 |
89 |
90 | sign-artifacts
91 | verify
92 |
93 | sign
94 |
95 |
96 | ${gpg.keyname}
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | org.apache.maven.plugins
110 | maven-javadoc-plugin
111 | 3.5.0
112 |
113 |
114 | aggregate
115 |
116 | aggregate
117 |
118 | site
119 |
120 |
121 |
122 |
123 |
124 |
125 | org.codehaus.mojo
126 | cobertura-maven-plugin
127 | 2.7
128 |
129 |
130 | xml
131 |
132 | true
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 | org.apache.maven.plugins
142 | maven-javadoc-plugin
143 | 3.0.1
144 |
145 |
146 | aggregate
147 |
148 | aggregate
149 |
150 |
151 |
152 |
153 |
154 | org.codehaus.mojo
155 | cobertura-maven-plugin
156 | 2.7
157 |
158 |
159 |
160 |
161 |
--------------------------------------------------------------------------------
/socket.io-server-test/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | socket.io-server-bom
7 | io.socket
8 | 4.1.2
9 |
10 | 4.0.0
11 |
12 | socket.io-server-test
13 | jar
14 | This module contains integration tests.
15 |
16 |
17 | true
18 | true
19 |
20 |
21 |
22 |
23 | org.junit.platform
24 | junit-platform-launcher
25 | 1.6.3
26 | test
27 |
28 |
29 | org.junit.jupiter
30 | junit-jupiter-engine
31 | 5.6.3
32 | test
33 |
34 |
35 | org.junit.vintage
36 | junit-vintage-engine
37 | 5.6.3
38 | test
39 |
40 |
41 | org.mockito
42 | mockito-core
43 | 5.4.0
44 | test
45 |
46 |
47 |
48 | org.eclipse.jetty
49 | jetty-server
50 | ${jetty.version}
51 | test
52 |
53 |
54 | org.eclipse.jetty
55 | jetty-servlet
56 | ${jetty.version}
57 | test
58 |
59 |
60 | org.eclipse.jetty.websocket
61 | websocket-jetty-server
62 | ${jetty.version}
63 | test
64 |
65 |
66 |
67 | io.socket
68 | engine.io-server
69 | 6.3.2
70 | test
71 |
72 |
73 | io.socket
74 | socket.io-server
75 | ${project.version}
76 |
77 |
78 |
79 |
80 |
81 |
82 | org.apache.maven.plugins
83 | maven-compiler-plugin
84 | 3.11.0
85 |
86 | 1.8
87 | 1.8
88 | UTF-8
89 |
90 | -Xlint:unchecked
91 |
92 | true
93 | true
94 |
95 |
96 |
97 | org.apache.maven.plugins
98 | maven-deploy-plugin
99 | 3.1.1
100 |
101 | true
102 |
103 |
104 |
105 |
106 | org.codehaus.mojo
107 | exec-maven-plugin
108 | 3.1.0
109 |
110 |
111 | npm-install
112 | process-test-resources
113 |
114 | exec
115 |
116 |
117 | ./src/test/resources
118 | npm
119 |
120 | install
121 |
122 |
123 |
124 |
125 |
126 |
127 | org.apache.maven.plugins
128 | maven-surefire-plugin
129 | 3.1.2
130 |
131 | -Dfile.encoding=UTF-8
132 |
133 |
134 | java.util.logging.config.file
135 | ./src/test/resources/logging.properties
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
--------------------------------------------------------------------------------
/socket.io-server-test/pom.xml.versionsBackup:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | socket.io-server-bom
7 | io.socket
8 | 4.1.1
9 |
10 | 4.0.0
11 |
12 | socket.io-server-test
13 | jar
14 | This module contains integration tests.
15 |
16 |
17 | true
18 | true
19 |
20 |
21 |
22 |
23 | org.junit.platform
24 | junit-platform-launcher
25 | 1.6.3
26 | test
27 |
28 |
29 | org.junit.jupiter
30 | junit-jupiter-engine
31 | 5.6.3
32 | test
33 |
34 |
35 | org.junit.vintage
36 | junit-vintage-engine
37 | 5.6.3
38 | test
39 |
40 |
41 | org.mockito
42 | mockito-core
43 | 5.4.0
44 | test
45 |
46 |
47 |
48 | org.eclipse.jetty
49 | jetty-server
50 | ${jetty.version}
51 | test
52 |
53 |
54 | org.eclipse.jetty
55 | jetty-servlet
56 | ${jetty.version}
57 | test
58 |
59 |
60 | org.eclipse.jetty.websocket
61 | websocket-jetty-server
62 | ${jetty.version}
63 | test
64 |
65 |
66 |
67 | io.socket
68 | engine.io-server
69 | 6.3.2
70 | test
71 |
72 |
73 | io.socket
74 | socket.io-server
75 | ${project.version}
76 |
77 |
78 |
79 |
80 |
81 |
82 | org.apache.maven.plugins
83 | maven-compiler-plugin
84 | 3.11.0
85 |
86 | 1.8
87 | 1.8
88 | UTF-8
89 |
90 | -Xlint:unchecked
91 |
92 | true
93 | true
94 |
95 |
96 |
97 | org.apache.maven.plugins
98 | maven-deploy-plugin
99 | 3.1.1
100 |
101 | true
102 |
103 |
104 |
105 |
106 | org.codehaus.mojo
107 | exec-maven-plugin
108 | 3.1.0
109 |
110 |
111 | npm-install
112 | process-test-resources
113 |
114 | exec
115 |
116 |
117 | ./src/test/resources
118 | npm
119 |
120 | install
121 |
122 |
123 |
124 |
125 |
126 |
127 | org.apache.maven.plugins
128 | maven-surefire-plugin
129 | 3.1.2
130 |
131 | -Dfile.encoding=UTF-8
132 |
133 |
134 | java.util.logging.config.file
135 | ./src/test/resources/logging.properties
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
--------------------------------------------------------------------------------
/socket.io-server-test/src/test/java/io/socket/socketio/server/JettyEngineIoWebSocketHandler.java:
--------------------------------------------------------------------------------
1 | package io.socket.socketio.server;
2 |
3 | import io.socket.engineio.server.EngineIoServer;
4 | import io.socket.engineio.server.EngineIoWebSocket;
5 | import io.socket.engineio.server.utils.ParseQS;
6 | import org.eclipse.jetty.websocket.api.Session;
7 | import org.eclipse.jetty.websocket.api.WebSocketListener;
8 | import org.eclipse.jetty.websocket.api.annotations.WebSocket;
9 |
10 | import java.io.IOException;
11 | import java.nio.ByteBuffer;
12 | import java.util.List;
13 | import java.util.Map;
14 |
15 | @WebSocket
16 | final class JettyEngineIoWebSocketHandler extends EngineIoWebSocket implements WebSocketListener {
17 |
18 | private final EngineIoServer mEngineIoServer;
19 | private Session mSession;
20 | private Map mQuery;
21 | private Map> mHeaders;
22 |
23 | public JettyEngineIoWebSocketHandler(EngineIoServer engineIoServer) {
24 | mEngineIoServer = engineIoServer;
25 | }
26 |
27 | @Override
28 | public void onWebSocketConnect(Session session) {
29 | mSession = session;
30 | mQuery = ParseQS.decode(session.getUpgradeRequest().getQueryString());
31 | mHeaders = session.getUpgradeRequest().getHeaders();
32 |
33 | mEngineIoServer.handleWebSocket(this);
34 | }
35 |
36 | @Override
37 | public void onWebSocketClose(int statusCode, String reason) {
38 | emit("close");
39 | mSession = null;
40 | }
41 |
42 | @Override
43 | public void onWebSocketError(Throwable cause) {
44 | emit("error", "write error", cause.getMessage());
45 | }
46 |
47 | @Override
48 | public void onWebSocketText(String message) {
49 | //noinspection RedundantCast
50 | emit("message", (Object) message);
51 | }
52 |
53 | @Override
54 | public void onWebSocketBinary(byte[] payload, int offset, int len) {
55 | byte[] message = payload;
56 | if (!(offset == 0 && len == payload.length)) {
57 | message = new byte[len];
58 | System.arraycopy(payload, offset, message, 0, len);
59 | }
60 |
61 | //noinspection RedundantCast
62 | emit("message", (Object) message);
63 | }
64 |
65 | @Override
66 | public Map getQuery() {
67 | return mQuery;
68 | }
69 |
70 | @Override
71 | public Map> getConnectionHeaders() {
72 | return mHeaders;
73 | }
74 |
75 | @Override
76 | public void write(String message) throws IOException {
77 | assert mSession != null;
78 |
79 | mSession.getRemote().sendString(message);
80 | }
81 |
82 | @Override
83 | public void write(byte[] message) throws IOException {
84 | assert mSession != null;
85 |
86 | mSession.getRemote().sendBytes(ByteBuffer.wrap(message));
87 | }
88 |
89 | @Override
90 | public void close() {
91 | if (mSession != null) {
92 | mSession.close();
93 | }
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/socket.io-server-test/src/test/java/io/socket/socketio/server/ServerWrapper.java:
--------------------------------------------------------------------------------
1 | package io.socket.socketio.server;
2 |
3 | import io.socket.engineio.server.EngineIoServer;
4 | import jakarta.servlet.ServletException;
5 | import jakarta.servlet.ServletRequest;
6 | import jakarta.servlet.ServletResponse;
7 | import jakarta.servlet.http.HttpServletRequest;
8 | import jakarta.servlet.http.HttpServletResponse;
9 | import org.eclipse.jetty.server.Handler;
10 | import org.eclipse.jetty.server.Server;
11 | import org.eclipse.jetty.server.handler.HandlerList;
12 | import org.eclipse.jetty.servlet.ServletContextHandler;
13 | import org.eclipse.jetty.servlet.ServletHolder;
14 | import org.eclipse.jetty.util.log.Log;
15 | import org.eclipse.jetty.util.log.Logger;
16 | import org.eclipse.jetty.websocket.server.JettyWebSocketServlet;
17 | import org.eclipse.jetty.websocket.server.JettyWebSocketServletFactory;
18 | import org.eclipse.jetty.websocket.server.config.JettyWebSocketServletContainerInitializer;
19 |
20 | import java.io.IOException;
21 | import java.util.concurrent.atomic.AtomicInteger;
22 |
23 | final class ServerWrapper {
24 |
25 | private static final AtomicInteger PORT_START = new AtomicInteger(3000);
26 |
27 | private final int mPort;
28 | private final Server mServer;
29 | private final EngineIoServer mEngineIoServer;
30 | private final SocketIoServer mSocketIoServer;
31 |
32 | static {
33 | Log.setLog(new JettyNoLogging());
34 | }
35 |
36 | ServerWrapper() {
37 | mPort = PORT_START.getAndIncrement();
38 | mServer = new Server(mPort);
39 | mEngineIoServer = new EngineIoServer();
40 | mSocketIoServer = new SocketIoServer(mEngineIoServer);
41 |
42 | System.setProperty("org.eclipse.jetty.util.log.class", "org.eclipse.jetty.util.log.StdErrLog");
43 | System.setProperty("org.eclipse.jetty.LEVEL", "OFF");
44 |
45 | ServletContextHandler servletContextHandler = new ServletContextHandler(ServletContextHandler.SESSIONS);
46 | servletContextHandler.setContextPath("/");
47 |
48 | final JettyWebSocketServlet webSocketServlet = new JettyWebSocketServlet() {
49 | private static final long serialVersionUID = 4525525859144703715L;
50 |
51 | @Override
52 | protected void configure(JettyWebSocketServletFactory jettyWebSocketServletFactory) {
53 | jettyWebSocketServletFactory.addMapping(
54 | "/",
55 | (request, response) -> new JettyEngineIoWebSocketHandler(mEngineIoServer));
56 | }
57 |
58 | @Override
59 | public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {
60 | if (request instanceof HttpServletRequest) {
61 | final String upgradeHeader = ((HttpServletRequest) request).getHeader("upgrade");
62 | if (upgradeHeader != null) {
63 | super.service(request, response);
64 | } else {
65 | mEngineIoServer.handleRequest((HttpServletRequest) request, (HttpServletResponse) response);
66 | }
67 | } else {
68 | super.service(request, response);
69 | }
70 | }
71 | };
72 | final ServletHolder webSocketServletHolder = new ServletHolder(webSocketServlet);
73 | webSocketServletHolder.setAsyncSupported(false);
74 | servletContextHandler.addServlet(webSocketServletHolder, "/socket.io/*");
75 | JettyWebSocketServletContainerInitializer.configure(servletContextHandler, null);
76 |
77 | HandlerList handlerList = new HandlerList();
78 | handlerList.setHandlers(new Handler[] { servletContextHandler });
79 | mServer.setHandler(handlerList);
80 | }
81 |
82 | void startServer() throws Exception {
83 | mServer.start();
84 | }
85 |
86 | void stopServer() throws Exception {
87 | mServer.stop();
88 | }
89 |
90 | int getPort() {
91 | return mPort;
92 | }
93 |
94 | SocketIoServer getSocketIoServer() {
95 | return mSocketIoServer;
96 | }
97 |
98 | private static final class JettyNoLogging implements Logger {
99 |
100 | @Override
101 | public String getName() {
102 | return "no";
103 | }
104 |
105 | @Override
106 | public void warn(String s, Object... objects) {
107 | }
108 |
109 | @Override
110 | public void warn(Throwable throwable) {
111 | }
112 |
113 | @Override
114 | public void warn(String s, Throwable throwable) {
115 | }
116 |
117 | @Override
118 | public void info(String s, Object... objects) {
119 | }
120 |
121 | @Override
122 | public void info(Throwable throwable) {
123 | }
124 |
125 | @Override
126 | public void info(String s, Throwable throwable) {
127 | }
128 |
129 | @Override
130 | public boolean isDebugEnabled() {
131 | return false;
132 | }
133 |
134 | @Override
135 | public void setDebugEnabled(boolean b) {
136 | }
137 |
138 | @Override
139 | public void debug(String s, Object... objects) {
140 | }
141 |
142 | @Override
143 | public void debug(String s, long l) {
144 | }
145 |
146 | @Override
147 | public void debug(Throwable throwable) {
148 | }
149 |
150 | @Override
151 | public void debug(String s, Throwable throwable) {
152 | }
153 |
154 | @Override
155 | public Logger getLogger(String s) {
156 | return this;
157 | }
158 |
159 | @Override
160 | public void ignore(Throwable throwable) {
161 | }
162 | }
163 | }
--------------------------------------------------------------------------------
/socket.io-server-test/src/test/java/io/socket/socketio/server/SocketIoTest.java:
--------------------------------------------------------------------------------
1 | package io.socket.socketio.server;
2 |
3 | import io.socket.engineio.server.Emitter;
4 | import org.junit.Test;
5 | import org.mockito.Mockito;
6 |
7 | import java.util.ArrayList;
8 | import java.util.regex.Pattern;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | public final class SocketIoTest {
13 |
14 | @Test
15 | public void test_connect() throws Exception {
16 | final ServerWrapper serverWrapper = new ServerWrapper();
17 | try {
18 | serverWrapper.startServer();
19 | assertEquals(0, Utils.executeScriptForResult("src/test/resources/test_connect.js", serverWrapper.getPort()));
20 | } finally {
21 | serverWrapper.stopServer();
22 | }
23 | }
24 |
25 | @Test
26 | public void test_connect_dynamic() throws Exception {
27 | final ServerWrapper serverWrapper = new ServerWrapper();
28 | serverWrapper.getSocketIoServer().namespace(Pattern.compile("^/foo[0-9]$"));
29 | try {
30 | serverWrapper.startServer();
31 | assertEquals(0, Utils.executeScriptForResult("src/test/resources/test_connect_dynamic.js", serverWrapper.getPort()));
32 | } finally {
33 | serverWrapper.stopServer();
34 | }
35 | }
36 |
37 | @Test
38 | public void test_message_to_server_nonbinary_noack() throws Exception {
39 | final ServerWrapper serverWrapper = new ServerWrapper();
40 |
41 | final Emitter.Listener messageListener = Mockito.mock(Emitter.Listener.class);
42 | Mockito.doAnswer(invocationOnMock -> {
43 | final Object[] messageArgs = invocationOnMock.getArguments();
44 | assertEquals(2, messageArgs.length);
45 | assertEquals(1, messageArgs[0]);
46 | assertEquals("bar", messageArgs[1]);
47 | return null;
48 | }).when(messageListener).call(Mockito.any());
49 |
50 | serverWrapper.getSocketIoServer().namespace("/").on("connection", args -> {
51 | final SocketIoSocket socket = (SocketIoSocket) args[0];
52 | socket.on("foo", messageListener);
53 | });
54 | try {
55 | serverWrapper.startServer();
56 | assertEquals(0, Utils.executeScriptForResult("src/test/resources/test_message_to_server_nonbinary_noack.js", serverWrapper.getPort()));
57 | Mockito.verify(messageListener, Mockito.times(1)).call(Mockito.any(Object[].class));
58 | } finally {
59 | serverWrapper.stopServer();
60 | }
61 | }
62 |
63 | @Test
64 | public void test_message_to_client_nonbinary_noack() throws Exception {
65 | final ServerWrapper serverWrapper = new ServerWrapper();
66 | serverWrapper.getSocketIoServer().namespace("/").on("connection", args -> {
67 | final SocketIoSocket socket = (SocketIoSocket) args[0];
68 | socket.send("foo", "bar");
69 | });
70 | try {
71 | serverWrapper.startServer();
72 | assertEquals(0, Utils.executeScriptForResult("src/test/resources/test_message_to_server_nonbinary_noack.js", serverWrapper.getPort()));
73 | } finally {
74 | serverWrapper.stopServer();
75 | }
76 | }
77 |
78 | @Test
79 | public void test_message_to_server_nonbinary_ack() throws Exception {
80 | final ServerWrapper serverWrapper = new ServerWrapper();
81 |
82 | final Emitter.Listener messageListener = Mockito.mock(Emitter.Listener.class);
83 | Mockito.doAnswer(invocationOnMock -> {
84 | final Object[] messageArgs = invocationOnMock.getArguments();
85 | assertEquals(3, messageArgs.length);
86 | assertEquals(1, messageArgs[0]);
87 | assertEquals("bar", messageArgs[1]);
88 | assertTrue(messageArgs[2] instanceof SocketIoSocket.ReceivedByLocalAcknowledgementCallback);
89 |
90 | ((SocketIoSocket.ReceivedByLocalAcknowledgementCallback) messageArgs[2]).sendAcknowledgement("baz");
91 | return null;
92 | }).when(messageListener).call(Mockito.any(Object[].class));
93 |
94 | serverWrapper.getSocketIoServer().namespace("/").on("connection", args -> {
95 | final SocketIoSocket socket = (SocketIoSocket) args[0];
96 | socket.on("foo", messageListener);
97 | });
98 | try {
99 | serverWrapper.startServer();
100 | assertEquals(0, Utils.executeScriptForResult("src/test/resources/test_message_to_server_nonbinary_ack.js", serverWrapper.getPort()));
101 | Mockito.verify(messageListener, Mockito.times(1)).call(Mockito.any(Object[].class));
102 | } finally {
103 | serverWrapper.stopServer();
104 | }
105 | }
106 |
107 | @Test
108 | public void test_message_to_client_nonbinary_ack() throws Exception {
109 | final ServerWrapper serverWrapper = new ServerWrapper();
110 |
111 | final SocketIoSocket.ReceivedByRemoteAcknowledgementCallback acknowledgementCallback = Mockito.mock(SocketIoSocket.ReceivedByRemoteAcknowledgementCallback.class);
112 | Mockito.doAnswer(invocationOnMock -> {
113 | final Object[] ackArgs = invocationOnMock.getArguments();
114 | assertEquals(1, ackArgs.length);
115 | assertEquals("baz", ackArgs[0]);
116 | return null;
117 | }).when(acknowledgementCallback).onReceivedByRemote(Mockito.any());
118 |
119 | serverWrapper.getSocketIoServer().namespace("/").on("connection", args -> {
120 | final SocketIoSocket socket = (SocketIoSocket) args[0];
121 | socket.send("foo", new Object[]{"bar"}, acknowledgementCallback);
122 | });
123 | try {
124 | serverWrapper.startServer();
125 | assertEquals(0, Utils.executeScriptForResult("src/test/resources/test_message_to_client_nonbinary_ack.js", serverWrapper.getPort()));
126 | Mockito.verify(acknowledgementCallback, Mockito.times(1)).onReceivedByRemote(Mockito.any());
127 | } finally {
128 | serverWrapper.stopServer();
129 | }
130 | }
131 |
132 | @Test
133 | public void test_message_to_server_binary_noack() throws Exception {
134 | final ServerWrapper serverWrapper = new ServerWrapper();
135 |
136 | final byte[] binaryValue = new byte[] {
137 | 0, 1, 2, 3, 4, 5, 6, 7
138 | };
139 |
140 | final Emitter.Listener messageListener = Mockito.mock(Emitter.Listener.class);
141 | Mockito.doAnswer(invocationOnMock -> {
142 | final Object[] messageArgs = invocationOnMock.getArguments();
143 | assertEquals(1, messageArgs.length);
144 | assertTrue(messageArgs[0] instanceof byte[]);
145 | assertArrayEquals(binaryValue, (byte[])messageArgs[0]);
146 | return null;
147 | }).when(messageListener).call(Mockito.any());
148 |
149 | serverWrapper.getSocketIoServer().namespace("/").on("connection", args -> {
150 | final SocketIoSocket socket = (SocketIoSocket) args[0];
151 | socket.on("foo", messageListener);
152 | });
153 | try {
154 | serverWrapper.startServer();
155 | assertEquals(0, Utils.executeScriptForResult("src/test/resources/test_message_to_server_binary_noack.js", serverWrapper.getPort()));
156 | Mockito.verify(messageListener, Mockito.times(1)).call(Mockito.any());
157 | } finally {
158 | serverWrapper.stopServer();
159 | }
160 | }
161 |
162 | @Test
163 | public void test_message_to_client_binary_noack() throws Exception {
164 | final ServerWrapper serverWrapper = new ServerWrapper();
165 |
166 | final byte[] binaryValue = new byte[] {
167 | 0, 1, 2, 3, 4, 5, 6, 7
168 | };
169 |
170 | serverWrapper.getSocketIoServer().namespace("/").on("connection", args -> {
171 | final SocketIoSocket socket = (SocketIoSocket) args[0];
172 | socket.send("foo", (Object)binaryValue);
173 | });
174 | try {
175 | serverWrapper.startServer();
176 | assertEquals(0, Utils.executeScriptForResult("src/test/resources/test_message_to_client_binary_noack.js", serverWrapper.getPort()));
177 | } finally {
178 | serverWrapper.stopServer();
179 | }
180 | }
181 |
182 | @Test
183 | public void test_broadcast_to_all_clients() throws Exception {
184 | final ServerWrapper serverWrapper = new ServerWrapper();
185 | final SocketIoNamespace namespace = serverWrapper.getSocketIoServer().namespace("/");
186 |
187 | namespace.on(
188 | "connection",
189 | args -> namespace.broadcast(null, "foo"));
190 | try {
191 | serverWrapper.startServer();
192 | assertEquals(0, Utils.executeScriptForResult("src/test/resources/test_broadcast_to_all_clients.js", serverWrapper.getPort()));
193 | } finally {
194 | serverWrapper.stopServer();
195 | }
196 | }
197 |
198 | @Test
199 | public void test_broadcast_to_one_room() throws Exception {
200 | final ServerWrapper serverWrapper = new ServerWrapper();
201 | final SocketIoNamespace namespace = serverWrapper.getSocketIoServer().namespace("/");
202 |
203 | namespace.on("connection", args -> {
204 | final SocketIoSocket socket = (SocketIoSocket) args[0];
205 | socket.on("join", args1 -> {
206 | socket.joinRoom("foo_room");
207 | namespace.broadcast("foo_room", "foo");
208 | });
209 | });
210 | try {
211 | serverWrapper.startServer();
212 | assertEquals(0, Utils.executeScriptForResult("src/test/resources/test_broadcast_to_one_room.js", serverWrapper.getPort()));
213 | } finally {
214 | serverWrapper.stopServer();
215 | }
216 | }
217 |
218 | @Test
219 | public void test_broadcast_to_multiple_rooms() throws Exception {
220 | final ServerWrapper serverWrapper = new ServerWrapper();
221 | final SocketIoNamespace namespace = serverWrapper.getSocketIoServer().namespace("/");
222 |
223 | namespace.on("connection", args -> {
224 | final SocketIoSocket socket = (SocketIoSocket) args[0];
225 | socket.on("join_foo", args1 -> {
226 | socket.joinRoom("foo_room");
227 |
228 | namespace.broadcast("foo_room", "foo");
229 | });
230 | socket.on("join_bar", args1 -> {
231 | socket.joinRoom("bar_room");
232 |
233 | namespace.broadcast("bar_room", "bar");
234 | });
235 | });
236 | try {
237 | serverWrapper.startServer();
238 | assertEquals(0, Utils.executeScriptForResult("src/test/resources/test_broadcast_to_multiple_rooms.js", serverWrapper.getPort()));
239 | } finally {
240 | serverWrapper.stopServer();
241 | }
242 | }
243 |
244 | @Test
245 | public void test_broadcast_to_all_clients_except_one() throws Exception {
246 | final ServerWrapper serverWrapper = new ServerWrapper();
247 | final SocketIoNamespace namespace = serverWrapper.getSocketIoServer().namespace("/");
248 |
249 | final ArrayList socketList = new ArrayList<>();
250 | namespace.on("connection", args -> {
251 | final SocketIoSocket socket = (SocketIoSocket) args[0];
252 | synchronized (socketList) {
253 | if (socketList.size() <= 0) {
254 | socketList.add(socket);
255 | }
256 | }
257 |
258 | socket.on("foo", args1 -> socketList.get(0).broadcast(null, "bar"));
259 | });
260 | try {
261 | serverWrapper.startServer();
262 | assertEquals(0, Utils.executeScriptForResult("src/test/resources/test_broadcast_to_all_clients_except_one.js", serverWrapper.getPort()));
263 | } finally {
264 | serverWrapper.stopServer();
265 | }
266 | }
267 | }
268 |
--------------------------------------------------------------------------------
/socket.io-server-test/src/test/java/io/socket/socketio/server/Utils.java:
--------------------------------------------------------------------------------
1 | package io.socket.socketio.server;
2 |
3 | import java.io.IOException;
4 |
5 | final class Utils {
6 |
7 | private Utils() {
8 | }
9 |
10 | static int executeScriptForResult(String script, int port) throws IOException {
11 | Process process = Runtime.getRuntime().exec("node " + script, new String[] {
12 | "PORT=" + port
13 | });
14 | try {
15 | int result = process.waitFor();
16 |
17 | /*InputStream inputStream = process.getInputStream();
18 | byte[] buffer = new byte[inputStream.available()];
19 | //noinspection ResultOfMethodCallIgnored
20 | inputStream.read(buffer);
21 | System.out.println("[script:stdout]\n" + (new String(buffer, StandardCharsets.UTF_8)));*/
22 |
23 | return result;
24 | } catch (InterruptedException ex) {
25 | throw new RuntimeException(ex);
26 | }
27 | }
28 | }
--------------------------------------------------------------------------------
/socket.io-server-test/src/test/resources/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "resources",
3 | "lockfileVersion": 2,
4 | "requires": true,
5 | "packages": {
6 | "": {
7 | "dependencies": {
8 | "get-stdin": "^6.0.0",
9 | "socket.io-client": "4.7.1"
10 | }
11 | },
12 | "node_modules/@socket.io/component-emitter": {
13 | "version": "3.1.0",
14 | "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz",
15 | "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg=="
16 | },
17 | "node_modules/debug": {
18 | "version": "4.3.4",
19 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
20 | "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
21 | "dependencies": {
22 | "ms": "2.1.2"
23 | },
24 | "engines": {
25 | "node": ">=6.0"
26 | },
27 | "peerDependenciesMeta": {
28 | "supports-color": {
29 | "optional": true
30 | }
31 | }
32 | },
33 | "node_modules/engine.io-client": {
34 | "version": "6.5.2",
35 | "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.5.2.tgz",
36 | "integrity": "sha512-CQZqbrpEYnrpGqC07a9dJDz4gePZUgTPMU3NKJPSeQOyw27Tst4Pl3FemKoFGAlHzgZmKjoRmiJvbWfhCXUlIg==",
37 | "dependencies": {
38 | "@socket.io/component-emitter": "~3.1.0",
39 | "debug": "~4.3.1",
40 | "engine.io-parser": "~5.2.1",
41 | "ws": "~8.11.0",
42 | "xmlhttprequest-ssl": "~2.0.0"
43 | }
44 | },
45 | "node_modules/engine.io-parser": {
46 | "version": "5.2.1",
47 | "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.1.tgz",
48 | "integrity": "sha512-9JktcM3u18nU9N2Lz3bWeBgxVgOKpw7yhRaoxQA3FUDZzzw+9WlA6p4G4u0RixNkg14fH7EfEc/RhpurtiROTQ==",
49 | "engines": {
50 | "node": ">=10.0.0"
51 | }
52 | },
53 | "node_modules/get-stdin": {
54 | "version": "6.0.0",
55 | "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz",
56 | "integrity": "sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==",
57 | "engines": {
58 | "node": ">=4"
59 | }
60 | },
61 | "node_modules/ms": {
62 | "version": "2.1.2",
63 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
64 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
65 | },
66 | "node_modules/socket.io-client": {
67 | "version": "4.7.1",
68 | "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.7.1.tgz",
69 | "integrity": "sha512-Qk3Xj8ekbnzKu3faejo4wk2MzXA029XppiXtTF/PkbTg+fcwaTw1PlDrTrrrU4mKoYC4dvlApOnSeyLCKwek2w==",
70 | "dependencies": {
71 | "@socket.io/component-emitter": "~3.1.0",
72 | "debug": "~4.3.2",
73 | "engine.io-client": "~6.5.1",
74 | "socket.io-parser": "~4.2.4"
75 | },
76 | "engines": {
77 | "node": ">=10.0.0"
78 | }
79 | },
80 | "node_modules/socket.io-parser": {
81 | "version": "4.2.4",
82 | "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz",
83 | "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==",
84 | "dependencies": {
85 | "@socket.io/component-emitter": "~3.1.0",
86 | "debug": "~4.3.1"
87 | },
88 | "engines": {
89 | "node": ">=10.0.0"
90 | }
91 | },
92 | "node_modules/ws": {
93 | "version": "8.11.0",
94 | "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz",
95 | "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==",
96 | "engines": {
97 | "node": ">=10.0.0"
98 | },
99 | "peerDependencies": {
100 | "bufferutil": "^4.0.1",
101 | "utf-8-validate": "^5.0.2"
102 | },
103 | "peerDependenciesMeta": {
104 | "bufferutil": {
105 | "optional": true
106 | },
107 | "utf-8-validate": {
108 | "optional": true
109 | }
110 | }
111 | },
112 | "node_modules/xmlhttprequest-ssl": {
113 | "version": "2.0.0",
114 | "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz",
115 | "integrity": "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==",
116 | "engines": {
117 | "node": ">=0.4.0"
118 | }
119 | }
120 | },
121 | "dependencies": {
122 | "@socket.io/component-emitter": {
123 | "version": "3.1.0",
124 | "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz",
125 | "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg=="
126 | },
127 | "debug": {
128 | "version": "4.3.4",
129 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
130 | "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
131 | "requires": {
132 | "ms": "2.1.2"
133 | }
134 | },
135 | "engine.io-client": {
136 | "version": "6.5.2",
137 | "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.5.2.tgz",
138 | "integrity": "sha512-CQZqbrpEYnrpGqC07a9dJDz4gePZUgTPMU3NKJPSeQOyw27Tst4Pl3FemKoFGAlHzgZmKjoRmiJvbWfhCXUlIg==",
139 | "requires": {
140 | "@socket.io/component-emitter": "~3.1.0",
141 | "debug": "~4.3.1",
142 | "engine.io-parser": "~5.2.1",
143 | "ws": "~8.11.0",
144 | "xmlhttprequest-ssl": "~2.0.0"
145 | }
146 | },
147 | "engine.io-parser": {
148 | "version": "5.2.1",
149 | "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.1.tgz",
150 | "integrity": "sha512-9JktcM3u18nU9N2Lz3bWeBgxVgOKpw7yhRaoxQA3FUDZzzw+9WlA6p4G4u0RixNkg14fH7EfEc/RhpurtiROTQ=="
151 | },
152 | "get-stdin": {
153 | "version": "6.0.0",
154 | "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz",
155 | "integrity": "sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g=="
156 | },
157 | "ms": {
158 | "version": "2.1.2",
159 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
160 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
161 | },
162 | "socket.io-client": {
163 | "version": "4.7.1",
164 | "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.7.1.tgz",
165 | "integrity": "sha512-Qk3Xj8ekbnzKu3faejo4wk2MzXA029XppiXtTF/PkbTg+fcwaTw1PlDrTrrrU4mKoYC4dvlApOnSeyLCKwek2w==",
166 | "requires": {
167 | "@socket.io/component-emitter": "~3.1.0",
168 | "debug": "~4.3.2",
169 | "engine.io-client": "~6.5.1",
170 | "socket.io-parser": "~4.2.4"
171 | }
172 | },
173 | "socket.io-parser": {
174 | "version": "4.2.4",
175 | "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz",
176 | "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==",
177 | "requires": {
178 | "@socket.io/component-emitter": "~3.1.0",
179 | "debug": "~4.3.1"
180 | }
181 | },
182 | "ws": {
183 | "version": "8.11.0",
184 | "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz",
185 | "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==",
186 | "requires": {}
187 | },
188 | "xmlhttprequest-ssl": {
189 | "version": "2.0.0",
190 | "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz",
191 | "integrity": "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A=="
192 | }
193 | }
194 | }
195 |
--------------------------------------------------------------------------------
/socket.io-server-test/src/test/resources/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "dependencies": {
4 | "get-stdin": "^6.0.0",
5 | "socket.io-client": "4.7.1"
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/socket.io-server-test/src/test/resources/test_broadcast_to_all_clients.js:
--------------------------------------------------------------------------------
1 | var io = require('socket.io-client');
2 | var port = process.env.PORT || 3000;
3 |
4 | var fooReceived = [false, false];
5 | function testReceived() {
6 | if (fooReceived[0] && fooReceived[1]) {
7 | process.exit(0);
8 | }
9 | }
10 |
11 | var socket1 = io('http://127.0.0.1:' + port, {
12 | autoConnect: false,
13 | transports: ['websocket']
14 | });
15 | socket1.on('foo', function () {
16 | fooReceived[0] = true;
17 | testReceived();
18 | });
19 |
20 | var socket2 = io('http://127.0.0.1:' + port, {
21 | autoConnect: false,
22 | transports: ['websocket']
23 | });
24 | socket2.on('foo', function () {
25 | fooReceived[1] = true;
26 | testReceived();
27 | });
28 |
29 | socket1.connect();
30 | socket2.connect();
31 |
32 | setTimeout(function () {
33 | process.exit(1);
34 | }, 2000);
--------------------------------------------------------------------------------
/socket.io-server-test/src/test/resources/test_broadcast_to_all_clients_except_one.js:
--------------------------------------------------------------------------------
1 | var io = require('socket.io-client');
2 | var port = process.env.PORT || 3000;
3 |
4 | var barReceived = [false, false];
5 |
6 | var socket1 = io('http://127.0.0.1:' + port, {
7 | autoConnect: false,
8 | forceNew: true,
9 | transports: ['websocket']
10 | });
11 | socket1.on('connect', function () {
12 | socket1.emit('foo');
13 | });
14 | socket1.on('bar', function () {
15 | barReceived[0] = true;
16 | });
17 |
18 | var socket2 = io('http://127.0.0.1:' + port, {
19 | autoConnect: false,
20 | forceNew: true,
21 | transports: ['websocket']
22 | });
23 | socket2.on('connect', function () {
24 | socket2.emit('foo');
25 | });
26 | socket2.on('bar', function () {
27 | barReceived[1] = true;
28 | });
29 |
30 | socket1.connect();
31 | socket2.connect();
32 |
33 | setTimeout(function () {
34 | console.log(JSON.stringify(barReceived));
35 |
36 | if (barReceived[0] !== barReceived[1]) {
37 | process.exit(0);
38 | } else {
39 | process.exit(1);
40 | }
41 | }, 2000);
--------------------------------------------------------------------------------
/socket.io-server-test/src/test/resources/test_broadcast_to_multiple_rooms.js:
--------------------------------------------------------------------------------
1 | var io = require('socket.io-client');
2 | var port = process.env.PORT || 3000;
3 |
4 | var fooReceived = [false, false, false];
5 | var barReceived = [false, false, false];
6 |
7 | var socket1 = io('http://127.0.0.1:' + port, {
8 | autoConnect: false,
9 | transports: ['websocket']
10 | });
11 | socket1.on('connect', function() {
12 | socket1.emit('join_foo');
13 | socket1.emit('join_bar');
14 | });
15 | socket1.on('foo', function () {
16 | fooReceived[0] = true;
17 | });
18 | socket1.on('bar', function () {
19 | barReceived[0] = true;
20 | });
21 |
22 | var socket2 = io('http://127.0.0.1:' + port, {
23 | autoConnect: false,
24 | transports: ['websocket']
25 | });
26 | socket2.on('connect', function() {
27 | socket2.emit('join_foo');
28 | });
29 | socket2.on('foo', function () {
30 | fooReceived[1] = true;
31 | });
32 | socket2.on('bar', function () {
33 | barReceived[1] = true;
34 | });
35 |
36 | var socket3 = io('http://127.0.0.1:' + port, {
37 | autoConnect: false,
38 | transports: ['websocket']
39 | });
40 | socket3.on('connect', function() {
41 | socket3.emit('join_bar');
42 | });
43 | socket3.on('foo', function () {
44 | fooReceived[2] = true;
45 | });
46 | socket3.on('bar', function () {
47 | barReceived[2] = true;
48 | });
49 |
50 | socket1.connect();
51 | socket2.connect();
52 | socket3.connect();
53 |
54 | setTimeout(function () {
55 | if (fooReceived[0] && fooReceived[1] && !fooReceived[2] &&
56 | barReceived[0] && !barReceived[1] && barReceived[2]) {
57 | process.exit(0);
58 | } else {
59 | process.exit(1);
60 | }
61 | }, 5000);
--------------------------------------------------------------------------------
/socket.io-server-test/src/test/resources/test_broadcast_to_one_room.js:
--------------------------------------------------------------------------------
1 | var io = require('socket.io-client');
2 | var port = process.env.PORT || 3000;
3 |
4 | var fooReceived = [false, false, false];
5 |
6 | var socket1 = io('http://127.0.0.1:' + port, {
7 | autoConnect: false,
8 | transports: ['websocket']
9 | });
10 | socket1.on('connect', function() {
11 | socket1.emit('join');
12 | });
13 | socket1.on('foo', function () {
14 | fooReceived[0] = true;
15 | });
16 |
17 | var socket2 = io('http://127.0.0.1:' + port, {
18 | autoConnect: false,
19 | transports: ['websocket']
20 | });
21 | socket2.on('connect', function() {
22 | socket2.emit('join');
23 | });
24 | socket2.on('foo', function () {
25 | fooReceived[1] = true;
26 | });
27 |
28 | var socket3 = io('http://127.0.0.1:' + port, {
29 | autoConnect: false,
30 | transports: ['websocket']
31 | });
32 | socket3.on('foo', function () {
33 | fooReceived[2] = true;
34 | });
35 |
36 | socket1.connect();
37 | socket2.connect();
38 | socket3.connect();
39 |
40 | setTimeout(function () {
41 | if (fooReceived[0] && fooReceived[1] && !fooReceived[2]) {
42 | process.exit(0);
43 | } else {
44 | process.exit(1);
45 | }
46 | }, 2000);
--------------------------------------------------------------------------------
/socket.io-server-test/src/test/resources/test_connect.js:
--------------------------------------------------------------------------------
1 | var io = require('socket.io-client');
2 | var port = process.env.PORT || 3000;
3 |
4 | var socket = io('http://127.0.0.1:' + port, {
5 | autoConnect: false,
6 | transports: ['websocket']
7 | });
8 | socket.on('connect', function () {
9 | process.exit(0);
10 | });
11 | socket.connect();
12 |
13 | setTimeout(function () {
14 | process.exit(1);
15 | }, 2000);
16 |
--------------------------------------------------------------------------------
/socket.io-server-test/src/test/resources/test_connect_dynamic.js:
--------------------------------------------------------------------------------
1 | var io = require('socket.io-client');
2 | var port = process.env.PORT || 3000;
3 |
4 | var fooConnections = {
5 | 0: false,
6 | 'a': false,
7 | 1: false
8 | };
9 | var barConnection = false;
10 |
11 | var socket1 = io('http://127.0.0.1:' + port + '/foo0', {
12 | autoConnect: false,
13 | transports: ['websocket']
14 | });
15 | socket1.on('connect', function () {
16 | fooConnections[0] = true;
17 | });
18 | socket1.connect();
19 |
20 | var socket2 = io('http://127.0.0.1:' + port + '/fooa', {
21 | autoConnect: false,
22 | transports: ['websocket']
23 | });
24 | socket2.on('connect', function () {
25 | fooConnections['a'] = true;
26 | });
27 | socket2.connect();
28 |
29 | var socket3 = io('http://127.0.0.1:' + port + '/foo1', {
30 | autoConnect: false,
31 | transports: ['websocket']
32 | });
33 | socket3.on('connect', function () {
34 | fooConnections[1] = true;
35 | });
36 | socket3.connect();
37 |
38 | var socket4 = io('http://127.0.0.1:' + port + '/bar', {
39 | autoConnect: false,
40 | transports: ['websocket']
41 | });
42 | socket4.on('connect', function () {
43 | barConnection = true;
44 | });
45 | socket4.connect();
46 |
47 | setTimeout(function () {
48 | if (fooConnections[0] && fooConnections[1] && !fooConnections['a'] && !barConnection) {
49 | process.exit(0);
50 | } else {
51 | process.exit(1);
52 | }
53 | }, 2000);
54 |
--------------------------------------------------------------------------------
/socket.io-server-test/src/test/resources/test_message_to_client_binary_noack.js:
--------------------------------------------------------------------------------
1 | var io = require('socket.io-client');
2 | var port = process.env.PORT || 3000;
3 |
4 | var binaryData = new ArrayBuffer(8);
5 | var view = new Uint8Array(binaryData);
6 | view[0] = 0;
7 | view[1] = 1;
8 | view[2] = 2;
9 | view[3] = 3;
10 | view[4] = 4;
11 | view[5] = 5;
12 | view[6] = 6;
13 | view[7] = 7;
14 |
15 | var socket = io('http://127.0.0.1:' + port, {
16 | autoConnect: false,
17 | transports: ['websocket']
18 | });
19 | socket.on('foo', function (data) {
20 | if (data && data.length === 8) {
21 | process.exit(0);
22 | }
23 | });
24 | socket.connect();
25 |
26 | setTimeout(function () {
27 | process.exit(1);
28 | }, 2000);
--------------------------------------------------------------------------------
/socket.io-server-test/src/test/resources/test_message_to_client_nonbinary_ack.js:
--------------------------------------------------------------------------------
1 | var io = require('socket.io-client');
2 | var port = process.env.PORT || 3000;
3 |
4 | var socket = io('http://127.0.0.1:' + port, {
5 | autoConnect: false,
6 | transports: ['websocket']
7 | });
8 | socket.on('foo', function (bar, callback) {
9 | if (bar === 'bar') {
10 | callback('baz');
11 | process.exit(0);
12 | }
13 | });
14 | socket.connect();
15 |
16 | setTimeout(function () {
17 | process.exit(1);
18 | }, 2000);
--------------------------------------------------------------------------------
/socket.io-server-test/src/test/resources/test_message_to_client_nonbinary_noack.js:
--------------------------------------------------------------------------------
1 | var io = require('socket.io-client');
2 | var port = process.env.PORT || 3000;
3 |
4 | var socket = io('http://127.0.0.1:' + port, {
5 | autoConnect: false,
6 | transports: ['websocket']
7 | });
8 | socket.on('foo', function (bar) {
9 | if (bar === 'bar') {
10 | process.exit(0);
11 | }
12 | });
13 | socket.connect();
14 |
15 | setTimeout(function () {
16 | process.exit(1);
17 | }, 2000);
--------------------------------------------------------------------------------
/socket.io-server-test/src/test/resources/test_message_to_server_binary_noack.js:
--------------------------------------------------------------------------------
1 | var io = require('socket.io-client');
2 | var port = process.env.PORT || 3000;
3 |
4 | var binaryData = new ArrayBuffer(8);
5 | var view = new Uint8Array(binaryData);
6 | view[0] = 0;
7 | view[1] = 1;
8 | view[2] = 2;
9 | view[3] = 3;
10 | view[4] = 4;
11 | view[5] = 5;
12 | view[6] = 6;
13 | view[7] = 7;
14 |
15 | var socket = io('http://127.0.0.1:' + port, {
16 | autoConnect: false,
17 | transports: ['websocket']
18 | });
19 | socket.on('connect', function () {
20 | socket.emit('foo', binaryData);
21 |
22 | // This is necessary because engine.io defers some writes
23 | setTimeout(function () {
24 | process.exit(0);
25 | }, 100);
26 | });
27 | socket.connect();
28 |
29 | setTimeout(function () {
30 | process.exit(1);
31 | }, 2000);
--------------------------------------------------------------------------------
/socket.io-server-test/src/test/resources/test_message_to_server_nonbinary_ack.js:
--------------------------------------------------------------------------------
1 | var io = require('socket.io-client');
2 | var port = process.env.PORT || 3000;
3 |
4 | var socket = io('http://127.0.0.1:' + port, {
5 | autoConnect: false,
6 | transports: ['websocket']
7 | });
8 | socket.on('connect', function () {
9 | socket.emit('foo', 1, 'bar', function(baz) {
10 | // Ack received
11 | if (baz === 'baz') {
12 | process.exit(0);
13 | }
14 | });
15 | });
16 | socket.connect();
17 |
18 | setTimeout(function () {
19 | process.exit(1);
20 | }, 2000);
--------------------------------------------------------------------------------
/socket.io-server-test/src/test/resources/test_message_to_server_nonbinary_noack.js:
--------------------------------------------------------------------------------
1 | var io = require('socket.io-client');
2 | var port = process.env.PORT || 3000;
3 |
4 | var socket = io('http://127.0.0.1:' + port, {
5 | autoConnect: false,
6 | transports: ['websocket']
7 | });
8 | socket.on('connect', function () {
9 | socket.emit('foo', 1, 'bar');
10 |
11 | setTimeout(function () {
12 | process.exit(0);
13 | }, 100);
14 | });
15 | socket.connect();
16 |
17 | setTimeout(function () {
18 | process.exit(1);
19 | }, 2000);
--------------------------------------------------------------------------------
/socket.io-server/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | socket.io-server-bom
7 | io.socket
8 | 4.1.2
9 |
10 | 4.0.0
11 |
12 | socket.io-server
13 | jar
14 | socket.io-server
15 | Socket.IO server library for Java
16 |
17 |
18 |
19 | io.socket
20 | engine.io-server
21 | 6.3.2
22 |
23 |
24 | org.json
25 | json
26 | 20230618
27 |
28 |
29 |
30 | jakarta.platform
31 | jakarta.jakartaee-api
32 | 10.0.0
33 | provided
34 |
35 |
36 |
37 |
38 | org.junit.platform
39 | junit-platform-launcher
40 | 1.6.3
41 | test
42 |
43 |
44 | org.junit.jupiter
45 | junit-jupiter-engine
46 | 5.6.3
47 | test
48 |
49 |
50 | org.junit.vintage
51 | junit-vintage-engine
52 | 5.6.3
53 | test
54 |
55 |
56 | org.mockito
57 | mockito-core
58 | 5.4.0
59 | test
60 |
61 |
62 |
63 |
64 |
65 |
66 | org.apache.maven.plugins
67 | maven-compiler-plugin
68 | 3.11.0
69 |
70 | 1.8
71 | 1.8
72 | UTF-8
73 |
74 | -Xlint:unchecked
75 |
76 | true
77 | true
78 |
79 |
80 |
81 | org.apache.maven.plugins
82 | maven-source-plugin
83 | 3.3.0
84 |
85 |
86 | attach-sources
87 |
88 | jar-no-fork
89 |
90 |
91 |
92 |
93 |
94 | org.apache.maven.plugins
95 | maven-javadoc-plugin
96 | 3.5.0
97 |
98 |
99 | attach-javadocs
100 |
101 | jar
102 |
103 |
104 |
105 |
106 |
107 | org.apache.maven.plugins
108 | maven-jar-plugin
109 | 3.3.0
110 |
111 |
112 |
113 | org.apache.maven.plugins
114 | maven-surefire-plugin
115 | 3.1.2
116 |
117 | -Dfile.encoding=UTF-8
118 |
119 |
120 | java.util.logging.config.file
121 | ./src/test/resources/logging.properties
122 |
123 |
124 | both
125 | true
126 |
127 |
128 |
129 |
130 |
131 |
--------------------------------------------------------------------------------
/socket.io-server/pom.xml.versionsBackup:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | socket.io-server-bom
7 | io.socket
8 | 4.1.1
9 |
10 | 4.0.0
11 |
12 | socket.io-server
13 | jar
14 | socket.io-server
15 | Socket.IO server library for Java
16 |
17 |
18 |
19 | io.socket
20 | engine.io-server
21 | 6.3.2
22 |
23 |
24 | org.json
25 | json
26 | 20230618
27 |
28 |
29 |
30 | jakarta.platform
31 | jakarta.jakartaee-api
32 | 10.0.0
33 | provided
34 |
35 |
36 |
37 |
38 | org.junit.platform
39 | junit-platform-launcher
40 | 1.6.3
41 | test
42 |
43 |
44 | org.junit.jupiter
45 | junit-jupiter-engine
46 | 5.6.3
47 | test
48 |
49 |
50 | org.junit.vintage
51 | junit-vintage-engine
52 | 5.6.3
53 | test
54 |
55 |
56 | org.mockito
57 | mockito-core
58 | 5.4.0
59 | test
60 |
61 |
62 |
63 |
64 |
65 |
66 | org.apache.maven.plugins
67 | maven-compiler-plugin
68 | 3.11.0
69 |
70 | 1.8
71 | 1.8
72 | UTF-8
73 |
74 | -Xlint:unchecked
75 |
76 | true
77 | true
78 |
79 |
80 |
81 | org.apache.maven.plugins
82 | maven-source-plugin
83 | 3.3.0
84 |
85 |
86 | attach-sources
87 |
88 | jar-no-fork
89 |
90 |
91 |
92 |
93 |
94 | org.apache.maven.plugins
95 | maven-javadoc-plugin
96 | 3.5.0
97 |
98 |
99 | attach-javadocs
100 |
101 | jar
102 |
103 |
104 |
105 |
106 |
107 | org.apache.maven.plugins
108 | maven-jar-plugin
109 | 3.3.0
110 |
111 |
112 |
113 | org.apache.maven.plugins
114 | maven-surefire-plugin
115 | 3.1.2
116 |
117 | -Dfile.encoding=UTF-8
118 |
119 |
120 | java.util.logging.config.file
121 | ./src/test/resources/logging.properties
122 |
123 |
124 | both
125 | true
126 |
127 |
128 |
129 |
130 |
131 |
--------------------------------------------------------------------------------
/socket.io-server/src/main/java/io/socket/socketio/server/PacketUtils.java:
--------------------------------------------------------------------------------
1 | package io.socket.socketio.server;
2 |
3 | import io.socket.socketio.server.parser.Packet;
4 | import org.json.JSONArray;
5 | import org.json.JSONException;
6 | import org.json.JSONObject;
7 |
8 | import java.util.Iterator;
9 |
10 | @SuppressWarnings({"BooleanMethodIsAlwaysInverted"})
11 | final class PacketUtils {
12 |
13 | private static final Object[] EMPTY_ARGS = new Object[0];
14 |
15 | /**
16 | * Validate args and create packet.
17 | *
18 | * @param type Type of packet to create.
19 | * @param event Name of event.
20 | * @param args Data to set.
21 | * @return Created packet.
22 | * @throws IllegalArgumentException If args contain any invalid data type.
23 | */
24 | @SuppressWarnings("SameParameterValue")
25 | static Packet> createDataPacket(int type, String event, Object[] args) throws IllegalArgumentException {
26 | if (args == null) {
27 | args = EMPTY_ARGS;
28 | }
29 |
30 | final JSONArray array = new JSONArray();
31 | if (event != null) {
32 | array.put(event);
33 | }
34 | for (Object arg : args) {
35 | array.put(arg);
36 | }
37 | if (!PacketUtils.isPacketDataValid(array)) {
38 | throw new IllegalArgumentException("args contain invalid data type.");
39 | }
40 |
41 | final Packet packet = new Packet<>();
42 | packet.type = type;
43 | packet.data = array;
44 | return packet;
45 | }
46 |
47 | @SuppressWarnings("Duplicates")
48 | private static boolean isPacketDataValid(JSONArray array) {
49 | try {
50 | for (int idx = 0; idx < array.length(); idx++) {
51 | final Object item = array.get(idx);
52 |
53 | if (!isPacketDataValidType(item)) {
54 | return false;
55 | }
56 | if (item == null) {
57 | array.put(idx, JSONObject.NULL);
58 | }
59 | if ((item instanceof JSONArray) && !isPacketDataValid((JSONArray)item)) {
60 | return false;
61 | }
62 | if ((item instanceof JSONObject) && !isPacketDataValid((JSONObject)item)) {
63 | return false;
64 | }
65 | }
66 |
67 | return true;
68 | } catch (JSONException ignore) {
69 | }
70 | return false;
71 | }
72 |
73 | @SuppressWarnings("Duplicates")
74 | private static boolean isPacketDataValid(JSONObject object) {
75 | try {
76 | final Iterator> keys = object.keys();
77 | while (keys.hasNext()) {
78 | final Object keyObj = keys.next();
79 | if (!(keyObj instanceof String)) {
80 | return false;
81 | }
82 |
83 | final String key = (String)keyObj;
84 | final Object item = object.get(key);
85 |
86 | if (!isPacketDataValidType(item)) {
87 | return false;
88 | }
89 | if (item == null) {
90 | object.put(key, JSONObject.NULL);
91 | }
92 | if ((item instanceof JSONArray) && !isPacketDataValid((JSONArray)item)) {
93 | return false;
94 | }
95 | if ((item instanceof JSONObject) && !isPacketDataValid((JSONObject)item)) {
96 | return false;
97 | }
98 | }
99 |
100 | return true;
101 | } catch (JSONException ignore) {
102 | }
103 | return false;
104 | }
105 |
106 | private static boolean isPacketDataValidType(Object object) {
107 | return ((object == null) ||
108 | (object == JSONObject.NULL) ||
109 | (object instanceof JSONObject) ||
110 | (object instanceof JSONArray) ||
111 | (object instanceof CharSequence) ||
112 | (object instanceof Number) ||
113 | (object instanceof Boolean) ||
114 | (object instanceof byte[]));
115 | }
116 | }
--------------------------------------------------------------------------------
/socket.io-server/src/main/java/io/socket/socketio/server/SocketIoAdapter.java:
--------------------------------------------------------------------------------
1 | package io.socket.socketio.server;
2 |
3 | import io.socket.engineio.server.Emitter;
4 | import io.socket.socketio.server.parser.Packet;
5 |
6 | import java.util.HashSet;
7 | import java.util.Map;
8 | import java.util.Set;
9 | import java.util.concurrent.ConcurrentHashMap;
10 |
11 | /**
12 | * Socket.io adapter class for broadcasts.
13 | */
14 | @SuppressWarnings("WeakerAccess")
15 | public abstract class SocketIoAdapter extends Emitter {
16 |
17 | /**
18 | * Factory to create new instance of adapter.
19 | */
20 | public interface AdapterFactory {
21 |
22 | /**
23 | * Create and return a new instance of adapter for a namespace.
24 | *
25 | * @param namespace The namespace to create adapter for.
26 | * @return Adapter instance for namespace.
27 | */
28 | SocketIoAdapter createAdapter(SocketIoNamespace namespace);
29 | }
30 |
31 | /**
32 | * The namespace that this adapter serves.
33 | */
34 | protected final SocketIoNamespace mNamespace;
35 |
36 | /**
37 | * Set of sockets contained within a room.
38 | */
39 | protected final Map> mRoomSockets = new ConcurrentHashMap<>();
40 |
41 | /**
42 | * Set of rooms joined by a socket.
43 | */
44 | protected final Map> mSocketRooms = new ConcurrentHashMap<>();
45 |
46 | protected SocketIoAdapter(SocketIoNamespace namespace) {
47 | mNamespace = namespace;
48 | }
49 |
50 | /**
51 | * Broadcast a packet to all sockets or sockets that have joined
52 | * specified rooms.
53 | *
54 | * @param packet Packet to broadcast.
55 | * @param rooms List of rooms to restrict packet to or null to send to all rooms.
56 | * @throws IllegalArgumentException If packet is null.
57 | */
58 | public void broadcast(Packet> packet, String[] rooms) throws IllegalArgumentException {
59 | broadcast(packet, rooms, null);
60 | }
61 |
62 | /**
63 | * Broadcast a packet to all sockets or sockets that have joined
64 | * specified rooms. Optionally, specify sockets to exclude from sending.
65 | *
66 | * @param packet Packet to broadcast.
67 | * @param rooms List of rooms to restrict packet to or null to send to all rooms.
68 | * @param socketsExcluded List of sockets to exclude from sending or null.
69 | * @throws IllegalArgumentException If packet is null.
70 | */
71 | public abstract void broadcast(Packet> packet, String[] rooms, String[] socketsExcluded) throws IllegalArgumentException;
72 |
73 | /**
74 | * Add a socket to the specified room.
75 | *
76 | * @param room Room name to add socket to.
77 | * @param socket Socket to add to room.
78 | * @throws IllegalArgumentException If room or socket is null.
79 | */
80 | public abstract void add(String room, SocketIoSocket socket) throws IllegalArgumentException;
81 |
82 | /**
83 | * Remove a socket from the specified room.
84 | *
85 | * @param room Room name to remove socket from.
86 | * @param socket Socket to remove from room.
87 | * @throws IllegalArgumentException If room or socket is null.
88 | */
89 | public abstract void remove(String room, SocketIoSocket socket) throws IllegalArgumentException;
90 |
91 | /**
92 | * Get list of sockets in specified room.
93 | *
94 | * @param room Room name to list sockets in.
95 | * @return List of sockets or empty list.
96 | * @throws IllegalArgumentException If room is null.
97 | */
98 | public abstract SocketIoSocket[] listClients(String room) throws IllegalArgumentException;
99 |
100 | /**
101 | * Get list of rooms joined by socket.
102 | *
103 | * @param socket Socket to list rooms joined.
104 | * @return List of rooms or empty list.
105 | * @throws IllegalArgumentException If socket is null.
106 | */
107 | public abstract String[] listClientRooms(SocketIoSocket socket) throws IllegalArgumentException;
108 | }
--------------------------------------------------------------------------------
/socket.io-server/src/main/java/io/socket/socketio/server/SocketIoClient.java:
--------------------------------------------------------------------------------
1 | package io.socket.socketio.server;
2 |
3 | import io.socket.engineio.server.EngineIoSocket;
4 | import io.socket.engineio.server.ReadyState;
5 | import io.socket.socketio.server.parser.IOParser;
6 | import io.socket.socketio.server.parser.Packet;
7 | import io.socket.socketio.server.parser.Parser;
8 | import org.json.JSONException;
9 | import org.json.JSONObject;
10 |
11 | import java.util.List;
12 | import java.util.Map;
13 | import java.util.concurrent.ConcurrentHashMap;
14 | import java.util.concurrent.TimeUnit;
15 |
16 | /**
17 | * Represents connection to one client.
18 | * Be careful if interacting with this class directly, it might leave the connection in an invalid state.
19 | */
20 | public final class SocketIoClient {
21 |
22 | private final SocketIoServer mServer;
23 | private final EngineIoSocket mConnection;
24 | private final Parser.Encoder mEncoder;
25 | private final Parser.Decoder mDecoder;
26 | private final String mId;
27 |
28 | private final Map mSockets = new ConcurrentHashMap<>();
29 | private final Map mNamespaceSockets = new ConcurrentHashMap<>();
30 |
31 | SocketIoClient(SocketIoServer server, EngineIoSocket connection) {
32 | mServer = server;
33 | mConnection = connection;
34 | mEncoder = server.getEncoder();
35 | mDecoder = new IOParser.Decoder();
36 | mId = connection.getId();
37 |
38 | setup();
39 | }
40 |
41 | /**
42 | * Get id of this client.
43 | */
44 | public String getId() {
45 | return mId;
46 | }
47 |
48 | /**
49 | * Get the query parameters of underlying engine.io connection.
50 | */
51 | public Map getInitialQuery() {
52 | return mConnection.getInitialQuery();
53 | }
54 |
55 | /**
56 | * Get the headers of the underlying engine.io connection.
57 | */
58 | public Map> getInitialHeaders() {
59 | return mConnection.getInitialHeaders();
60 | }
61 |
62 | /**
63 | * Sends a packet over the transport.
64 | *
65 | * @param packet Packet to send.
66 | */
67 | public void sendPacket(final Packet> packet) {
68 | if (mConnection.getReadyState() == ReadyState.OPEN) {
69 | mEncoder.encode(packet, objects -> {
70 | // TODO: Check for volatile flag
71 |
72 | for (Object item : objects) {
73 | final io.socket.engineio.server.parser.Packet engineIoPacket = new io.socket.engineio.server.parser.Packet<>(io.socket.engineio.server.parser.Packet.MESSAGE);
74 | engineIoPacket.data = item;
75 | mConnection.send(engineIoPacket);
76 | }
77 | });
78 | }
79 | }
80 |
81 | /**
82 | * Connects client to namespace.
83 | *
84 | * @param namespace Namespace to connect to.
85 | */
86 | public void connect(String namespace, Object data) {
87 | if (mServer.hasNamespace(namespace) || mServer.checkNamespace(namespace)) {
88 | doConnect(namespace, data);
89 | } else {
90 | final JSONObject errorData = new JSONObject();
91 | try {
92 | errorData.put("message", "Invalid namespace");
93 | } catch (JSONException ignore) {
94 | }
95 |
96 | final Packet packet = new Packet<>(Parser.CONNECT_ERROR);
97 | packet.nsp = namespace;
98 | packet.data = errorData;
99 |
100 | sendPacket(packet);
101 | }
102 | }
103 |
104 | /**
105 | * Removes a socket.
106 | *
107 | * @param socket Socket to remove.
108 | */
109 | public void remove(SocketIoSocket socket) {
110 | if (mSockets.containsValue(socket)) {
111 | final SocketIoNamespace namespace = socket.getNamespace();
112 | mSockets.remove(socket.getId());
113 | mNamespaceSockets.remove(namespace.getName());
114 | }
115 | }
116 |
117 | /**
118 | * Disconnect from all namespaces and close transport.
119 | */
120 | public void disconnect() {
121 | for (SocketIoSocket socket : mSockets.values()) {
122 | socket.disconnect(false);
123 | }
124 |
125 | mSockets.clear();
126 | close();
127 | }
128 |
129 | /**
130 | * Get the underlying engine.io connection.
131 | * @return Engine.IO connection object.
132 | */
133 | public EngineIoSocket getConnection() {
134 | return mConnection;
135 | }
136 |
137 | /**
138 | * Close the connection.
139 | */
140 | private void close() {
141 | if (mConnection.getReadyState() == ReadyState.OPEN) {
142 | mConnection.close();
143 | onClose("forced server close");
144 | }
145 | }
146 |
147 | private void setup() {
148 | mDecoder.onDecoded(packet -> {
149 | if (packet.type == IOParser.CONNECT) {
150 | if (mConnection.getProtocolVersion() == 3) {
151 | String namespace = packet.nsp;
152 | String queryString = null;
153 | if (namespace.contains("?")) {
154 | queryString = namespace.substring(namespace.indexOf('?') + 1);
155 | namespace = namespace.substring(0, namespace.indexOf('?'));
156 | }
157 | connect(namespace, queryString);
158 | } else {
159 | connect(packet.nsp, packet.data);
160 | }
161 | } else {
162 | final SocketIoSocket socket = mNamespaceSockets.get(packet.nsp);
163 | if (socket != null) {
164 | socket.onPacket(packet);
165 | }
166 | }
167 | });
168 | mConnection.on("data", args -> {
169 | try {
170 | final Object data = args[0];
171 | if (data instanceof String) {
172 | mDecoder.add((String) data);
173 | } else if(data instanceof byte[]) {
174 | mDecoder.add((byte[]) data);
175 | }
176 | } catch (Exception ex) {
177 | onError(ex.getMessage());
178 | }
179 | });
180 | mConnection.on("error", args -> onError((String) args[0]));
181 | mConnection.on("close", args -> onClose((String) args[0]));
182 |
183 | mServer.getScheduledExecutor().schedule(() -> {
184 | if (mNamespaceSockets.isEmpty()) {
185 | close();
186 | }
187 | }, mServer.getOptions().getConnectionTimeout(), TimeUnit.MILLISECONDS);
188 | }
189 |
190 | private void destroy() {
191 | mConnection.off("data");
192 | mConnection.off("error");
193 | mConnection.off("close");
194 | }
195 |
196 | private void doConnect(String namespace, Object data) {
197 | final SocketIoNamespaceImpl nsp = (SocketIoNamespaceImpl)mServer.namespace(namespace);
198 | final SocketIoSocket socket = nsp.add(this, data);
199 | if (socket.isConnected()) {
200 | mSockets.put(socket.getId(), socket);
201 | mNamespaceSockets.put(namespace, socket);
202 | }
203 | }
204 |
205 | private void onClose(String reason) {
206 | destroy();
207 |
208 | for (SocketIoSocket socket : mSockets.values()) {
209 | socket.onClose(reason);
210 | }
211 | mSockets.clear();
212 |
213 | mDecoder.destroy();
214 | }
215 |
216 | private void onError(String error) {
217 | for (SocketIoSocket socket : mSockets.values()) {
218 | socket.onError(error);
219 | }
220 |
221 | mConnection.close();
222 | }
223 | }
--------------------------------------------------------------------------------
/socket.io-server/src/main/java/io/socket/socketio/server/SocketIoMemoryAdapter.java:
--------------------------------------------------------------------------------
1 | package io.socket.socketio.server;
2 |
3 | import io.socket.socketio.server.parser.Packet;
4 |
5 | import java.util.*;
6 |
7 | /**
8 | * In-memory adapter class.
9 | * This is the default adapter used.
10 | */
11 | public final class SocketIoMemoryAdapter extends SocketIoAdapter {
12 |
13 | private static final String[] EMPTY_SOCKET_EXCLUSION = new String[0];
14 |
15 | /**
16 | * Factory for {@link SocketIoMemoryAdapter} class.
17 | */
18 | public static final class Factory implements AdapterFactory {
19 |
20 | @Override
21 | public SocketIoAdapter createAdapter(SocketIoNamespace namespace) {
22 | return new SocketIoMemoryAdapter(namespace);
23 | }
24 | }
25 |
26 | private SocketIoMemoryAdapter(SocketIoNamespace namespace) {
27 | super(namespace);
28 | }
29 |
30 | @Override
31 | public synchronized void broadcast(Packet> packet, String[] rooms, String[] socketsExcluded) throws IllegalArgumentException {
32 | if (packet == null) {
33 | throw new IllegalArgumentException("packet must not be null.");
34 | }
35 |
36 | socketsExcluded = (socketsExcluded != null)? socketsExcluded : EMPTY_SOCKET_EXCLUSION;
37 | final Set socketsExcludedSet = new HashSet<>();
38 | Collections.addAll(socketsExcludedSet, socketsExcluded);
39 |
40 | final Map connectedSockets = mNamespace.getConnectedSockets();
41 |
42 | if (rooms != null) {
43 | final Set sentSocketIds = new HashSet<>(); // To ensure only one packet is sent if socket is added to multiple rooms
44 |
45 | for (String room : rooms) {
46 | if (mRoomSockets.containsKey(room)) {
47 | final Set sockets = mRoomSockets.get(room);
48 | for (SocketIoSocket socket : sockets) {
49 | if (!socketsExcludedSet.contains(socket.getId()) &&
50 | !sentSocketIds.contains(socket.getId()) &&
51 | connectedSockets.containsKey(socket.getId())) {
52 | socket.sendPacket(packet);
53 | sentSocketIds.add(socket.getId());
54 | }
55 | }
56 | }
57 | }
58 | } else {
59 | for (String socketId : mSocketRooms.keySet()) {
60 | if (!socketsExcludedSet.contains(socketId)) {
61 | final SocketIoSocket socket = connectedSockets.get(socketId);
62 | if (socket != null) {
63 | socket.sendPacket(packet);
64 | }
65 | }
66 | }
67 | }
68 | }
69 |
70 | @Override
71 | public synchronized void add(String room, SocketIoSocket socket) throws IllegalArgumentException {
72 | if (room == null) {
73 | throw new IllegalArgumentException("room must not be null.");
74 | }
75 | if (socket == null) {
76 | throw new IllegalArgumentException("socket must not be null.");
77 | }
78 |
79 | if (!mSocketRooms.containsKey(socket.getId())) {
80 | mSocketRooms.put(socket.getId(), new HashSet<>());
81 | }
82 | if (!mRoomSockets.containsKey(room)) {
83 | mRoomSockets.put(room, new HashSet<>());
84 | }
85 |
86 | mSocketRooms.get(socket.getId()).add(room);
87 | mRoomSockets.get(room).add(socket);
88 | }
89 |
90 | @Override
91 | public synchronized void remove(String room, SocketIoSocket socket) throws IllegalArgumentException {
92 | if (room == null) {
93 | throw new IllegalArgumentException("room must not be null.");
94 | }
95 | if (socket == null) {
96 | throw new IllegalArgumentException("socket must not be null.");
97 | }
98 |
99 | if (mRoomSockets.containsKey(room)) {
100 | final Set roomSockets = mRoomSockets.get(room);
101 |
102 | roomSockets.remove(socket);
103 | if (roomSockets.size() == 0) {
104 | mRoomSockets.remove(room);
105 | }
106 | }
107 | if (mSocketRooms.containsKey(socket.getId())) {
108 | final Set socketRooms = mSocketRooms.get(socket.getId());
109 |
110 | socketRooms.remove(room);
111 | if (socketRooms.size() == 0) {
112 | mSocketRooms.remove(socket.getId());
113 | }
114 | }
115 | }
116 |
117 | @Override
118 | public SocketIoSocket[] listClients(String room) throws IllegalArgumentException {
119 | if (room == null) {
120 | throw new IllegalArgumentException("room must not be null.");
121 | }
122 |
123 | if (mRoomSockets.containsKey(room)) {
124 | return mRoomSockets.get(room).toArray(new SocketIoSocket[0]);
125 | } else {
126 | return new SocketIoSocket[0];
127 | }
128 | }
129 |
130 | @Override
131 | public String[] listClientRooms(SocketIoSocket socket) throws IllegalArgumentException {
132 | if (socket == null) {
133 | throw new IllegalArgumentException("socket must not be null.");
134 | }
135 |
136 | if (mSocketRooms.containsKey(socket.getId())) {
137 | return mSocketRooms.get(socket.getId()).toArray(new String[0]);
138 | } else {
139 | return new String[0];
140 | }
141 | }
142 | }
--------------------------------------------------------------------------------
/socket.io-server/src/main/java/io/socket/socketio/server/SocketIoNamespace.java:
--------------------------------------------------------------------------------
1 | package io.socket.socketio.server;
2 |
3 | import io.socket.engineio.server.Emitter;
4 |
5 | import java.util.Map;
6 |
7 | /**
8 | * Socket.io namespace class.
9 | * This class represents a namespace created on the server.
10 | */
11 | @SuppressWarnings("WeakerAccess")
12 | public abstract class SocketIoNamespace extends Emitter {
13 |
14 | protected final SocketIoServer mServer;
15 | protected final String mName;
16 | protected final SocketIoAdapter mAdapter;
17 |
18 | SocketIoNamespace(SocketIoServer server, String name) {
19 | mServer = server;
20 | mName = name;
21 | mAdapter = mServer.getAdapterFactory().createAdapter(this);
22 | }
23 |
24 | /**
25 | * Get the name of this namespace.
26 | *
27 | * @return Namespace name with '/' prefix.
28 | */
29 | public String getName() {
30 | return mName;
31 | }
32 |
33 | /**
34 | * Get the server associated with this namespace.
35 | *
36 | * @return Server instance of this namespace.
37 | */
38 | public SocketIoServer getServer() {
39 | return mServer;
40 | }
41 |
42 | /**
43 | * Get the adapter for this namespace.
44 | *
45 | * @return Adapter instance for this namespace.
46 | */
47 | public SocketIoAdapter getAdapter() {
48 | return mAdapter;
49 | }
50 |
51 | /**
52 | * Broadcast a message to all clients in this namespace that
53 | * have joined specified room.
54 | *
55 | * @param room Room to send message to or null.
56 | * @param event Name of event to raise on remote client.
57 | * @param args Arguments to send. Supported types are: JSONObject, JSONArray, null
58 | */
59 | public final void broadcast(String room, String event, Object... args) throws IllegalArgumentException {
60 | broadcast((room != null)? (new String[] { room }) : null, event, args);
61 | }
62 |
63 | /**
64 | * Broadcast a message to all clients in this namespace that
65 | * have joined specified rooms.
66 | *
67 | * @param rooms Rooms to send message to.
68 | * @param event Name of event to raise on remote client.
69 | * @param args Array of arguments to send. Supported types are: JSONObject, JSONArray, null
70 | * @throws IllegalArgumentException If event is null or argument is not of supported type.
71 | */
72 | public abstract void broadcast(String[] rooms, String event, Object[] args) throws IllegalArgumentException;
73 |
74 | abstract Map getConnectedSockets();
75 | }
--------------------------------------------------------------------------------
/socket.io-server/src/main/java/io/socket/socketio/server/SocketIoNamespaceGroupImpl.java:
--------------------------------------------------------------------------------
1 | package io.socket.socketio.server;
2 |
3 | import io.socket.engineio.server.Emitter;
4 |
5 | import java.util.HashMap;
6 | import java.util.HashSet;
7 | import java.util.Map;
8 | import java.util.concurrent.atomic.AtomicInteger;
9 |
10 | final class SocketIoNamespaceGroupImpl extends SocketIoNamespace {
11 |
12 | private static final AtomicInteger NAME_COUNTER = new AtomicInteger(0);
13 |
14 | private final HashSet mChildNamespaces = new HashSet<>();
15 |
16 | SocketIoNamespaceGroupImpl(SocketIoServer server) {
17 | super(server, "/_" + NAME_COUNTER.incrementAndGet());
18 | }
19 |
20 | @Override
21 | public void broadcast(String[] rooms, String event, Object[] args) throws IllegalArgumentException {
22 | for (SocketIoNamespaceImpl namespace : mChildNamespaces) {
23 | namespace.broadcast(rooms, event, args);
24 | }
25 | }
26 |
27 | @Override
28 | Map getConnectedSockets() {
29 | final Map sockets = new HashMap<>();
30 | for (SocketIoNamespaceImpl namespace : mChildNamespaces) {
31 | sockets.putAll(namespace.getConnectedSockets());
32 | }
33 | return sockets;
34 | }
35 |
36 | SocketIoNamespaceImpl createChild(String name) {
37 | final SocketIoNamespaceImpl nsp = new SocketIoNamespaceImpl(getServer(), name);
38 | for (Emitter.Listener listener : listeners("connect")) {
39 | nsp.on("connect", listener);
40 | }
41 | for (Emitter.Listener listener : listeners("connection")) {
42 | nsp.on("connection", listener);
43 | }
44 | mChildNamespaces.add(nsp);
45 | return nsp;
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/socket.io-server/src/main/java/io/socket/socketio/server/SocketIoNamespaceImpl.java:
--------------------------------------------------------------------------------
1 | package io.socket.socketio.server;
2 |
3 | import io.socket.engineio.server.ReadyState;
4 | import io.socket.socketio.server.parser.Packet;
5 | import io.socket.socketio.server.parser.Parser;
6 |
7 | import java.util.Map;
8 | import java.util.concurrent.ConcurrentHashMap;
9 | import java.util.concurrent.atomic.AtomicInteger;
10 |
11 | /**
12 | * Socket.io namespace class.
13 | */
14 | final class SocketIoNamespaceImpl extends SocketIoNamespace {
15 |
16 | @SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
17 | private final Map mSockets = new ConcurrentHashMap<>();
18 | private final Map mConnectedSockets = new ConcurrentHashMap<>();
19 | private final AtomicInteger mAckId = new AtomicInteger(0);
20 |
21 | SocketIoNamespaceImpl(SocketIoServer server, String name) {
22 | super(server, name);
23 | }
24 |
25 | @Override
26 | public void broadcast(String[] rooms, String event, Object[] args) throws IllegalArgumentException {
27 | if (event == null) {
28 | throw new IllegalArgumentException("event cannot be null.");
29 | }
30 |
31 | final Packet packet = PacketUtils.createDataPacket(Parser.EVENT, event, args);
32 | mAdapter.broadcast(packet, rooms);
33 | }
34 |
35 | @Override
36 | Map getConnectedSockets() {
37 | return mConnectedSockets;
38 | }
39 |
40 | /**
41 | * Return an atomically increasing integer for packet id.
42 | *
43 | * @return Int value for use as packet id.
44 | */
45 | int nextId() {
46 | return mAckId.incrementAndGet();
47 | }
48 |
49 | /**
50 | * Add a client instance to this namespace.
51 | *
52 | * @param client Client instance to add.
53 | * @param data Data sent with the CONNECT packet.
54 | * @return Socket instance created from client.
55 | */
56 | synchronized SocketIoSocket add(SocketIoClient client, Object data) {
57 | final SocketIoSocket socket = new SocketIoSocket(this, client, data);
58 | if (client.getConnection().getReadyState() == ReadyState.OPEN) {
59 | mSockets.put(socket.getId(), socket);
60 | socket.onConnect();
61 |
62 | emit("connect", socket);
63 | emit("connection", socket);
64 | }
65 |
66 | return socket;
67 | }
68 |
69 | /**
70 | * Remove a socket instance from this namespace.
71 | *
72 | * @param socket Socket instance to remove.
73 | */
74 | synchronized void remove(SocketIoSocket socket) {
75 | mSockets.remove(socket.getId());
76 | }
77 |
78 | /**
79 | * Mark a socket as connected.
80 | *
81 | * @param socket Socket to mark as connected.
82 | */
83 | synchronized void addConnected(SocketIoSocket socket) {
84 | mConnectedSockets.put(socket.getId(), socket);
85 | }
86 |
87 | /**
88 | * Mark a socket as not connected.
89 | *
90 | * @param socket Socket to mark as not connected.
91 | */
92 | synchronized void removeConnected(SocketIoSocket socket) {
93 | mConnectedSockets.remove(socket.getId());
94 | }
95 | }
--------------------------------------------------------------------------------
/socket.io-server/src/main/java/io/socket/socketio/server/SocketIoNamespaceProvider.java:
--------------------------------------------------------------------------------
1 | package io.socket.socketio.server;
2 |
3 | /**
4 | * Provides methods for checking validity of dynamic namespaces.
5 | */
6 | public interface SocketIoNamespaceProvider {
7 |
8 | /**
9 | * Check if the namespace provided is valid.
10 | *
11 | * @param namespace Namespace to check for validity.
12 | * @return Boolean value indicating namespace validity.
13 | */
14 | boolean checkNamespace(String namespace);
15 | }
16 |
--------------------------------------------------------------------------------
/socket.io-server/src/main/java/io/socket/socketio/server/SocketIoServer.java:
--------------------------------------------------------------------------------
1 | package io.socket.socketio.server;
2 |
3 | import io.socket.engineio.server.EngineIoServer;
4 | import io.socket.engineio.server.EngineIoSocket;
5 | import io.socket.socketio.server.parser.IOParser;
6 | import io.socket.socketio.server.parser.Parser;
7 |
8 | import java.util.Map;
9 | import java.util.concurrent.ConcurrentHashMap;
10 | import java.util.concurrent.ScheduledExecutorService;
11 | import java.util.regex.Pattern;
12 |
13 | /**
14 | * The socket.io server.
15 | */
16 | @SuppressWarnings("WeakerAccess")
17 | public final class SocketIoServer {
18 |
19 | private final SocketIoServerOptions mOptions;
20 |
21 | private final Map mNamespaceRegexProviderMap = new ConcurrentHashMap<>();
22 | private final Map mNamespaceGroups = new ConcurrentHashMap<>();
23 | private final Map mNamespaces = new ConcurrentHashMap<>();
24 | private final Parser.Encoder mEncoder = new IOParser.Encoder();
25 | private final ScheduledExecutorService mScheduledExecutor;
26 |
27 | /**
28 | * Create instance of server with default options.
29 | *
30 | * @param server The underlying engine.io server.
31 | */
32 | public SocketIoServer(EngineIoServer server) {
33 | this(server, SocketIoServerOptions.DEFAULT);
34 | }
35 |
36 | /**
37 | * Create instance of server with provided options.
38 | *
39 | * @param server The underlying engine.io server.
40 | * @param options Server options.
41 | */
42 | public SocketIoServer(EngineIoServer server, SocketIoServerOptions options) {
43 | mOptions = options;
44 | mOptions.lock();
45 | mScheduledExecutor = server.getScheduledExecutor();
46 |
47 | namespace("/");
48 |
49 | server.on("connection", args -> {
50 | final EngineIoSocket socket = (EngineIoSocket) args[0];
51 | final SocketIoClient client = new SocketIoClient(SocketIoServer.this, socket);
52 | if (socket.getProtocolVersion() == 3) {
53 | client.connect("/", null);
54 | }
55 | });
56 | }
57 |
58 | SocketIoServerOptions getOptions() {
59 | return mOptions;
60 | }
61 |
62 | ScheduledExecutorService getScheduledExecutor() {
63 | return mScheduledExecutor;
64 | }
65 |
66 | /**
67 | * Get the packet encoder of this server.
68 | *
69 | * @return Packet encoder instance.
70 | */
71 | Parser.Encoder getEncoder() {
72 | return mEncoder;
73 | }
74 |
75 | /**
76 | * Gets the adapter factory of this server.
77 | *
78 | * @return Adapter factory instance.
79 | */
80 | SocketIoAdapter.AdapterFactory getAdapterFactory() {
81 | return mOptions.getAdapterFactory();
82 | }
83 |
84 | boolean checkNamespace(String namespace) {
85 | if (namespace.charAt(0) != '/') {
86 | namespace = "/" + namespace;
87 | }
88 |
89 | for (SocketIoNamespaceProvider provider : mNamespaceGroups.keySet()) {
90 | if (provider.checkNamespace(namespace)) {
91 | SocketIoNamespaceGroupImpl namespaceGroup = mNamespaceGroups.get(provider);
92 | SocketIoNamespaceImpl nsp = namespaceGroup.createChild(namespace);
93 | mNamespaces.put(namespace, nsp);
94 | return true;
95 | }
96 | }
97 | return false;
98 | }
99 |
100 | /**
101 | * Checks if the given namespace has been created.
102 | *
103 | * @param namespace Name of namespace with or without '/' prefix.
104 | * @return Boolean value indicating if namespace has been created or not.
105 | */
106 | public boolean hasNamespace(String namespace) {
107 | if (namespace.charAt(0) != '/') {
108 | namespace = "/" + namespace;
109 | }
110 |
111 | return mNamespaces.containsKey(namespace);
112 | }
113 |
114 | /**
115 | * Retrieve instance of namespace with specified name.
116 | * This method creates the namespace if not already present.
117 | *
118 | * @param namespace Name of namespace with or without '/' prefix.
119 | * @return Namespace instance.
120 | */
121 | public synchronized SocketIoNamespace namespace(String namespace) {
122 | if (namespace.charAt(0) != '/') {
123 | namespace = "/" + namespace;
124 | }
125 |
126 | SocketIoNamespaceImpl nsp = mNamespaces.get(namespace);
127 | if (nsp == null) {
128 | nsp = new SocketIoNamespaceImpl(this, namespace);
129 | mNamespaces.put(namespace, nsp);
130 | }
131 |
132 | return nsp;
133 | }
134 |
135 | public synchronized SocketIoNamespace namespace(SocketIoNamespaceProvider namespaceProvider) {
136 | SocketIoNamespaceGroupImpl nsp = mNamespaceGroups.get(namespaceProvider);
137 | if (nsp == null) {
138 | nsp = new SocketIoNamespaceGroupImpl(this);
139 | mNamespaceGroups.put(namespaceProvider, nsp);
140 | }
141 |
142 | return nsp;
143 | }
144 |
145 | public synchronized SocketIoNamespace namespace(final Pattern namespaceRegex) {
146 | final SocketIoNamespaceProvider provider = mNamespaceRegexProviderMap.computeIfAbsent(
147 | namespaceRegex,
148 | r -> namespace -> r.matcher(namespace).matches());
149 | return namespace(provider);
150 | }
151 | }
--------------------------------------------------------------------------------
/socket.io-server/src/main/java/io/socket/socketio/server/SocketIoServerOptions.java:
--------------------------------------------------------------------------------
1 | package io.socket.socketio.server;
2 |
3 | /**
4 | * Options for {@link SocketIoServer}
5 | */
6 | @SuppressWarnings("WeakerAccess")
7 | public final class SocketIoServerOptions {
8 |
9 | /**
10 | * The default options used by server.
11 | * This instance is locked and cannot be modified.
12 | *
13 | * adapter factory: {@link SocketIoMemoryAdapter.Factory}
14 | */
15 | public static final SocketIoServerOptions DEFAULT = new SocketIoServerOptions();
16 |
17 | private static final SocketIoAdapter.AdapterFactory MEMORY_ADAPTER_FACTORY = new SocketIoMemoryAdapter.Factory();
18 |
19 | static {
20 | DEFAULT.setAdapterFactory(MEMORY_ADAPTER_FACTORY);
21 | DEFAULT.setConnectionTimeout(45000);
22 | DEFAULT.lock();
23 | }
24 |
25 | private boolean mIsLocked;
26 | private long mConnectionTimeout;
27 | private SocketIoAdapter.AdapterFactory mAdapterFactory;
28 |
29 | private SocketIoServerOptions() {
30 | mIsLocked = false;
31 | }
32 |
33 | /**
34 | * Create a new instance of {@link SocketIoServerOptions} by copying
35 | * default options.
36 | *
37 | * @return New instance of {@link SocketIoServerOptions} with default options.
38 | */
39 | public static SocketIoServerOptions newFromDefault() {
40 | return (new SocketIoServerOptions())
41 | .setConnectionTimeout(DEFAULT.getConnectionTimeout())
42 | .setAdapterFactory(DEFAULT.getAdapterFactory());
43 | }
44 |
45 | /**
46 | * Gets the amount of time to wait (ms) before a client without namespace is closed.
47 | */
48 | public long getConnectionTimeout() {
49 | return mConnectionTimeout;
50 | }
51 |
52 | /**
53 | * Sets the amount of time to wait (ms) before a client without namespace is closed.
54 | */
55 | public SocketIoServerOptions setConnectionTimeout(long connectionTimeout) {
56 | mConnectionTimeout = connectionTimeout;
57 | return this;
58 | }
59 |
60 | /**
61 | * Gets the adapter factory instance.
62 | */
63 | public SocketIoAdapter.AdapterFactory getAdapterFactory() {
64 | return mAdapterFactory;
65 | }
66 |
67 | /**
68 | * Sets the adapter factory instance.
69 | *
70 | * @param adapterFactory Adapter factory instance to set or null for default.
71 | * @return Instance for chaining.
72 | * @throws IllegalStateException If instance is locked.
73 | */
74 | public SocketIoServerOptions setAdapterFactory(SocketIoAdapter.AdapterFactory adapterFactory) throws IllegalStateException {
75 | if (mIsLocked) {
76 | throw new IllegalStateException("Adapter factory cannot be set. Instance is locked.");
77 | }
78 |
79 | if (adapterFactory == null) {
80 | adapterFactory = MEMORY_ADAPTER_FACTORY;
81 | }
82 |
83 | mAdapterFactory = adapterFactory;
84 | return this;
85 | }
86 |
87 | /**
88 | * Lock this options instance to prevent modifications.
89 | */
90 | public void lock() {
91 | mIsLocked = true;
92 | }
93 | }
--------------------------------------------------------------------------------
/socket.io-server/src/main/java/io/socket/socketio/server/parser/Binary.java:
--------------------------------------------------------------------------------
1 | package io.socket.socketio.server.parser;
2 |
3 | import org.json.JSONArray;
4 | import org.json.JSONException;
5 | import org.json.JSONObject;
6 |
7 | import java.util.ArrayList;
8 | import java.util.Iterator;
9 | import java.util.List;
10 | import java.util.logging.Level;
11 | import java.util.logging.Logger;
12 |
13 | public class Binary {
14 |
15 | private static final String KEY_PLACEHOLDER = "_placeholder";
16 |
17 | private static final String KEY_NUM = "num";
18 |
19 | private static final Logger logger = Logger.getLogger(Binary.class.getName());
20 |
21 | @SuppressWarnings("unchecked")
22 | public static DeconstructedPacket deconstructPacket(Packet packet) {
23 | List buffers = new ArrayList<>();
24 |
25 | packet.data = _deconstructPacket(packet.data, buffers);
26 | packet.attachments = buffers.size();
27 |
28 | DeconstructedPacket result = new DeconstructedPacket();
29 | result.packet = packet;
30 | result.buffers = buffers.toArray(new byte[buffers.size()][]);
31 | return result;
32 | }
33 |
34 | private static Object _deconstructPacket(Object data, List buffers) {
35 | if (data == null) return null;
36 |
37 | if (data instanceof byte[]) {
38 | JSONObject placeholder = new JSONObject();
39 | try {
40 | placeholder.put(KEY_PLACEHOLDER, true);
41 | placeholder.put(KEY_NUM, buffers.size());
42 | } catch (JSONException e) {
43 | logger.log(Level.WARNING, "An error occured while putting data to JSONObject", e);
44 | return null;
45 | }
46 | buffers.add((byte[])data);
47 | return placeholder;
48 | } else if (data instanceof JSONArray) {
49 | JSONArray newData = new JSONArray();
50 | JSONArray _data = (JSONArray)data;
51 | int len = _data.length();
52 | for (int i = 0; i < len; i ++) {
53 | try {
54 | newData.put(i, _deconstructPacket(_data.get(i), buffers));
55 | } catch (JSONException e) {
56 | logger.log(Level.WARNING, "An error occured while putting packet data to JSONObject", e);
57 | return null;
58 | }
59 | }
60 | return newData;
61 | } else if (data instanceof JSONObject) {
62 | JSONObject newData = new JSONObject();
63 | JSONObject _data = (JSONObject)data;
64 | Iterator> iterator = _data.keys();
65 | while (iterator.hasNext()) {
66 | String key = (String)iterator.next();
67 | try {
68 | newData.put(key, _deconstructPacket(_data.get(key), buffers));
69 | } catch (JSONException e) {
70 | logger.log(Level.WARNING, "An error occured while putting data to JSONObject", e);
71 | return null;
72 | }
73 | }
74 | return newData;
75 | }
76 | return data;
77 | }
78 |
79 | @SuppressWarnings("unchecked")
80 | public static Packet reconstructPacket(Packet packet, byte[][] buffers) {
81 | packet.data = _reconstructPacket(packet.data, buffers);
82 | packet.attachments = -1;
83 | return packet;
84 | }
85 |
86 | private static Object _reconstructPacket(Object data, byte[][] buffers) {
87 | if (data instanceof JSONArray) {
88 | JSONArray _data = (JSONArray)data;
89 | int len = _data.length();
90 | for (int i = 0; i < len; i ++) {
91 | try {
92 | _data.put(i, _reconstructPacket(_data.get(i), buffers));
93 | } catch (JSONException e) {
94 | logger.log(Level.WARNING, "An error occured while putting packet data to JSONObject", e);
95 | return null;
96 | }
97 | }
98 | return _data;
99 | } else if (data instanceof JSONObject) {
100 | JSONObject _data = (JSONObject)data;
101 | if (_data.optBoolean(KEY_PLACEHOLDER)) {
102 | int num = _data.optInt(KEY_NUM, -1);
103 | return num >= 0 && num < buffers.length ? buffers[num] : null;
104 | }
105 | Iterator> iterator = _data.keys();
106 | while (iterator.hasNext()) {
107 | String key = (String)iterator.next();
108 | try {
109 | _data.put(key, _reconstructPacket(_data.get(key), buffers));
110 | } catch (JSONException e) {
111 | logger.log(Level.WARNING, "An error occured while putting data to JSONObject", e);
112 | return null;
113 | }
114 | }
115 | return _data;
116 | }
117 | return data;
118 | }
119 |
120 | public static class DeconstructedPacket {
121 |
122 | public Packet packet;
123 | public byte[][] buffers;
124 | }
125 | }
126 |
--------------------------------------------------------------------------------
/socket.io-server/src/main/java/io/socket/socketio/server/parser/DecodingException.java:
--------------------------------------------------------------------------------
1 | package io.socket.socketio.server.parser;
2 |
3 | public class DecodingException extends RuntimeException {
4 |
5 | public DecodingException(String message) {
6 | super(message);
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/socket.io-server/src/main/java/io/socket/socketio/server/parser/IOParser.java:
--------------------------------------------------------------------------------
1 | package io.socket.socketio.server.parser;
2 |
3 | import io.socket.socketio.server.utils.HasBinary;
4 | import org.json.JSONArray;
5 | import org.json.JSONException;
6 | import org.json.JSONObject;
7 | import org.json.JSONTokener;
8 |
9 | import java.util.ArrayList;
10 | import java.util.Arrays;
11 | import java.util.List;
12 | import java.util.logging.Level;
13 | import java.util.logging.Logger;
14 |
15 | final public class IOParser implements Parser {
16 |
17 | private static final Logger logger = Logger.getLogger(IOParser.class.getName());
18 |
19 | private IOParser() {}
20 |
21 | final public static class Encoder implements Parser.Encoder {
22 |
23 | public Encoder() {}
24 |
25 | @Override
26 | public void encode(Packet obj, Callback callback) {
27 | if ((obj.type == EVENT || obj.type == ACK) && HasBinary.hasBinary(obj.data)) {
28 | obj.type = obj.type == EVENT ? BINARY_EVENT : BINARY_ACK;
29 | }
30 |
31 | logger.fine(String.format("encoding packet %s", obj));
32 |
33 | if (BINARY_EVENT == obj.type || BINARY_ACK == obj.type) {
34 | encodeAsBinary(obj, callback);
35 | } else {
36 | String encoding = encodeAsString(obj);
37 | callback.call(new String[] {encoding});
38 | }
39 | }
40 |
41 | private String encodeAsString(Packet obj) {
42 | StringBuilder str = new StringBuilder("" + obj.type);
43 |
44 | if (BINARY_EVENT == obj.type || BINARY_ACK == obj.type) {
45 | str.append(obj.attachments);
46 | str.append("-");
47 | }
48 |
49 | if (obj.nsp != null && obj.nsp.length() != 0 && !"/".equals(obj.nsp)) {
50 | str.append(obj.nsp);
51 | str.append(",");
52 | }
53 |
54 | if (obj.id >= 0) {
55 | str.append(obj.id);
56 | }
57 |
58 | if (obj.data != null) {
59 | str.append(obj.data);
60 | }
61 |
62 | logger.fine(String.format("encoded %s as %s", obj, str));
63 | return str.toString();
64 | }
65 |
66 | private void encodeAsBinary(Packet obj, Callback callback) {
67 | Binary.DeconstructedPacket deconstruction = Binary.deconstructPacket(obj);
68 | String pack = encodeAsString(deconstruction.packet);
69 | List buffers = new ArrayList(Arrays.asList(deconstruction.buffers));
70 |
71 | buffers.add(0, pack);
72 | callback.call(buffers.toArray());
73 | }
74 | }
75 |
76 | final public static class Decoder implements Parser.Decoder {
77 |
78 | /*package*/ BinaryReconstructor reconstructor;
79 |
80 | private Decoder.Callback onDecodedCallback;
81 |
82 | public Decoder() {
83 | this.reconstructor = null;
84 | }
85 |
86 | @Override
87 | public void add(String obj) {
88 | Packet packet = decodeString(obj);
89 | if (BINARY_EVENT == packet.type || BINARY_ACK == packet.type) {
90 | this.reconstructor = new BinaryReconstructor(packet);
91 |
92 | if (this.reconstructor.reconPack.attachments == 0) {
93 | if (this.onDecodedCallback != null) {
94 | this.onDecodedCallback.call(packet);
95 | }
96 | }
97 | } else {
98 | if (this.onDecodedCallback != null) {
99 | this.onDecodedCallback.call(packet);
100 | }
101 | }
102 | }
103 |
104 | @Override
105 | public void add(byte[] obj) {
106 | if (this.reconstructor == null) {
107 | throw new RuntimeException("got binary data when not reconstructing a packet");
108 | } else {
109 | Packet packet = this.reconstructor.takeBinaryData(obj);
110 | if (packet != null) {
111 | this.reconstructor = null;
112 | if (this.onDecodedCallback != null) {
113 | this.onDecodedCallback.call(packet);
114 | }
115 | }
116 | }
117 | }
118 |
119 | private static Packet decodeString(String str) {
120 | int i = 0;
121 | int length = str.length();
122 |
123 | Packet p = new Packet<>(Character.getNumericValue(str.charAt(0)));
124 |
125 | if (p.type < 0 || p.type > types.length - 1) {
126 | throw new DecodingException("unknown packet type " + p.type);
127 | }
128 |
129 | if (BINARY_EVENT == p.type || BINARY_ACK == p.type) {
130 | if (!str.contains("-") || length <= i + 1) {
131 | throw new DecodingException("illegal attachments");
132 | }
133 | StringBuilder attachments = new StringBuilder();
134 | while (str.charAt(++i) != '-') {
135 | attachments.append(str.charAt(i));
136 | }
137 | p.attachments = Integer.parseInt(attachments.toString());
138 | }
139 |
140 | if (length > i + 1 && '/' == str.charAt(i + 1)) {
141 | StringBuilder nsp = new StringBuilder();
142 | while (true) {
143 | ++i;
144 | char c = str.charAt(i);
145 | if (',' == c) break;
146 | nsp.append(c);
147 | if (i + 1 == length) break;
148 | }
149 | p.nsp = nsp.toString();
150 | } else {
151 | p.nsp = "/";
152 | }
153 |
154 | if (length > i + 1){
155 | Character next = str.charAt(i + 1);
156 | if (Character.getNumericValue(next) > -1) {
157 | StringBuilder id = new StringBuilder();
158 | while (true) {
159 | ++i;
160 | char c = str.charAt(i);
161 | if (Character.getNumericValue(c) < 0) {
162 | --i;
163 | break;
164 | }
165 | id.append(c);
166 | if (i + 1 == length) break;
167 | }
168 | try {
169 | p.id = Integer.parseInt(id.toString());
170 | } catch (NumberFormatException e){
171 | throw new DecodingException("invalid payload");
172 | }
173 | }
174 | }
175 |
176 | if (length > i + 1){
177 | try {
178 | str.charAt(++i);
179 | p.data = new JSONTokener(str.substring(i)).nextValue();
180 | } catch (JSONException e) {
181 | logger.log(Level.WARNING, "An error occured while retrieving data from JSONTokener", e);
182 | throw new DecodingException("invalid payload");
183 | }
184 | if (!isPayloadValid(p.type, p.data)) {
185 | throw new DecodingException("invalid payload");
186 | }
187 | }
188 |
189 | logger.fine(String.format("decoded %s as %s", str, p));
190 | return p;
191 | }
192 |
193 | private static boolean isPayloadValid(int type, Object payload) {
194 | switch (type) {
195 | case Parser.CONNECT:
196 | case Parser.CONNECT_ERROR:
197 | return payload instanceof JSONObject;
198 | case Parser.DISCONNECT:
199 | return payload == null;
200 | case Parser.EVENT:
201 | case Parser.BINARY_EVENT:
202 | return payload instanceof JSONArray
203 | && ((JSONArray) payload).length() > 0
204 | && !((JSONArray) payload).isNull(0);
205 | case Parser.ACK:
206 | case Parser.BINARY_ACK:
207 | return payload instanceof JSONArray;
208 | default:
209 | return false;
210 | }
211 | }
212 |
213 | @Override
214 | public void destroy() {
215 | if (this.reconstructor != null) {
216 | this.reconstructor.finishReconstruction();
217 | }
218 | this.onDecodedCallback = null;
219 | }
220 |
221 | @Override
222 | public void onDecoded (Callback callback) {
223 | this.onDecodedCallback = callback;
224 | }
225 | }
226 |
227 |
228 | /*package*/ static class BinaryReconstructor {
229 |
230 | public Packet reconPack;
231 |
232 | /*package*/ List buffers;
233 |
234 | BinaryReconstructor(Packet packet) {
235 | this.reconPack = packet;
236 | this.buffers = new ArrayList<>();
237 | }
238 |
239 | public Packet takeBinaryData(byte[] binData) {
240 | this.buffers.add(binData);
241 | if (this.buffers.size() == this.reconPack.attachments) {
242 | Packet packet = Binary.reconstructPacket(this.reconPack,
243 | this.buffers.toArray(new byte[this.buffers.size()][]));
244 | this.finishReconstruction();
245 | return packet;
246 | }
247 | return null;
248 | }
249 |
250 | public void finishReconstruction () {
251 | this.reconPack = null;
252 | this.buffers = new ArrayList<>();
253 | }
254 | }
255 | }
256 |
--------------------------------------------------------------------------------
/socket.io-server/src/main/java/io/socket/socketio/server/parser/Packet.java:
--------------------------------------------------------------------------------
1 | package io.socket.socketio.server.parser;
2 |
3 | public class Packet {
4 |
5 | public int type = -1;
6 | public int id = -1;
7 | public String nsp;
8 | public T data;
9 | public int attachments;
10 |
11 | public Packet() {}
12 |
13 | public Packet(int type) {
14 | this.type = type;
15 | }
16 |
17 | public Packet(int type, T data) {
18 | this.type = type;
19 | this.data = data;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/socket.io-server/src/main/java/io/socket/socketio/server/parser/Parser.java:
--------------------------------------------------------------------------------
1 | package io.socket.socketio.server.parser;
2 |
3 | public interface Parser {
4 |
5 | /**
6 | * Packet type `connect`.
7 | */
8 | int CONNECT = 0;
9 |
10 | /**
11 | * Packet type `disconnect`.
12 | */
13 | int DISCONNECT = 1;
14 |
15 | /**
16 | * Packet type `event`.
17 | */
18 | int EVENT = 2;
19 |
20 | /**
21 | * Packet type `ack`.
22 | */
23 | int ACK = 3;
24 |
25 | /**
26 | * Packet type `error`.
27 | */
28 | int CONNECT_ERROR = 4;
29 |
30 | /**
31 | * Packet type `binary event`.
32 | */
33 | int BINARY_EVENT = 5;
34 |
35 | /**
36 | * Packet type `binary ack`.
37 | */
38 | int BINARY_ACK = 6;
39 |
40 | int protocol = 5;
41 |
42 | /**
43 | * Packet types.
44 | */
45 | String[] types = new String[] {
46 | "CONNECT",
47 | "DISCONNECT",
48 | "EVENT",
49 | "ACK",
50 | "ERROR",
51 | "BINARY_EVENT",
52 | "BINARY_ACK"
53 | };
54 |
55 | interface Encoder {
56 |
57 | void encode(Packet obj, Callback callback);
58 |
59 | interface Callback {
60 |
61 | void call(Object[] data);
62 | }
63 | }
64 |
65 | interface Decoder {
66 |
67 | void add(String obj);
68 |
69 | void add(byte[] obj);
70 |
71 | void destroy();
72 |
73 | void onDecoded(Callback callback);
74 |
75 | interface Callback {
76 |
77 | void call(Packet packet);
78 | }
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/socket.io-server/src/main/java/io/socket/socketio/server/utils/HasBinary.java:
--------------------------------------------------------------------------------
1 | package io.socket.socketio.server.utils;
2 |
3 | import org.json.JSONArray;
4 | import org.json.JSONException;
5 | import org.json.JSONObject;
6 |
7 | import java.util.Iterator;
8 | import java.util.logging.Level;
9 | import java.util.logging.Logger;
10 |
11 | public interface HasBinary {
12 |
13 | Logger logger = Logger.getLogger(HasBinary.class.getName());
14 |
15 | static boolean hasBinary(Object data) {
16 | if (data == null) return false;
17 |
18 | if (data instanceof byte[]) {
19 | return true;
20 | }
21 |
22 | if (data instanceof JSONArray) {
23 | JSONArray _obj = (JSONArray)data;
24 | int length = _obj.length();
25 | for (int i = 0; i < length; i++) {
26 | Object v;
27 | try {
28 | v = _obj.isNull(i) ? null : _obj.get(i);
29 | } catch (JSONException e) {
30 | logger.log(Level.WARNING, "An error occured while retrieving data from JSONArray", e);
31 | return false;
32 | }
33 | if (hasBinary(v)) {
34 | return true;
35 | }
36 | }
37 | } else if (data instanceof JSONObject) {
38 | JSONObject _obj = (JSONObject)data;
39 | Iterator keys = _obj.keys();
40 | while (keys.hasNext()) {
41 | String key = keys.next();
42 | Object v;
43 | try {
44 | v = _obj.get(key);
45 | } catch (JSONException e) {
46 | logger.log(Level.WARNING, "An error occured while retrieving data from JSONObject", e);
47 | return false;
48 | }
49 | if (hasBinary(v)) {
50 | return true;
51 | }
52 | }
53 | }
54 |
55 | return false;
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/socket.io-server/src/test/java/io/socket/socketio/server/SocketIoAdapterImpl.java:
--------------------------------------------------------------------------------
1 | package io.socket.socketio.server;
2 |
3 | import io.socket.socketio.server.parser.Packet;
4 |
5 | public final class SocketIoAdapterImpl extends SocketIoAdapter {
6 |
7 | SocketIoAdapterImpl(SocketIoNamespace namespace) {
8 | super(namespace);
9 | }
10 |
11 | @Override
12 | public void broadcast(Packet packet, String[] rooms) throws IllegalArgumentException {
13 | super.broadcast(packet, rooms);
14 | }
15 |
16 | @Override
17 | public void broadcast(Packet packet, String[] rooms, String[] socketsExcluded) throws IllegalArgumentException {
18 | }
19 |
20 | @Override
21 | public void add(String room, SocketIoSocket socket) throws IllegalArgumentException {
22 | }
23 |
24 | @Override
25 | public void remove(String room, SocketIoSocket socket) throws IllegalArgumentException {
26 | }
27 |
28 | @Override
29 | public SocketIoSocket[] listClients(String room) throws IllegalArgumentException {
30 | return new SocketIoSocket[0];
31 | }
32 |
33 | @Override
34 | public String[] listClientRooms(SocketIoSocket socket) throws IllegalArgumentException {
35 | return new String[0];
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/socket.io-server/src/test/java/io/socket/socketio/server/SocketIoAdapterTest.java:
--------------------------------------------------------------------------------
1 | package io.socket.socketio.server;
2 |
3 | import io.socket.socketio.server.parser.Packet;
4 | import io.socket.socketio.server.parser.Parser;
5 | import org.junit.Test;
6 | import org.mockito.Mockito;
7 |
8 | public final class SocketIoAdapterTest {
9 |
10 | @Test
11 | public void test_broadcast() {
12 | final SocketIoAdapter adapter = Mockito.spy(new SocketIoAdapter(null) {
13 | @Override
14 | public void broadcast(Packet> packet, String[] rooms, String[] socketsExcluded) throws IllegalArgumentException {
15 | }
16 |
17 | @Override
18 | public void add(String room, SocketIoSocket socket) throws IllegalArgumentException {
19 | }
20 |
21 | @Override
22 | public void remove(String room, SocketIoSocket socket) throws IllegalArgumentException {
23 | }
24 |
25 | @Override
26 | public SocketIoSocket[] listClients(String room) throws IllegalArgumentException {
27 | return new SocketIoSocket[0];
28 | }
29 |
30 | @Override
31 | public String[] listClientRooms(SocketIoSocket socket) throws IllegalArgumentException {
32 | return new String[0];
33 | }
34 | });
35 | Mockito.doCallRealMethod().when(adapter)
36 | .broadcast(Mockito.any(Packet.class), Mockito.any(String[].class));
37 | Mockito.doAnswer(invocationOnMock -> null)
38 | .when(adapter)
39 | .broadcast(Mockito.any(Packet.class), Mockito.any(String[].class), Mockito.any(String[].class));
40 |
41 | adapter.broadcast(new Packet<>(Parser.CONNECT), null);
42 | Mockito.verify(adapter, Mockito.times(1))
43 | .broadcast(Mockito.any(Packet.class), Mockito.isNull(), Mockito.isNull());
44 | }
45 | }
--------------------------------------------------------------------------------
/socket.io-server/src/test/java/io/socket/socketio/server/SocketIoClientTest.java:
--------------------------------------------------------------------------------
1 | package io.socket.socketio.server;
2 |
3 | import io.socket.engineio.server.Emitter;
4 | import io.socket.engineio.server.EngineIoServer;
5 | import io.socket.engineio.server.EngineIoSocket;
6 | import io.socket.engineio.server.EngineIoWebSocket;
7 | import io.socket.socketio.server.parser.Packet;
8 | import io.socket.socketio.server.parser.Parser;
9 | import org.json.JSONArray;
10 | import org.junit.Test;
11 | import org.mockito.Mockito;
12 |
13 | import java.io.IOException;
14 |
15 | import static org.junit.Assert.assertEquals;
16 |
17 | public final class SocketIoClientTest {
18 |
19 | @Test
20 | public void test_constructor() {
21 | final EngineIoServer engineIoServer = new EngineIoServer();
22 | final SocketIoServer socketIoServer = new SocketIoServer(engineIoServer);
23 |
24 | final Emitter.Listener connectionListener = Mockito.mock(Emitter.Listener.class);
25 | Mockito.doAnswer(invocation -> {
26 | final Object[] args = invocation.getArguments();
27 | final EngineIoSocket socket = Mockito.spy((EngineIoSocket) args[0]);
28 | final SocketIoClient client = new SocketIoClient(socketIoServer, socket);
29 |
30 | assertEquals(socket.getId(), client.getId());
31 | assertEquals(socket, client.getConnection());
32 | Mockito.verify(socket, Mockito.times(1))
33 | .on(Mockito.eq("data"), Mockito.any(Emitter.Listener.class));
34 | Mockito.verify(socket, Mockito.times(1))
35 | .on(Mockito.eq("error"), Mockito.any(Emitter.Listener.class));
36 | Mockito.verify(socket, Mockito.times(1))
37 | .on(Mockito.eq("close"), Mockito.any(Emitter.Listener.class));
38 | return null;
39 | }).when(connectionListener).call(Mockito.any());
40 | engineIoServer.on("connection", connectionListener);
41 | engineIoServer.handleWebSocket(new StubEngineIoWebSocket());
42 |
43 | Mockito.verify(connectionListener, Mockito.times(1))
44 | .call(Mockito.any(EngineIoSocket.class));
45 | }
46 |
47 | @Test
48 | public void test_sendPacket_nonbinary() {
49 | final EngineIoServer engineIoServer = new EngineIoServer();
50 | final SocketIoServer socketIoServer = new SocketIoServer(engineIoServer);
51 |
52 | final EngineIoWebSocket webSocket = Mockito.spy(new StubEngineIoWebSocket());
53 |
54 | final Emitter.Listener connectionListener = Mockito.mock(Emitter.Listener.class);
55 | Mockito.doAnswer(invocation -> {
56 | final Object[] args = invocation.getArguments();
57 | final EngineIoSocket socket = (EngineIoSocket) args[0];
58 | final SocketIoClient client = new SocketIoClient(socketIoServer, socket);
59 |
60 | final JSONArray packetData = new JSONArray();
61 | packetData.put("foo");
62 | packetData.put(1);
63 |
64 | final Packet packet = new Packet<>(Parser.EVENT, packetData);
65 |
66 | try {
67 | Mockito.reset(webSocket);
68 | client.sendPacket(packet);
69 | Mockito.verify(webSocket, Mockito.times(1))
70 | .write(Mockito.anyString());
71 | } catch (IOException ignore) {
72 | }
73 | return null;
74 | }).when(connectionListener).call(Mockito.any());
75 | engineIoServer.on("connection", connectionListener);
76 | engineIoServer.handleWebSocket(webSocket);
77 |
78 | Mockito.verify(connectionListener, Mockito.times(1))
79 | .call(Mockito.any(EngineIoSocket.class));
80 | }
81 |
82 | @Test
83 | public void test_sendPacket_binary() {
84 | final EngineIoServer engineIoServer = new EngineIoServer();
85 | final SocketIoServer socketIoServer = new SocketIoServer(engineIoServer);
86 |
87 | final EngineIoWebSocket webSocket = Mockito.spy(new StubEngineIoWebSocket());
88 |
89 | final Emitter.Listener connectionListener = Mockito.mock(Emitter.Listener.class);
90 | Mockito.doAnswer(invocation -> {
91 | final Object[] args = invocation.getArguments();
92 | final EngineIoSocket socket = (EngineIoSocket) args[0];
93 | final SocketIoClient client = new SocketIoClient(socketIoServer, socket);
94 |
95 | final JSONArray packetData = new JSONArray();
96 | packetData.put("foo");
97 | packetData.put(1);
98 | packetData.put(new byte[16]);
99 |
100 | final Packet packet = new Packet<>(Parser.EVENT, packetData);
101 |
102 | try {
103 | Mockito.reset(webSocket);
104 | client.sendPacket(packet);
105 | Mockito.verify(webSocket, Mockito.times(1))
106 | .write(Mockito.anyString());
107 | Mockito.verify(webSocket, Mockito.times(1))
108 | .write(Mockito.any(byte[].class));
109 | } catch (IOException ignore) {
110 | }
111 | return null;
112 | }).when(connectionListener).call(Mockito.any());
113 | engineIoServer.on("connection", connectionListener);
114 | engineIoServer.handleWebSocket(webSocket);
115 |
116 | Mockito.verify(connectionListener, Mockito.times(1))
117 | .call(Mockito.any(EngineIoSocket.class));
118 | }
119 |
120 | @Test
121 | public void test_sendPacket_after_close() {
122 | final EngineIoServer engineIoServer = new EngineIoServer();
123 | final SocketIoServer socketIoServer = new SocketIoServer(engineIoServer);
124 |
125 | final EngineIoWebSocket webSocket = Mockito.spy(new StubEngineIoWebSocket());
126 |
127 | final Emitter.Listener connectionListener = Mockito.mock(Emitter.Listener.class);
128 | Mockito.doAnswer(invocation -> {
129 | final Object[] args = invocation.getArguments();
130 | final EngineIoSocket socket = (EngineIoSocket) args[0];
131 | final SocketIoClient client = new SocketIoClient(socketIoServer, socket);
132 |
133 | final JSONArray packetData = new JSONArray();
134 | packetData.put("foo");
135 | packetData.put(1);
136 |
137 | socket.close();
138 |
139 | final Packet packet = new Packet<>(Parser.EVENT, packetData);
140 |
141 | try {
142 | Mockito.reset(webSocket);
143 | client.sendPacket(packet);
144 | Mockito.verify(webSocket, Mockito.times(0))
145 | .write(Mockito.anyString());
146 | } catch (IOException ignore) {
147 | }
148 | return null;
149 | }).when(connectionListener).call(Mockito.any());
150 | engineIoServer.on("connection", connectionListener);
151 | engineIoServer.handleWebSocket(webSocket);
152 |
153 | Mockito.verify(connectionListener, Mockito.times(1))
154 | .call(Mockito.any(EngineIoSocket.class));
155 | }
156 |
157 | @Test
158 | public void test_disconnect() {
159 | final EngineIoServer engineIoServer = new EngineIoServer();
160 | final SocketIoServer socketIoServer = new SocketIoServer(engineIoServer);
161 |
162 | final EngineIoWebSocket webSocket = Mockito.spy(new StubEngineIoWebSocket());
163 |
164 | final Emitter.Listener connectionListener = Mockito.mock(Emitter.Listener.class);
165 | Mockito.doAnswer(invocation -> {
166 | final Object[] args = invocation.getArguments();
167 | final EngineIoSocket socket = Mockito.spy((EngineIoSocket) args[0]);
168 | final SocketIoClient client = new SocketIoClient(socketIoServer, socket);
169 |
170 | client.disconnect();
171 |
172 | Mockito.verify(socket, Mockito.times(1))
173 | .close();
174 | return null;
175 |
176 | }).when(connectionListener).call(Mockito.any());
177 | engineIoServer.on("connection", connectionListener);
178 | engineIoServer.handleWebSocket(webSocket);
179 |
180 | Mockito.verify(connectionListener, Mockito.times(1))
181 | .call(Mockito.any(EngineIoSocket.class));
182 | }
183 |
184 | @Test
185 | public void test_socket_error() {
186 | final EngineIoServer engineIoServer = new EngineIoServer();
187 | final SocketIoServer socketIoServer = new SocketIoServer(engineIoServer);
188 |
189 | final EngineIoWebSocket webSocket = Mockito.spy(new StubEngineIoWebSocket());
190 |
191 | final Emitter.Listener connectionListener = Mockito.mock(Emitter.Listener.class);
192 | Mockito.doAnswer(invocation -> {
193 | final Object[] args = invocation.getArguments();
194 | final EngineIoSocket socket = Mockito.spy((EngineIoSocket) args[0]);
195 | final SocketIoClient client = new SocketIoClient(socketIoServer, socket);
196 |
197 | socket.emit("error", "parse error", null);
198 |
199 | Mockito.verify(socket, Mockito.times(1))
200 | .close();
201 | return null;
202 | }).when(connectionListener).call(Mockito.any());
203 | engineIoServer.on("connection", connectionListener);
204 | engineIoServer.handleWebSocket(webSocket);
205 |
206 | Mockito.verify(connectionListener, Mockito.times(1))
207 | .call(Mockito.any(EngineIoSocket.class));
208 | }
209 | }
210 |
--------------------------------------------------------------------------------
/socket.io-server/src/test/java/io/socket/socketio/server/SocketIoNamespaceImplTest.java:
--------------------------------------------------------------------------------
1 | package io.socket.socketio.server;
2 |
3 | import io.socket.engineio.server.EngineIoServer;
4 | import io.socket.socketio.server.parser.Packet;
5 | import io.socket.socketio.server.parser.Parser;
6 | import org.json.JSONArray;
7 | import org.junit.Test;
8 | import org.mockito.Mockito;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | public final class SocketIoNamespaceImplTest {
13 |
14 | @SuppressWarnings("ResultOfMethodCallIgnored")
15 | @Test
16 | public void test_constructor_new_instance() {
17 | final SocketIoServer server = Mockito.spy(new SocketIoServer(new EngineIoServer()));
18 |
19 | final SocketIoNamespaceImpl namespace = new SocketIoNamespaceImpl(server, "/_foo");
20 |
21 | Mockito.verify(server, Mockito.times(1)).getAdapterFactory();
22 | assertEquals("/_foo", namespace.getName());
23 | assertEquals(server, namespace.getServer());
24 | assertNotNull(namespace.getAdapter());
25 | assertEquals(0, namespace.getConnectedSockets().size());
26 | }
27 |
28 | @Test
29 | public void test_broadcast_all_rooms() {
30 | final SocketIoAdapter adapter = Mockito.mock(SocketIoAdapter.class);
31 | Mockito.doCallRealMethod().when(adapter)
32 | .broadcast(Mockito.any(Packet.class), Mockito.isNull());
33 | Mockito.doAnswer(invocationOnMock -> {
34 | final Packet packet = invocationOnMock.getArgument(0);
35 | final String[] rooms = invocationOnMock.getArgument(1);
36 | final String[] socketsExcluded = invocationOnMock.getArgument(2);
37 |
38 | assertEquals(Parser.EVENT, packet.type);
39 | assertNotNull(packet.data);
40 | assertEquals(JSONArray.class, packet.data.getClass());
41 | assertEquals(1, ((JSONArray) packet.data).length());
42 | assertEquals("foo", ((JSONArray) packet.data).get(0));
43 |
44 | assertNull(rooms);
45 | assertNull(socketsExcluded);
46 |
47 | return null;
48 | }).when(adapter).broadcast(Mockito.any(Packet.class), Mockito.isNull(), Mockito.isNull());
49 |
50 | final SocketIoAdapter.AdapterFactory adapterFactory = Mockito.mock(SocketIoAdapter.AdapterFactory.class);
51 | Mockito.doAnswer(invocationOnMock -> adapter)
52 | .when(adapterFactory)
53 | .createAdapter(Mockito.any(SocketIoNamespaceImpl.class));
54 |
55 | final SocketIoServer server = Mockito.spy(new SocketIoServer(
56 | new EngineIoServer(),
57 | SocketIoServerOptions.newFromDefault()
58 | .setAdapterFactory(adapterFactory)));
59 | final SocketIoNamespace namespace = server.namespace("/");
60 |
61 | namespace.broadcast(null, "foo");
62 | Mockito.verify(adapter, Mockito.times(1))
63 | .broadcast(Mockito.any(Packet.class), Mockito.isNull(), Mockito.isNull());
64 | }
65 |
66 | @Test
67 | public void test_broadcast_one_room() {
68 | final SocketIoAdapter adapter = Mockito.mock(SocketIoAdapter.class);
69 | Mockito.doCallRealMethod().when(adapter)
70 | .broadcast(Mockito.any(Packet.class), Mockito.any(String[].class));
71 | Mockito.doAnswer(invocationOnMock -> {
72 | final Packet packet = invocationOnMock.getArgument(0);
73 | final String[] rooms = invocationOnMock.getArgument(1);
74 | final String[] socketsExcluded = invocationOnMock.getArgument(2);
75 |
76 | assertEquals(Parser.EVENT, packet.type);
77 | assertNotNull(packet.data);
78 | assertEquals(JSONArray.class, packet.data.getClass());
79 | assertEquals(1, ((JSONArray) packet.data).length());
80 | assertEquals("bar", ((JSONArray) packet.data).get(0));
81 |
82 | assertNotNull(rooms);
83 | assertEquals(1, rooms.length);
84 | assertEquals("foo", rooms[0]);
85 |
86 | assertNull(socketsExcluded);
87 |
88 | return null;
89 | }).when(adapter).broadcast(Mockito.any(Packet.class), Mockito.any(String[].class), Mockito.isNull());
90 |
91 | final SocketIoAdapter.AdapterFactory adapterFactory = Mockito.mock(SocketIoAdapter.AdapterFactory.class);
92 | Mockito.doAnswer(invocationOnMock -> adapter)
93 | .when(adapterFactory)
94 | .createAdapter(Mockito.any(SocketIoNamespaceImpl.class));
95 |
96 | final SocketIoServer server = Mockito.spy(new SocketIoServer(
97 | new EngineIoServer(),
98 | SocketIoServerOptions.newFromDefault()
99 | .setAdapterFactory(adapterFactory)));
100 | final SocketIoNamespace namespace = server.namespace("/");
101 |
102 | namespace.broadcast("foo", "bar");
103 | Mockito.verify(adapter, Mockito.times(1))
104 | .broadcast(Mockito.any(Packet.class), Mockito.any(String[].class), Mockito.isNull());
105 | }
106 |
107 | @Test
108 | public void test_broadcast_multiple_rooms() {
109 | final SocketIoAdapter adapter = Mockito.mock(SocketIoAdapter.class);
110 | Mockito.doCallRealMethod().when(adapter)
111 | .broadcast(Mockito.any(Packet.class), Mockito.any(String[].class));
112 | Mockito.doAnswer(invocationOnMock -> {
113 | final Packet packet = invocationOnMock.getArgument(0);
114 | final String[] rooms = invocationOnMock.getArgument(1);
115 | final String[] socketsExcluded = invocationOnMock.getArgument(2);
116 |
117 | assertEquals(Parser.EVENT, packet.type);
118 | assertNotNull(packet.data);
119 | assertEquals(JSONArray.class, packet.data.getClass());
120 | assertEquals(1, ((JSONArray) packet.data).length());
121 | assertEquals("baz", ((JSONArray) packet.data).get(0));
122 |
123 | assertNotNull(rooms);
124 | assertArrayEquals(new String[] { "foo", "bar" }, rooms);
125 |
126 | assertNull(socketsExcluded);
127 |
128 | return null;
129 | }).when(adapter).broadcast(Mockito.any(Packet.class), Mockito.any(String[].class), Mockito.isNull());
130 |
131 | final SocketIoAdapter.AdapterFactory adapterFactory = Mockito.mock(SocketIoAdapter.AdapterFactory.class);
132 | Mockito.doAnswer(invocationOnMock -> adapter)
133 | .when(adapterFactory)
134 | .createAdapter(Mockito.any(SocketIoNamespaceImpl.class));
135 |
136 | final SocketIoServer server = Mockito.spy(new SocketIoServer(
137 | new EngineIoServer(),
138 | SocketIoServerOptions.newFromDefault()
139 | .setAdapterFactory(adapterFactory)));
140 | final SocketIoNamespace namespace = server.namespace("/");
141 |
142 | namespace.broadcast(new String[] { "foo", "bar" }, "baz", null);
143 | Mockito.verify(adapter, Mockito.times(1))
144 | .broadcast(Mockito.any(Packet.class), Mockito.any(String[].class), Mockito.isNull());
145 | }
146 | }
--------------------------------------------------------------------------------
/socket.io-server/src/test/java/io/socket/socketio/server/SocketIoServerOptionsTest.java:
--------------------------------------------------------------------------------
1 | package io.socket.socketio.server;
2 |
3 | import org.junit.Test;
4 | import org.mockito.Mockito;
5 |
6 | import static org.junit.Assert.*;
7 |
8 | public final class SocketIoServerOptionsTest {
9 |
10 | @Test(expected = IllegalStateException.class)
11 | public void testDefaultLocked_setAdapterFactory() {
12 | SocketIoServerOptions.DEFAULT.setAdapterFactory(null);
13 | }
14 |
15 | @Test
16 | public void test_setAdapterFactory() {
17 | final SocketIoServerOptions options = SocketIoServerOptions.newFromDefault();
18 | options.setAdapterFactory(Mockito.mock(SocketIoAdapter.AdapterFactory.class));
19 |
20 | assertNotNull(options.getAdapterFactory());
21 | assertTrue(options.getAdapterFactory() instanceof SocketIoMemoryAdapter.AdapterFactory);
22 | }
23 |
24 | @Test
25 | public void test_setAdapterFactory_null() {
26 | final SocketIoServerOptions options = SocketIoServerOptions.newFromDefault();
27 | options.setAdapterFactory(null);
28 |
29 | assertNotNull(options.getAdapterFactory());
30 | assertTrue(options.getAdapterFactory() instanceof SocketIoMemoryAdapter.AdapterFactory);
31 | }
32 |
33 | @Test(expected = IllegalStateException.class)
34 | public void test_lock() {
35 | final SocketIoServerOptions options = SocketIoServerOptions.newFromDefault();
36 | options.setAdapterFactory(Mockito.mock(SocketIoAdapter.AdapterFactory.class));
37 | options.lock();
38 |
39 | options.setAdapterFactory(null);
40 | }
41 | }
--------------------------------------------------------------------------------
/socket.io-server/src/test/java/io/socket/socketio/server/SocketIoServerTest.java:
--------------------------------------------------------------------------------
1 | package io.socket.socketio.server;
2 |
3 | import io.socket.engineio.server.Emitter;
4 | import io.socket.engineio.server.EngineIoServer;
5 | import io.socket.socketio.server.parser.IOParser;
6 | import org.junit.Test;
7 | import org.mockito.Mockito;
8 |
9 | import java.util.regex.Pattern;
10 |
11 | import static org.junit.Assert.*;
12 |
13 | public final class SocketIoServerTest {
14 |
15 | @Test
16 | public void test_constructor() {
17 | final EngineIoServer engineIoServer = Mockito.spy(new EngineIoServer());
18 | final SocketIoServer server = new SocketIoServer(engineIoServer);
19 |
20 | // Verify 'connection' event bind
21 | Mockito.verify(engineIoServer, Mockito.times(1))
22 | .on(Mockito.eq("connection"), Mockito.any(Emitter.Listener.class));
23 |
24 | // Verify encoder
25 | assertNotNull(server.getEncoder());
26 | assertEquals(IOParser.Encoder.class, server.getEncoder().getClass());
27 |
28 | // Verify adapter factory
29 | assertNotNull(server.getAdapterFactory());
30 | assertEquals(SocketIoMemoryAdapter.Factory.class, server.getAdapterFactory().getClass());
31 |
32 | // Verify default namespace '/'
33 | assertTrue(server.hasNamespace("/"));
34 | }
35 |
36 | @Test
37 | public void test_namespace_new() {
38 | final SocketIoServer server = new SocketIoServer(new EngineIoServer());
39 |
40 | // With slash
41 | assertFalse(server.hasNamespace("/foo"));
42 | server.namespace("/foo");
43 | assertTrue(server.hasNamespace("/foo"));
44 | assertTrue(server.hasNamespace("foo"));
45 |
46 | // Without slash
47 | assertFalse(server.hasNamespace("bar"));
48 | server.namespace("bar");
49 | assertTrue(server.hasNamespace("/bar"));
50 | assertTrue(server.hasNamespace("bar"));
51 | }
52 |
53 | @Test
54 | public void test_namespaceGroup_new() {
55 | final SocketIoServer server = new SocketIoServer(new EngineIoServer());
56 |
57 | server.namespace(Pattern.compile("^/foo[0-9]$"));
58 | assertFalse(server.checkNamespace("foo"));
59 | assertTrue(server.checkNamespace("foo1"));
60 | assertFalse(server.checkNamespace("foo10"));
61 | assertFalse(server.checkNamespace("foo1a"));
62 | assertFalse(server.checkNamespace("bar"));
63 |
64 | server.namespace(namespace -> {
65 | switch (namespace) {
66 | case "/bar":
67 | return true;
68 | case "/baz":
69 | return true;
70 | }
71 | return false;
72 | });
73 | assertTrue(server.checkNamespace("bar"));
74 | assertTrue(server.checkNamespace("baz"));
75 | assertFalse(server.checkNamespace("foobaz"));
76 | }
77 |
78 | @Test
79 | public void test_connection() {
80 | final EngineIoServer engineIoServer = new EngineIoServer();
81 | final SocketIoServer server = new SocketIoServer(engineIoServer);
82 | final SocketIoNamespace namespace = server.namespace("/");
83 |
84 | assertNotNull(namespace);
85 |
86 | final Emitter.Listener connectionListener = Mockito.mock(Emitter.Listener.class);
87 | namespace.on("connect", connectionListener);
88 | namespace.on("connection", connectionListener);
89 |
90 | final StubEngineIoWebSocket webSocket = new StubEngineIoWebSocket();
91 | engineIoServer.handleWebSocket(webSocket);
92 | webSocket.emitConnect(null);
93 |
94 | Mockito.verify(connectionListener, Mockito.times(2))
95 | .call(Mockito.any(SocketIoSocket.class));
96 | }
97 |
98 | @Test
99 | public void test_disconnect() {
100 | final EngineIoServer engineIoServer = new EngineIoServer();
101 | final SocketIoServer server = new SocketIoServer(engineIoServer);
102 | final SocketIoNamespace namespace = server.namespace("/");
103 |
104 | assertNotNull(namespace);
105 |
106 | final Emitter.Listener disconnectListener = Mockito.mock(Emitter.Listener.class);
107 |
108 | final Emitter.Listener connectionListener = Mockito.mock(Emitter.Listener.class);
109 | Mockito.doAnswer(invocation -> {
110 | final Object[] args = invocation.getArguments();
111 | final SocketIoSocket socket = (SocketIoSocket) args[0];
112 | socket.on("disconnect", disconnectListener);
113 | return null;
114 | }).when(connectionListener).call(Mockito.any());
115 | namespace.on("connect", connectionListener);
116 |
117 | final StubEngineIoWebSocket webSocket = new StubEngineIoWebSocket();
118 | engineIoServer.handleWebSocket(webSocket);
119 | webSocket.emitConnect(null);
120 |
121 | Mockito.verify(connectionListener, Mockito.times(1))
122 | .call(Mockito.any(SocketIoSocket.class));
123 |
124 | webSocket.emit("close", "client close", null);
125 |
126 | Mockito.verify(disconnectListener, Mockito.times(1))
127 | .call(Mockito.anyString());
128 | }
129 | }
--------------------------------------------------------------------------------
/socket.io-server/src/test/java/io/socket/socketio/server/StubEngineIoWebSocket.java:
--------------------------------------------------------------------------------
1 | package io.socket.socketio.server;
2 |
3 | import io.socket.engineio.server.EngineIoWebSocket;
4 | import io.socket.socketio.server.parser.IOParser;
5 | import io.socket.socketio.server.parser.Packet;
6 | import io.socket.socketio.server.parser.Parser;
7 |
8 | import java.util.HashMap;
9 | import java.util.List;
10 | import java.util.Map;
11 |
12 | public final class StubEngineIoWebSocket extends EngineIoWebSocket {
13 |
14 | private final Map mQuery = new HashMap<>();
15 |
16 | StubEngineIoWebSocket() {
17 | this(4);
18 | }
19 |
20 | StubEngineIoWebSocket(int version) {
21 | mQuery.put("EIO", Integer.toString(version, 10));
22 | }
23 |
24 | @Override
25 | public Map getQuery() {
26 | return mQuery;
27 | }
28 |
29 | @Override
30 | public Map> getConnectionHeaders() {
31 | return new HashMap<>();
32 | }
33 |
34 | @Override
35 | public void write(String message) {
36 | }
37 |
38 | @Override
39 | public void write(byte[] message) {
40 | }
41 |
42 | @Override
43 | public void close() {
44 | }
45 |
46 | public void emitConnect(Object data) {
47 | final Packet connectionPacket = new Packet<>();
48 | connectionPacket.type = Parser.CONNECT;
49 | connectionPacket.nsp = "/";
50 | connectionPacket.data = data;
51 | (new IOParser.Encoder()).encode(connectionPacket, encodedConnectionPacket -> {
52 | final io.socket.engineio.server.parser.Packet dataPacket = new io.socket.engineio.server.parser.Packet<>(io.socket.engineio.server.parser.Packet.MESSAGE);
53 | dataPacket.data = (String) encodedConnectionPacket[0];
54 |
55 | io.socket.engineio.server.parser.Parser.PROTOCOL_V4.encodePacket(dataPacket, true, encodedDataPacket -> {
56 | emit("message", encodedDataPacket);
57 | });
58 | });
59 | }
60 | }
61 |
--------------------------------------------------------------------------------