From fa650b73aec9d44d4d734a0f8e77f2e29316f77b Mon Sep 17 00:00:00 2001 From: Matt Hsieh Date: Sat, 20 Dec 2014 15:32:32 +0800 Subject: [PATCH 01/10] MoChat current used modifications --- .../java/com/github/nkzawa/engineio/client/Socket.java | 2 ++ .../nkzawa/engineio/client/transports/PollingXHR.java | 10 +++++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/github/nkzawa/engineio/client/Socket.java b/src/main/java/com/github/nkzawa/engineio/client/Socket.java index e7aaae29..1d3cb0b2 100644 --- a/src/main/java/com/github/nkzawa/engineio/client/Socket.java +++ b/src/main/java/com/github/nkzawa/engineio/client/Socket.java @@ -672,6 +672,8 @@ public void run() { Socket.this.onClose("forced close"); logger.fine("socket closing - telling transport to close"); Socket.this.transport.close(); + // added by matt + Socket.this.heartbeatScheduler.shutdownNow(); } } diff --git a/src/main/java/com/github/nkzawa/engineio/client/transports/PollingXHR.java b/src/main/java/com/github/nkzawa/engineio/client/transports/PollingXHR.java index 8e54ec4b..0e34ddc1 100644 --- a/src/main/java/com/github/nkzawa/engineio/client/transports/PollingXHR.java +++ b/src/main/java/com/github/nkzawa/engineio/client/transports/PollingXHR.java @@ -184,6 +184,7 @@ public void create() { for (Map.Entry header : headers.entrySet()) { xhr.setRequestProperty(header.getKey(), header.getValue()); } + xhr.setRequestProperty("Connection", "Close"); logger.fine(String.format("sending xhr with url %s | data %s", this.uri, this.data)); xhrService.submit(new Runnable() { @@ -201,9 +202,12 @@ public void run() { } Map headers = new TreeMap(String.CASE_INSENSITIVE_ORDER); - for (String key : xhr.getHeaderFields().keySet()) { - if (key == null) continue; - headers.put(key, xhr.getHeaderField(key)); + Map> xhrHeaderFields = xhr.getHeaderFields(); + if(xhrHeaderFields != null) { + for (String key : xhrHeaderFields.keySet()) { + if (key == null) continue; + headers.put(key, xhr.getHeaderField(key)); + } } self.onResponseHeaders(headers); From e970d14fa35c3d6bc104e18b0d104da102ab2cbf Mon Sep 17 00:00:00 2001 From: Matt Hsieh Date: Sun, 21 Dec 2014 02:36:56 +0800 Subject: [PATCH 02/10] Add build.gradle --- build.gradle | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 build.gradle diff --git a/build.gradle b/build.gradle new file mode 100644 index 00000000..1ce65faf --- /dev/null +++ b/build.gradle @@ -0,0 +1,19 @@ +/* + * This build file was auto generated by running the Gradle 'init' task + * by 'Matt' at '2014/12/21 上午 2:00' with Gradle 2.0 + * + * This generated file contains a sample Java project to get you started. + * For more details take a look at the Java Quickstart chapter in the Gradle + * user guide available at http://gradle.org/docs/2.0/userguide/tutorial_java_projects.html + */ + +apply plugin: 'java' + +repositories { + mavenCentral() +} + +dependencies { + compile 'org.java-websocket:Java-WebSocket:1.3.0' + compile 'org.json:json:20090211' +} From d63f0201f32abd42b312d1c4b50eef429ad342b0 Mon Sep 17 00:00:00 2001 From: Matt Hsieh Date: Thu, 25 Dec 2014 19:05:48 +0800 Subject: [PATCH 03/10] Remove one line added by me --- src/main/java/com/github/nkzawa/engineio/client/Socket.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/com/github/nkzawa/engineio/client/Socket.java b/src/main/java/com/github/nkzawa/engineio/client/Socket.java index 3ae75a30..a70e94f6 100644 --- a/src/main/java/com/github/nkzawa/engineio/client/Socket.java +++ b/src/main/java/com/github/nkzawa/engineio/client/Socket.java @@ -701,8 +701,6 @@ public void run() { self.onClose("forced close"); logger.fine("socket closing - telling transport to close"); self.transport.close(); - // added by matt - self.heartbeatScheduler.shutdownNow(); } }; From da0665f89e79fbaf3a0db0b0ccb5ab36f36e24a2 Mon Sep 17 00:00:00 2001 From: Matt Hsieh Date: Mon, 19 Jan 2015 13:42:54 +0800 Subject: [PATCH 04/10] Fix: Closing socket before open completed will cause disconnect incorrectly --- src/main/java/com/github/nkzawa/engineio/client/Socket.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/github/nkzawa/engineio/client/Socket.java b/src/main/java/com/github/nkzawa/engineio/client/Socket.java index a70e94f6..1ccc7d1f 100644 --- a/src/main/java/com/github/nkzawa/engineio/client/Socket.java +++ b/src/main/java/com/github/nkzawa/engineio/client/Socket.java @@ -484,6 +484,7 @@ private void onPacket(Packet packet) { } } else { logger.fine(String.format("packet received with socket readyState '%s'", this.readyState)); + this.flush(); // added by Matt } } From e287900d59a7f8102593c089e73c50693c5404b4 Mon Sep 17 00:00:00 2001 From: Matt Hsieh Date: Sat, 9 Jul 2016 16:30:40 +0800 Subject: [PATCH 05/10] Update build.gradle --- build.gradle | 3 +++ 1 file changed, 3 insertions(+) diff --git a/build.gradle b/build.gradle index 7dcb9993..4a2f9136 100644 --- a/build.gradle +++ b/build.gradle @@ -17,3 +17,6 @@ dependencies { compile 'com.squareup.okhttp:okhttp-ws:2.4.0' compile 'org.json:json:20090211' } + +targetCompatibility = '1.7' +sourceCompatibility = '1.7' \ No newline at end of file From 84f415cae4e8502490bbbcd1f95dcd9674c01d67 Mon Sep 17 00:00:00 2001 From: Matt Hsieh Date: Mon, 9 Sep 2019 19:19:50 +0800 Subject: [PATCH 06/10] Add missing PollingXHR.java --- .../client/transports/PollingXHR.java | 292 ++++++++++++++++++ 1 file changed, 292 insertions(+) create mode 100644 src/main/java/io/socket/engineio/client/transports/PollingXHR.java diff --git a/src/main/java/io/socket/engineio/client/transports/PollingXHR.java b/src/main/java/io/socket/engineio/client/transports/PollingXHR.java new file mode 100644 index 00000000..ed118eb3 --- /dev/null +++ b/src/main/java/io/socket/engineio/client/transports/PollingXHR.java @@ -0,0 +1,292 @@ +package io.socket.engineio.client.transports; + + +import java.io.IOException; +import java.util.Arrays; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; +import java.util.logging.Level; +import java.util.logging.Logger; + +import io.socket.emitter.Emitter; +import io.socket.engineio.client.Transport; +import io.socket.thread.EventThread; +import okhttp3.Call; +import okhttp3.Callback; +import okhttp3.HttpUrl; +import okhttp3.MediaType; +import okhttp3.OkHttpClient; +import okhttp3.RequestBody; +import okhttp3.Response; +import okhttp3.ResponseBody; + +public class PollingXHR extends Polling { + + private static final Logger logger = Logger.getLogger(PollingXHR.class.getName()); + + private static boolean LOGGABLE_FINE = logger.isLoggable(Level.FINE); + + public PollingXHR(Transport.Options opts) { + super(opts); + } + + protected Request request() { + return this.request(null); + } + + protected Request request(Request.Options opts) { + if (opts == null) { + opts = new Request.Options(); + } + opts.uri = this.uri(); + opts.callFactory = this.callFactory; + + Request req = new Request(opts); + + final PollingXHR self = this; + req.on(Request.EVENT_REQUEST_HEADERS, new Emitter.Listener() { + @Override + public void call(Object... args) { + // Never execute asynchronously for support to modify headers. + self.emit(Transport.EVENT_REQUEST_HEADERS, args[0]); + } + }).on(Request.EVENT_RESPONSE_HEADERS, new Emitter.Listener() { + @Override + public void call(final Object... args) { + EventThread.exec(new Runnable() { + @Override + public void run() { + self.emit(Transport.EVENT_RESPONSE_HEADERS, args[0]); + } + }); + } + }); + return req; + } + + @Override + protected void doWrite(byte[] data, final Runnable fn) { + this.doWrite((Object) data, fn); + } + + @Override + protected void doWrite(String data, final Runnable fn) { + this.doWrite((Object) data, fn); + } + + private void doWrite(Object data, final Runnable fn) { + Request.Options opts = new Request.Options(); + opts.method = "POST"; + opts.data = data; + Request req = this.request(opts); + final PollingXHR self = this; + req.on(Request.EVENT_SUCCESS, new Emitter.Listener() { + @Override + public void call(Object... args) { + EventThread.exec(new Runnable() { + @Override + public void run() { + fn.run(); + } + }); + } + }); + req.on(Request.EVENT_ERROR, new Emitter.Listener() { + @Override + public void call(final Object... args) { + EventThread.exec(new Runnable() { + @Override + public void run() { + Exception err = args.length > 0 && args[0] instanceof Exception ? (Exception)args[0] : null; + self.onError("xhr post error", err); + } + }); + } + }); + req.create(); + } + + @Override + protected void doPoll() { + logger.fine("xhr poll"); + Request req = this.request(); + final PollingXHR self = this; + req.on(Request.EVENT_DATA, new Emitter.Listener() { + @Override + public void call(final Object... args) { + EventThread.exec(new Runnable() { + @Override + public void run() { + Object arg = args.length > 0 ? args[0] : null; + if (arg instanceof String) { + self.onData((String)arg); + } else if (arg instanceof byte[]) { + self.onData((byte[])arg); + } + } + }); + } + }); + req.on(Request.EVENT_ERROR, new Emitter.Listener() { + @Override + public void call(final Object... args) { + EventThread.exec(new Runnable() { + @Override + public void run() { + Exception err = args.length > 0 && args[0] instanceof Exception ? (Exception) args[0] : null; + self.onError("xhr poll error", err); + } + }); + } + }); + req.create(); + } + + public static class Request extends Emitter { + + public static final String EVENT_SUCCESS = "success"; + public static final String EVENT_DATA = "data"; + public static final String EVENT_ERROR = "error"; + public static final String EVENT_REQUEST_HEADERS = "requestHeaders"; + public static final String EVENT_RESPONSE_HEADERS = "responseHeaders"; + + private static final String BINARY_CONTENT_TYPE = "application/octet-stream"; + private static final String TEXT_CONTENT_TYPE = "text/plain;charset=UTF-8"; + + private static final MediaType BINARY_MEDIA_TYPE = MediaType.parse(BINARY_CONTENT_TYPE); + private static final MediaType TEXT_MEDIA_TYPE = MediaType.parse(TEXT_CONTENT_TYPE); + + private String method; + private String uri; + + private Object data; + + private Call.Factory callFactory; + private Response response; + private Call requestCall; + + public Request(Options opts) { + this.method = opts.method != null ? opts.method : "GET"; + this.uri = opts.uri; + this.data = opts.data; + this.callFactory = opts.callFactory != null ? opts.callFactory : new OkHttpClient(); + } + + public void create() { + final Request self = this; + if (LOGGABLE_FINE) logger.fine(String.format("xhr open %s: %s", this.method, this.uri)); + Map> headers = new TreeMap>(String.CASE_INSENSITIVE_ORDER); + + if ("POST".equals(this.method)) { + if (this.data instanceof byte[]) { + headers.put("Content-type", new LinkedList(Collections.singletonList(BINARY_CONTENT_TYPE))); + } else { + headers.put("Content-type", new LinkedList(Collections.singletonList(TEXT_CONTENT_TYPE))); + } + } + + headers.put("Accept", new LinkedList(Collections.singletonList("*/*"))); + + this.onRequestHeaders(headers); + + if (LOGGABLE_FINE) { + logger.fine(String.format("sending xhr with url %s | data %s", this.uri, + this.data instanceof byte[] ? Arrays.toString((byte[]) this.data) : this.data)); + } + + okhttp3.Request.Builder requestBuilder = new okhttp3.Request.Builder(); + for (Map.Entry> header : headers.entrySet()) { + for (String v : header.getValue()){ + requestBuilder.addHeader(header.getKey(), v); + } + } + RequestBody body = null; + if (this.data instanceof byte[]) { + body = RequestBody.create(BINARY_MEDIA_TYPE, (byte[])this.data); + } else if (this.data instanceof String) { + body = RequestBody.create(TEXT_MEDIA_TYPE, (String)this.data); + } + + okhttp3.Request request = requestBuilder + .url(HttpUrl.parse(self.uri)) + .method(self.method, body) + .build(); + + requestCall = callFactory.newCall(request); + requestCall.enqueue(new Callback() { + @Override + public void onFailure(Call call, IOException e) { + self.onError(e); + } + + @Override + public void onResponse(Call call, Response response) throws IOException { + self.response = response; + self.onResponseHeaders(response.headers().toMultimap()); + + try { + if (response.isSuccessful()) { + self.onLoad(); + } else { + self.onError(new IOException(Integer.toString(response.code()))); + } + } finally { + response.close(); + } + } + }); + } + + private void onSuccess() { + this.emit(EVENT_SUCCESS); + } + + private void onData(String data) { + this.emit(EVENT_DATA, data); + this.onSuccess(); + } + + private void onData(byte[] data) { + this.emit(EVENT_DATA, data); + this.onSuccess(); + } + + private void onError(Exception err) { + this.emit(EVENT_ERROR, err); + } + + private void onRequestHeaders(Map> headers) { + this.emit(EVENT_REQUEST_HEADERS, headers); + } + + private void onResponseHeaders(Map> headers) { + this.emit(EVENT_RESPONSE_HEADERS, headers); + } + + private void onLoad() { + ResponseBody body = response.body(); + String contentType = body.contentType().toString(); + + try { + if (BINARY_CONTENT_TYPE.equalsIgnoreCase(contentType)) { + this.onData(body.bytes()); + } else { + this.onData(body.string()); + } + } catch (IOException e) { + this.onError(e); + } + } + + public static class Options { + + public String uri; + public String method; + public Object data; + public Call.Factory callFactory; + } + } +} From d9d3c8260c95dbb8f63281bbab3586178473005c Mon Sep 17 00:00:00 2001 From: Matt Hsieh Date: Mon, 9 Sep 2019 19:20:16 +0800 Subject: [PATCH 07/10] Force use utf8 encoding when encode payload --- src/main/java/io/socket/engineio/parser/Parser.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/io/socket/engineio/parser/Parser.java b/src/main/java/io/socket/engineio/parser/Parser.java index fe6c3622..93128624 100644 --- a/src/main/java/io/socket/engineio/parser/Parser.java +++ b/src/main/java/io/socket/engineio/parser/Parser.java @@ -136,7 +136,11 @@ public static void encodePayload(Packet[] packets, EncodeCallback callback) thro final StringBuilder result = new StringBuilder(); for (Packet packet : packets) { - encodePacket(packet, false, new EncodeCallback() { + /* + matt modified utf8encode=true + socket.io 1.7.4 decode utf8 message by default + */ + encodePacket(packet, true, new EncodeCallback() { @Override public void call(Object message) { result.append(setLengthHeader((String)message)); From 1211570017be2a12bcccd1139768ba5893151dd2 Mon Sep 17 00:00:00 2001 From: Matt Hsieh Date: Wed, 23 Jun 2021 16:11:08 +0800 Subject: [PATCH 08/10] Update to fix runtime crash on new JDK build env see: https://www.morling.dev/blog/bytebuffer-and-the-dreaded-nosuchmethoderror/ --- build.gradle | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index 3a31d378..54dd1bbd 100644 --- a/build.gradle +++ b/build.gradle @@ -7,7 +7,9 @@ * user guide available at http://gradle.org/docs/2.0/userguide/tutorial_java_projects.html */ -apply plugin: 'java' +plugins { + id 'java-library' +} repositories { mavenCentral() @@ -18,5 +20,11 @@ dependencies { implementation 'com.squareup.okhttp3:okhttp:3.8.1' } -targetCompatibility = '1.7' -sourceCompatibility = '1.7' \ No newline at end of file +compileJava { + options.release = 8 +} + +java { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 +} \ No newline at end of file From ea4b352e0735e3fecd95c12dc30973316fc2050a Mon Sep 17 00:00:00 2001 From: Matt Hsieh Date: Wed, 10 Nov 2021 11:49:12 +0800 Subject: [PATCH 09/10] chore: update gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index d26349c8..b0a3b6ab 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,4 @@ .DS_Store target/ node_modules/ +build/ \ No newline at end of file From 6f1e4d330015778f705b66acec6e505ab21e72cc Mon Sep 17 00:00:00 2001 From: Matt Hsieh Date: Mon, 4 Aug 2025 20:16:04 +0800 Subject: [PATCH 10/10] Update to latest IDE env --- build.gradle | 4 ---- 1 file changed, 4 deletions(-) diff --git a/build.gradle b/build.gradle index 54dd1bbd..0bf50171 100644 --- a/build.gradle +++ b/build.gradle @@ -11,10 +11,6 @@ plugins { id 'java-library' } -repositories { - mavenCentral() -} - dependencies { implementation 'org.json:json:20090211' implementation 'com.squareup.okhttp3:okhttp:3.8.1'