i want to send event to socket io server that ran on java spring boot application,
the weird point is that my angular app can connect to server perfectly and i can get connect and disconnect events in java.but when it comes to emit an event to server or get any event from server it is not working
Java Class:
public class SocketIOServerImpl {
public static void main(String[] args) throws InterruptedException {
Configuration config = new Configuration();
config.setHostname("localhost");
config.setPort(8090);
websocket
final SocketIOServer server = new SocketIOServer(config);
server.addConnectListener(socketIOClient -> {
System.out.println("User Connected");
server.getBroadcastOperations().sendEvent("daniyal", "You Connected to Server Successfully");
});
server.addDisconnectListener(client -> {
server.getBroadcastOperations().sendEvent("daniyal", "You Connected to Server Successfully");
});
server.addEventListener("daniyal", String.class, new DataListener<String>() {
#Override
public void onData(SocketIOClient socketIOClient, String s, AckRequest ackRequest) throws Exception {
System.out.println("User Connected");
server.getBroadcastOperations().sendEvent("daniyal", "You Emited STH to Server Successfully");
}
});
server.start();
Thread.sleep(Integer.MAX_VALUE);
server.stop();
}
}
angular servise.ts:
#Injectable({
providedIn: 'root'
})
export class SocketServiceService {
readonly uri: string = 'ws://localhost:8090';
socket: any;
constructor() {
this.socket = io.connect(this.uri,{ transports: [ 'websocket' ] });
}
listen(eventName: string) {
return new Observable((subscriber) => {
this.socket.on(eventName, (data: any) => {
subscriber.next(data);
});
});
}
emit(eventName: string, data: any) {
this.socket.emit(eventName, data);
}
}
app.component.ts:
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
constructor(private socketService: SocketServiceService) {
}
ngOnInit() {
this.socketService.listen('daniyal').subscribe(
(res) => {
console.log('Server Response: ',res);
});
}
emit(){
this.socketService.emit('daniyal','HI SERVER');
}
}
i use angular version 14 and java 11
i expected server can get the event and when send event to client,client get that too
Related
I'm struggling how to send message to all users in a private channel in Spring. Here is my WebSocket config class:
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/all", "/message","/topic");
config.setUserDestinationPrefix("/secured/user");
config.setApplicationDestinationPrefixes("/app");
}
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws");
registry.addEndpoint("/ws")
.setHandshakeHandler(new UserHandshakeHandler())
.withSockJS();
}
}
Then I have a list of all my usernames, so I loop my list to send each of them a private message, like this:
#Service
#Slf4j
public class MessageService {
private final SimpMessagingTemplate simpMessagingTemplate;
public MessageService(SimpMessagingTemplate simpMessagingTemplate) {
this.simpMessagingTemplate = simpMessagingTemplate;
}
#Async
#Scheduled(fixedDelay = 1000, initialDelay = 1000)
public void sendMessageToUser() {
List<String> nameList = Lists.newArrayList("admin", "user");
for(String username : nameList){
simpMessagingTemplate.convertAndSendToUser(username,"/message", "Hello "+username);
}
}
}
Then in my web frontend, I setup a websocket connection like this:
function connect() {
const socket = new SockJS('/ws');
stompClient = Stomp.over(socket);
stompClient.connect({}, function (frame) {
console.log('Connected: ' + frame);
stompClient.subscribe('/secured/user/message',
function (message) {
console.log(message);
});
});
}
I got confirmation that frontend successfully establish the websocket connection:
Opening Web Socket...
stomp.min.js:8 Web Socket Opened...
stomp.min.js:8 >>> CONNECT
accept-version:1.1,1.0
heart-beat:10000,10000
stomp.min.js:8 <<< CONNECTED
version:1.1
heart-beat:0,0
user-name:admin
stomp.min.js:8 connected to server undefined
message.js:18 Connected: CONNECTED
user-name:admin
heart-beat:0,0
version:1.1
stomp.min.js:8 >>> SUBSCRIBE
id:sub-0
destination:/secured/user/message
The problem is the message is indeed sent from server side, but simply not able to be received in the frontend.
Hugely appreciate if anyone could help spot the issue in my code. Thanks a lot!
I have a websocket server file called server.js
const express = require('express');
const http = require('http');
const WebSocket = require('ws');
const port = 1234;
const server = http.createServer(express);
const wss = new WebSocket.Server({ server });
server.listen(port, function() {
console.log(`Server is listening on port ${port}`);
})
wss.on('connection', function connection(ws, req) {
console.log("connected");
ws.on('message', function incoming(data) {
wss.clients.forEach(function each(client) {
if(client !== ws && client.readyState == WebSocket.OPEN) {
client.send(data.toString());
console.log(client.id + " => " + data.toString());
}
})
})
})
In java i wanted to connect to the websocket with initiateWebSocket() function
private void instantiateWebSocket() {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().url(WEBSOCKET_URL).build();
SocketListener socketListener = new SocketListener(this);
webSocket = client.newWebSocket(request, socketListener);
}
public class SocketListener extends WebSocketListener {
public MainActivity activity;
public SocketListener (MainActivity activity) {
this.activity = activity;
}
#Override
public void onOpen(#NonNull WebSocket webSocket, #NonNull Response response) {
super.onOpen(webSocket, response);
activity.runOnUiThread(() -> Toast.makeText(activity, "Connection starts", Toast.LENGTH_LONG).show());
webSocket.send("Hello..."); // send message here Hello
}
}
So I wanted to send the word "Hello..." when the connection is connected to the websocket.
On my server.js, it showed connected, which means ws.on("connection") is executed...
But the weird part is ws.on("message") is not executed and Hello... is not received
Also note that I didn't received any errors, everything is working fine, only Hello... is not received.
Any advice? Thank you.
I made a demo referring to this project (websokets-spring),I mainly added WebSocketListener,this is my code
#Component
#Slf4j
public class WebSocketListener {
#EventListener
public void handleWebSocketConnectListener(SessionConnectEvent sessionConnectEvent) {
StompHeaderAccessor headerAccessor = StompHeaderAccessor.wrap(sessionConnectEvent.getMessage());
log.debug("connect, sessionId = {}", headerAccessor.getSessionId());
}
#EventListener
public void handleWebSocketConnectedListener(SessionConnectedEvent sessionConnectedEvent) {
log.debug("connected ");
}
#EventListener
public void handleWebSocketDisconnectListener(SessionDisconnectEvent sessionDisconnectEvent) {
StompHeaderAccessor headerAccessor = StompHeaderAccessor.wrap(sessionDisconnectEvent.getMessage());
log.debug("disconnect, session id = {}", sessionDisconnectEvent.getSessionId());
}
#EventListener
public void handleWebSocketSubscribeEvent(SessionSubscribeEvent sessionSubscribeEvent) {
log.debug("subscribe, {}", sessionSubscribeEvent.toString());
}
#EventListener
public void handleWebSocketUnsubscribeEvent(SessionUnsubscribeEvent sessionUnsubscribeEvent) {
log.debug("unsubscribe, {}", sessionUnsubscribeEvent.getSource());
}
}
When I enter the page to open the WebSocket connection and close the WebSocket connection or Close page, I can listen to the event。enter image description hereenter image description here
But when I use the front-end and back-end separated projects to connect WebSocket, I can listen to the SessionConnectEvent, but not the SessionDisconnectEvententer image description hereenter image description hereenter image description hereenter image description herethis is my front-end stomp code
function chatClient(): CompatClient {
const socket = SockJS('http://localhost/ws');
const client = Stomp.over(socket);
return client;
}
client = chatClient();
client.connect(
{
Authorization: getAuthorization(),
},
(frame: any) => {
console.log("ws success", frame);
client.subscribe(`/user/${userStore.userInfo.username}/messages`, function (message) {
console.log('msg', message.body);
});
}, (err: any) => {
console.log("ws err");
});
When using a proxy across domains, you need to enable websocket true
server: {
proxy: {
'/api': {
target: 'http://localhost:8080',
changeOrigin: true,
// rewrite: (path: string) => path.replace(/^\/api/, ""),
},
'/ws': {
target: 'http://localhost:8080',
changeOrigin: true,
ws: true
}
},
// port: 80,
open: false,
fs: {
strict: true,
},
}
I'm building a react application that uses atmosphere library to listen to a SpringBoot websocket, when the client tries to connect to the server, it throws an error in the console saying Some cookies are misusing the recommended “sameSite“ attribute. I added some attributes to the request object to fix the issue as recommended (SameSite cookies). but I'm still getting the same error.
ReactJS code:
import React from 'react';
import * as atmosphere from 'atmosphere.js';
//import $ from 'jquery';
var transport = 'websocket';
//var req = new atmosphere.AtmosphereRequest();
// We are now ready to cut the request
var request = {
url:'http://localhost:8080/stream',
contentType: "application/json",
trackMessageLength: true,
shared: true,
enableXDR: true,
headers: { 'Access-Control-Allow-Origin': '*',
'sameSite': ' None; Secure'
},
//sameSite: 'None; Secure',
rewriteURL:true,
transport: transport,
fallbackTransport: 'long-polling',
onOpen: function(response:any) {
console.log('Atmosphere connected using ' , response.transport);
transport = response.transport;
},
onTransportFailure: function(errorMsg: Atmosphere.Response, request: Atmosphere.Request) {
console.log('Atmosphere Chat. Default transport is WebSocket, fallback is ' ,request.fallbackTransport );
},
onMessage: function (response:Atmosphere.Response) {
var message = response.responseBody;
try {
console.log('message: ', message);
} catch (e) {
console.log('This doesn\'t look like a valid JSON: ', message);
return;
}
},
onClose : function(response: Atmosphere.Response) {
console.log("Close connection !!!");
}
};
const socket = atmosphere;
// Connect to the server, hook up to the request handler.
console.log('socket : ', socket.subscribe);
socket.subscribe && socket.subscribe(request);
const AtmosphereWebSocket = () => {
return ( <div> </div> );
}
export default AtmosphereWebSocket;
SpringBoot Code:
#Component
#CrossOrigin(origins = "http://localhost:3000")
#WebSocketHandlerService(path = "/stream", broadcaster = SimpleBroadcaster.class,
atmosphereConfig = {"org.atmosphere.websocket.WebSocketProtocol=" +
"org.atmosphere.websocket.protocol.StreamingHttpProtocol"})
public class WebSocketStream extends WebSocketStreamingHandlerAdapter {
private final Logger logger = LoggerFactory.getLogger(WebSocketStream.class);
public WebSocketStream() {
System.out.println(" ** WebSocketStream ** ");
}
// A thread which sends a stream of data out of a websocket. Create when the class
// is instantiated, inject the websocket when open.
private class Stream extends Thread {
protected WebSocket socket;
protected final ObjectMapper mapper = new ObjectMapper();
protected boolean stop = false;
public Stream(WebSocket socket) {
this.socket = socket;
}
public void run() {
int count = 0;
try {
while (!stop) {
Map<String, Object> message = new HashMap<String, Object>();
message.put("time", new Date().toString());
message.put("count", count++);
String string = mapper.writeValueAsString(message);
socket.write(string);
System.out.println("tick: " + string);
Thread.sleep(1000);
}
} catch (Exception x) {
// break.
}
}
}
int clients = 0;
#Override
public void onOpen(WebSocket webSocket) throws IOException {
// Hook up the stream.
final Stream stream = new Stream(webSocket);
stream.start();
logger.info(" on open was called !!!");
webSocket.broadcast("client " + clients++ + " connected");
webSocket.resource().addEventListener(new WebSocketEventListenerAdapter() {
#Override
public void onDisconnect(AtmosphereResourceEvent event) {
if (event.isCancelled()) {
logger.info("Browser {} unexpectedly disconnected", event.getResource().uuid());
} else if (event.isClosedByClient()) {
logger.info("Browser {} closed the connection", event.getResource().uuid());
}
stream.stop = true;
}
});
}
}
Error Message:
Websocket failed on first connection attempt. Downgrading to long- polling and resending 1.chunk.js:3632:18
Atmosphere Chat. Default transport is WebSocket, fallback is long-polling atmosphere.tsx:27
The development server has disconnected.
Refresh the page if necessary. 1.chunk.js:7419:13
Sat Jul 11 2020 15:52:07 GMT-0500 (Central Daylight Time) Atmosphere: unload event 1.chunk.js:3632:18
[HMR] Waiting for update signal from WDS... log.js:24
Download the React DevTools for a better development experience: react-dom.development.js:24994
socket :
function subscribe(url, callback, request)
atmosphere.tsx:47
Firefox can’t establish a connection to the server at ws://localhost:8080/stream?X-Atmosphere-tracking-id=0&X-Atmosphere-Framework=3.0.5-javascript&X-Atmosphere-Transport=websocket&X-Atmosphere-TrackMessageSize=true&Content-Type=application/json&X-atmo-protocol=true&Access-Control-Allow-Origin=*&sameSite=%20None%3B%20Secure. atmosphere.js:1201
Websocket closed, reason: Connection was closed abnormally (that is, with no close frame being sent). - wasClean: false atmosphere.js:3302
Close connection !!! atmosphere.tsx:40
Websocket failed on first connection attempt. Downgrading to long-polling and resending atmosphere.js:3302
Atmosphere Chat. Default transport is WebSocket, fallback is long-polling
Scenario:
Client(angular js 1.4) will call Rest endpoint to get data, the server(spring boot) will process the list of files and will return accurate data. To process the list of files, the server will take time depending on the number of files. so I have implements STOMP notification as to send a notification to the client saying "List of files have been processed and here is the bunch of files(result)".
Issue:
Stomp connection is established successfully and client also gets subscribed, but when the server publishes the events, client is not able to receive.
Below is my code snippet:
WebSocketConfig.java
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws").withSockJS();
}
#Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.setApplicationDestinationPrefixes("/app");
registry.enableSimpleBroker("/topic"); // Enables a simple in-memory broker
}
}
SocketController.java
#Controller
public class SocketController {
#SendTo("/topic/public")
public String sendMessage() {
LOGGER.info("====> chatMessage()");
return "List updated successfully";
}
}
main.js
connect() {
var socket = new SockJS('/ws');
var stompClient = Stomp.over(socket);
event.preventDefault();
console.log("socket: ", socket);
console.log("stompClient: ", stompClient);
stompClient.connect({}, function (frame) {
console.log('Connected: ' + frame);
stompClient.subscribe('/topic/public', function (payload) {
console.log("payload: ", payload);
var message = JSON.parse(payload.body);
console.log("message: ", message);
});
}, function (error) {
console.log("onError() called");
console.log("error: ",error);
});
};
Scripts used:
<script src="https://cdnjs.cloudflare.com/ajax/libs/sockjs-client/1.1.4/sockjs.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/stomp.js/2.3.3/stomp.min.js"></script>
connect() method of main.js is called on button click. Probably there is an issue regarding scope I guess.
Use SimpMessagingTemplate to convert and send messages to the specific topic.
#Controller
public class SocketController {
private static final Logger LOGGER = LoggerFactory.getLogger(SocketController.class);
#Autowired private SimpMessagingTemplate template;
public void sendMessage(String message) {
LOGGER.info("====> sendMessage:");
this.template.convertAndSend("/topic/public", message);
}
}