Merge pull request #2950 from dotnet-maestro-bot/merge/release/2.2-to-master
[automated] Merge branch 'release/2.2' => 'master'
This commit is contained in:
commit
7af3472ef4
|
|
@ -7,23 +7,27 @@ import java.util.ArrayList;
|
|||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.Collections;
|
||||
|
||||
class CallbackMap {
|
||||
private ConcurrentHashMap<String, List<ActionBase>> handlers = new ConcurrentHashMap<>();
|
||||
private ConcurrentHashMap<String, List<InvocationHandler>> handlers = new ConcurrentHashMap<>();
|
||||
|
||||
public InvocationHandler put(String target, ActionBase action, ArrayList<Class<?>> classes) {
|
||||
InvocationHandler handler = new InvocationHandler(action, Collections.unmodifiableList(classes));
|
||||
|
||||
public void put(String target, ActionBase action) {
|
||||
handlers.computeIfPresent(target, (methodName, handlerList) -> {
|
||||
handlerList.add(action);
|
||||
handlerList.add(handler);
|
||||
return handlerList;
|
||||
});
|
||||
handlers.computeIfAbsent(target, (ac) -> new ArrayList<>(Arrays.asList(action)));
|
||||
handlers.computeIfAbsent(target, (ac) -> new ArrayList<>(Arrays.asList(handler)));
|
||||
return handler;
|
||||
}
|
||||
|
||||
public Boolean containsKey(String key) {
|
||||
return handlers.containsKey(key);
|
||||
}
|
||||
|
||||
public List<ActionBase> get(String key) {
|
||||
public List<InvocationHandler> get(String key) {
|
||||
return handlers.get(key);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,26 +9,24 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonArray;
|
||||
|
||||
public class HubConnection {
|
||||
private String url;
|
||||
private Transport transport;
|
||||
private OnReceiveCallBack callback;
|
||||
private CallbackMap handlers = new CallbackMap();
|
||||
private HubProtocol protocol;
|
||||
private Gson gson = new Gson();
|
||||
private Boolean handshakeReceived = false;
|
||||
private static final String RECORD_SEPARATOR = "\u001e";
|
||||
private HubConnectionState connectionState = HubConnectionState.DISCONNECTED;
|
||||
private HubConnectionState hubConnectionState = HubConnectionState.DISCONNECTED;
|
||||
private Logger logger;
|
||||
private List<Consumer<Exception>> onClosedCallbackList;
|
||||
private boolean skipNegotiate = false;
|
||||
private NegotiateResponse negotiateResponse;
|
||||
private String accessToken;
|
||||
private Map<String, String> headers = new HashMap<>();
|
||||
private ConnectionState connectionState = null;
|
||||
|
||||
private static ArrayList<Class<?>> emptyArray = new ArrayList<>();
|
||||
private static int MAX_NEGOTIATE_ATTEMPTS = 100;
|
||||
|
||||
public HubConnection(String url, Transport transport, Logger logger, boolean skipNegotiate) {
|
||||
|
|
@ -61,24 +59,20 @@ public class HubConnection {
|
|||
}
|
||||
}
|
||||
|
||||
HubMessage[] messages = protocol.parseMessages(payload);
|
||||
HubMessage[] messages = protocol.parseMessages(payload, connectionState);
|
||||
|
||||
for (HubMessage message : messages) {
|
||||
logger.log(LogLevel.Debug, "Received message of type %s", message.getMessageType());
|
||||
logger.log(LogLevel.Debug, "Received message of type %s.", message.getMessageType());
|
||||
switch (message.getMessageType()) {
|
||||
case INVOCATION:
|
||||
InvocationMessage invocationMessage = (InvocationMessage) message;
|
||||
if (handlers.containsKey(invocationMessage.target)) {
|
||||
ArrayList<Object> args = gson.fromJson((JsonArray) invocationMessage.arguments[0], (new ArrayList<>()).getClass());
|
||||
List<ActionBase> actions = handlers.get(invocationMessage.target);
|
||||
if (actions != null) {
|
||||
logger.log(LogLevel.Debug, "Invoking handlers for target %s", invocationMessage.target);
|
||||
for (ActionBase action : actions) {
|
||||
action.invoke(args.toArray());
|
||||
}
|
||||
List<InvocationHandler> handlers = this.handlers.get(invocationMessage.target);
|
||||
if (handlers != null) {
|
||||
for (InvocationHandler handler : handlers) {
|
||||
handler.getAction().invoke(invocationMessage.arguments);
|
||||
}
|
||||
} else {
|
||||
logger.log(LogLevel.Warning, "Failed to find handler for %s method", invocationMessage.target);
|
||||
logger.log(LogLevel.Warning, "Failed to find handler for %s method.", invocationMessage.target);
|
||||
}
|
||||
break;
|
||||
case CLOSE:
|
||||
|
|
@ -93,7 +87,7 @@ public class HubConnection {
|
|||
case STREAM_ITEM:
|
||||
case CANCEL_INVOCATION:
|
||||
case COMPLETION:
|
||||
logger.log(LogLevel.Error, "This client does not support %s messages", message.getMessageType());
|
||||
logger.log(LogLevel.Error, "This client does not support %s messages.", message.getMessageType());
|
||||
|
||||
throw new UnsupportedOperationException(String.format("The message type %s is not supported yet.", message.getMessageType()));
|
||||
}
|
||||
|
|
@ -148,7 +142,7 @@ public class HubConnection {
|
|||
* @return HubConnection state enum.
|
||||
*/
|
||||
public HubConnectionState getConnectionState() {
|
||||
return connectionState;
|
||||
return hubConnectionState;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -157,7 +151,7 @@ public class HubConnection {
|
|||
* @throws Exception An error occurred while connecting.
|
||||
*/
|
||||
public void start() throws Exception {
|
||||
if (connectionState != HubConnectionState.DISCONNECTED) {
|
||||
if (hubConnectionState != HubConnectionState.DISCONNECTED) {
|
||||
return;
|
||||
}
|
||||
if (!skipNegotiate) {
|
||||
|
|
@ -198,7 +192,8 @@ public class HubConnection {
|
|||
transport.start();
|
||||
String handshake = HandshakeProtocol.createHandshakeRequestMessage(new HandshakeRequestMessage(protocol.getName(), protocol.getVersion()));
|
||||
transport.send(handshake);
|
||||
connectionState = HubConnectionState.CONNECTED;
|
||||
hubConnectionState = HubConnectionState.CONNECTED;
|
||||
connectionState = new ConnectionState(this);
|
||||
logger.log(LogLevel.Information, "HubConnected started.");
|
||||
}
|
||||
|
||||
|
|
@ -206,7 +201,7 @@ public class HubConnection {
|
|||
* Stops a connection to the server.
|
||||
*/
|
||||
private void stop(String errorMessage) {
|
||||
if (connectionState == HubConnectionState.DISCONNECTED) {
|
||||
if (hubConnectionState == HubConnectionState.DISCONNECTED) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -217,7 +212,8 @@ public class HubConnection {
|
|||
}
|
||||
|
||||
transport.stop();
|
||||
connectionState = HubConnectionState.DISCONNECTED;
|
||||
hubConnectionState = HubConnectionState.DISCONNECTED;
|
||||
connectionState = null;
|
||||
logger.log(LogLevel.Information, "HubConnection stopped.");
|
||||
if (onClosedCallbackList != null) {
|
||||
HubException hubException = new HubException(errorMessage);
|
||||
|
|
@ -243,7 +239,7 @@ public class HubConnection {
|
|||
* @throws Exception If there was an error while sending.
|
||||
*/
|
||||
public void send(String method, Object... args) throws Exception {
|
||||
if (connectionState != HubConnectionState.CONNECTED) {
|
||||
if (hubConnectionState != HubConnectionState.CONNECTED) {
|
||||
throw new HubException("The 'send' method cannot be called if the connection is not active");
|
||||
}
|
||||
|
||||
|
|
@ -262,9 +258,9 @@ public class HubConnection {
|
|||
*/
|
||||
public Subscription on(String target, Action callback) {
|
||||
ActionBase action = args -> callback.invoke();
|
||||
handlers.put(target, action);
|
||||
InvocationHandler handler = handlers.put(target, action, emptyArray);
|
||||
logger.log(LogLevel.Trace, "Registering handler for client method: %s", target);
|
||||
return new Subscription(handlers, action, target);
|
||||
return new Subscription(handlers, handler, target);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -278,9 +274,11 @@ public class HubConnection {
|
|||
*/
|
||||
public <T1> Subscription on(String target, Action1<T1> callback, Class<T1> param1) {
|
||||
ActionBase action = params -> callback.invoke(param1.cast(params[0]));
|
||||
handlers.put(target, action);
|
||||
ArrayList<Class<?>> classes = new ArrayList<>(1);
|
||||
classes.add(param1);
|
||||
InvocationHandler handler = handlers.put(target, action, classes);
|
||||
logger.log(LogLevel.Trace, "Registering handler for client method: %s", target);
|
||||
return new Subscription(handlers, action, target);
|
||||
return new Subscription(handlers, handler, target);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -298,9 +296,12 @@ public class HubConnection {
|
|||
ActionBase action = params -> {
|
||||
callback.invoke(param1.cast(params[0]), param2.cast(params[1]));
|
||||
};
|
||||
handlers.put(target, action);
|
||||
ArrayList<Class<?>> classes = new ArrayList<>(2);
|
||||
classes.add(param1);
|
||||
classes.add(param2);
|
||||
InvocationHandler handler = handlers.put(target, action, classes);
|
||||
logger.log(LogLevel.Trace, "Registering handler for client method: %s", target);
|
||||
return new Subscription(handlers, action, target);
|
||||
return new Subscription(handlers, handler, target);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -321,9 +322,13 @@ public class HubConnection {
|
|||
ActionBase action = params -> {
|
||||
callback.invoke(param1.cast(params[0]), param2.cast(params[1]), param3.cast(params[2]));
|
||||
};
|
||||
handlers.put(target, action);
|
||||
ArrayList<Class<?>> classes = new ArrayList<>(3);
|
||||
classes.add(param1);
|
||||
classes.add(param2);
|
||||
classes.add(param3);
|
||||
InvocationHandler handler = handlers.put(target, action, classes);
|
||||
logger.log(LogLevel.Trace, "Registering handler for client method: %s", target);
|
||||
return new Subscription(handlers, action, target);
|
||||
return new Subscription(handlers, handler, target);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -346,9 +351,14 @@ public class HubConnection {
|
|||
ActionBase action = params -> {
|
||||
callback.invoke(param1.cast(params[0]), param2.cast(params[1]), param3.cast(params[2]), param4.cast(params[3]));
|
||||
};
|
||||
handlers.put(target, action);
|
||||
ArrayList<Class<?>> classes = new ArrayList<>(4);
|
||||
classes.add(param1);
|
||||
classes.add(param2);
|
||||
classes.add(param3);
|
||||
classes.add(param4);
|
||||
InvocationHandler handler = handlers.put(target, action, classes);
|
||||
logger.log(LogLevel.Trace, "Registering handler for client method: %s", target);
|
||||
return new Subscription(handlers, action, target);
|
||||
return new Subscription(handlers, handler, target);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -374,9 +384,15 @@ public class HubConnection {
|
|||
callback.invoke(param1.cast(params[0]), param2.cast(params[1]), param3.cast(params[2]), param4.cast(params[3]),
|
||||
param5.cast(params[4]));
|
||||
};
|
||||
handlers.put(target, action);
|
||||
ArrayList<Class<?>> classes = new ArrayList<>(5);
|
||||
classes.add(param1);
|
||||
classes.add(param2);
|
||||
classes.add(param3);
|
||||
classes.add(param4);
|
||||
classes.add(param5);
|
||||
InvocationHandler handler = handlers.put(target, action, classes);
|
||||
logger.log(LogLevel.Trace, "Registering handler for client method: %s", target);
|
||||
return new Subscription(handlers, action, target);
|
||||
return new Subscription(handlers, handler, target);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -404,9 +420,16 @@ public class HubConnection {
|
|||
callback.invoke(param1.cast(params[0]), param2.cast(params[1]), param3.cast(params[2]), param4.cast(params[3]),
|
||||
param5.cast(params[4]), param6.cast(params[5]));
|
||||
};
|
||||
handlers.put(target, action);
|
||||
ArrayList<Class<?>> classes = new ArrayList<>(6);
|
||||
classes.add(param1);
|
||||
classes.add(param2);
|
||||
classes.add(param3);
|
||||
classes.add(param4);
|
||||
classes.add(param5);
|
||||
classes.add(param6);
|
||||
InvocationHandler handler = handlers.put(target, action, classes);
|
||||
logger.log(LogLevel.Trace, "Registering handler for client method: %s", target);
|
||||
return new Subscription(handlers, action, target);
|
||||
return new Subscription(handlers, handler, target);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -436,9 +459,17 @@ public class HubConnection {
|
|||
callback.invoke(param1.cast(params[0]), param2.cast(params[1]), param3.cast(params[2]), param4.cast(params[3]),
|
||||
param5.cast(params[4]), param6.cast(params[5]), param7.cast(params[6]));
|
||||
};
|
||||
handlers.put(target, action);
|
||||
ArrayList<Class<?>> classes = new ArrayList<>(7);
|
||||
classes.add(param1);
|
||||
classes.add(param2);
|
||||
classes.add(param3);
|
||||
classes.add(param4);
|
||||
classes.add(param5);
|
||||
classes.add(param6);
|
||||
classes.add(param7);
|
||||
InvocationHandler handler = handlers.put(target, action, classes);
|
||||
logger.log(LogLevel.Trace, "Registering handler for client method: %s", target);
|
||||
return new Subscription(handlers, action, target);
|
||||
return new Subscription(handlers, handler, target);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -470,9 +501,18 @@ public class HubConnection {
|
|||
callback.invoke(param1.cast(params[0]), param2.cast(params[1]), param3.cast(params[2]), param4.cast(params[3]),
|
||||
param5.cast(params[4]), param6.cast(params[5]), param7.cast(params[6]), param8.cast(params[7]));
|
||||
};
|
||||
handlers.put(target, action);
|
||||
ArrayList<Class<?>> classes = new ArrayList<>(8);
|
||||
classes.add(param1);
|
||||
classes.add(param2);
|
||||
classes.add(param3);
|
||||
classes.add(param4);
|
||||
classes.add(param5);
|
||||
classes.add(param6);
|
||||
classes.add(param7);
|
||||
classes.add(param8);
|
||||
InvocationHandler handler = handlers.put(target, action, classes);
|
||||
logger.log(LogLevel.Trace, "Registering handler for client method: %s", target);
|
||||
return new Subscription(handlers, action, target);
|
||||
return new Subscription(handlers, handler, target);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -492,4 +532,32 @@ public class HubConnection {
|
|||
|
||||
onClosedCallbackList.add(callback);
|
||||
}
|
||||
|
||||
private class ConnectionState implements InvocationBinder {
|
||||
HubConnection connection;
|
||||
|
||||
public ConnectionState(HubConnection connection) {
|
||||
this.connection = connection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getReturnType(String invocationId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Class<?>> getParameterTypes(String methodName) throws Exception {
|
||||
List<InvocationHandler> handlers = connection.handlers.get(methodName);
|
||||
if (handlers == null) {
|
||||
logger.log(LogLevel.Warning, "Failed to find handler for '%s' method.", methodName);
|
||||
return emptyArray;
|
||||
}
|
||||
|
||||
if (handlers.size() == 0) {
|
||||
throw new Exception(String.format("There are no callbacks registered for the method '%s'.", methodName));
|
||||
}
|
||||
|
||||
return handlers.get(0).getClasses();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
package com.microsoft.aspnet.signalr;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* A protocol abstraction for communicating with SignalR hubs.
|
||||
*/
|
||||
|
|
@ -16,7 +18,7 @@ interface HubProtocol {
|
|||
* @param message A string representation of one or more {@link HubMessage}s.
|
||||
* @return A list of {@link HubMessage}s.
|
||||
*/
|
||||
HubMessage[] parseMessages(String message);
|
||||
HubMessage[] parseMessages(String message, InvocationBinder binder) throws Exception;
|
||||
|
||||
/**
|
||||
* Writes the specified {@link HubMessage} to a String.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,11 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
package com.microsoft.aspnet.signalr;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
interface InvocationBinder {
|
||||
Class<?> getReturnType(String invocationId);
|
||||
List<Class<?>> getParameterTypes(String methodName) throws Exception;
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
package com.microsoft.aspnet.signalr;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
class InvocationHandler {
|
||||
private List<Class<?>> classes;
|
||||
private ActionBase action;
|
||||
|
||||
InvocationHandler(ActionBase action, List<Class<?>> classes) {
|
||||
this.action = action;
|
||||
this.classes = classes;
|
||||
}
|
||||
|
||||
public List<Class<?>> getClasses() {
|
||||
return classes;
|
||||
}
|
||||
|
||||
public ActionBase getAction() {
|
||||
return action;
|
||||
}
|
||||
}
|
||||
|
|
@ -11,7 +11,7 @@ class InvocationMessage extends HubMessage {
|
|||
|
||||
public InvocationMessage(String target, Object[] args) {
|
||||
this.target = target;
|
||||
arguments = args;
|
||||
this.arguments = args;
|
||||
}
|
||||
|
||||
public String getInvocationId() {
|
||||
|
|
|
|||
|
|
@ -3,13 +3,16 @@
|
|||
|
||||
package com.microsoft.aspnet.signalr;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.google.gson.stream.JsonReader;
|
||||
import com.google.gson.stream.JsonToken;
|
||||
|
||||
class JsonHubProtocol implements HubProtocol {
|
||||
private final JsonParser jsonParser = new JsonParser();
|
||||
|
|
@ -32,41 +35,105 @@ class JsonHubProtocol implements HubProtocol {
|
|||
}
|
||||
|
||||
@Override
|
||||
public HubMessage[] parseMessages(String payload) {
|
||||
public HubMessage[] parseMessages(String payload, InvocationBinder binder) throws Exception {
|
||||
String[] messages = payload.split(RECORD_SEPARATOR);
|
||||
List<HubMessage> hubMessages = new ArrayList<>();
|
||||
for (String splitMessage : messages) {
|
||||
for (String str : messages) {
|
||||
HubMessageType messageType = null;
|
||||
String invocationId = null;
|
||||
String target = null;
|
||||
String error = null;
|
||||
ArrayList<Object> arguments = null;
|
||||
JsonArray argumentsToken = null;
|
||||
|
||||
JsonReader reader = new JsonReader(new StringReader(str));
|
||||
reader.beginObject();
|
||||
|
||||
do {
|
||||
String name = reader.nextName();
|
||||
switch (name) {
|
||||
case "type":
|
||||
messageType = HubMessageType.values()[reader.nextInt() - 1];
|
||||
break;
|
||||
case "invocationId":
|
||||
invocationId = reader.nextString();
|
||||
break;
|
||||
case "target":
|
||||
target = reader.nextString();
|
||||
break;
|
||||
case "error":
|
||||
error = reader.nextString();
|
||||
break;
|
||||
case "result":
|
||||
reader.skipValue();
|
||||
break;
|
||||
case "item":
|
||||
reader.skipValue();
|
||||
break;
|
||||
case "arguments":
|
||||
if (target != null) {
|
||||
reader.beginArray();
|
||||
List<Class<?>> types = binder.getParameterTypes(target);
|
||||
if (types != null && types.size() >= 1) {
|
||||
arguments = new ArrayList<>();
|
||||
for (int i = 0; i < types.size(); i++) {
|
||||
arguments.add(gson.fromJson(reader, types.get(i)));
|
||||
}
|
||||
}
|
||||
reader.endArray();
|
||||
} else {
|
||||
argumentsToken = (JsonArray)jsonParser.parse(reader);
|
||||
}
|
||||
break;
|
||||
case "headers":
|
||||
throw new HubException("Headers not implemented yet.");
|
||||
default:
|
||||
// Skip unknown property, allows new clients to still work with old protocols
|
||||
reader.skipValue();
|
||||
break;
|
||||
}
|
||||
} while (reader.hasNext());
|
||||
|
||||
reader.endObject();
|
||||
reader.close();
|
||||
|
||||
JsonObject jsonMessage = jsonParser.parse(splitMessage).getAsJsonObject();
|
||||
HubMessageType messageType = HubMessageType.values()[jsonMessage.get("type").getAsInt() -1];
|
||||
switch (messageType) {
|
||||
case INVOCATION:
|
||||
//Invocation Message
|
||||
String target = jsonMessage.get("target").getAsString();
|
||||
JsonElement args = jsonMessage.get("arguments");
|
||||
hubMessages.add(new InvocationMessage(target, new Object[] {args}));
|
||||
if (argumentsToken != null) {
|
||||
List<Class<?>> types = binder.getParameterTypes(target);
|
||||
if (types != null && types.size() >= 1) {
|
||||
arguments = new ArrayList<>();
|
||||
for (int i = 0; i < types.size(); i++) {
|
||||
arguments.add(gson.fromJson(argumentsToken.get(i), types.get(i)));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (arguments == null) {
|
||||
hubMessages.add(new InvocationMessage(target, new Object[0]));
|
||||
} else {
|
||||
hubMessages.add(new InvocationMessage(target, arguments.toArray()));
|
||||
}
|
||||
break;
|
||||
case STREAM_INVOCATION:
|
||||
case STREAM_ITEM:
|
||||
case COMPLETION:
|
||||
case STREAM_INVOCATION:
|
||||
case CANCEL_INVOCATION:
|
||||
throw new UnsupportedOperationException(String.format("The message type %s is not supported yet.", messageType));
|
||||
case PING:
|
||||
//Ping
|
||||
hubMessages.add(new PingMessage());
|
||||
break;
|
||||
case CLOSE:
|
||||
CloseMessage closeMessage;
|
||||
if (jsonMessage.has("error")) {
|
||||
String error = jsonMessage.get("error").getAsString();
|
||||
closeMessage = new CloseMessage(error);
|
||||
if (error != null) {
|
||||
hubMessages.add(new CloseMessage(error));
|
||||
} else {
|
||||
closeMessage = new CloseMessage();
|
||||
hubMessages.add(new CloseMessage());
|
||||
}
|
||||
hubMessages.add(closeMessage);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return hubMessages.toArray(new HubMessage[hubMessages.size()]);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
package com.microsoft.aspnet.signalr;
|
||||
|
||||
class StreamInvocationMessage extends InvocationMessage {
|
||||
|
||||
int type = HubMessageType.STREAM_INVOCATION.value;
|
||||
|
||||
public StreamInvocationMessage(String invocationId, String target, Object[] arguments) {
|
||||
super(target, arguments);
|
||||
this.invocationId = invocationId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HubMessageType getMessageType() {
|
||||
return HubMessageType.STREAM_INVOCATION;
|
||||
}
|
||||
}
|
||||
|
|
@ -7,19 +7,19 @@ import java.util.List;
|
|||
|
||||
public class Subscription {
|
||||
private CallbackMap handlers;
|
||||
private ActionBase action;
|
||||
private InvocationHandler handler;
|
||||
private String target;
|
||||
|
||||
public Subscription(CallbackMap handlers, ActionBase action, String target) {
|
||||
public Subscription(CallbackMap handlers, InvocationHandler handler, String target) {
|
||||
this.handlers = handlers;
|
||||
this.action = action;
|
||||
this.handler = handler;
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
public void unsubscribe() {
|
||||
List<ActionBase> actions = this.handlers.get(target);
|
||||
if (actions != null) {
|
||||
actions.remove(action);
|
||||
List<InvocationHandler> handler = this.handlers.get(target);
|
||||
if (handler != null) {
|
||||
handler.remove(this.handler);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ public class HubConnectionTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void HubConnectionClosesAfterCloseMessage() throws Exception {
|
||||
public void hubConnectionClosesAfterCloseMessage() throws Exception {
|
||||
MockTransport mockTransport = new MockTransport();
|
||||
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, true);
|
||||
|
||||
|
|
@ -46,7 +46,7 @@ public class HubConnectionTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void HubConnectionReceiveHandshakeResponseWithError() throws Exception {
|
||||
public void hubConnectionReceiveHandshakeResponseWithError() throws Exception {
|
||||
exceptionRule.expect(HubException.class);
|
||||
exceptionRule.expectMessage("Requested protocol 'messagepack' is not available.");
|
||||
|
||||
|
|
@ -58,7 +58,7 @@ public class HubConnectionTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void RegisteringMultipleHandlersAndBothGetTriggered() throws Exception {
|
||||
public void registeringMultipleHandlersAndBothGetTriggered() throws Exception {
|
||||
AtomicReference<Double> value = new AtomicReference<>(0.0);
|
||||
MockTransport mockTransport = new MockTransport();
|
||||
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, true);
|
||||
|
|
@ -84,7 +84,7 @@ public class HubConnectionTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void RemoveHandlerByName() throws Exception {
|
||||
public void removeHandlerByName() throws Exception {
|
||||
AtomicReference<Double> value = new AtomicReference<>(0.0);
|
||||
MockTransport mockTransport = new MockTransport();
|
||||
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, true);
|
||||
|
|
@ -111,7 +111,7 @@ public class HubConnectionTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void AddAndRemoveHandlerImmediately() throws Exception {
|
||||
public void addAndRemoveHandlerImmediately() throws Exception {
|
||||
AtomicReference<Double> value = new AtomicReference<>(0.0);
|
||||
MockTransport mockTransport = new MockTransport();
|
||||
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, true);
|
||||
|
|
@ -132,11 +132,11 @@ public class HubConnectionTest {
|
|||
mockTransport.receiveMessage("{\"type\":1,\"target\":\"inc\",\"arguments\":[]}" + RECORD_SEPARATOR);
|
||||
|
||||
// Confirming that the handler was removed.
|
||||
assertEquals(0, value.get(), 0);
|
||||
assertEquals(0.0, value.get(), 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void RemovingMultipleHandlersWithOneCallToRemove() throws Exception {
|
||||
public void removingMultipleHandlersWithOneCallToRemove() throws Exception {
|
||||
AtomicReference<Double> value = new AtomicReference<>(0.0);
|
||||
MockTransport mockTransport = new MockTransport();
|
||||
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, true);
|
||||
|
|
@ -168,7 +168,7 @@ public class HubConnectionTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void RemoveHandlerWithUnsubscribe() throws Exception {
|
||||
public void removeHandlerWithUnsubscribe() throws Exception {
|
||||
AtomicReference<Double> value = new AtomicReference<>(0.0);
|
||||
MockTransport mockTransport = new MockTransport();
|
||||
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, true);
|
||||
|
|
@ -191,12 +191,17 @@ public class HubConnectionTest {
|
|||
assertEquals(1, value.get(), 0);
|
||||
|
||||
subscription.unsubscribe();
|
||||
mockTransport.receiveMessage("{\"type\":1,\"target\":\"inc\",\"arguments\":[]}" + RECORD_SEPARATOR);
|
||||
try {
|
||||
mockTransport.receiveMessage("{\"type\":1,\"target\":\"inc\",\"arguments\":[]}" + RECORD_SEPARATOR);
|
||||
} catch (Exception ex) {
|
||||
assertEquals("There are no callbacks registered for the method 'inc'.", ex.getMessage());
|
||||
}
|
||||
|
||||
assertEquals(1, value.get(), 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void UnsubscribeTwice() throws Exception {
|
||||
public void unsubscribeTwice() throws Exception {
|
||||
AtomicReference<Double> value = new AtomicReference<>(0.0);
|
||||
MockTransport mockTransport = new MockTransport();
|
||||
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, true);
|
||||
|
|
@ -220,12 +225,17 @@ public class HubConnectionTest {
|
|||
|
||||
subscription.unsubscribe();
|
||||
subscription.unsubscribe();
|
||||
mockTransport.receiveMessage("{\"type\":1,\"target\":\"inc\",\"arguments\":[]}" + RECORD_SEPARATOR);
|
||||
try {
|
||||
mockTransport.receiveMessage("{\"type\":1,\"target\":\"inc\",\"arguments\":[]}" + RECORD_SEPARATOR);
|
||||
} catch (Exception ex) {
|
||||
assertEquals("There are no callbacks registered for the method 'inc'.", ex.getMessage());
|
||||
}
|
||||
|
||||
assertEquals(1, value.get(), 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void RemoveSingleHandlerWithUnsubscribe() throws Exception {
|
||||
public void removeSingleHandlerWithUnsubscribe() throws Exception {
|
||||
AtomicReference<Double> value = new AtomicReference<>(0.0);
|
||||
MockTransport mockTransport = new MockTransport();
|
||||
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, true);
|
||||
|
|
@ -255,7 +265,7 @@ public class HubConnectionTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void AddAndRemoveHandlerImmediatelyWithSubscribe() throws Exception {
|
||||
public void addAndRemoveHandlerImmediatelyWithSubscribe() throws Exception {
|
||||
AtomicReference<Double> value = new AtomicReference<>(0.0);
|
||||
MockTransport mockTransport = new MockTransport();
|
||||
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, true);
|
||||
|
|
@ -268,13 +278,19 @@ public class HubConnectionTest {
|
|||
|
||||
hubConnection.start();
|
||||
mockTransport.receiveMessage("{}" + RECORD_SEPARATOR);
|
||||
mockTransport.receiveMessage("{\"type\":1,\"target\":\"inc\",\"arguments\":[]}" + RECORD_SEPARATOR);
|
||||
|
||||
try {
|
||||
mockTransport.receiveMessage("{\"type\":1,\"target\":\"inc\",\"arguments\":[]}" + RECORD_SEPARATOR);
|
||||
} catch (Exception ex) {
|
||||
assertEquals("There are no callbacks registered for the method 'inc'.", ex.getMessage());
|
||||
}
|
||||
|
||||
// Confirming that the handler was removed.
|
||||
assertEquals(0, value.get(), 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void RegisteringMultipleHandlersThatTakeParamsAndBothGetTriggered() throws Exception {
|
||||
public void registeringMultipleHandlersThatTakeParamsAndBothGetTriggered() throws Exception {
|
||||
AtomicReference<Double> value = new AtomicReference<>(0.0);
|
||||
MockTransport mockTransport = new MockTransport();
|
||||
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, true);
|
||||
|
|
@ -296,7 +312,7 @@ public class HubConnectionTest {
|
|||
|
||||
// We're using AtomicReference<Double> in the send tests instead of int here because Gson has trouble deserializing to Integer
|
||||
@Test
|
||||
public void SendWithNoParamsTriggersOnHandler() throws Exception {
|
||||
public void sendWithNoParamsTriggersOnHandler() throws Exception {
|
||||
AtomicReference<Double> value = new AtomicReference<Double>(0.0);
|
||||
MockTransport mockTransport = new MockTransport();
|
||||
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, true);
|
||||
|
|
@ -315,7 +331,7 @@ public class HubConnectionTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void SendWithParamTriggersOnHandler() throws Exception {
|
||||
public void sendWithParamTriggersOnHandler() throws Exception {
|
||||
AtomicReference<String> value = new AtomicReference<>();
|
||||
MockTransport mockTransport = new MockTransport();
|
||||
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, true);
|
||||
|
|
@ -335,7 +351,7 @@ public class HubConnectionTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void SendWithTwoParamsTriggersOnHandler() throws Exception {
|
||||
public void sendWithTwoParamsTriggersOnHandler() throws Exception {
|
||||
AtomicReference<String> value1 = new AtomicReference<>();
|
||||
AtomicReference<Double> value2 = new AtomicReference<>();
|
||||
|
||||
|
|
@ -361,7 +377,7 @@ public class HubConnectionTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void SendWithThreeParamsTriggersOnHandler() throws Exception {
|
||||
public void sendWithThreeParamsTriggersOnHandler() throws Exception {
|
||||
AtomicReference<String> value1 = new AtomicReference<>();
|
||||
AtomicReference<String> value2 = new AtomicReference<>();
|
||||
AtomicReference<String> value3 = new AtomicReference<>();
|
||||
|
|
@ -391,7 +407,7 @@ public class HubConnectionTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void SendWithFourParamsTriggersOnHandler() throws Exception {
|
||||
public void sendWithFourParamsTriggersOnHandler() throws Exception {
|
||||
AtomicReference<String> value1 = new AtomicReference<>();
|
||||
AtomicReference<String> value2 = new AtomicReference<>();
|
||||
AtomicReference<String> value3 = new AtomicReference<>();
|
||||
|
|
@ -424,7 +440,7 @@ public class HubConnectionTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void SendWithFiveParamsTriggersOnHandler() throws Exception {
|
||||
public void sendWithFiveParamsTriggersOnHandler() throws Exception {
|
||||
AtomicReference<String> value1 = new AtomicReference<>();
|
||||
AtomicReference<String> value2 = new AtomicReference<>();
|
||||
AtomicReference<String> value3 = new AtomicReference<>();
|
||||
|
|
@ -461,7 +477,7 @@ public class HubConnectionTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void SendWithSixParamsTriggersOnHandler() throws Exception {
|
||||
public void sendWithSixParamsTriggersOnHandler() throws Exception {
|
||||
AtomicReference<String> value1 = new AtomicReference<>();
|
||||
AtomicReference<String> value2 = new AtomicReference<>();
|
||||
AtomicReference<String> value3 = new AtomicReference<>();
|
||||
|
|
@ -502,7 +518,7 @@ public class HubConnectionTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void SendWithSevenParamsTriggersOnHandler() throws Exception {
|
||||
public void sendWithSevenParamsTriggersOnHandler() throws Exception {
|
||||
AtomicReference<String> value1 = new AtomicReference<>();
|
||||
AtomicReference<String> value2 = new AtomicReference<>();
|
||||
AtomicReference<String> value3 = new AtomicReference<>();
|
||||
|
|
@ -547,7 +563,7 @@ public class HubConnectionTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void SendWithEightParamsTriggersOnHandler() throws Exception {
|
||||
public void sendWithEightParamsTriggersOnHandler() throws Exception {
|
||||
AtomicReference<String> value1 = new AtomicReference<>();
|
||||
AtomicReference<String> value2 = new AtomicReference<>();
|
||||
AtomicReference<String> value3 = new AtomicReference<>();
|
||||
|
|
@ -594,8 +610,40 @@ public class HubConnectionTest {
|
|||
assertEquals("F", value8.get());
|
||||
}
|
||||
|
||||
private class Custom {
|
||||
public int number;
|
||||
public String str;
|
||||
public boolean[] bools;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ReceiveHandshakeResponseAndMessage() throws Exception {
|
||||
public void sendWithCustomObjectTriggersOnHandler() throws Exception {
|
||||
AtomicReference<Custom> value1 = new AtomicReference<>();
|
||||
|
||||
MockTransport mockTransport = new MockTransport();
|
||||
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, true);
|
||||
|
||||
hubConnection.on("inc", (param1) -> {
|
||||
assertNull(value1.get());
|
||||
|
||||
value1.set(param1);
|
||||
}, Custom.class);
|
||||
|
||||
hubConnection.start();
|
||||
mockTransport.receiveMessage("{}" + RECORD_SEPARATOR);
|
||||
mockTransport.receiveMessage("{\"type\":1,\"target\":\"inc\",\"arguments\":[{\"number\":1,\"str\":\"A\",\"bools\":[true,false]}]}" + RECORD_SEPARATOR);
|
||||
|
||||
// Confirming that our handler was called and the correct message was passed in.
|
||||
Custom custom = value1.get();
|
||||
assertEquals(1, custom.number);
|
||||
assertEquals("A", custom.str);
|
||||
assertEquals(2, custom.bools.length);
|
||||
assertEquals(true, custom.bools[0]);
|
||||
assertEquals(false, custom.bools[1]);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void receiveHandshakeResponseAndMessage() throws Exception {
|
||||
AtomicReference<Double> value = new AtomicReference<Double>(0.0);
|
||||
MockTransport mockTransport = new MockTransport();
|
||||
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, true);
|
||||
|
|
@ -660,7 +708,7 @@ public class HubConnectionTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void HubConnectionClosesAndRunsOnClosedCallbackAfterCloseMessageWithError() throws Exception {
|
||||
public void hubConnectionClosesAndRunsOnClosedCallbackAfterCloseMessageWithError() throws Exception {
|
||||
MockTransport mockTransport = new MockTransport();
|
||||
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, true);
|
||||
hubConnection.onClosed((ex) -> {
|
||||
|
|
@ -677,7 +725,7 @@ public class HubConnectionTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void CallingStartOnStartedHubConnectionNoOps() throws Exception {
|
||||
public void callingStartOnStartedHubConnectionNoOps() throws Exception {
|
||||
Transport mockTransport = new MockTransport();
|
||||
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, true);
|
||||
hubConnection.start();
|
||||
|
|
@ -691,7 +739,7 @@ public class HubConnectionTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void CannotSendBeforeStart() throws Exception {
|
||||
public void cannotSendBeforeStart() throws Exception {
|
||||
exceptionRule.expect(HubException.class);
|
||||
exceptionRule.expectMessage("The 'send' method cannot be called if the connection is not active");
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,11 @@ package com.microsoft.aspnet.signalr;
|
|||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.PriorityBlockingQueue;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
|
|
@ -30,7 +35,7 @@ public class JsonHubProtocolTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void VerifyWriteMessage() {
|
||||
public void verifyWriteMessage() {
|
||||
InvocationMessage invocationMessage = new InvocationMessage("test", new Object[] {"42"});
|
||||
String result = jsonHubProtocol.writeMessage(invocationMessage);
|
||||
String expectedResult = "{\"type\":1,\"target\":\"test\",\"arguments\":[\"42\"]}\u001E";
|
||||
|
|
@ -38,9 +43,11 @@ public class JsonHubProtocolTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void ParsePingMessage() {
|
||||
public void parsePingMessage() throws Exception {
|
||||
String stringifiedMessage = "{\"type\":6}\u001E";
|
||||
HubMessage[] messages = jsonHubProtocol.parseMessages(stringifiedMessage);
|
||||
TestBinder binder = new TestBinder(new PingMessage());
|
||||
|
||||
HubMessage[] messages = jsonHubProtocol.parseMessages(stringifiedMessage, binder);
|
||||
|
||||
//We know it's only one message
|
||||
assertEquals(1, messages.length);
|
||||
|
|
@ -48,9 +55,11 @@ public class JsonHubProtocolTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void ParseCloseMessage() {
|
||||
public void parseCloseMessage() throws Exception {
|
||||
String stringifiedMessage = "{\"type\":7}\u001E";
|
||||
HubMessage[] messages = jsonHubProtocol.parseMessages(stringifiedMessage);
|
||||
TestBinder binder = new TestBinder(new CloseMessage());
|
||||
|
||||
HubMessage[] messages = jsonHubProtocol.parseMessages(stringifiedMessage, binder);
|
||||
|
||||
//We know it's only one message
|
||||
assertEquals(1, messages.length);
|
||||
|
|
@ -64,9 +73,11 @@ public class JsonHubProtocolTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void ParseCloseMessageWithError() {
|
||||
public void parseCloseMessageWithError() throws Exception {
|
||||
String stringifiedMessage = "{\"type\":7,\"error\": \"There was an error\"}\u001E";
|
||||
HubMessage[] messages = jsonHubProtocol.parseMessages(stringifiedMessage);
|
||||
TestBinder binder = new TestBinder(new CloseMessage("There was an error"));
|
||||
|
||||
HubMessage[] messages = jsonHubProtocol.parseMessages(stringifiedMessage, binder);
|
||||
|
||||
//We know it's only one message
|
||||
assertEquals(1, messages.length);
|
||||
|
|
@ -80,9 +91,11 @@ public class JsonHubProtocolTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void ParseSingleMessage() {
|
||||
public void parseSingleMessage() throws Exception {
|
||||
String stringifiedMessage = "{\"type\":1,\"target\":\"test\",\"arguments\":[42]}\u001E";
|
||||
HubMessage[] messages = jsonHubProtocol.parseMessages(stringifiedMessage);
|
||||
TestBinder binder = new TestBinder(new InvocationMessage("test", new Object[] { 42 }));
|
||||
|
||||
HubMessage[] messages = jsonHubProtocol.parseMessages(stringifiedMessage, binder);
|
||||
|
||||
//We know it's only one message
|
||||
assertEquals(1, messages.length);
|
||||
|
|
@ -95,50 +108,59 @@ public class JsonHubProtocolTest {
|
|||
assertEquals("test", invocationMessage.getTarget());
|
||||
assertEquals(null, invocationMessage.getInvocationId());
|
||||
|
||||
JsonArray messageResult = (JsonArray) invocationMessage.getArguments()[0];
|
||||
assertEquals(42, messageResult.getAsInt());
|
||||
int messageResult = (int)invocationMessage.getArguments()[0];
|
||||
assertEquals(42, messageResult);
|
||||
}
|
||||
|
||||
@Rule
|
||||
public ExpectedException exceptionRule = ExpectedException.none();
|
||||
|
||||
@Test
|
||||
public void ParseSingleUnsupportedStreamItemMessage() {
|
||||
public void parseSingleUnsupportedStreamItemMessage() throws Exception {
|
||||
exceptionRule.expect(UnsupportedOperationException.class);
|
||||
exceptionRule.expectMessage("The message type STREAM_ITEM is not supported yet.");
|
||||
String stringifiedMessage = "{\"type\":2,\"Id\":1,\"Item\":42}\u001E";
|
||||
HubMessage[] messages = jsonHubProtocol.parseMessages(stringifiedMessage);
|
||||
TestBinder binder = new TestBinder(null);
|
||||
|
||||
HubMessage[] messages = jsonHubProtocol.parseMessages(stringifiedMessage, binder);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ParseSingleUnsupportedStreamInvocationMessage() {
|
||||
public void parseSingleUnsupportedStreamInvocationMessage() throws Exception {
|
||||
exceptionRule.expect(UnsupportedOperationException.class);
|
||||
exceptionRule.expectMessage("The message type STREAM_INVOCATION is not supported yet.");
|
||||
String stringifiedMessage = "{\"type\":4,\"Id\":1,\"target\":\"test\",\"arguments\":[42]}\u001E";
|
||||
TestBinder binder = new TestBinder(new StreamInvocationMessage("1", "test", new Object[] { 42 }));
|
||||
|
||||
HubMessage[] messages = jsonHubProtocol.parseMessages(stringifiedMessage);
|
||||
HubMessage[] messages = jsonHubProtocol.parseMessages(stringifiedMessage, binder);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ParseSingleUnsupportedCancelInvocationMessage() {
|
||||
public void parseSingleUnsupportedCancelInvocationMessage() throws Exception {
|
||||
exceptionRule.expect(UnsupportedOperationException.class);
|
||||
exceptionRule.expectMessage("The message type CANCEL_INVOCATION is not supported yet.");
|
||||
String stringifiedMessage = "{\"type\":5,\"invocationId\":123}\u001E";
|
||||
HubMessage[] messages = jsonHubProtocol.parseMessages(stringifiedMessage);
|
||||
TestBinder binder = new TestBinder(null);
|
||||
|
||||
HubMessage[] messages = jsonHubProtocol.parseMessages(stringifiedMessage, binder);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ParseSingleUnsupportedCompletionMessage() {
|
||||
public void parseSingleUnsupportedCompletionMessage() throws Exception {
|
||||
exceptionRule.expect(UnsupportedOperationException.class);
|
||||
exceptionRule.expectMessage("The message type COMPLETION is not supported yet.");
|
||||
String stringifiedMessage = "{\"type\":3,\"invocationId\":123}\u001E";
|
||||
HubMessage[] messages = jsonHubProtocol.parseMessages(stringifiedMessage);
|
||||
TestBinder binder = new TestBinder(null);
|
||||
|
||||
HubMessage[] messages = jsonHubProtocol.parseMessages(stringifiedMessage, binder);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ParseTwoMessages() {
|
||||
public void parseTwoMessages() throws Exception {
|
||||
String twoMessages = "{\"type\":1,\"target\":\"one\",\"arguments\":[42]}\u001E{\"type\":1,\"target\":\"two\",\"arguments\":[43]}\u001E";
|
||||
HubMessage[] messages = jsonHubProtocol.parseMessages(twoMessages);
|
||||
TestBinder binder = new TestBinder(new InvocationMessage("one", new Object[] { 42 }));
|
||||
|
||||
HubMessage[] messages = jsonHubProtocol.parseMessages(twoMessages, binder);
|
||||
assertEquals(2, messages.length);
|
||||
|
||||
// Check the first message
|
||||
|
|
@ -149,8 +171,8 @@ public class JsonHubProtocolTest {
|
|||
|
||||
assertEquals("one", invocationMessage.getTarget());
|
||||
assertEquals(null, invocationMessage.getInvocationId());
|
||||
JsonArray messageResult = (JsonArray) invocationMessage.getArguments()[0];
|
||||
assertEquals(42, messageResult.getAsInt());
|
||||
int messageResult = (int)invocationMessage.getArguments()[0];
|
||||
assertEquals(42, messageResult);
|
||||
|
||||
// Check the second message
|
||||
assertEquals(HubMessageType.INVOCATION, messages[1].getMessageType());
|
||||
|
|
@ -160,14 +182,16 @@ public class JsonHubProtocolTest {
|
|||
|
||||
assertEquals("two", invocationMessage2.getTarget());
|
||||
assertEquals(null, invocationMessage2.getInvocationId());
|
||||
JsonArray secondMessageResult = (JsonArray) invocationMessage2.getArguments()[0];
|
||||
assertEquals(43, secondMessageResult.getAsInt());
|
||||
int secondMessageResult = (int)invocationMessage2.getArguments()[0];
|
||||
assertEquals(43, secondMessageResult);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ParseSingleMessageMutipleArgs() {
|
||||
public void parseSingleMessageMutipleArgs() throws Exception {
|
||||
String stringifiedMessage = "{\"type\":1,\"target\":\"test\",\"arguments\":[42, 24]}\u001E";
|
||||
HubMessage[] messages = jsonHubProtocol.parseMessages(stringifiedMessage);
|
||||
TestBinder binder = new TestBinder(new InvocationMessage("test", new Object[] { 42, 24 }));
|
||||
|
||||
HubMessage[] messages = jsonHubProtocol.parseMessages(stringifiedMessage, binder);
|
||||
|
||||
//We know it's only one message
|
||||
assertEquals(HubMessageType.INVOCATION, messages[0].getMessageType());
|
||||
|
|
@ -175,8 +199,72 @@ public class JsonHubProtocolTest {
|
|||
InvocationMessage message = (InvocationMessage)messages[0];
|
||||
assertEquals("test", message.getTarget());
|
||||
assertEquals(null, message.getInvocationId());
|
||||
JsonArray messageResult = ((JsonArray) message.getArguments()[0]);
|
||||
assertEquals(42, messageResult.get(0).getAsInt());
|
||||
assertEquals(24, messageResult.get(1).getAsInt());
|
||||
int messageResult = (int) message.getArguments()[0];
|
||||
int messageResult2 = (int) message.getArguments()[1];
|
||||
assertEquals(42, messageResult);
|
||||
assertEquals(24, messageResult2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseMessageWithOutOfOrderProperties() throws Exception {
|
||||
String stringifiedMessage = "{\"arguments\":[42, 24],\"type\":1,\"target\":\"test\"}\u001E";
|
||||
TestBinder binder = new TestBinder(new InvocationMessage("test", new Object[] { 42, 24 }));
|
||||
|
||||
HubMessage[] messages = jsonHubProtocol.parseMessages(stringifiedMessage, binder);
|
||||
|
||||
// We know it's only one message
|
||||
assertEquals(HubMessageType.INVOCATION, messages[0].getMessageType());
|
||||
|
||||
InvocationMessage message = (InvocationMessage) messages[0];
|
||||
assertEquals("test", message.getTarget());
|
||||
assertEquals(null, message.getInvocationId());
|
||||
int messageResult = (int) message.getArguments()[0];
|
||||
int messageResult2 = (int) message.getArguments()[1];
|
||||
assertEquals(42, messageResult);
|
||||
assertEquals(24, messageResult2);
|
||||
}
|
||||
|
||||
private class TestBinder implements InvocationBinder {
|
||||
private Class<?>[] paramTypes = null;
|
||||
|
||||
public TestBinder(HubMessage expectedMessage) {
|
||||
if (expectedMessage == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (expectedMessage.getMessageType()) {
|
||||
case STREAM_INVOCATION:
|
||||
ArrayList<Class<?>> streamTypes = new ArrayList<>();
|
||||
for (Object obj : ((StreamInvocationMessage) expectedMessage).getArguments()) {
|
||||
streamTypes.add(obj.getClass());
|
||||
}
|
||||
paramTypes = streamTypes.toArray(new Class<?>[streamTypes.size()]);
|
||||
break;
|
||||
case INVOCATION:
|
||||
ArrayList<Class<?>> types = new ArrayList<>();
|
||||
for (Object obj : ((InvocationMessage) expectedMessage).getArguments()) {
|
||||
types.add(obj.getClass());
|
||||
}
|
||||
paramTypes = types.toArray(new Class<?>[types.size()]);
|
||||
break;
|
||||
case STREAM_ITEM:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getReturnType(String invocationId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Class<?>> getParameterTypes(String methodName) {
|
||||
if (paramTypes == null) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
return new ArrayList<Class<?>>(Arrays.asList(paramTypes));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -228,17 +228,17 @@ namespace Microsoft.AspNetCore.SignalR.Protocol
|
|||
completed = true;
|
||||
break;
|
||||
default:
|
||||
throw new InvalidDataException($"Unexpected token '{reader.TokenType}' when reading handshake request JSON.");
|
||||
throw new InvalidDataException($"Unexpected token '{reader.TokenType}' when reading handshake request JSON. Message content: {GetPayloadAsString()}");
|
||||
}
|
||||
}
|
||||
|
||||
if (protocol == null)
|
||||
{
|
||||
throw new InvalidDataException($"Missing required property '{ProtocolPropertyName}'.");
|
||||
throw new InvalidDataException($"Missing required property '{ProtocolPropertyName}'. Message content: {GetPayloadAsString()}");
|
||||
}
|
||||
if (protocolVersion == null)
|
||||
{
|
||||
throw new InvalidDataException($"Missing required property '{ProtocolVersionPropertyName}'.");
|
||||
throw new InvalidDataException($"Missing required property '{ProtocolVersionPropertyName}'. Message content: {GetPayloadAsString()}");
|
||||
}
|
||||
|
||||
requestMessage = new HandshakeRequestMessage(protocol, protocolVersion.Value);
|
||||
|
|
@ -249,6 +249,13 @@ namespace Microsoft.AspNetCore.SignalR.Protocol
|
|||
Utf8BufferTextReader.Return(textReader);
|
||||
}
|
||||
|
||||
// For error messages, we want to print the payload as text
|
||||
string GetPayloadAsString()
|
||||
{
|
||||
// REVIEW: Should we show hex for binary charaters?
|
||||
return Encoding.UTF8.GetString(payload.ToArray());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,10 +61,11 @@ namespace Microsoft.AspNetCore.SignalR.Common.Tests.Internal.Protocol
|
|||
[InlineData("42\u001e", "Unexpected JSON Token Type 'Integer'. Expected a JSON Object.")]
|
||||
[InlineData("\"42\"\u001e", "Unexpected JSON Token Type 'String'. Expected a JSON Object.")]
|
||||
[InlineData("null\u001e", "Unexpected JSON Token Type 'Null'. Expected a JSON Object.")]
|
||||
[InlineData("{}\u001e", "Missing required property 'protocol'.")]
|
||||
[InlineData("{}\u001e", "Missing required property 'protocol'. Message content: {}")]
|
||||
[InlineData("[]\u001e", "Unexpected JSON Token Type 'Array'. Expected a JSON Object.")]
|
||||
[InlineData("{\"protocol\":\"json\"}\u001e", "Missing required property 'version'.")]
|
||||
[InlineData("{\"version\":1}\u001e", "Missing required property 'protocol'.")]
|
||||
[InlineData("{\"protocol\":\"json\"}\u001e", "Missing required property 'version'. Message content: {\"protocol\":\"json\"}")]
|
||||
[InlineData("{\"version\":1}\u001e", "Missing required property 'protocol'. Message content: {\"version\":1}")]
|
||||
[InlineData("{\"type\":4,\"invocationId\":\"42\",\"target\":\"foo\",\"arguments\":{}}\u001e", "Missing required property 'protocol'. Message content: {\"type\":4,\"invocationId\":\"42\",\"target\":\"foo\",\"arguments\":{}}")]
|
||||
[InlineData("{\"version\":\"123\"}\u001e", "Expected 'version' to be of type Integer.")]
|
||||
[InlineData("{\"protocol\":null,\"version\":123}\u001e", "Expected 'protocol' to be of type String.")]
|
||||
public void ParsingHandshakeRequestMessageThrowsForInvalidMessages(string payload, string expectedMessage)
|
||||
|
|
|
|||
Loading…
Reference in New Issue