how to fulfill functionality of httpclient use tcpclient in Reactor-netty - reactor-netty

i'm trying to make a tcp version of gateway. and this is the gateway code . it's use httpclient
NettyInbound serverInbound;
NettyOutbound serverOutbound;
Map map;
Flux<HttpClientResponse> flux = HttpClient.create()
.port(8080)
.request(HttpMethod.POST)
.send((req, outbound) -> {
// send infomation
return outbound.send(serverInbound.receive().retain());
}).responseConnection((res, connection) -> {
// save connection
map.put("connection",connection);
return Mono.just(res);
});
flux.then(Mono.defer(()->{
// this is after the gateway server receiving from backend and send to the front
Connection connection = map.get("connectoin");
return serverOutbound.send(connection.inbound().receive().retain());
}));
and i'm trying to do the same thing with tcpclient
TcpClient client = TcpClient.create()
.port(8900);
TcpServer.create()
.port(8080)
.handle((inbound,outbound)->{
// must be something wrong with it
return client.connect().flatMap(con->{
NettyInbound cin = con.inbound();
NettyOutbound cout = con.outbound();
return cout.send(inbound.receive().retain()).then().map(ss->{
return cin;
});
}).map(cin->{
return outbound.send(cin.receive());
}).then();
}).bindNow()
.onDispose()
.block();
but it won't work . is anything i can do to fulfill the functionality like responseConnection ?

Related

Why can't subscribe the request in reactor-netty?

I just want access the Http content in reactor-netty project. But the result is null.
Code is below.
DisposableServer server =
HttpServer.create()
.host("localhost")
.port(8000)
.route(routes ->
.post("/echo",
(request, response) ->
{ request.receive()
.retain()
.aggregate()
.asString()
.subscribe(System.out::println);
return response.sendString(Mono.just("hello"));})
.bindNow();
I can't get the rerult in the console.
Could I access the request as what I do in the code?
Anyone can help? Thanks.
You return the response before the request data is received, so Reactor Netty will drop any incoming data that is received AFTER the response is sent.
I don't know your use case but changing the example to this below, you will be able to see the incoming data:
DisposableServer server =
HttpServer.create()
.host("localhost")
.port(8000)
.route(routes ->
routes.post("/echo",
(request, response) ->
response.sendString(request.receive()
.retain()
.aggregate()
.asString()
.flatMap(s -> {
System.out.println(s);
return Mono.just("hello");
})))
)
.bindNow();

How can i handle connection and reconnect if connection got closed?

I need this client stay connected for long, How can i make sure about connection? because the issue was in connection, so i am updating my question. what should i do if server close connection? or if client close connection? how can i handle it and reconnect client to the server?
public void consumeServerSentEvent() {
WebClient client = WebClient.create("http://localhost:8080/sse-server");
ParameterizedTypeReference<ServerSentEvent<String>> type
= new ParameterizedTypeReference<ServerSentEvent<String>>() {};
Flux<ServerSentEvent<String>> eventStream = client.get()
.uri("/stream-sse")
.retrieve()
.bodyToFlux(type);
eventStream.subscribe(
content -> logger.info("Time: {} - event: name[{}], id [{}], content[{}] ",
LocalTime.now(), content.event(), content.id(), content.data()),
error -> logger.error("Error receiving SSE: {}", error),
() -> logger.info("Completed!!!"));
}
According to documentation retrieve() returns Mono of ClientResponse, but for your case you need to consume Flux of the body.
Try some thing like this:
Flux<ServerSentEvent<String>> eventStream = client.get()
.uri("/stream-sse")
.retrieve()
.flatMapMany(response -> response.bodyToFlux(type));

How to use routes with reactive websocketstream in vertx

Vertx vertx = Vertx.vertx();
var router = Router.router(vertx).route("/entity/:id")
vertx.createHttpServer()
.websocketStream()
.toObservable()
.subscribe(sock -> sock.)
.map(ServerWebSocket::toObservable)
I'm new to vert.x I've managed to create an observable socket, but I don't understand how to use routes and url route parameters with reactive version of API.
Vert.x Web router deals with HTTP requests. You can use it to handle the upgrade to websocket request:
router.route("/entity/:id").handler(rc -> {
String entityId = rc.pathParam("id");
HttpServerRequest request = rc.request();
ServerWebSocket webSocket = request.upgrade();
webSocket.frameHandler(frame -> {
webSocket.writeFrame(WebSocketFrame.textFrame("Pong " + entityId, true));
});
webSocket.accept();
});
Inside the router handler, you may retrieve path parameters with the RoutingContext#pathParam method.

Spring WebSocket - notifying subscribers is not working

I'm trying to get Spring Websockets (Spring 4) to work in the project that I've been working on. So far I have opening Websocket, adding subscribers and sending messages.
Since yesterday I've been trying to figure out why my endpoint doesn't process the message that is being send by stomp client included in my HTML. There's actually no error in the console as well (ok, I'm not 100% sure what "connected to server undefined" here means).
Here's output from Chrome console:
Opening Web Socket...
Web Socket Opened...
>>> CONNECT
accept-version:1.1,1.0
heart-beat:10000,10000
<<< CONNECTED
version:1.1
heart-beat:0,0
user-name:xxx#yyy.com
connected to server undefined
Connected: CONNECTED
user-name:xxx#yyy.com
heart-beat:0,0
version:1.1
>>> SUBSCRIBE
id:sub-0
destination:/my-project/notify-open-documents/1
Sending message : {"documentId":"1"}
>>> SEND
destination:/my-project/ws/lock-document
content-length:19
{"documentId":"1"}
and here's my code:
Configuration:
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
#Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker("/notify-open-documents");
registry.setApplicationDestinationPrefixes("/ws");
}
#Override
public void registerStompEndpoints(StompEndpointRegistry stompEndpointRegistry) {
stompEndpointRegistry.addEndpoint("/lock-document");
stompEndpointRegistry.addEndpoint("/lock-document").withSockJS();
}
}
The controller:
#Controller
public class DocumentWebsocketController {
#MessageMapping("/lock-document")
#SendTo("/notify-open-documents/{id}")
public Response response(#DestinationVariable("id") Long id, Message message) {
return new Response(message.getDocumentId());
}
}
and STOMP related part of my HTML:
<script type="text/javascript">
$(document).ready(function() {
connect();
});
var stompClient = null;
function connect() {
var socket = new SockJS('<spring:url value="/lock-document"/>');
stompClient = Stomp.over(socket);
stompClient.connect({}, function (frame) {
console.log('Connected: ' + frame);
stompClient.subscribe('<spring:url value="/notify-open-documents/${id}"/>', function (messageOutput) {
console.log('Receiving message: ' + JSON.parse(messageOutput.body));
});
sendName();
});
}
function disconnect() {
if (stompClient !== null) {
stompClient.disconnect();
}
console.log("Disconnected");
}
function sendName() {
console.log("Sending message : " + JSON.stringify({'documentId' : "${id}" }));
stompClient.send('<spring:url value="/ws/lock-document"/>', {}, JSON.stringify({'documentId': "${id}"}));
}
</script>
I'm really running out of ideas what might be wrong, my browser supports WebSockets, from what I see in logs, WebSocket is being open properly, the message is being send, but what I can't figure out is why my Controller is unable to process the incoming messages.
From your HTML snippet I see you are using the spring:url tag to generate STOMP destinations. The spring:url tag adds the context path which doesn't make sense for a STOMP destination.
The application destination prefix you are configuring is /ws and the broker destination prefix /notify-open-documents, none of these will match your context path which is /my-project (from your console output). Remove the context path from your subscription destinations and when sending messages (not from the SockJS URL):
stompClient.send('/ws/lock-document', {}, JSON.stringify({'documentId': "${id}"}));

Why websocket sendMessage is required

This is the code taken from the book "The Definitive Guide to HTML5 websocket"
div id="output"></div>
<script>
function setup() {
output = document.getElementById("output");
ws = new WebSocket("ws://localhost:7777");
ws.onopen = function(e) {
log("Connected");
sendMessage("Hello Websocket!");
}
ws.onclose = function(e){
log("Disconnected: " + e.reason);
}
ws.onerror = function(e){
log("Error ");
}
ws.onmessage = function(e) {
log("Message received: " + e.data);
ws.close();
}
}
function sendMessage(msg){
ws.send(msg);
log("Message Sent");
}
function log(s){
var p = document.createElement("p");
p.style.wordWrap = "break-word";
Could anybody please let me know for what reason this below event is required ??.
ws.send(msg);
I understand that the below will call the onMessage method on server side as shown below
public void onMessage(String data) {
}
But the actual purpose of onMessage on server side is to send data from backend to the javascript which will inturn call onmessage of client side javascript .
could anybody please help me understand this .
In the above code the ws.onopen, ws.onclose, ws.onmessage are all events associated with WebSocket object.
Whereas ws.send() is a method associated with WebSocket object. There is a huge difference between them.
The following event ensures that the Web Socket is connected to the server i.e you've opened your connection
ws.onopen = function(e) {
//Once you've opened your connection
//you can begin transmitting data to the server
//using the following method
ws.send("You\'re message");
}
So the main purpose of ws.send() method is to transmit data from the client to the server which is done by simply calling the WebSocket object's send() [in your case ws.send(msg)].
And also send data only takes place once a connection is established with the server by defining an onopen event handler.

Resources