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.
Related
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
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'm new in Spring and I trying log in to chat application with spring security username.
But controller or stomp don't recognize input. And don't allows to enter chat
Where is I should to write in stomp or controller?
Thank you.
Chat Controller
#Controller
public class ChatController {
#GetMapping("/chat")
public String chat() {
return "chat";
}
#MessageMapping("/chat.sendMessage")
#SendTo("/topic/public")
public ChatMessagePojo sendMessage(#Payload ChatMessagePojo chatMessagePojo) {
return chatMessagePojo;
}
#MessageMapping("/chat.addUser")
#SendTo("/topic/public")
public ChatMessagePojo addUser(#Payload ChatMessagePojo chatMessagePojo, SimpMessageHeaderAccessor headerAccessor) {
// Add username in web socket session
headerAccessor.getSessionAttributes().put("email", chatMessagePojo.getSender());
return chatMessagePojo;
}
ChatMessage class
public class ChatMessagePojo {
private MessageType type;
private String content;
private String sender;
public enum MessageType {
CHAT,
JOIN,
LEAVE
}
}
Stomp
const connect = () => {
const Stomp = require("stompjs");
var SockJS = require("sockjs-client");
SockJS = new SockJS("http://localhost:8080/ws");
stompClient = Stomp.over(SockJS);
stompClient.connect({}, onConnected, onError);
};
const onConnected = () => {
console.log("connected");
stompClient.subscribe(
"/user/" + currentUser.id + "/queue/messages",
onMessageReceived
);
};
const sendMessage = (msg) => {
if (msg.trim() !== "") {
const message = {
senderId: currentUser.id,
recipientId: activeContact.id,
senderName: currentUser.name,
recipientName: activeContact.name,
content: msg,
timestamp: new Date(),
};
stompClient.send("/app/chat", {}, JSON.stringify(message));
}
};
Example login screen to chat:
I tried but failed, and then I solved it with my own solution. Maybe you can refer to it.
Make a socket endpoint for authentication and send the ID and password for authentication.
Save id and session after successful authentication.
Then get the user id through the session map SESSION_USERID.
Frontend
stompClient.send("/app/chat/login", {}, "{type: AUTH, data: {id: 'mock', pwd: '12345678'}}");
Backend
public static final Map<String, Long> SESSION_USERID = new ConcurrentHashMap<>();
#Override
public void handleTextMessage(WebSocketSession session, TextMessage message)
// parse message to object
if (message.type == AUTH) {
// do auth
// if auth succeed, cache the user
SESSION_USERID.put(userId, session.getId());
} else if (message.type == CHAT) {
Long userId = SESSION_USERID.get(session.getId());
if (userId == null) {
// Send error or close session
} else {
// Send messages to other peoples
}
}
}
//----
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
I just started with Atmosphere for a simple chat application. I downloaded an example with java. This app is sending messages to all clients how can I send a message to a particular client. i think I am able to get uuid. Please someone guide me in right direction.
#Config
#ManagedService(path = "/chat", atmosphereConfig = MAX_INACTIVE + "=9990000")
public class Chat {
private final Logger logger = LoggerFactory.getLogger(Chat.class);
#Inject
private BroadcasterFactory factory;
#Heartbeat
public void onHeartbeat(final AtmosphereResourceEvent event) {
logger.trace("Heartbeat send by {}", event.getResource());
}
#Ready
public void onReady(final AtmosphereResource r) {
logger.info("Browser {} connected", r.uuid());
if(null!=factory && null!=factory.getClass()){
logger.info("BroadcasterFactory used {}", factory.getClass().getName());
}
}
#Disconnect
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());
}
}
#org.atmosphere.config.service.Message(encoders = {JacksonEncoder.class}, decoders = {JacksonDecoder.class})
#DeliverTo(DeliverTo.DELIVER_TO.BROADCASTER)
public Message onMessage(Message message) throws IOException {
logger.info("{} just send {}", message.getAuthor(), message.getMessage());
return message;
}
}
Your Java class is incomplete.
Firstly, there is a missing variable which identify each chat room in your path :
#ManagedService(path = "/chat/{chatRoomId}", atmosphereConfig = MAX_INACTIVE + "=9990000")
public class Chat {
#PathParam("chatRoomId")
private String chatRoomId;
[...]
}
But, you can send all messages to only one socke connected.
Secondly, where is your script JS file to send and receive websocket message ?
This script JS file must contains these methods :
request.onOpen = function(request, response) {
};
request.onTransportFailure = function(request, response) {
};
request.onMessage = function(request, response) {
};
request.onClose = function(request, response) {
};
request.onError= function(request, response) {
};
request.onReconnect = function(request, response) {
};
The most important is to declare the structure of your request :
var socket = atmosphere;
var subSocket;
var transport = 'websocket';
var request = {
url: document.location.toString() + 'chat' + chatRoomId,
contentType : "application/json",
logLevel : 'debug',
transport : transport ,
trackMessageLength : true,
reconnectInterval : 5000
};