I need to keep track of users opening a websocket to my stomp broker in Spring 4.x.
The stomp endpoint get configured the usual way:
#Configuration
#EnableWebSocketMessageBroker
public class StompWebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/stomp");
}
#Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.setApplicationDestinationPrefixes("/app")
.enableSimpleBroker("/queue", "/topic");
}
}
I tried to implement the ApplicationListener interface in order to receive SessionConnectEvent SessionConnectedEvent but I'm unable to get the remote host ip from those events.
How I'm supposed to get the ip of the client connecting to my service?
My goal is to limit the number of connections to my websocket handler from the same ip.
The way to do it is to customize the HandshakeHandler and overriding functions like isvalidOrigin.
To add an HandshakeHandler using XML config a snippet like this one can be used:
<bean id="customHandler" class="my.CustomWebsocketHandshakeHandler"/>
<websocket:message-broker application-destination-prefix="/app">
<websocket:stomp-endpoint path="/Stomp">
<websocket:handshake-handler ref="customHandler"/>
</websocket:stomp-endpoint>
<websocket:simple-broker prefix="/topic,/queue" />
</websocket:message-broker>
I'm not able to produce the equivalent configuration using Java Config, though.
I'll appreciate very much help on that subject
Related
I've struggled to connect the JS client with the Java server with a client using Stomp over WebSocket. The problem was fixed when I got rid of .withSockJs() while configuring stompEndpoints. Can someone explain to me what was the case here and why it happened? My understanding was that this method offers fallback but should not mess up a normal WebSocket connection.
Working alternatives:
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/chat");
registry.addEndpoint("/chat").withSockJS();
}
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/chat");
}
Notworking case:
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/chat").withSockJS();
}
Also: I have noticed that adding .setAllowedOrigins("http://localhost:5050") doesn't have any impact on communication in my case. I was able to connect to the server via a client on port 5050 but also via postman on 5555. Before the problem with withSockJs() I struggled with a different problem related to CORS. The solution was to change the socket configuration on the client from SockJs to WebSocket but before finding this I tried many different approaches on the server side as I thought that my server implementation was the problem. I was working with setAllowedOrigins, but when I was finally able to connect I noticed that this method seems to not work.
One more question: How is the controller of WebSocket endpoints implemented? I want to keep track of active clients username to sessionId mapping. Do I need thread safe static map or all of messaging happen on a single thread? In other words, will there be more than one WebSocket controller instance if multiple clients are connected?
I created a basic web socket with a tutorial.
Here is a configuration:
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic");
config.setApplicationDestinationPrefixes("/app");
}
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/chat");
registry.addEndpoint("/chat").withSockJS();
}
}
And here is the message handling controller:
#MessageMapping("/chat")
#SendTo("/topic/messages")
public OutputMessage send(Message message) throws Exception {
return new OutputMessage("Hello World!");
}
Everything works, but from my investigation, it looks like the WebSockets by default has an application scope (by connecting to the channel I can see all calls, from all users).
What I want to do is to be able to see only calls from the current user session or current view only.
Any ideas on how to apply these configurations?
I was able to solve this puzzle, so I'm sharing with you my findings.
First, I found information that a simple in-memory message broker can not handle this:
/*
* This enables a simple (in-memory) message broker for our application.
* The `/topic` designates that any destination prefixed with `/topic`
* will be routed back to the client.
* It's important to keep in mind, this will not work with more than one
* application instance, and it does not support all of the features a
* full message broker like RabbitMQ, ActiveMQ, etc... provide.
*/
But this was misleading, as it can be easily achieved by #SendToUser annotation.
Also, the important thing that now on the client-side, you need to add an additional prefix /user/ while subscribing to the channel, so the solution would be:
On the server-side: change #SendTo("/topic/messages") into #SendToUser("/topic/messages").
On the client-side: /topic/messages into the /user/topic/messages.
I have a springboot app and i want to make the websocket connect via devices like phone so i am looking for a way to make my websocket have an entry point that starts with "ws://". When testing my default websocket url which is supposed to be "ws://localhost:8080/websocket-example" on "http://www.websocket.org/echo.html" it does not go through. but the sockjs calls it in my client side using ("http://localhost:8080/websocket-example") which works :
var socket = new SockJS('http://localhost:8080/websocket-example');
stompClient = Stomp.over(socket);
stompClient.connect({},function (frame) {
}
I am presently using stomp on it and my configuration looks like this:
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfiguration extends AbstractWebSocketMessageBrokerConfigurer {
#Override
public void registerStompEndpoints(StompEndpointRegistry stompEndpointRegistry) {
stompEndpointRegistry.addEndpoint("/websocket-example")
.setHandshakeHandler(new CustomHandshakeHandler()).setAllowedOrigins("*")
.withSockJS();
}
#Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker("/topic");
registry.setApplicationDestinationPrefixes("/app");
}
}
according to this post it said i could achieve a ws:// entrypoint by removing .withSockJS() which i did, but it still didnt work (on further reading, it was stated that this doesnt work on springboot). The other option was to remove stomp totally, this option works, but then i wouldn't be able to route messages directly to individuals users.
How can i create a ws:// entry point while maintaining stomp on my server side ?
I had a similar problem. Try this, should help.
var socket = new WebSocket('ws://localhost:8080/websocket-example/websocket');
I want to exchange messages by web sockets between 2 java apps.
I have the following server configuration:
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
#Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.setApplicationDestinationPrefixes("/app");
registry.enableSimpleBroker("/queue", "/topic");
registry.setUserDestinationPrefix("/user");
}
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
//todo remove handshake handler when authorization is implemented
registry.addEndpoint("/ws").setAllowedOrigins("*").setHandshakeHandler(new TestHandshakeHandler()).withSockJS();
}
}
and inside class marked with #Controller I have wrote following theme:
#MessageMapping("/consumer/client/add")
public void addClientRequest(String msgReq) {
logger.info(msgReq);
}
and inside clien I do connect and in sime bean I wrote following:
#Autowired
private SimpMessagingTemplate simpMessagingTemplate;
...
simpMessagingTemplate.convertAndSend("/app/consumer/client/add", new StubObject("message"));
But after sending from client method addClientRequest doesn't invoke.
Please advice ways to troubleshot this issue.
Actually I don't understand issue. Maybe I send to wrong destination or I have issue with configuration or path is wrong or something else.
P.S.
I know that I can extend StompSessionHandlerAdapter
and obtain session from there but looks like it is the bad style and should be another way to achieve it
P.S.2
Inside class WebSocketTcpConnectionHandlerAdapter(inner class inside WebSocketStompClient) I see private volatile WebSocketSession session;
I want to obtain this object to send messages
I don't think it was designed to be used like this.
I think you must use a specific websocket client. This one for exemple :
http://www.programmingforliving.com/2013/08/jsr-356-java-api-for-websocket-client-api.html
This code :
#MessageMapping("/consumer/client/add")
public void addClientRequest(String msgReq) {
logger.info(msgReq);
}
Will NOT connect to a websocket client and wait to have messages. It expect a client to connect throught it and send messages.
I'm receiving the following message every 5 seconds:
[WEBAPP] 02 Nov 2014 17:55:43 INFO NettyTcpClient - Failed to connect to /127.0.0.1:61613. Attempting reconnect in 5000ms.
I'm using spring 4 with stomp and activemq
any ideas why that happnes?
BTW: the webapp runs on tomcat #1 while my activemq broker is located # a different machine.
Ok the URL was wrong.
I fixed it with the following code:
config.enableStompBrokerRelay("/topic","/queue/").setRelayHost(THE_RIGHT_URL);
I slved this problem with this configuration:
#Configuration
#EnableConfigurationProperties(ActiveMQProperties.class)
public class WebSocketConfig extends WebSocketMessageBrokerConfigurationSupport {
#Autowired
private ActiveMQProperties activeMQProperties;
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableStompBrokerRelay("/notify").setRelayHost("192.168.99.100")
.setSystemLogin("admin").setSystemPasscode("admin");
config.setApplicationDestinationPrefixes("/app");
}
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/createBookJob").withSockJS();
}
}
In the my use case I'm experiencing whe use activeMq as STOMP provider ina docker image.
setRelayHost("192.168.99.100") was usefull becouse 192.168.99.100 is the defualt ip that I use
.setClientLogin("admin").setClientPasscode("admin")
.setSystemLogin("admin").setSystemPasscode("admin");
becouse in active mq the default users has admin admin as user and password
it works for me
I hope that this can help you