Skip to content

Add MessagePack support for Java SignalR Client #23532

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 64 commits into from
Aug 20, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
58739e0
Implement ParseMessages for java messagePack client
wtgodbe Jun 27, 2020
1bd2ae6
Fix some spacing & syntax
wtgodbe Jun 27, 2020
417805b
Implement write
wtgodbe Jun 30, 2020
77e2033
Tab -> Spaces
wtgodbe Jun 30, 2020
3362173
MessagePacker -> MessageBufferPacker
wtgodbe Jun 30, 2020
8b53f5b
Tabs -> Spaces
wtgodbe Jun 30, 2020
f13df5a
Tabs -> Spaces
wtgodbe Jun 30, 2020
27e4765
InvocationMessage may not include streamIDs
wtgodbe Jul 9, 2020
2b59b77
Only 1 ctor per message type
wtgodbe Jul 9, 2020
8ace703
Fixup HubConnection.java
wtgodbe Jul 9, 2020
3da3d24
Change return type of parseMessages to List
wtgodbe Jul 9, 2020
960180a
Fix HubConnection
wtgodbe Jul 9, 2020
6bfdf7a
Check for primitive value before returning
wtgodbe Jul 27, 2020
9f4b606
Implement length header prefix
wtgodbe Jul 27, 2020
4693ac6
Minor fixes
wtgodbe Jul 30, 2020
fa2e257
Use ByteBuffer to read length header
wtgodbe Jul 30, 2020
0a629de
Add case for Char
wtgodbe Jul 30, 2020
ca2df70
Close unpacker
wtgodbe Jul 30, 2020
769b94e
Typo
wtgodbe Jul 30, 2020
538cb0c
Override onMessage w/ ByteString
wtgodbe Jul 30, 2020
834bfc4
Change OKHttpWebSocketWrapper
wtgodbe Jul 30, 2020
65776fb
Account for nil InvocationId
wtgodbe Jul 30, 2020
c9df345
Change interface & MessagePack impl
wtgodbe Jul 30, 2020
b1d3e9f
Update JsonHubProtocol
wtgodbe Jul 30, 2020
a9c83e4
Use ByteBuffer
wtgodbe Jul 30, 2020
d71da9d
Fixup HubConnection
wtgodbe Jul 30, 2020
9dc60f1
Fixup more stuff
wtgodbe Jul 30, 2020
f2b414c
Convert more stuff to ByteBuffer
wtgodbe Aug 4, 2020
7559cc4
Account for ReadOnly
wtgodbe Aug 4, 2020
89b126e
Spacing
wtgodbe Aug 4, 2020
4895d6d
No need to reset ByteBuffer when setting position
wtgodbe Aug 5, 2020
7c8a2fb
Add Protocol to HubConnection ctor
wtgodbe Aug 5, 2020
63b49fc
Set default, make stuff public
wtgodbe Aug 5, 2020
e9a2b6a
Fixup tests
wtgodbe Aug 5, 2020
897a15f
More test cleanup
wtgodbe Aug 5, 2020
28eadc5
Spacing
wtgodbe Aug 5, 2020
303832e
only grab remaining buffer bytes in json
wtgodbe Aug 5, 2020
5fa92c6
Last test fixes
wtgodbe Aug 5, 2020
a8c640e
Get rid of some unused imports
wtgodbe Aug 5, 2020
125cd7f
First round of msgpack tests
wtgodbe Aug 6, 2020
4771aa2
Flip condition
wtgodbe Aug 6, 2020
3f85c55
Respond to feedback
wtgodbe Aug 6, 2020
e46b2ee
Spacing
wtgodbe Aug 6, 2020
745b0dc
More tests
wtgodbe Aug 6, 2020
5ee8301
Add test for primitives
wtgodbe Aug 6, 2020
a4a0e8f
Add more tests, start using msgpack-jackson
wtgodbe Aug 7, 2020
7f6fe1c
Fix build.gradle
wtgodbe Aug 7, 2020
1f3034b
Remove debug prints
wtgodbe Aug 7, 2020
58bbad3
Start using Type instead of Class
wtgodbe Aug 10, 2020
7c3a18c
Add overloads for Type, make messagePack readValue() more efficient
wtgodbe Aug 12, 2020
43711b1
Apply feedback, add some tests
wtgodbe Aug 12, 2020
77cb968
Add some tests, fix some tests
wtgodbe Aug 13, 2020
c4d1fec
Fix tests for real
wtgodbe Aug 13, 2020
602ef33
Add a whole buncha tests
wtgodbe Aug 13, 2020
02a83a5
Add TestUtils change that I didn't commit yesterday
wtgodbe Aug 14, 2020
057a3ae
Respond to some feedback
wtgodbe Aug 14, 2020
58a539d
Add a couple Json tests
wtgodbe Aug 14, 2020
ebd6344
Apply more feedback
wtgodbe Aug 14, 2020
3476f89
Move readonly fix to msgpack
wtgodbe Aug 14, 2020
5dc8c5c
Minor optimization
wtgodbe Aug 14, 2020
9746105
Fixup some javadocs
wtgodbe Aug 14, 2020
5a2357e
Respond to feedback
wtgodbe Aug 18, 2020
e2bcd96
Remove TypeReference, make Protocols private again
wtgodbe Aug 19, 2020
6e53284
Feedback
wtgodbe Aug 20, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/SignalR/clients/java/signalr/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ dependencies {
implementation 'com.squareup.okhttp3:okhttp:3.11.0'
api 'io.reactivex.rxjava2:rxjava:2.2.3'
implementation 'org.slf4j:slf4j-api:1.7.25'
compile 'org.msgpack:msgpack-core:0.8.20'
compile 'org.msgpack:jackson-dataformat-msgpack:0.8.20'
}

spotless {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

package com.microsoft.signalr;

import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
Expand All @@ -13,10 +14,10 @@ class CallbackMap {
private final Map<String, List<InvocationHandler>> handlers = new HashMap<>();
private final ReentrantLock lock = new ReentrantLock();

public InvocationHandler put(String target, ActionBase action, Class<?>... classes) {
public InvocationHandler put(String target, ActionBase action, Type... types) {
try {
lock.lock();
InvocationHandler handler = new InvocationHandler(action, classes);
InvocationHandler handler = new InvocationHandler(action, types);
if (!handlers.containsKey(target)) {
handlers.put(target, new ArrayList<>());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,28 @@

package com.microsoft.signalr;

import java.util.Map;

final class CancelInvocationMessage extends HubMessage {
private final int type = HubMessageType.CANCEL_INVOCATION.value;
private Map<String, String> headers;
private final String invocationId;

public CancelInvocationMessage(String invocationId) {

public CancelInvocationMessage(Map<String, String> headers, String invocationId) {
if (headers != null && !headers.isEmpty()) {
this.headers = headers;
}
this.invocationId = invocationId;
}

public Map<String, String> getHeaders() {
return headers;
}

public String getInvocationId() {
return invocationId;
}

@Override
public HubMessageType getMessageType() {
return HubMessageType.CANCEL_INVOCATION;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,35 @@

final class CloseMessage extends HubMessage {
private final String error;
private final boolean allowReconnect;

@Override
public HubMessageType getMessageType() {
return HubMessageType.CLOSE;
}

public CloseMessage() {
this(null);
this(null, false);
}

public CloseMessage(String error) {
this(error, false);
}

public CloseMessage(boolean allowReconnect) {
this(null, allowReconnect);
}

public CloseMessage(String error, boolean allowReconnect) {
this.error = error;
this.allowReconnect = allowReconnect;
}

public String getError() {
return this.error;
}

public boolean getAllowReconnect() {
return this.allowReconnect;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,30 @@

package com.microsoft.signalr;

import java.util.Map;

final class CompletionMessage extends HubMessage {
private final int type = HubMessageType.COMPLETION.value;
private Map<String, String> headers;
private final String invocationId;
private final Object result;
private final String error;

public CompletionMessage(String invocationId, Object result, String error) {

public CompletionMessage(Map<String, String> headers, String invocationId, Object result, String error) {
if (headers != null && !headers.isEmpty()) {
this.headers = headers;
}
if (error != null && result != null) {
throw new IllegalArgumentException("Expected either 'error' or 'result' to be provided, but not both.");
}
this.invocationId = invocationId;
this.result = result;
this.error = error;
}

public Map<String, String> getHeaders() {
return headers;
}

public Object getResult() {
return result;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package com.microsoft.signalr;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
Expand All @@ -15,6 +16,7 @@
import io.reactivex.Single;
import io.reactivex.subjects.SingleSubject;
import okhttp3.*;
import okio.ByteString;

final class DefaultHttpClient extends HttpClient {
private OkHttpClient client = null;
Expand Down Expand Up @@ -104,7 +106,7 @@ public Single<HttpResponse> send(HttpRequest httpRequest) {
}

@Override
public Single<HttpResponse> send(HttpRequest httpRequest, String bodyContent) {
public Single<HttpResponse> send(HttpRequest httpRequest, ByteBuffer bodyContent) {
Request.Builder requestBuilder = new Request.Builder().url(httpRequest.getUrl());

switch (httpRequest.getMethod()) {
Expand All @@ -114,7 +116,7 @@ public Single<HttpResponse> send(HttpRequest httpRequest, String bodyContent) {
case "POST":
RequestBody body;
if (bodyContent != null) {
body = RequestBody.create(MediaType.parse("text/plain"), bodyContent);
body = RequestBody.create(MediaType.parse("text/plain"), ByteString.of(bodyContent));
} else {
body = RequestBody.create(null, new byte[]{});
}
Expand Down Expand Up @@ -150,7 +152,7 @@ public void onFailure(Call call, IOException e) {
@Override
public void onResponse(Call call, Response response) throws IOException {
try (ResponseBody body = response.body()) {
HttpResponse httpResponse = new HttpResponse(response.code(), response.message(), body.string());
HttpResponse httpResponse = new HttpResponse(response.code(), response.message(), ByteBuffer.wrap(body.bytes()));
responseSubject.onSuccess(httpResponse);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,18 @@

package com.microsoft.signalr;

import java.nio.charset.StandardCharsets;
import java.nio.ByteBuffer;

import com.google.gson.Gson;

final class HandshakeProtocol {
private static final Gson gson = new Gson();
private static final String RECORD_SEPARATOR = "\u001e";

public static String createHandshakeRequestMessage(HandshakeRequestMessage message) {
public static ByteBuffer createHandshakeRequestMessage(HandshakeRequestMessage message) {
// The handshake request is always in the JSON format
return gson.toJson(message) + RECORD_SEPARATOR;
return ByteBuffer.wrap((gson.toJson(message) + RECORD_SEPARATOR).getBytes(StandardCharsets.UTF_8));
}

public static HandshakeResponseMessage parseHandshakeResponse(String message) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

package com.microsoft.signalr;

import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;

Expand Down Expand Up @@ -45,23 +46,23 @@ public Map<String, String> getHeaders() {
class HttpResponse {
private final int statusCode;
private final String statusText;
private final String content;
private final ByteBuffer content;

public HttpResponse(int statusCode) {
this(statusCode, "");
}

public HttpResponse(int statusCode, String statusText) {
this(statusCode, statusText, "");
this(statusCode, statusText, ByteBuffer.wrap(new byte[] {}));
}

public HttpResponse(int statusCode, String statusText, String content) {
public HttpResponse(int statusCode, String statusText, ByteBuffer content) {
this.statusCode = statusCode;
this.statusText = statusText;
this.content = content;
}

public String getContent() {
public ByteBuffer getContent() {
return content;
}

Expand Down Expand Up @@ -95,7 +96,7 @@ public Single<HttpResponse> post(String url) {
return this.send(request);
}

public Single<HttpResponse> post(String url, String body, HttpRequest options) {
public Single<HttpResponse> post(String url, ByteBuffer body, HttpRequest options) {
options.setUrl(url);
options.setMethod("POST");
return this.send(options, body);
Expand All @@ -122,7 +123,7 @@ public Single<HttpResponse> delete(String url, HttpRequest options) {

public abstract Single<HttpResponse> send(HttpRequest request);

public abstract Single<HttpResponse> send(HttpRequest request, String body);
public abstract Single<HttpResponse> send(HttpRequest request, ByteBuffer body);

public abstract WebSocketWrapper createWebSocket(String url, Map<String, String> headers);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ public class HttpHubConnectionBuilder {
private final String url;
private Transport transport;
private HttpClient httpClient;
private HubProtocol protocol = new JsonHubProtocol();
private boolean skipNegotiate;
private Single<String> accessTokenProvider;
private long handshakeResponseTimeout = 0;
Expand Down Expand Up @@ -54,6 +55,16 @@ HttpHubConnectionBuilder withHttpClient(HttpClient httpClient) {
this.httpClient = httpClient;
return this;
}

/**
* Sets MessagePack as the {@link HubProtocol} to be used by the {@link HubConnection}.
*
* @return This instance of the HttpHubConnectionBuilder.
*/
public HttpHubConnectionBuilder withMessagePackHubProtocol() {
this.protocol = new MessagePackHubProtocol();
return this;
}

/**
* Indicates to the {@link HubConnection} that it should skip the negotiate process.
Expand Down Expand Up @@ -133,7 +144,7 @@ public HttpHubConnectionBuilder setHttpClientBuilderCallback(Action1<OkHttpClien
* @return A new instance of {@link HubConnection}.
*/
public HubConnection build() {
return new HubConnection(url, transport, skipNegotiate, httpClient, accessTokenProvider,
return new HubConnection(url, transport, skipNegotiate, httpClient, protocol, accessTokenProvider,
handshakeResponseTimeout, headers, transportEnum, configureBuilder);
}
}
Loading