commit
36b407e5a3
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
package com.microsoft.aspnet.signalr;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface Action {
|
||||
void invoke();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
package com.microsoft.aspnet.signalr;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface Action1<T1> {
|
||||
void invoke(T1 param1);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
package com.microsoft.aspnet.signalr;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface Action2<T1, T2> {
|
||||
void invoke(T1 param1, T2 param2);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
package com.microsoft.aspnet.signalr;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface Action3<T1, T2, T3> {
|
||||
void invoke(T1 param1, T2 param2, T3 param3);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
package com.microsoft.aspnet.signalr;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface Action4<T1, T2, T3, T4> {
|
||||
void invoke(T1 param1, T2 param2, T3 param3, T4 param4);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
package com.microsoft.aspnet.signalr;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface Action5<T1, T2, T3, T4, T5> {
|
||||
void invoke(T1 param1, T2 param2, T3 param3, T4 param4, T5 param5);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
package com.microsoft.aspnet.signalr;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface Action6<T1, T2, T3, T4, T5, T6> {
|
||||
void invoke(T1 param1, T2 param2, T3 param3, T4 param4, T5 param5, T6 param6);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
package com.microsoft.aspnet.signalr;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface Action7<T1, T2, T3, T4, T5, T6, T7> {
|
||||
void invoke(T1 param1, T2 param2, T3 param3, T4 param4, T5 param5, T6 param6, T7 param7);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
package com.microsoft.aspnet.signalr;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface Action8<T1, T2, T3, T4, T5, T6, T7, T8> {
|
||||
void invoke(T1 param1, T2 param2, T3 param3, T4 param4, T5 param5, T6 param6, T7 param7, T8 param8);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
package com.microsoft.aspnet.signalr;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface ActionBase {
|
||||
void invoke(Object ... params);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,32 +3,30 @@
|
|||
|
||||
package com.microsoft.aspnet.signalr;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class HttpConnectionOptions {
|
||||
private String url;
|
||||
private Transport transport;
|
||||
private LogLevel loglevel;
|
||||
|
||||
private Logger logger;
|
||||
private boolean skipNegotiate;
|
||||
private Supplier<CompletableFuture<String>> accessTokenProvider;
|
||||
private HttpClient client;
|
||||
|
||||
public HttpConnectionOptions() {}
|
||||
|
||||
public HttpConnectionOptions(String url, Transport transport, LogLevel logLevel, boolean skipNegotiate) {
|
||||
this.url = url;
|
||||
public HttpConnectionOptions(Transport transport, LogLevel logLevel, boolean skipNegotiate) {
|
||||
this.transport = transport;
|
||||
this.skipNegotiate = skipNegotiate;
|
||||
this.loglevel = logLevel;
|
||||
}
|
||||
|
||||
public HttpConnectionOptions(String url, Transport transport, Logger logger, boolean skipNegotiate) {
|
||||
this.url = url;
|
||||
public HttpConnectionOptions(Transport transport, Logger logger, boolean skipNegotiate) {
|
||||
this.transport = transport;
|
||||
this.skipNegotiate = skipNegotiate;
|
||||
this.logger = logger;
|
||||
}
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public void setTransport(Transport transport) {
|
||||
this.transport = transport;
|
||||
|
|
@ -42,10 +40,6 @@ public class HttpConnectionOptions {
|
|||
this.skipNegotiate = skipNegotiate;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public Transport getTransport() {
|
||||
return transport;
|
||||
}
|
||||
|
|
@ -65,4 +59,21 @@ public class HttpConnectionOptions {
|
|||
public void setLogger(Logger logger) {
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
public void setAccessTokenProvider(Supplier<CompletableFuture<String>> accessTokenProvider) {
|
||||
this.accessTokenProvider = accessTokenProvider;
|
||||
}
|
||||
|
||||
public Supplier<CompletableFuture<String>> getAccessTokenProvider() {
|
||||
return accessTokenProvider;
|
||||
}
|
||||
|
||||
// For testing purposes only
|
||||
void setHttpClient(HttpClient client) {
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
HttpClient getHttpClient() {
|
||||
return client;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class HubConnection {
|
||||
private String baseUrl;
|
||||
|
|
@ -28,7 +29,7 @@ public class HubConnection {
|
|||
private Logger logger;
|
||||
private List<Consumer<Exception>> onClosedCallbackList;
|
||||
private boolean skipNegotiate = false;
|
||||
private String accessToken;
|
||||
private Supplier<CompletableFuture<String>> accessTokenProvider;
|
||||
private Map<String, String> headers = new HashMap<>();
|
||||
private ConnectionState connectionState = null;
|
||||
private HttpClient httpClient;
|
||||
|
|
@ -36,7 +37,7 @@ public class HubConnection {
|
|||
private static ArrayList<Class<?>> emptyArray = new ArrayList<>();
|
||||
private static int MAX_NEGOTIATE_ATTEMPTS = 100;
|
||||
|
||||
public HubConnection(String url, Transport transport, Logger logger, boolean skipNegotiate, HttpClient client) {
|
||||
public HubConnection(String url, HttpConnectionOptions options) {
|
||||
if (url == null || url.isEmpty()) {
|
||||
throw new IllegalArgumentException("A valid url is required.");
|
||||
}
|
||||
|
|
@ -44,26 +45,31 @@ public class HubConnection {
|
|||
this.baseUrl = url;
|
||||
this.protocol = new JsonHubProtocol();
|
||||
|
||||
if (logger != null) {
|
||||
this.logger = logger;
|
||||
if (options.getAccessTokenProvider() != null) {
|
||||
this.accessTokenProvider = options.getAccessTokenProvider();
|
||||
} else {
|
||||
this.accessTokenProvider = () -> CompletableFuture.completedFuture(null);
|
||||
}
|
||||
|
||||
if (options.getLogger() != null) {
|
||||
this.logger = options.getLogger();
|
||||
} else {
|
||||
this.logger = new NullLogger();
|
||||
}
|
||||
|
||||
if (client != null) {
|
||||
this.httpClient = client;
|
||||
if (options.getHttpClient() != null) {
|
||||
this.httpClient = options.getHttpClient();
|
||||
} else {
|
||||
this.httpClient = new DefaultHttpClient(this.logger);
|
||||
}
|
||||
|
||||
if (transport != null) {
|
||||
this.transport = transport;
|
||||
if (options.getTransport() != null) {
|
||||
this.transport = options.getTransport();
|
||||
}
|
||||
|
||||
this.skipNegotiate = skipNegotiate;
|
||||
this.skipNegotiate = options.getSkipNegotiate();
|
||||
|
||||
this.callback = (payload) -> {
|
||||
|
||||
if (!handshakeReceived) {
|
||||
int handshakeLength = payload.indexOf(RECORD_SEPARATOR) + 1;
|
||||
String handshakeResponseString = payload.substring(0, handshakeLength - 1);
|
||||
|
|
@ -126,11 +132,14 @@ public class HubConnection {
|
|||
};
|
||||
}
|
||||
|
||||
private CompletableFuture<NegotiateResponse> handleNegotiate(String url) throws IOException, InterruptedException, ExecutionException {
|
||||
private CompletableFuture<NegotiateResponse> handleNegotiate(String url) {
|
||||
HttpRequest request = new HttpRequest();
|
||||
request.setHeaders(this.headers);
|
||||
|
||||
return httpClient.post(Negotiate.resolveNegotiateUrl(url), request).thenCompose((response) -> {
|
||||
if (response.getStatusCode() != 200) {
|
||||
throw new RuntimeException(String.format("Unexpected status code returned from negotiate: %d %s.", response.getStatusCode(), response.getStatusText()));
|
||||
}
|
||||
NegotiateResponse negotiateResponse;
|
||||
try {
|
||||
negotiateResponse = new NegotiateResponse(response.getContent());
|
||||
|
|
@ -143,7 +152,15 @@ public class HubConnection {
|
|||
}
|
||||
|
||||
if (negotiateResponse.getAccessToken() != null) {
|
||||
this.headers.put("Authorization", "Bearer " + negotiateResponse.getAccessToken());
|
||||
this.accessTokenProvider = () -> CompletableFuture.completedFuture(negotiateResponse.getAccessToken());
|
||||
String token = "";
|
||||
try {
|
||||
// We know the future is already completed in this case
|
||||
// It's fine to call get() on it.
|
||||
token = this.accessTokenProvider.get().get();
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
}
|
||||
this.headers.put("Authorization", "Bearer " + token);
|
||||
}
|
||||
|
||||
return CompletableFuture.completedFuture(negotiateResponse);
|
||||
|
|
@ -169,11 +186,18 @@ public class HubConnection {
|
|||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
|
||||
CompletableFuture<Void> tokenFuture = accessTokenProvider.get()
|
||||
.thenAccept((token) -> {
|
||||
if (token != null) {
|
||||
this.headers.put("Authorization", "Bearer " + token);
|
||||
}
|
||||
});
|
||||
|
||||
CompletableFuture<String> negotiate = null;
|
||||
if (!skipNegotiate) {
|
||||
negotiate = startNegotiate(baseUrl, 0);
|
||||
negotiate = tokenFuture.thenCompose((v) -> startNegotiate(baseUrl, 0));
|
||||
} else {
|
||||
negotiate = CompletableFuture.completedFuture(baseUrl);
|
||||
negotiate = tokenFuture.thenCompose((v) -> CompletableFuture.completedFuture(baseUrl));
|
||||
}
|
||||
|
||||
return negotiate.thenCompose((url) -> {
|
||||
|
|
@ -207,7 +231,7 @@ public class HubConnection {
|
|||
});
|
||||
}
|
||||
|
||||
private CompletableFuture<String> startNegotiate(String url, int negotiateAttempts) throws IOException, InterruptedException, ExecutionException {
|
||||
private CompletableFuture<String> startNegotiate(String url, int negotiateAttempts) {
|
||||
if (hubConnectionState != HubConnectionState.DISCONNECTED) {
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
|
|
@ -238,11 +262,7 @@ public class HubConnection {
|
|||
return CompletableFuture.completedFuture(finalUrl);
|
||||
}
|
||||
|
||||
try {
|
||||
return startNegotiate(response.getRedirectUrl(), negotiateAttempts + 1);
|
||||
} catch (IOException | InterruptedException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return startNegotiate(response.getRedirectUrl(), negotiateAttempts + 1);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,8 +7,7 @@ public class HubConnectionBuilder {
|
|||
private String url;
|
||||
private Transport transport;
|
||||
private Logger logger;
|
||||
private boolean skipNegotiate;
|
||||
private HttpClient client;
|
||||
private HttpConnectionOptions options = null;
|
||||
|
||||
public HubConnectionBuilder withUrl(String url) {
|
||||
if (url == null || url.isEmpty()) {
|
||||
|
|
@ -30,13 +29,7 @@ public class HubConnectionBuilder {
|
|||
|
||||
public HubConnectionBuilder withUrl(String url, HttpConnectionOptions options) {
|
||||
this.url = url;
|
||||
this.transport = options.getTransport();
|
||||
if (options.getLogger() != null) {
|
||||
this.logger = options.getLogger();
|
||||
} else if (options.getLoglevel() != null) {
|
||||
this.logger = new ConsoleLogger(options.getLoglevel());
|
||||
}
|
||||
this.skipNegotiate = options.getSkipNegotiate();
|
||||
this.options = options;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
@ -50,16 +43,23 @@ public class HubConnectionBuilder {
|
|||
return this;
|
||||
}
|
||||
|
||||
// For testing purposes only
|
||||
HubConnectionBuilder configureHttpClient(HttpClient client) {
|
||||
this.client = client;
|
||||
return this;
|
||||
}
|
||||
|
||||
public HubConnection build() {
|
||||
if (this.url == null) {
|
||||
throw new RuntimeException("The 'HubConnectionBuilder.withUrl' method must be called before building the connection.");
|
||||
}
|
||||
return new HubConnection(url, transport, logger, skipNegotiate, client);
|
||||
if (options == null) {
|
||||
options = new HttpConnectionOptions();
|
||||
}
|
||||
if (options.getTransport() == null && this.transport != null) {
|
||||
options.setTransport(this.transport);
|
||||
}
|
||||
if (options.getLogger() == null && options.getLoglevel() != null) {
|
||||
options.setLogger(new ConsoleLogger(options.getLoglevel()));
|
||||
}
|
||||
if (options.getLogger() == null && this.logger != null) {
|
||||
options.setLogger(this.logger);
|
||||
}
|
||||
|
||||
return new HubConnection(url, options);
|
||||
}
|
||||
}
|
||||
|
|
@ -13,8 +13,7 @@ class HttpConnectionOptionsTest {
|
|||
@Test
|
||||
public void CheckHttpConnectionOptionsFields() {
|
||||
Transport mockTransport = new MockTransport();
|
||||
HttpConnectionOptions options = new HttpConnectionOptions("http://example.com", mockTransport, LogLevel.Information, true);
|
||||
assertEquals("http://example.com",options.getUrl());
|
||||
HttpConnectionOptions options = new HttpConnectionOptions(mockTransport, LogLevel.Information, true);
|
||||
assertEquals(LogLevel.Information, options.getLoglevel());
|
||||
assertTrue(options.getSkipNegotiate());
|
||||
assertNotNull(options.getTransport());
|
||||
|
|
|
|||
|
|
@ -21,8 +21,7 @@ class HubConnectionTest {
|
|||
|
||||
@Test
|
||||
public void checkHubConnectionState() throws Exception {
|
||||
Transport mockTransport = new MockTransport();
|
||||
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, new NullLogger(), true, new TestHttpClient());
|
||||
HubConnection hubConnection = TestUtils.createHubConnection("http://example.com");
|
||||
hubConnection.start();
|
||||
assertEquals(HubConnectionState.CONNECTED, hubConnection.getConnectionState());
|
||||
|
||||
|
|
@ -48,7 +47,7 @@ class HubConnectionTest {
|
|||
@Test
|
||||
public void hubConnectionClosesAfterCloseMessage() throws Exception {
|
||||
MockTransport mockTransport = new MockTransport();
|
||||
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, new NullLogger(), true, new TestHttpClient());
|
||||
HubConnection hubConnection = TestUtils.createHubConnection("http://example.com", mockTransport);
|
||||
|
||||
hubConnection.start();
|
||||
mockTransport.receiveMessage("{}" + RECORD_SEPARATOR);
|
||||
|
|
@ -63,7 +62,7 @@ class HubConnectionTest {
|
|||
@Test
|
||||
public void hubConnectionReceiveHandshakeResponseWithError() throws Exception {
|
||||
MockTransport mockTransport = new MockTransport();
|
||||
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, new NullLogger(), true, new TestHttpClient());
|
||||
HubConnection hubConnection = TestUtils.createHubConnection("http://example.com", mockTransport);
|
||||
|
||||
hubConnection.start();
|
||||
Throwable exception = assertThrows(HubException.class, () -> mockTransport.receiveMessage("{\"error\":\"Requested protocol 'messagepack' is not available.\"}" + RECORD_SEPARATOR));
|
||||
|
|
@ -74,7 +73,7 @@ class HubConnectionTest {
|
|||
public void registeringMultipleHandlersAndBothGetTriggered() throws Exception {
|
||||
AtomicReference<Double> value = new AtomicReference<>(0.0);
|
||||
MockTransport mockTransport = new MockTransport();
|
||||
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, new NullLogger(), true, new TestHttpClient());
|
||||
HubConnection hubConnection = TestUtils.createHubConnection("http://example.com", mockTransport);
|
||||
Action action = () -> value.getAndUpdate((val) -> val + 1);
|
||||
|
||||
hubConnection.on("inc", action);
|
||||
|
|
@ -100,7 +99,7 @@ class HubConnectionTest {
|
|||
public void removeHandlerByName() throws Exception {
|
||||
AtomicReference<Double> value = new AtomicReference<>(0.0);
|
||||
MockTransport mockTransport = new MockTransport();
|
||||
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, new NullLogger(), true, new TestHttpClient());
|
||||
HubConnection hubConnection = TestUtils.createHubConnection("http://example.com", mockTransport);
|
||||
Action action = () -> value.getAndUpdate((val) -> val + 1);
|
||||
|
||||
hubConnection.on("inc", action);
|
||||
|
|
@ -127,7 +126,7 @@ class HubConnectionTest {
|
|||
public void addAndRemoveHandlerImmediately() throws Exception {
|
||||
AtomicReference<Double> value = new AtomicReference<>(0.0);
|
||||
MockTransport mockTransport = new MockTransport();
|
||||
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, new NullLogger(), true, new TestHttpClient());
|
||||
HubConnection hubConnection = TestUtils.createHubConnection("http://example.com", mockTransport);
|
||||
Action action = () -> value.getAndUpdate((val) -> val + 1);
|
||||
|
||||
hubConnection.on("inc", action);
|
||||
|
|
@ -152,7 +151,7 @@ class HubConnectionTest {
|
|||
public void removingMultipleHandlersWithOneCallToRemove() throws Exception {
|
||||
AtomicReference<Double> value = new AtomicReference<>(0.0);
|
||||
MockTransport mockTransport = new MockTransport();
|
||||
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, new NullLogger(), true, new TestHttpClient());
|
||||
HubConnection hubConnection = TestUtils.createHubConnection("http://example.com", mockTransport);
|
||||
Action action = () -> value.getAndUpdate((val) -> val + 1);
|
||||
Action secondAction = () -> value.getAndUpdate((val) -> val + 2);
|
||||
|
||||
|
|
@ -184,7 +183,7 @@ class HubConnectionTest {
|
|||
public void removeHandlerWithUnsubscribe() throws Exception {
|
||||
AtomicReference<Double> value = new AtomicReference<>(0.0);
|
||||
MockTransport mockTransport = new MockTransport();
|
||||
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, new NullLogger(), true, new TestHttpClient());
|
||||
HubConnection hubConnection = TestUtils.createHubConnection("http://example.com", mockTransport);
|
||||
Action action = () -> value.getAndUpdate((val) -> val + 1);
|
||||
|
||||
Subscription subscription = hubConnection.on("inc", action);
|
||||
|
|
@ -217,7 +216,7 @@ class HubConnectionTest {
|
|||
public void unsubscribeTwice() throws Exception {
|
||||
AtomicReference<Double> value = new AtomicReference<>(0.0);
|
||||
MockTransport mockTransport = new MockTransport();
|
||||
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, new NullLogger(),true, new TestHttpClient());
|
||||
HubConnection hubConnection = TestUtils.createHubConnection("http://example.com", mockTransport);
|
||||
Action action = () -> value.getAndUpdate((val) -> val + 1);
|
||||
|
||||
Subscription subscription = hubConnection.on("inc", action);
|
||||
|
|
@ -251,7 +250,7 @@ class HubConnectionTest {
|
|||
public void removeSingleHandlerWithUnsubscribe() throws Exception {
|
||||
AtomicReference<Double> value = new AtomicReference<>(0.0);
|
||||
MockTransport mockTransport = new MockTransport();
|
||||
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, new NullLogger(), true, new TestHttpClient());
|
||||
HubConnection hubConnection = TestUtils.createHubConnection("http://example.com", mockTransport);
|
||||
Action action = () -> value.getAndUpdate((val) -> val + 1);
|
||||
Action secondAction = () -> value.getAndUpdate((val) -> val + 2);
|
||||
|
||||
|
|
@ -281,7 +280,7 @@ class HubConnectionTest {
|
|||
public void addAndRemoveHandlerImmediatelyWithSubscribe() throws Exception {
|
||||
AtomicReference<Double> value = new AtomicReference<>(0.0);
|
||||
MockTransport mockTransport = new MockTransport();
|
||||
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, new NullLogger(), true, new TestHttpClient());
|
||||
HubConnection hubConnection = TestUtils.createHubConnection("http://example.com", mockTransport);
|
||||
Action action = () -> value.getAndUpdate((val) -> val + 1);
|
||||
|
||||
Subscription sub = hubConnection.on("inc", action);
|
||||
|
|
@ -306,7 +305,7 @@ class HubConnectionTest {
|
|||
public void registeringMultipleHandlersThatTakeParamsAndBothGetTriggered() throws Exception {
|
||||
AtomicReference<Double> value = new AtomicReference<>(0.0);
|
||||
MockTransport mockTransport = new MockTransport();
|
||||
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, new NullLogger(), true, new TestHttpClient());
|
||||
HubConnection hubConnection = TestUtils.createHubConnection("http://example.com", mockTransport);
|
||||
|
||||
Action1<Double> action = (number) -> value.getAndUpdate((val) -> val + number);
|
||||
|
||||
|
|
@ -325,7 +324,7 @@ class HubConnectionTest {
|
|||
@Test
|
||||
public void invokeWaitsForCompletionMessage() throws Exception {
|
||||
MockTransport mockTransport = new MockTransport();
|
||||
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, new NullLogger(), true, new TestHttpClient());
|
||||
HubConnection hubConnection = TestUtils.createHubConnection("http://example.com", mockTransport);
|
||||
|
||||
hubConnection.start();
|
||||
mockTransport.receiveMessage("{}" + RECORD_SEPARATOR);
|
||||
|
|
@ -342,7 +341,7 @@ class HubConnectionTest {
|
|||
@Test
|
||||
public void multipleInvokesWaitForOwnCompletionMessage() throws Exception {
|
||||
MockTransport mockTransport = new MockTransport();
|
||||
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, new NullLogger(), true, new TestHttpClient());
|
||||
HubConnection hubConnection = TestUtils.createHubConnection("http://example.com", mockTransport);
|
||||
|
||||
hubConnection.start();
|
||||
mockTransport.receiveMessage("{}" + RECORD_SEPARATOR);
|
||||
|
|
@ -365,7 +364,7 @@ class HubConnectionTest {
|
|||
@Test
|
||||
public void invokeWorksForPrimitiveTypes() throws Exception {
|
||||
MockTransport mockTransport = new MockTransport();
|
||||
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, new NullLogger(), true, new TestHttpClient());
|
||||
HubConnection hubConnection = TestUtils.createHubConnection("http://example.com", mockTransport);
|
||||
|
||||
hubConnection.start();
|
||||
mockTransport.receiveMessage("{}" + RECORD_SEPARATOR);
|
||||
|
|
@ -383,7 +382,7 @@ class HubConnectionTest {
|
|||
@Test
|
||||
public void completionMessageCanHaveError() throws Exception {
|
||||
MockTransport mockTransport = new MockTransport();
|
||||
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, new NullLogger(), true, new TestHttpClient());
|
||||
HubConnection hubConnection = TestUtils.createHubConnection("http://example.com", mockTransport);
|
||||
|
||||
hubConnection.start();
|
||||
mockTransport.receiveMessage("{}" + RECORD_SEPARATOR);
|
||||
|
|
@ -407,7 +406,7 @@ class HubConnectionTest {
|
|||
@Test
|
||||
public void stopCancelsActiveInvokes() throws Exception {
|
||||
MockTransport mockTransport = new MockTransport();
|
||||
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, new NullLogger(), true, new TestHttpClient());
|
||||
HubConnection hubConnection = TestUtils.createHubConnection("http://example.com", mockTransport);
|
||||
|
||||
hubConnection.start();
|
||||
mockTransport.receiveMessage("{}" + RECORD_SEPARATOR);
|
||||
|
|
@ -432,7 +431,7 @@ class HubConnectionTest {
|
|||
public void sendWithNoParamsTriggersOnHandler() throws Exception {
|
||||
AtomicReference<Integer> value = new AtomicReference<>(0);
|
||||
MockTransport mockTransport = new MockTransport();
|
||||
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, new NullLogger(), true, new TestHttpClient());
|
||||
HubConnection hubConnection = TestUtils.createHubConnection("http://example.com", mockTransport);
|
||||
|
||||
hubConnection.on("inc", () ->{
|
||||
assertEquals(Integer.valueOf(0), value.get());
|
||||
|
|
@ -451,7 +450,7 @@ class HubConnectionTest {
|
|||
public void sendWithParamTriggersOnHandler() throws Exception {
|
||||
AtomicReference<String> value = new AtomicReference<>();
|
||||
MockTransport mockTransport = new MockTransport();
|
||||
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, new NullLogger(), true, new TestHttpClient());
|
||||
HubConnection hubConnection = TestUtils.createHubConnection("http://example.com", mockTransport);
|
||||
|
||||
hubConnection.on("inc", (param) ->{
|
||||
assertNull(value.get());
|
||||
|
|
@ -473,7 +472,7 @@ class HubConnectionTest {
|
|||
AtomicReference<Double> value2 = new AtomicReference<>();
|
||||
|
||||
MockTransport mockTransport = new MockTransport();
|
||||
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, new NullLogger(), true, new TestHttpClient());
|
||||
HubConnection hubConnection = TestUtils.createHubConnection("http://example.com", mockTransport);
|
||||
|
||||
hubConnection.on("inc", (param1, param2) ->{
|
||||
assertNull(value1.get());
|
||||
|
|
@ -500,7 +499,7 @@ class HubConnectionTest {
|
|||
AtomicReference<String> value3 = new AtomicReference<>();
|
||||
|
||||
MockTransport mockTransport = new MockTransport();
|
||||
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, new NullLogger(), true, new TestHttpClient());
|
||||
HubConnection hubConnection = TestUtils.createHubConnection("http://example.com", mockTransport);
|
||||
|
||||
hubConnection.on("inc", (param1, param2, param3) ->{
|
||||
assertNull(value1.get());
|
||||
|
|
@ -531,7 +530,7 @@ class HubConnectionTest {
|
|||
AtomicReference<String> value4 = new AtomicReference<>();
|
||||
|
||||
MockTransport mockTransport = new MockTransport();
|
||||
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, new NullLogger(), true, new TestHttpClient());
|
||||
HubConnection hubConnection = TestUtils.createHubConnection("http://example.com", mockTransport);
|
||||
|
||||
hubConnection.on("inc", (param1, param2, param3, param4) ->{
|
||||
assertNull(value1.get());
|
||||
|
|
@ -565,7 +564,7 @@ class HubConnectionTest {
|
|||
AtomicReference<Double> value5 = new AtomicReference<>();
|
||||
|
||||
MockTransport mockTransport = new MockTransport();
|
||||
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, new NullLogger(), true, new TestHttpClient());
|
||||
HubConnection hubConnection = TestUtils.createHubConnection("http://example.com", mockTransport);
|
||||
|
||||
hubConnection.on("inc", (param1, param2, param3, param4, param5) ->{
|
||||
assertNull(value1.get());
|
||||
|
|
@ -603,7 +602,7 @@ class HubConnectionTest {
|
|||
AtomicReference<String> value6 = new AtomicReference<>();
|
||||
|
||||
MockTransport mockTransport = new MockTransport();
|
||||
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, new NullLogger(), true, new TestHttpClient());
|
||||
HubConnection hubConnection = TestUtils.createHubConnection("http://example.com", mockTransport);
|
||||
|
||||
hubConnection.on("inc", (param1, param2, param3, param4, param5, param6) -> {
|
||||
assertNull(value1.get());
|
||||
|
|
@ -645,7 +644,7 @@ class HubConnectionTest {
|
|||
AtomicReference<String> value7 = new AtomicReference<>();
|
||||
|
||||
MockTransport mockTransport = new MockTransport();
|
||||
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, new NullLogger(), true, new TestHttpClient());
|
||||
HubConnection hubConnection = TestUtils.createHubConnection("http://example.com", mockTransport);
|
||||
|
||||
hubConnection.on("inc", (param1, param2, param3, param4, param5, param6, param7) -> {
|
||||
assertNull(value1.get());
|
||||
|
|
@ -691,7 +690,7 @@ class HubConnectionTest {
|
|||
AtomicReference<String> value8 = new AtomicReference<>();
|
||||
|
||||
MockTransport mockTransport = new MockTransport();
|
||||
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, new NullLogger(), true, new TestHttpClient());
|
||||
HubConnection hubConnection = TestUtils.createHubConnection("http://example.com", mockTransport);
|
||||
|
||||
hubConnection.on("inc", (param1, param2, param3, param4, param5, param6, param7, param8) -> {
|
||||
assertNull(value1.get());
|
||||
|
|
@ -738,7 +737,7 @@ class HubConnectionTest {
|
|||
AtomicReference<Custom> value1 = new AtomicReference<>();
|
||||
|
||||
MockTransport mockTransport = new MockTransport();
|
||||
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, new NullLogger(), true, new TestHttpClient());
|
||||
HubConnection hubConnection = TestUtils.createHubConnection("http://example.com", mockTransport);
|
||||
|
||||
hubConnection.on("inc", (param1) -> {
|
||||
assertNull(value1.get());
|
||||
|
|
@ -763,7 +762,7 @@ class HubConnectionTest {
|
|||
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, new NullLogger(), true, new TestHttpClient());
|
||||
HubConnection hubConnection = TestUtils.createHubConnection("http://example.com", mockTransport);
|
||||
|
||||
hubConnection.on("inc", () ->{
|
||||
assertEquals(Double.valueOf(0), value.get());
|
||||
|
|
@ -784,8 +783,7 @@ class HubConnectionTest {
|
|||
@Test
|
||||
public void onClosedCallbackRunsWhenStopIsCalled() throws Exception {
|
||||
AtomicReference<String> value1 = new AtomicReference<>();
|
||||
Transport mockTransport = new MockTransport();
|
||||
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, new NullLogger(), true, new TestHttpClient());
|
||||
HubConnection hubConnection = TestUtils.createHubConnection("http://example.com");
|
||||
hubConnection.start();
|
||||
hubConnection.onClosed((ex) -> {
|
||||
assertNull(value1.get());
|
||||
|
|
@ -801,8 +799,7 @@ class HubConnectionTest {
|
|||
public void multipleOnClosedCallbacksRunWhenStopIsCalled() throws Exception {
|
||||
AtomicReference<String> value1 = new AtomicReference<>();
|
||||
AtomicReference<String> value2 = new AtomicReference<>();
|
||||
Transport mockTransport = new MockTransport();
|
||||
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, new NullLogger(), true, new TestHttpClient());
|
||||
HubConnection hubConnection = TestUtils.createHubConnection("http://example.com");
|
||||
hubConnection.start();
|
||||
|
||||
hubConnection.onClosed((ex) -> {
|
||||
|
|
@ -827,7 +824,7 @@ class HubConnectionTest {
|
|||
@Test
|
||||
public void hubConnectionClosesAndRunsOnClosedCallbackAfterCloseMessageWithError() throws Exception {
|
||||
MockTransport mockTransport = new MockTransport();
|
||||
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, new NullLogger(), true, new TestHttpClient());
|
||||
HubConnection hubConnection = TestUtils.createHubConnection("http://example.com", mockTransport);
|
||||
hubConnection.onClosed((ex) -> {
|
||||
assertEquals(ex.getMessage(), "There was an error");
|
||||
});
|
||||
|
|
@ -843,8 +840,7 @@ class HubConnectionTest {
|
|||
|
||||
@Test
|
||||
public void callingStartOnStartedHubConnectionNoOps() throws Exception {
|
||||
Transport mockTransport = new MockTransport();
|
||||
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, new NullLogger(), true, new TestHttpClient());
|
||||
HubConnection hubConnection = TestUtils.createHubConnection("http://example.com");
|
||||
hubConnection.start();
|
||||
assertEquals(HubConnectionState.CONNECTED, hubConnection.getConnectionState());
|
||||
|
||||
|
|
@ -857,8 +853,7 @@ class HubConnectionTest {
|
|||
|
||||
@Test
|
||||
public void cannotSendBeforeStart() throws Exception {
|
||||
Transport mockTransport = new MockTransport();
|
||||
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, new NullLogger(), true, new TestHttpClient());
|
||||
HubConnection hubConnection = TestUtils.createHubConnection("http://example.com");
|
||||
assertEquals(HubConnectionState.DISCONNECTED, hubConnection.getConnectionState());
|
||||
|
||||
Throwable exception = assertThrows(HubException.class, () -> hubConnection.send("inc"));
|
||||
|
|
@ -868,7 +863,7 @@ class HubConnectionTest {
|
|||
@Test
|
||||
public void errorWhenReceivingInvokeWithIncorrectArgumentLength() throws Exception {
|
||||
MockTransport mockTransport = new MockTransport();
|
||||
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, new NullLogger(), true, new TestHttpClient());
|
||||
HubConnection hubConnection = TestUtils.createHubConnection("http://example.com", mockTransport);
|
||||
hubConnection.on("Send", (s) -> {
|
||||
assertTrue(false);
|
||||
}, String.class);
|
||||
|
|
@ -886,9 +881,10 @@ class HubConnectionTest {
|
|||
TestHttpClient client = new TestHttpClient()
|
||||
.on("POST", (req) -> CompletableFuture.completedFuture(new HttpResponse(404, "", "")));
|
||||
|
||||
HttpConnectionOptions options = new HttpConnectionOptions();
|
||||
options.setHttpClient(client);
|
||||
HubConnection hubConnection = new HubConnectionBuilder()
|
||||
.withUrl("http://example.com")
|
||||
.configureHttpClient(client)
|
||||
.withUrl("http://example.com", options)
|
||||
.build();
|
||||
|
||||
try {
|
||||
|
|
@ -905,8 +901,11 @@ class HubConnectionTest {
|
|||
TestHttpClient client = new TestHttpClient().on("POST", "http://example.com/negotiate",
|
||||
(req) -> CompletableFuture.completedFuture(new HttpResponse(200, "", "{\"url\":\"http://example.com\"}")));
|
||||
|
||||
HubConnection hubConnection = new HubConnectionBuilder().withUrl("http://example.com")
|
||||
.configureHttpClient(client).build();
|
||||
HttpConnectionOptions options = new HttpConnectionOptions();
|
||||
options.setHttpClient(client);
|
||||
HubConnection hubConnection = new HubConnectionBuilder()
|
||||
.withUrl("http://example.com", options)
|
||||
.build();
|
||||
|
||||
ExecutionException exception = assertThrows(ExecutionException.class, () -> hubConnection.start().get(1000, TimeUnit.MILLISECONDS));
|
||||
assertEquals("Negotiate redirection limit exceeded.", exception.getCause().getMessage());
|
||||
|
|
@ -922,8 +921,10 @@ class HubConnectionTest {
|
|||
MockTransport transport = new MockTransport();
|
||||
HttpConnectionOptions options = new HttpConnectionOptions();
|
||||
options.setTransport(transport);
|
||||
HubConnection hubConnection = new HubConnectionBuilder().withUrl("http://example.com", options)
|
||||
.configureHttpClient(client).build();
|
||||
options.setHttpClient(client);
|
||||
HubConnection hubConnection = new HubConnectionBuilder()
|
||||
.withUrl("http://example.com", options)
|
||||
.build();
|
||||
|
||||
hubConnection.start().get(1000, TimeUnit.MILLISECONDS);
|
||||
|
||||
|
|
@ -940,8 +941,10 @@ class HubConnectionTest {
|
|||
MockTransport transport = new MockTransport();
|
||||
HttpConnectionOptions options = new HttpConnectionOptions();
|
||||
options.setTransport(transport);
|
||||
HubConnection hubConnection = new HubConnectionBuilder().withUrl("http://example.com", options)
|
||||
.configureHttpClient(client).build();
|
||||
options.setHttpClient(client);
|
||||
HubConnection hubConnection = new HubConnectionBuilder()
|
||||
.withUrl("http://example.com", options)
|
||||
.build();
|
||||
|
||||
ExecutionException exception = assertThrows(ExecutionException.class, () -> hubConnection.start().get(1000, TimeUnit.MILLISECONDS));
|
||||
assertEquals("Test error.", exception.getCause().getMessage());
|
||||
|
|
@ -958,18 +961,75 @@ class HubConnectionTest {
|
|||
MockTransport transport = new MockTransport();
|
||||
HttpConnectionOptions options = new HttpConnectionOptions();
|
||||
options.setTransport(transport);
|
||||
HubConnection hubConnection = new HubConnectionBuilder().withUrl("http://example.com", options)
|
||||
.configureHttpClient(client).build();
|
||||
options.setHttpClient(client);
|
||||
HubConnection hubConnection = new HubConnectionBuilder()
|
||||
.withUrl("http://example.com", options)
|
||||
.build();
|
||||
|
||||
hubConnection.start().get(1000, TimeUnit.MILLISECONDS);
|
||||
assertEquals(HubConnectionState.CONNECTED, hubConnection.getConnectionState());
|
||||
hubConnection.stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void accessTokenProviderIsUsedForNegotiate()
|
||||
throws InterruptedException, ExecutionException, TimeoutException, Exception {
|
||||
AtomicReference<String> token = new AtomicReference<>();
|
||||
TestHttpClient client = new TestHttpClient()
|
||||
.on("POST", "http://example.com/negotiate",
|
||||
(req) -> {
|
||||
token.set(req.getHeaders().get("Authorization"));
|
||||
return CompletableFuture
|
||||
.completedFuture(new HttpResponse(200, "", "{\"connectionId\":\"bVOiRPG8-6YiJ6d7ZcTOVQ\",\""
|
||||
+ "availableTransports\":[{\"transport\":\"WebSockets\",\"transferFormats\":[\"Text\",\"Binary\"]}]}"));
|
||||
});
|
||||
|
||||
MockTransport transport = new MockTransport();
|
||||
HttpConnectionOptions options = new HttpConnectionOptions();
|
||||
options.setTransport(transport);
|
||||
options.setHttpClient(client);
|
||||
options.setAccessTokenProvider(() -> CompletableFuture.completedFuture("secretToken"));
|
||||
HubConnection hubConnection = new HubConnectionBuilder().withUrl("http://example.com", options).build();
|
||||
|
||||
hubConnection.start().get(1000, TimeUnit.MILLISECONDS);
|
||||
assertEquals(HubConnectionState.CONNECTED, hubConnection.getConnectionState());
|
||||
hubConnection.stop();
|
||||
assertEquals("Bearer secretToken", token.get());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void accessTokenProviderIsOverriddenFromRedirectNegotiate()
|
||||
throws InterruptedException, ExecutionException, TimeoutException, Exception {
|
||||
AtomicReference<String> token = new AtomicReference<>();
|
||||
TestHttpClient client = new TestHttpClient()
|
||||
.on("POST", "http://example.com/negotiate", (req) -> CompletableFuture.completedFuture(new HttpResponse(200, "", "{\"url\":\"http://testexample.com/\",\"accessToken\":\"newToken\"}")))
|
||||
.on("POST", "http://testexample.com/negotiate", (req) -> {
|
||||
token.set(req.getHeaders().get("Authorization"));
|
||||
return CompletableFuture
|
||||
.completedFuture(new HttpResponse(200, "", "{\"connectionId\":\"bVOiRPG8-6YiJ6d7ZcTOVQ\",\""
|
||||
+ "availableTransports\":[{\"transport\":\"WebSockets\",\"transferFormats\":[\"Text\",\"Binary\"]}]}"));
|
||||
});
|
||||
|
||||
MockTransport transport = new MockTransport();
|
||||
HttpConnectionOptions options = new HttpConnectionOptions();
|
||||
options.setTransport(transport);
|
||||
options.setHttpClient(client);
|
||||
options.setAccessTokenProvider(() -> CompletableFuture.completedFuture("secretToken"));
|
||||
HubConnection hubConnection = new HubConnectionBuilder().withUrl("http://example.com", options).build();
|
||||
|
||||
hubConnection.start().get(1000, TimeUnit.MILLISECONDS);
|
||||
assertEquals(HubConnectionState.CONNECTED, hubConnection.getConnectionState());
|
||||
hubConnection.stop();
|
||||
assertEquals("Bearer newToken", token.get());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hubConnectionCanBeStartedAfterBeingStopped() throws Exception {
|
||||
MockTransport mockTransport = new MockTransport();
|
||||
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, new NullLogger(), true, new TestHttpClient());
|
||||
MockTransport transport = new MockTransport();
|
||||
HttpConnectionOptions options = new HttpConnectionOptions();
|
||||
options.setTransport(transport);
|
||||
options.setSkipNegotiate(true);
|
||||
HubConnection hubConnection = new HubConnectionBuilder().withUrl("http://example.com", options).build();
|
||||
|
||||
hubConnection.start().get(1000, TimeUnit.MILLISECONDS);
|
||||
assertEquals(HubConnectionState.CONNECTED, hubConnection.getConnectionState());
|
||||
|
|
@ -990,7 +1050,10 @@ class HubConnectionTest {
|
|||
.on("POST", "http://testexample.com/negotiate", (req) -> CompletableFuture
|
||||
.completedFuture(new HttpResponse(200, "", "{\"connectionId\":\"bVOiRPG8-6YiJ6d7ZcTOVQ\",\""
|
||||
+ "availableTransports\":[{\"transport\":\"WebSockets\",\"transferFormats\":[\"Text\",\"Binary\"]}]}")));
|
||||
HubConnection hubConnection = new HubConnection("http://example.com", mockTransport, new NullLogger(), false, client);
|
||||
HttpConnectionOptions options = new HttpConnectionOptions();
|
||||
options.setTransport(mockTransport);
|
||||
options.setHttpClient(client);
|
||||
HubConnection hubConnection = new HubConnectionBuilder().withUrl("http://example.com", options).build();
|
||||
|
||||
hubConnection.start().get(1000, TimeUnit.MILLISECONDS);
|
||||
assertEquals(HubConnectionState.CONNECTED, hubConnection.getConnectionState());
|
||||
|
|
@ -1001,4 +1064,21 @@ class HubConnectionTest {
|
|||
hubConnection.stop().get(1000, TimeUnit.MILLISECONDS);
|
||||
assertEquals(HubConnectionState.DISCONNECTED, hubConnection.getConnectionState());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void non200FromNegotiateThrowsError() {
|
||||
TestHttpClient client = new TestHttpClient()
|
||||
.on("POST", "http://example.com/negotiate",
|
||||
(req) -> CompletableFuture
|
||||
.completedFuture(new HttpResponse(500, "Internal server error", "")));
|
||||
|
||||
MockTransport transport = new MockTransport();
|
||||
HttpConnectionOptions options = new HttpConnectionOptions();
|
||||
options.setTransport(transport);
|
||||
options.setHttpClient(client);
|
||||
HubConnection hubConnection = new HubConnectionBuilder().withUrl("http://example.com", options).build();
|
||||
|
||||
ExecutionException exception = assertThrows(ExecutionException.class, () -> hubConnection.start().get(1000, TimeUnit.MILLISECONDS));
|
||||
assertEquals("Unexpected status code returned from negotiate: 500 Internal server error.", exception.getCause().getMessage());
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
||||
class TestUtils {
|
||||
static HubConnection createHubConnection(String url) {
|
||||
return createHubConnection(url, new MockTransport(), new NullLogger(), true, new TestHttpClient());
|
||||
}
|
||||
|
||||
static HubConnection createHubConnection(String url, Transport transport) {
|
||||
return createHubConnection(url, transport, new NullLogger(), true, new TestHttpClient());
|
||||
}
|
||||
|
||||
static HubConnection createHubConnection(String url, Transport transport, Logger logger, boolean skipNegotiate, HttpClient client) {
|
||||
HttpConnectionOptions options = new HttpConnectionOptions();
|
||||
options.setTransport(transport);
|
||||
options.setLogger(logger);
|
||||
options.setSkipNegotiate(skipNegotiate);
|
||||
options.setHttpClient(client);
|
||||
HubConnectionBuilder builder = new HubConnectionBuilder();
|
||||
return builder.withUrl(url, options).build();
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue