diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 439755f9..8531e775 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,24 +11,38 @@ jobs: runs-on: ubuntu-latest strategy: + fail-fast: false matrix: java: [7, 8, 11] steps: - uses: actions/checkout@v2 + + - name: Install Maven 3.8.x (instead of 3.9.x) + run: | + MAVEN_VERSION=3.8.9 + wget https://downloads.apache.org/maven/maven-3/$MAVEN_VERSION/binaries/apache-maven-$MAVEN_VERSION-bin.tar.gz + tar xzvf apache-maven-$MAVEN_VERSION-bin.tar.gz + sudo mv apache-maven-$MAVEN_VERSION /opt/maven + sudo rm -f /usr/bin/mvn # Remove existing symbolic link if it exists + sudo ln -s /opt/maven/bin/mvn /usr/bin/mvn # Create new symbolic link + - name: Setup java uses: actions/setup-java@v1 with: java-version: ${{ matrix.java }} + - name: Cache Maven packages - uses: actions/cache@v2 + uses: actions/cache@v4 with: - path: ~/.m2 + path: ~/.m2/repository key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} restore-keys: ${{ runner.os }}-m2 + - name: Setup Node.js uses: actions/setup-node@v1 with: node-version: 14.x + - name: Run the Maven verify phase run: mvn verify -Dgpg.skip=true diff --git a/History.md b/History.md index 18e4f07b..1366aaec 100644 --- a/History.md +++ b/History.md @@ -1,4 +1,38 @@ +2.1.2 / 2025-02-18 +================== + +### Bug Fixes + +- make acks thread safe ([4f45e3c](https://github.com/socketio/socket.io-client-java/commit/4f45e3c1271554da5b3457f447a6d6b060ef5ffd)) + + + +2.1.1 / 2024-07-10 +================== + +### Bug Fixes + +* discard acknowledgements upon disconnection ([54645ec](https://github.com/socketio/socket.io-client-java/commit/54645ece2cd132f3e305b80904e1fc38bd41c4f9)) +* make sendBuffer thread safe ([#769](https://github.com/socketio/socket.io-client-java/issues/769)) ([b00ae8e](https://github.com/socketio/socket.io-client-java/commit/b00ae8eec1ef0aa5094fca7fad918a437603eb12)) + + + +1.0.2 / 2022-07-11 +================== + +From the "1.x" branch. + +### Bug Fixes + +* ensure buffered events are sent in order ([8bd35da](https://github.com/socketio/socket.io-client-java/commit/8bd35da19c1314318fe122876d22e30ae3673ff9)) +* ensure randomizationFactor is always between 0 and 1 ([cb966d5](https://github.com/socketio/socket.io-client-java/commit/cb966d5a64790c0584ad97cf55c205cae8bd1287)) +* ensure the payload format is valid ([8664499](https://github.com/socketio/socket.io-client-java/commit/8664499b6f31154f49783531f778dac5387b766b)) +* fix usage with ws:// scheme ([e57160a](https://github.com/socketio/socket.io-client-java/commit/e57160a00ca1fbb38396effdbc87eb10d6759a51)) +* increase the readTimeout value of the default OkHttpClient ([2d87497](https://github.com/socketio/engine.io-client-java/commit/2d874971c2428a7a444b3a33afe66aedcdce3a96)) (from `engine.io-client`) + + + 2.1.0 / 2022-07-10 ================== diff --git a/pom.xml b/pom.xml index e6ff6051..4636cb1b 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 io.socket socket.io-client - 2.1.0 + 2.1.3-SNAPSHOT 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.1.0 + HEAD diff --git a/src/main/java/io/socket/client/Manager.java b/src/main/java/io/socket/client/Manager.java index a3c5f19e..04198998 100644 --- a/src/main/java/io/socket/client/Manager.java +++ b/src/main/java/io/socket/client/Manager.java @@ -72,20 +72,20 @@ public class Manager extends Emitter { private long _reconnectionDelay; private long _reconnectionDelayMax; private double _randomizationFactor; - private Backoff backoff; + private final Backoff backoff; private long _timeout; - private URI uri; - private List packetBuffer; - private Queue subs; - private Options opts; + private final URI uri; + private final List packetBuffer = new ArrayList<>(); + private final Queue subs = new LinkedList<>();; + private final Options opts; /*package*/ io.socket.engineio.client.Socket engine; - private Parser.Encoder encoder; - private Parser.Decoder decoder; + private final Parser.Encoder encoder; + private final Parser.Decoder decoder; /** * This HashMap can be accessed from outside of EventThread. */ - /*package*/ ConcurrentHashMap nsps; + /*package*/ final Map nsps = new ConcurrentHashMap<>(); public Manager() { @@ -114,8 +114,6 @@ public Manager(URI uri, Options opts) { opts.callFactory = defaultCallFactory; } this.opts = opts; - 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 +127,6 @@ public Manager(URI uri, Options opts) { this.readyState = ReadyState.CLOSED; this.uri = uri; this.encoding = false; - this.packetBuffer = new ArrayList<>(); this.encoder = opts.encoder != null ? opts.encoder : new IOParser.Encoder(); this.decoder = opts.decoder != null ? opts.decoder : new IOParser.Decoder(); } diff --git a/src/main/java/io/socket/client/Socket.java b/src/main/java/io/socket/client/Socket.java index 49bc3784..2227a30d 100644 --- a/src/main/java/io/socket/client/Socket.java +++ b/src/main/java/io/socket/client/Socket.java @@ -9,6 +9,7 @@ import org.json.JSONObject; import java.util.*; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.logging.Level; import java.util.logging.Logger; @@ -56,23 +57,21 @@ public class Socket extends Emitter { private volatile boolean connected; private int ids; - private String nsp; - private Manager io; - private Map auth; - private Map acks = new HashMap<>(); + private final String nsp; + private final Manager io; + private final Map auth; + private final Map acks = new ConcurrentHashMap<>(); private Queue subs; - private final Queue> receiveBuffer = new LinkedList<>(); - private final Queue> sendBuffer = new LinkedList<>(); + private final Queue> receiveBuffer = new ConcurrentLinkedQueue<>(); + private final Queue> sendBuffer = new ConcurrentLinkedQueue<>(); - private ConcurrentLinkedQueue onAnyIncomingListeners = new ConcurrentLinkedQueue<>(); - private ConcurrentLinkedQueue onAnyOutgoingListeners = new ConcurrentLinkedQueue<>(); + private final ConcurrentLinkedQueue onAnyIncomingListeners = new ConcurrentLinkedQueue<>(); + private final ConcurrentLinkedQueue onAnyOutgoingListeners = new ConcurrentLinkedQueue<>(); public Socket(Manager io, String nsp, Manager.Options opts) { this.io = io; this.nsp = nsp; - if (opts != null) { - this.auth = opts.auth; - } + this.auth = opts != null ? opts.auth : null; } private void subEvents() { @@ -283,6 +282,21 @@ private void onclose(String reason) { this.connected = false; this.id = null; super.emit(EVENT_DISCONNECT, reason); + this.clearAcks(); + } + + /** + * Clears the acknowledgement handlers upon disconnection, since the client will never receive an acknowledgement from + * the server. + */ + private void clearAcks() { + for (Ack ack : this.acks.values()) { + if (ack instanceof AckWithTimeout) { + ((AckWithTimeout) ack).onTimeout(); + } + // note: basic Ack objects have no way to report an error, so they are simply ignored here + } + this.acks.clear(); } private void onpacket(Packet packet) { @@ -301,13 +315,7 @@ private void onpacket(Packet packet) { break; } - case Parser.EVENT: { - @SuppressWarnings("unchecked") - Packet p = (Packet) packet; - this.onevent(p); - break; - } - + case Parser.EVENT: case Parser.BINARY_EVENT: { @SuppressWarnings("unchecked") Packet p = (Packet) packet; @@ -315,13 +323,7 @@ private void onpacket(Packet packet) { break; } - case Parser.ACK: { - @SuppressWarnings("unchecked") - Packet p = (Packet) packet; - this.onack(p); - break; - } - + case Parser.ACK: case Parser.BINARY_ACK: { @SuppressWarnings("unchecked") Packet p = (Packet) packet; @@ -448,12 +450,6 @@ private void destroy() { this.subs = null; } - for (Ack ack : acks.values()) { - if (ack instanceof AckWithTimeout) { - ((AckWithTimeout) ack).cancelTimer(); - } - } - this.io.destroy(); } diff --git a/src/site/markdown/android.md b/src/site/markdown/android.md index a33b2f92..be5c7906 100644 --- a/src/site/markdown/android.md +++ b/src/site/markdown/android.md @@ -57,3 +57,27 @@ Starting with Android 9 (API level 28) you need to explicitly allow cleartext tr ``` Reference: https://developer.android.com/training/articles/security-config + +## How to run unit tests in Android Studio? + +Local unit tests are tests that run on your machine's local Java Virtual Machine. + +Reference: https://developer.android.com/studio/test/test-in-android-studio + +Since they run on your machine, the JSON library must be manually included for the tests (because it is not provided by the Android runtime): + +`build.gradle` + +``` +dependencies { + implementation ('io.socket:socket.io-client:2.0.1') { + exclude group: 'org.json', module: 'json' + } + + testImplementation 'org.json:json:20090211' + + ... +} +``` + +Note: we use this ancient version of `org.json` because it is compatible with the one bundled in Android. diff --git a/src/site/markdown/changelog.md b/src/site/markdown/changelog.md index d197c228..e671c86a 100644 --- a/src/site/markdown/changelog.md +++ b/src/site/markdown/changelog.md @@ -1,3 +1,50 @@ +# History + +| Version | Release date | +|--------------------------------------------------------------------------------------------------------------|---------------| +| [2.1.2](#211-2025-02-18) | February 2025 | +| [2.1.1](#211-2024-07-10) | July 2024 | +| [1.0.2](#102-2022-07-11) (from the [1.x](https://github.com/socketio/socket.io-client-java/tree/1.x) branch) | July 2022 | +| [2.1.0](#210-2022-07-10) | July 2022 | +| [2.0.1](#201-2021-04-27) | April 2021 | +| [2.0.0](#200-2020-12-14) | December 2020 | +| [1.0.1](#101-2020-12-10) | December 2020 | + + +# Release notes + +## [2.1.2](https://github.com/socketio/socket.io-client-java/compare/socket.io-client-2.1.1...socket.io-client-2.1.2) (2025-02-18) + + +### Bug Fixes + +* make acks thread safe ([4f45e3c](https://github.com/socketio/socket.io-client-java/commit/4f45e3c1271554da5b3457f447a6d6b060ef5ffd)) + + + +## [2.1.1](https://github.com/socketio/socket.io-client-java/compare/socket.io-client-2.1.0...socket.io-client-2.1.1) (2024-07-10) + + +### Bug Fixes + +* discard acknowledgements upon disconnection ([54645ec](https://github.com/socketio/socket.io-client-java/commit/54645ece2cd132f3e305b80904e1fc38bd41c4f9)) +* make sendBuffer thread safe ([#769](https://github.com/socketio/socket.io-client-java/issues/769)) ([b00ae8e](https://github.com/socketio/socket.io-client-java/commit/b00ae8eec1ef0aa5094fca7fad918a437603eb12)) + + + +## [1.0.2](https://github.com/socketio/socket.io-client-java/compare/socket.io-client-1.0.1...socket.io-client-1.0.2) (2022-07-11) + +From the "1.x" branch. + +### Bug Fixes + +* ensure buffered events are sent in order ([8bd35da](https://github.com/socketio/socket.io-client-java/commit/8bd35da19c1314318fe122876d22e30ae3673ff9)) +* ensure randomizationFactor is always between 0 and 1 ([cb966d5](https://github.com/socketio/socket.io-client-java/commit/cb966d5a64790c0584ad97cf55c205cae8bd1287)) +* ensure the payload format is valid ([8664499](https://github.com/socketio/socket.io-client-java/commit/8664499b6f31154f49783531f778dac5387b766b)) +* fix usage with ws:// scheme ([e57160a](https://github.com/socketio/socket.io-client-java/commit/e57160a00ca1fbb38396effdbc87eb10d6759a51)) +* increase the readTimeout value of the default OkHttpClient ([2d87497](https://github.com/socketio/engine.io-client-java/commit/2d874971c2428a7a444b3a33afe66aedcdce3a96)) (from `engine.io-client`) + + ## [2.1.0](https://github.com/socketio/socket.io-client-java/compare/socket.io-client-2.0.1...socket.io-client-2.1.0) (2022-07-10) diff --git a/src/site/markdown/installation.md b/src/site/markdown/installation.md index a14593a8..de61a1e7 100644 --- a/src/site/markdown/installation.md +++ b/src/site/markdown/installation.md @@ -17,7 +17,7 @@ Add the following dependency to your `pom.xml`. io.socket socket.io-client - 2.1.0 + 2.1.1 ``` @@ -26,7 +26,7 @@ Add the following dependency to your `pom.xml`. Add it as a gradle dependency for Android Studio, in `build.gradle`: ```groovy -implementation ('io.socket:socket.io-client:2.1.0') { +implementation ('io.socket:socket.io-client:2.1.1') { // excluding org.json which is provided by Android exclude group: 'org.json', module: 'json' } @@ -36,8 +36,10 @@ implementation ('io.socket:socket.io-client:2.1.0') { | `socket.io-client` | `engine.io-client` | `okhttp` | |-----------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------| +| `2.1.1` ([diff](https://github.com/socketio/socket.io-client-java/compare/socket.io-client-2.1.0...socket.io-client-2.1.1)) | `2.1.0` | `3.12.12` | | `2.1.0` ([diff](https://github.com/socketio/socket.io-client-java/compare/socket.io-client-2.0.1...socket.io-client-2.1.0)) | `2.1.0` ([diff](https://github.com/socketio/engine.io-client-java/compare/engine.io-client-2.0.0...engine.io-client-2.1.0)) | `3.12.12` | | `2.0.1` ([diff](https://github.com/socketio/socket.io-client-java/compare/socket.io-client-2.0.0...socket.io-client-2.0.1)) | `2.0.0` | `3.12.12` | | `2.0.0` ([diff](https://github.com/socketio/socket.io-client-java/compare/socket.io-client-1.0.1...socket.io-client-2.0.0)) | `2.0.0` ([diff](https://github.com/socketio/engine.io-client-java/compare/engine.io-client-1.0.1...engine.io-client-2.0.0)) | `3.12.12` | +| `1.0.2` ([diff](https://github.com/socketio/socket.io-client-java/compare/socket.io-client-1.0.1...socket.io-client-1.0.2)) | `1.0.2` ([diff](https://github.com/socketio/engine.io-client-java/compare/engine.io-client-1.0.1...engine.io-client-1.0.2)) | `3.12.12` | | `1.0.1` ([diff](https://github.com/socketio/socket.io-client-java/compare/socket.io-client-1.0.0...socket.io-client-1.0.1)) | `1.0.1` ([diff](https://github.com/socketio/engine.io-client-java/compare/engine.io-client-1.0.0...engine.io-client-1.0.1)) | `3.12.12` ([changelog](https://square.github.io/okhttp/changelogs/changelog_3x/#version-31212)) | | `1.0.0` | `1.0.0` | `3.8.1` | diff --git a/src/test/java/io/socket/parser/ParserTest.java b/src/test/java/io/socket/parser/ParserTest.java index 17d48863..8b239cb8 100644 --- a/src/test/java/io/socket/parser/ParserTest.java +++ b/src/test/java/io/socket/parser/ParserTest.java @@ -1,5 +1,8 @@ package io.socket.parser; +import java.util.logging.Level; +import java.util.logging.Logger; + import org.json.JSONArray; import org.json.JSONException; import org.junit.Test; @@ -49,6 +52,9 @@ public void encodeAck() throws JSONException { @Test public void decodeInError() throws JSONException { + Logger logger = Logger.getLogger(IOParser.class.getName()); + Level tmpLevel = logger.getLevel(); + logger.setLevel(Level.SEVERE); // Random string Helpers.testDecodeError("asdf"); // Unknown type @@ -62,9 +68,10 @@ public void decodeInError() throws JSONException { // event non numeric id Helpers.testDecodeError(Parser.EVENT + "2sd"); // event with invalid json data - Helpers.testDecodeError(Parser.EVENT + "2[\"a\",1,{asdf}]"); Helpers.testDecodeError(Parser.EVENT + "2{}"); Helpers.testDecodeError(Parser.EVENT + "2[]"); Helpers.testDecodeError(Parser.EVENT + "2[null]"); + Helpers.testDecodeError(Parser.EVENT + "2[\"a\",1,{asdf}]"); + logger.setLevel(tmpLevel); } }