|
|
|
@ -1,5 +1,5 @@ |
|
|
|
/* |
|
|
|
/* |
|
|
|
* Copyright 2002-2018 the original author or authors. |
|
|
|
* Copyright 2002-2020 the original author or authors. |
|
|
|
* |
|
|
|
* |
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
|
|
* you may not use this file except in compliance with the License. |
|
|
|
* you may not use this file except in compliance with the License. |
|
|
|
@ -35,6 +35,7 @@ import org.springframework.lang.Nullable; |
|
|
|
import org.springframework.util.Assert; |
|
|
|
import org.springframework.util.Assert; |
|
|
|
import org.springframework.web.reactive.socket.CloseStatus; |
|
|
|
import org.springframework.web.reactive.socket.CloseStatus; |
|
|
|
import org.springframework.web.reactive.socket.HandshakeInfo; |
|
|
|
import org.springframework.web.reactive.socket.HandshakeInfo; |
|
|
|
|
|
|
|
import org.springframework.web.reactive.socket.WebSocketHandler; |
|
|
|
import org.springframework.web.reactive.socket.WebSocketMessage; |
|
|
|
import org.springframework.web.reactive.socket.WebSocketMessage; |
|
|
|
import org.springframework.web.reactive.socket.WebSocketMessage.Type; |
|
|
|
import org.springframework.web.reactive.socket.WebSocketMessage.Type; |
|
|
|
import org.springframework.web.reactive.socket.WebSocketSession; |
|
|
|
import org.springframework.web.reactive.socket.WebSocketSession; |
|
|
|
@ -44,8 +45,8 @@ import org.springframework.web.reactive.socket.WebSocketSession; |
|
|
|
* event-listener WebSocket APIs (e.g. Java WebSocket API JSR-356, Jetty, |
|
|
|
* event-listener WebSocket APIs (e.g. Java WebSocket API JSR-356, Jetty, |
|
|
|
* Undertow) and Reactive Streams. |
|
|
|
* Undertow) and Reactive Streams. |
|
|
|
* |
|
|
|
* |
|
|
|
* <p>Also an implementation of {@code Subscriber<Void>} so it can be used as |
|
|
|
* <p>Also implements {@code Subscriber<Void>} so it can be used to subscribe to |
|
|
|
* the completion subscriber for session handling |
|
|
|
* the completion of {@link WebSocketHandler#handle(WebSocketSession)}. |
|
|
|
* |
|
|
|
* |
|
|
|
* @author Violeta Georgieva |
|
|
|
* @author Violeta Georgieva |
|
|
|
* @author Rossen Stoyanchev |
|
|
|
* @author Rossen Stoyanchev |
|
|
|
@ -63,7 +64,7 @@ public abstract class AbstractListenerWebSocketSession<T> extends AbstractWebSoc |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Nullable |
|
|
|
@Nullable |
|
|
|
private final MonoProcessor<Void> completionMono; |
|
|
|
private final MonoProcessor<Void> handlerCompletion; |
|
|
|
|
|
|
|
|
|
|
|
private final WebSocketReceivePublisher receivePublisher; |
|
|
|
private final WebSocketReceivePublisher receivePublisher; |
|
|
|
|
|
|
|
|
|
|
|
@ -72,6 +73,8 @@ public abstract class AbstractListenerWebSocketSession<T> extends AbstractWebSoc |
|
|
|
|
|
|
|
|
|
|
|
private final AtomicBoolean sendCalled = new AtomicBoolean(); |
|
|
|
private final AtomicBoolean sendCalled = new AtomicBoolean(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private final MonoProcessor<CloseStatus> closeStatusProcessor = MonoProcessor.create(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Base constructor. |
|
|
|
* Base constructor. |
|
|
|
@ -87,15 +90,16 @@ public abstract class AbstractListenerWebSocketSession<T> extends AbstractWebSoc |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Alternative constructor with completion {@code Mono<Void>} to propagate |
|
|
|
* Alternative constructor with completion {@code Mono<Void>} to propagate |
|
|
|
* the session completion (success or error) (for client-side use). |
|
|
|
* session completion (success or error). This is primarily for use with the |
|
|
|
|
|
|
|
* {@code WebSocketClient} to be able to report the end of execution. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public AbstractListenerWebSocketSession(T delegate, String id, HandshakeInfo info, |
|
|
|
public AbstractListenerWebSocketSession(T delegate, String id, HandshakeInfo info, |
|
|
|
DataBufferFactory bufferFactory, @Nullable MonoProcessor<Void> completionMono) { |
|
|
|
DataBufferFactory bufferFactory, @Nullable MonoProcessor<Void> handlerCompletion) { |
|
|
|
|
|
|
|
|
|
|
|
super(delegate, id, info, bufferFactory); |
|
|
|
super(delegate, id, info, bufferFactory); |
|
|
|
this.receivePublisher = new WebSocketReceivePublisher(); |
|
|
|
this.receivePublisher = new WebSocketReceivePublisher(); |
|
|
|
this.completionMono = completionMono; |
|
|
|
this.handlerCompletion = handlerCompletion; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -126,6 +130,11 @@ public abstract class AbstractListenerWebSocketSession<T> extends AbstractWebSoc |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
|
|
|
public Mono<CloseStatus> closeStatus() { |
|
|
|
|
|
|
|
return this.closeStatusProcessor; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Whether the underlying WebSocket API has flow control and can suspend and |
|
|
|
* Whether the underlying WebSocket API has flow control and can suspend and |
|
|
|
* resume the receiving of messages. |
|
|
|
* resume the receiving of messages. |
|
|
|
@ -170,6 +179,7 @@ public abstract class AbstractListenerWebSocketSession<T> extends AbstractWebSoc |
|
|
|
|
|
|
|
|
|
|
|
/** Handle an error callback from the WebSocketHandler adapter. */ |
|
|
|
/** Handle an error callback from the WebSocketHandler adapter. */ |
|
|
|
void handleError(Throwable ex) { |
|
|
|
void handleError(Throwable ex) { |
|
|
|
|
|
|
|
this.closeStatusProcessor.onComplete(); |
|
|
|
this.receivePublisher.onError(ex); |
|
|
|
this.receivePublisher.onError(ex); |
|
|
|
WebSocketSendProcessor sendProcessor = this.sendProcessor; |
|
|
|
WebSocketSendProcessor sendProcessor = this.sendProcessor; |
|
|
|
if (sendProcessor != null) { |
|
|
|
if (sendProcessor != null) { |
|
|
|
@ -179,7 +189,8 @@ public abstract class AbstractListenerWebSocketSession<T> extends AbstractWebSoc |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** Handle a close callback from the WebSocketHandler adapter. */ |
|
|
|
/** Handle a close callback from the WebSocketHandler adapter. */ |
|
|
|
void handleClose(CloseStatus reason) { |
|
|
|
void handleClose(CloseStatus closeStatus) { |
|
|
|
|
|
|
|
this.closeStatusProcessor.onNext(closeStatus); |
|
|
|
this.receivePublisher.onAllDataRead(); |
|
|
|
this.receivePublisher.onAllDataRead(); |
|
|
|
WebSocketSendProcessor sendProcessor = this.sendProcessor; |
|
|
|
WebSocketSendProcessor sendProcessor = this.sendProcessor; |
|
|
|
if (sendProcessor != null) { |
|
|
|
if (sendProcessor != null) { |
|
|
|
@ -189,7 +200,7 @@ public abstract class AbstractListenerWebSocketSession<T> extends AbstractWebSoc |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Subscriber<Void> implementation
|
|
|
|
// Subscriber<Void> implementation tracking WebSocketHandler#handle completion
|
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
@Override |
|
|
|
public void onSubscribe(Subscription subscription) { |
|
|
|
public void onSubscribe(Subscription subscription) { |
|
|
|
@ -203,17 +214,16 @@ public abstract class AbstractListenerWebSocketSession<T> extends AbstractWebSoc |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
@Override |
|
|
|
public void onError(Throwable ex) { |
|
|
|
public void onError(Throwable ex) { |
|
|
|
if (this.completionMono != null) { |
|
|
|
if (this.handlerCompletion != null) { |
|
|
|
this.completionMono.onError(ex); |
|
|
|
this.handlerCompletion.onError(ex); |
|
|
|
} |
|
|
|
} |
|
|
|
int code = CloseStatus.SERVER_ERROR.getCode(); |
|
|
|
close(CloseStatus.SERVER_ERROR.withReason(ex.getMessage())); |
|
|
|
close(new CloseStatus(code, ex.getMessage())); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
@Override |
|
|
|
public void onComplete() { |
|
|
|
public void onComplete() { |
|
|
|
if (this.completionMono != null) { |
|
|
|
if (this.handlerCompletion != null) { |
|
|
|
this.completionMono.onComplete(); |
|
|
|
this.handlerCompletion.onComplete(); |
|
|
|
} |
|
|
|
} |
|
|
|
close(); |
|
|
|
close(); |
|
|
|
} |
|
|
|
} |
|
|
|
|