diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
new file mode 100644
index 00000000..7bbbc83a
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -0,0 +1,63 @@
+---
+name: Bug report
+about: Create a report to help us improve
+title: ''
+labels: 'bug'
+assignees: ''
+
+---
+
+**Describe the bug**
+A clear and concise description of what the bug is.
+
+**To Reproduce**
+
+Please fill the following code example:
+
+Socket.IO server version: `x.y.z`
+
+*Server*
+
+```js
+import { Server } from "socket.io";
+
+const io = new Server(8080);
+
+io.on("connection", (socket) => {
+ // ...
+});
+```
+
+Socket.IO java client version: `x.y.z`
+
+*Client*
+
+```java
+public class MyApplication {
+ public static void main(String[] args) throws URISyntaxException {
+ IO.Options options = IO.Options.builder()
+ .build();
+
+ Socket socket = IO.socket("http://localhost:8080", options);
+
+ socket.on(Socket.EVENT_CONNECT, new Emitter.Listener() {
+ @Override
+ public void call(Object... args) {
+ System.out.println("connect");
+ }
+ });
+
+ socket.open();
+ }
+}
+```
+
+**Expected behavior**
+A clear and concise description of what you expected to happen.
+
+**Platform:**
+ - Device: [e.g. Samsung S8]
+ - OS: [e.g. Android 9.2]
+
+**Additional context**
+Add any other context about the problem here.
\ No newline at end of file
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
new file mode 100644
index 00000000..36014cde
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -0,0 +1,20 @@
+---
+name: Feature request
+about: Suggest an idea for this project
+title: ''
+labels: 'enhancement'
+assignees: ''
+
+---
+
+**Is your feature request related to a problem? Please describe.**
+A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
+
+**Describe the solution you'd like**
+A clear and concise description of what you want to happen.
+
+**Describe alternatives you've considered**
+A clear and concise description of any alternative solutions or features you've considered.
+
+**Additional context**
+Add any other context or screenshots about the feature request here.
diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md
new file mode 100644
index 00000000..53c39215
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/question.md
@@ -0,0 +1,9 @@
+---
+name: Ask a Question
+about: Ask the community for help
+title: ''
+labels: 'question'
+assignees: ''
+
+---
+
diff --git a/History.md b/History.md
index a393673e..02f66f43 100644
--- a/History.md
+++ b/History.md
@@ -1,4 +1,15 @@
+2.0.1 / 2021-04-27
+==================
+
+### Bug Fixes
+
+* fix usage with ws:// scheme ([67fd5f3](https://github.com/socketio/socket.io-client-java/commit/67fd5f34a31c63f7884f82ab39386ad343527590))
+* ensure buffered events are sent in order ([4885e7d](https://github.com/socketio/socket.io-client-java/commit/4885e7d59fad78285448694cb5681e8a9ce809ef))
+* ensure the payload format is valid ([e8ffe9d](https://github.com/socketio/socket.io-client-java/commit/e8ffe9d1383736f6a21090ab959a2f4fa5a41284))
+* emit a CONNECT_ERROR event upon connection failure ([d324e7f](https://github.com/socketio/socket.io-client-java/commit/d324e7f396a444ddd556c3d70a85a28eefb1e02b))
+
+
2.0.0 / 2020-12-15
==================
diff --git a/Makefile b/Makefile
index cc752f8b..d0927070 100644
--- a/Makefile
+++ b/Makefile
@@ -2,6 +2,6 @@ help: ## print this message
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}'
build-site: ## build the site
- mvn javadoc:javadoc site -DskipTests
+ mvn clean javadoc:javadoc site -DskipTests
.PHONY: build-site
diff --git a/README.md b/README.md
index 41a4705a..28c73c09 100644
--- a/README.md
+++ b/README.md
@@ -2,9 +2,7 @@
[](https://github.com/socketio/socket.io-client-java/actions)
-This is the Socket.IO v1.x and v2.x Client Library for Java, which is simply ported from the [JavaScript client](https://github.com/socketio/socket.io-client).
-
-**Does not yet support Socket:IO v3.x, use v2.x instead!**
+This is the Socket.IO Client Library for Java, which is simply ported from the [JavaScript client](https://github.com/socketio/socket.io-client).
See also:
@@ -14,11 +12,7 @@ See also:
## Table of content
- [Compatibility](#compatibility)
-- [Installation](#installation)
- - [Maven](#maven)
- - [Gradle](#gradle)
-- [Usage](#usage)
-- [Features](#features)
+- [Documentation](#documentation)
- [License](#license)
## Compatibility
@@ -27,182 +21,13 @@ See also:
| -------------- | ---------------- |
| 0.9.x | 1.x |
| 1.x | 2.x |
-| 2.x | 3.x |
-
-## Installation
-The latest artifact is available on Maven Central.
-
-### Maven
-Add the following dependency to your `pom.xml`.
-
-```xml
-
-
- io.socket
- socket.io-client
- 2.0.0
-
-
-```
-
-### Gradle
-Add it as a gradle dependency for Android Studio, in `build.gradle`:
-
-```groovy
-compile ('io.socket:socket.io-client:2.0.0') {
- // excluding org.json which is provided by Android
- exclude group: 'org.json', module: 'json'
-}
-```
-
-## Usage
-Socket.IO-client Java has almost the same api and features with the original JS client. You use `IO#socket` to initialize `Socket`:
-
-```java
-import io.socket.client.IO;
-import io.socket.client.Socket;
-...
-
-Socket socket = IO.socket("http://localhost");
-socket.on(Socket.EVENT_CONNECT, new Emitter.Listener() {
-
- @Override
- public void call(Object... args) {
- socket.emit("foo", "hi");
- socket.disconnect();
- }
-
-}).on("event", new Emitter.Listener() {
-
- @Override
- public void call(Object... args) {}
-
-}).on(Socket.EVENT_DISCONNECT, new Emitter.Listener() {
-
- @Override
- public void call(Object... args) {}
-
-});
-socket.connect();
-```
-
-This Library uses [org.json](https://github.com/stleary/JSON-java) to parse and compose JSON strings:
-
-```java
-// Sending an object
-JSONObject obj = new JSONObject();
-obj.put("hello", "server");
-obj.put("binary", new byte[42]);
-socket.emit("foo", obj);
-
-// Receiving an object
-socket.on("foo", new Emitter.Listener() {
- @Override
- public void call(Object... args) {
- JSONObject obj = (JSONObject)args[0];
- }
-});
-```
-
-Options are supplied as follows:
-
-```java
-IO.Options opts = new IO.Options();
-opts.forceNew = true;
-opts.reconnection = false;
-
-socket = IO.socket("http://localhost", opts);
-```
-
-You can supply query parameters with the `query` option. NB: if you don't want to reuse a cached socket instance when the query parameter changes, you should use the `forceNew` option, the use case might be if your app allows for a user to logout, and a new user to login again:
-
-```java
-IO.Options opts = new IO.Options();
-opts.forceNew = true;
-opts.query = "auth_token=" + authToken;
-Socket socket = IO.socket("http://localhost", opts);
-```
-
-You can get a callback with `Ack` when the server received a message:
-
-```java
-socket.emit("foo", "woot", new Ack() {
- @Override
- public void call(Object... args) {}
-});
-```
-
-And vice versa:
-
-```java
-// ack from client to server
-socket.on("foo", new Emitter.Listener() {
- @Override
- public void call(Object... args) {
- Ack ack = (Ack) args[args.length - 1];
- ack.call();
- }
-});
-```
-
-SSL (HTTPS, WSS) settings:
-
-```java
-OkHttpClient okHttpClient = new OkHttpClient.Builder()
- .hostnameVerifier(myHostnameVerifier)
- .sslSocketFactory(mySSLContext.getSocketFactory(), myX509TrustManager)
- .build();
-
-// default settings for all sockets
-IO.setDefaultOkHttpWebSocketFactory(okHttpClient);
-IO.setDefaultOkHttpCallFactory(okHttpClient);
-
-// set as an option
-opts = new IO.Options();
-opts.callFactory = okHttpClient;
-opts.webSocketFactory = okHttpClient;
-socket = IO.socket("https://localhost", opts);
-```
-
-See the Javadoc for more details.
-
-http://socketio.github.io/socket.io-client-java/apidocs/
-
-### Transports and HTTP Headers
-You can access transports and their HTTP headers as follows.
-
-```java
-// Called upon transport creation.
-socket.io().on(Manager.EVENT_TRANSPORT, new Emitter.Listener() {
- @Override
- public void call(Object... args) {
- Transport transport = (Transport)args[0];
+| 2.x | 3.x / 4.x |
- transport.on(Transport.EVENT_REQUEST_HEADERS, new Emitter.Listener() {
- @Override
- public void call(Object... args) {
- @SuppressWarnings("unchecked")
- Map> headers = (Map>)args[0];
- // modify request headers
- headers.put("Cookie", Arrays.asList("foo=1;"));
- }
- });
+## Documentation
- transport.on(Transport.EVENT_RESPONSE_HEADERS, new Emitter.Listener() {
- @Override
- public void call(Object... args) {
- @SuppressWarnings("unchecked")
- Map> headers = (Map>)args[0];
- // access response headers
- String cookie = headers.get("Set-Cookie").get(0);
- }
- });
- }
-});
-```
+The documentation can be found [here](https://socketio.github.io/socket.io-client-java/installation.html).
-## Features
-This library supports all of the features the JS client does, including events, options and upgrading transport. Android is fully supported.
+The source of this documentation is in the `src/site/` directory of the repository. Pull requests are welcome!
## License
diff --git a/pom.xml b/pom.xml
index 7da6dcdd..66b4d2f2 100644
--- a/pom.xml
+++ b/pom.xml
@@ -2,7 +2,7 @@
4.0.0
io.socket
socket.io-client
- 2.0.0
+ 2.0.1
jar
socket.io-client
Socket.IO Client Library for Java
@@ -30,7 +30,7 @@
https://github.com/socketio/socket.io-client-java
scm:git:https://github.com/socketio/socket.io-client-java.git
scm:git:https://github.com/socketio/socket.io-client-java.git
- socket.io-client-2.0.0
+ socket.io-client-2.0.1
diff --git a/src/main/java/io/socket/client/Ack.java b/src/main/java/io/socket/client/Ack.java
index 8bd6a1e8..592838cb 100644
--- a/src/main/java/io/socket/client/Ack.java
+++ b/src/main/java/io/socket/client/Ack.java
@@ -5,7 +5,7 @@
*/
public interface Ack {
- public void call(Object... args);
+ void call(Object... args);
}
diff --git a/src/main/java/io/socket/client/IO.java b/src/main/java/io/socket/client/IO.java
index e307b6e0..1da0c197 100644
--- a/src/main/java/io/socket/client/IO.java
+++ b/src/main/java/io/socket/client/IO.java
@@ -7,7 +7,6 @@
import java.net.URI;
import java.net.URISyntaxException;
-import java.net.URL;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -17,7 +16,7 @@ public class IO {
private static final Logger logger = Logger.getLogger(IO.class.getName());
- private static final ConcurrentHashMap managers = new ConcurrentHashMap();
+ private static final ConcurrentHashMap managers = new ConcurrentHashMap<>();
/**
* Protocol version.
@@ -58,21 +57,16 @@ public static Socket socket(URI uri, Options opts) {
opts = new Options();
}
- URL parsed = Url.parse(uri);
- URI source;
- try {
- source = parsed.toURI();
- } catch (URISyntaxException e) {
- throw new RuntimeException(e);
- }
- String id = Url.extractId(parsed);
- String path = parsed.getPath();
+ Url.ParsedURI parsed = Url.parse(uri);
+ URI source = parsed.uri;
+ String id = parsed.id;
+
boolean sameNamespace = managers.containsKey(id)
- && managers.get(id).nsps.containsKey(path);
+ && managers.get(id).nsps.containsKey(source.getPath());
boolean newConnection = opts.forceNew || !opts.multiplex || sameNamespace;
Manager io;
- String query = parsed.getQuery();
+ String query = source.getQuery();
if (query != null && (opts.query == null || opts.query.isEmpty())) {
opts.query = query;
}
@@ -92,7 +86,7 @@ public static Socket socket(URI uri, Options opts) {
io = managers.get(id);
}
- return io.socket(parsed.getPath(), opts);
+ return io.socket(source.getPath(), opts);
}
diff --git a/src/main/java/io/socket/client/Manager.java b/src/main/java/io/socket/client/Manager.java
index 67c2f704..a3c5f19e 100644
--- a/src/main/java/io/socket/client/Manager.java
+++ b/src/main/java/io/socket/client/Manager.java
@@ -114,8 +114,8 @@ public Manager(URI uri, Options opts) {
opts.callFactory = defaultCallFactory;
}
this.opts = opts;
- this.nsps = new ConcurrentHashMap();
- this.subs = new LinkedList();
+ this.nsps = new ConcurrentHashMap<>();
+ this.subs = new LinkedList<>();
this.reconnection(opts.reconnection);
this.reconnectionAttempts(opts.reconnectionAttempts != 0 ? opts.reconnectionAttempts : Integer.MAX_VALUE);
this.reconnectionDelay(opts.reconnectionDelay != 0 ? opts.reconnectionDelay : 1000);
@@ -129,7 +129,7 @@ public Manager(URI uri, Options opts) {
this.readyState = ReadyState.CLOSED;
this.uri = uri;
this.encoding = false;
- this.packetBuffer = new ArrayList();
+ this.packetBuffer = new ArrayList<>();
this.encoder = opts.encoder != null ? opts.encoder : new IOParser.Encoder();
this.decoder = opts.decoder != null ? opts.decoder : new IOParser.Decoder();
}
@@ -271,23 +271,28 @@ public void call(Object... objects) {
}
});
- if (Manager.this._timeout >= 0) {
- final long timeout = Manager.this._timeout;
+ final long timeout = Manager.this._timeout;
+ final Runnable onTimeout = new Runnable() {
+ @Override
+ public void run() {
+ logger.fine(String.format("connect attempt timed out after %d", timeout));
+ openSub.destroy();
+ socket.close();
+ socket.emit(Engine.EVENT_ERROR, new SocketIOException("timeout"));
+ }
+ };
+
+ if (timeout == 0) {
+ EventThread.exec(onTimeout);
+ return;
+ } else if (Manager.this._timeout > 0) {
logger.fine(String.format("connection attempt will timeout after %d", timeout));
final Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
- EventThread.exec(new Runnable() {
- @Override
- public void run() {
- logger.fine(String.format("connect attempt timed out after %d", timeout));
- openSub.destroy();
- socket.close();
- socket.emit(Engine.EVENT_ERROR, new SocketIOException("timeout"));
- }
- });
+ EventThread.exec(onTimeout);
}
}, timeout);
@@ -321,10 +326,14 @@ private void onopen() {
@Override
public void call(Object... objects) {
Object data = objects[0];
- if (data instanceof String) {
- Manager.this.ondata((String)data);
- } else if (data instanceof byte[]) {
- Manager.this.ondata((byte[])data);
+ try {
+ if (data instanceof String) {
+ Manager.this.decoder.add((String) data);
+ } else if (data instanceof byte[]) {
+ Manager.this.decoder.add((byte[]) data);
+ }
+ } catch (DecodingException e) {
+ logger.fine("error while decoding the packet: " + e.getMessage());
}
}
}));
@@ -348,22 +357,6 @@ public void call (Packet packet) {
});
}
- private void ondata(String data) {
- try {
- this.decoder.add(data);
- } catch (DecodingException e) {
- this.onerror(e);
- }
- }
-
- private void ondata(byte[] data) {
- try {
- this.decoder.add(data);
- } catch (DecodingException e) {
- this.onerror(e);
- }
- }
-
private void ondecoded(Packet packet) {
this.emit(EVENT_PACKET, packet);
}
@@ -550,9 +543,9 @@ private void onreconnect() {
}
- public static interface OpenCallback {
+ public interface OpenCallback {
- public void call(Exception err);
+ void call(Exception err);
}
diff --git a/src/main/java/io/socket/client/On.java b/src/main/java/io/socket/client/On.java
index b962f131..26b46f34 100644
--- a/src/main/java/io/socket/client/On.java
+++ b/src/main/java/io/socket/client/On.java
@@ -16,8 +16,8 @@ public void destroy() {
};
}
- public static interface Handle {
+ public interface Handle {
- public void destroy();
+ void destroy();
}
}
diff --git a/src/main/java/io/socket/client/Socket.java b/src/main/java/io/socket/client/Socket.java
index 203c61f4..05feff39 100644
--- a/src/main/java/io/socket/client/Socket.java
+++ b/src/main/java/io/socket/client/Socket.java
@@ -58,10 +58,10 @@ public class Socket extends Emitter {
private String nsp;
private Manager io;
private Map auth;
- private Map acks = new HashMap();
+ private Map acks = new HashMap<>();
private Queue subs;
- private final Queue> receiveBuffer = new LinkedList>();
- private final Queue> sendBuffer = new LinkedList>();
+ private final Queue> receiveBuffer = new LinkedList<>();
+ private final Queue> sendBuffer = new LinkedList<>();
public Socket(Manager io, String nsp, Manager.Options opts) {
this.io = io;
@@ -91,7 +91,9 @@ public void call(Object... args) {
add(On.on(io, Manager.EVENT_ERROR, new Listener() {
@Override
public void call(Object... args) {
- Socket.super.emit(EVENT_CONNECT_ERROR, args[0]);
+ if (!Socket.this.connected) {
+ Socket.super.emit(EVENT_CONNECT_ERROR, args[0]);
+ }
}
}));
add(On.on(io, Manager.EVENT_CLOSE, new Listener() {
@@ -205,7 +207,7 @@ public void run() {
}
}
- Packet packet = new Packet(Parser.EVENT, jsonArgs);
+ Packet packet = new Packet<>(Parser.EVENT, jsonArgs);
if (ack != null) {
logger.fine(String.format("emitting packet with ack id %d", ids));
@@ -302,7 +304,7 @@ private void onpacket(Packet> packet) {
}
private void onevent(Packet packet) {
- List