WebSocket stomp client subscribe for some devices are not working - javascript

I am trying to implement a spring boot chat application using WebSocket stomp client. If I send messages from one device to 4,5 devices then some are getting the messages and some are not. Some can send messages but don't receive any message and some are working completely fine. My application is running on wildfly server and the URL is over https.
Here is my js file. From my JSP page I am calling sendMsg with all parameter and through render method I am attaching the response with JSP using Handlebars.
if (!window.location.origin) {
window.location.origin = window.location.protocol + "//" + window.location.hostname + (window.location.port ? ':' + window.location.port: '');
}
const url = window.location.origin+contextPath;
let stompClient;
let selectedUser;
let newMessages = new Map();
function connectToChat(userName, topicName) {
console.log("connecting to chat...")
let socket = new SockJS(url + '/chat');
stompClient = Stomp.over(socket);
stompClient.connect({}, function (frame) {
console.log("connected to: " + frame);
stompClient.subscribe("/topic/decision-log", function (response) {
let data = JSON.parse(response.body);
var msg = data.message;
var fromlogin = data.message;
render(data.username, msg, fromlogin);
});
});
}
connectToChat("1", "decision-log");
function sendMsg(from, text, username) {
stompClient.send("/app/chat/" + from, {}, JSON.stringify({
fromLogin: from,
message: text,
topicName: topicName,
username: username
}));
}
function render(username, message, projectId) {
var templateResponse = Handlebars.compile($("#message-response-template").html());
var contextResponse = {
username: username,
response: message,
date: date,
projectId: projectId
};
setTimeout(function () {
$chatHistoryList.append(templateResponse(contextResponse));
scrollToBottom();
}.bind(this), 1500);
}
Here is my WebSocket configuration file:
#Configuration
#EnableWebSocketMessageBroker
public class WebsocketConfiguration implements WebSocketMessageBrokerConfigurer{
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/chat").setAllowedOrigins("*").withSockJS();
}
#Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.setApplicationDestinationPrefixes("/app").enableSimpleBroker("/topic");
}
}
This is the controller. I always save all messages on the database that are coming through WebSocket that's why I can be sure that all devices can send messages as they have been saved on the database.
#Controller
#AllArgsConstructor
public class MessageController {
#Autowired
private SimpMessagingTemplate simpMessagingTemplate;
private final DecisionLogService decisionLogService;
#MessageMapping("/chat/{to}")
public void sendMessage(#DestinationVariable String to, MessageModel message, Authentication authentication ) {
simpMessagingTemplate.convertAndSend("/topic/decision-log", message);
AuthResponse userDetails = (AuthResponse) authentication.getDetails();
DecisionLogCreateRequest decisionLogCreateRequest = new DecisionLogCreateRequest();
decisionLogCreateRequest.setDecision(message.getMessage());
decisionLogCreateRequest.setProjectId(to);
ServiceResponseExtended<Boolean> response = decisionLogService.addDecisionLog(userDetails.getAccessToken(), decisionLogCreateRequest);
}
}
I can not find anything similar this issue. Please help me with right information and suggestion, and if anyone faced same kind of problem please share with me.

The problem was solved after configuring RabbitMQ Stomp Broker as a message broker instead of SimpleBroker.
Current WebSocket configuration:
#Configuration
#EnableWebSocketMessageBroker
public class WebsocketConfiguration implements WebSocketMessageBrokerConfigurer{
#Value("${stomp-broker-relay-host}")
private String RELAY_HOST;
#Value("${stomp-broker-relay-port}")
private String RELAY_PORT;
#Value("${stomp-broker-login-user}")
private String USER;
#Value("${stomp-broker-login-pass}")
private String PASS;
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/chat").setAllowedOrigins("*").withSockJS();
}
#Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.setApplicationDestinationPrefixes("/app");
registry.enableStompBrokerRelay("/topic").setRelayHost(RELAY_HOST).setRelayPort(Integer.parseInt(RELAY_PORT)).setClientLogin(USER)
.setClientPasscode(PASS);
}
}
Reference:
https://medium.com/#rameez.s.shaikh/build-a-chat-application-using-spring-boot-websocket-rabbitmq-2b82c142f85a
https://www.javainuse.com/misc/rabbitmq-hello-world

Related

Can't connect client (Javascript) to existing socket server

I have an existing socket server that listens on port 6868. It is written in Java.
I need to connect a client to the server. The client is coded in Javascript in my React app.
I have tried just about every possible combination of tutorials I have found on the internet but I still can't get the client to connect.
import * as io from "socket.io-client";
export default () => {
// eslint-disable-next-line no-restricted-globals
self.onmessage = (message) => {
const data = message.data;
try {
var socket = io("http://localhost:6868/");
} catch (error) {
console.log("do nothing: " + error);
}
};
};
No matter what, I get the same error: ReferenceError: socket_io_client__WEBPACK_IMPORTED_MODULE_0___default is not defined.
This is the version I am using as seen in package.json: "socket.io-client": "^4.4.0"
I installed it with this command: npm i socket.io-client
Turns out that socket.io can't be used to connect to the ServerSocket that I have in Java. To fix this, I changed ServerSocket to be a WebSocketServer.
Here is all of the code needed to make Java WebSocket connect with JavaScript client:
WebsocketServer.java
import org.java_websocket.WebSocket;
import org.java_websocket.handshake.ClientHandshake;
import org.java_websocket.server.WebSocketServer;
import java.net.InetSocketAddress;
import java.util.HashSet;
import java.util.Set;
public class WebsocketServer extends WebSocketServer {
private static int TCP_PORT = 6868;
private static Set<WebSocket> conns;
public WebsocketServer() {
super(new InetSocketAddress(TCP_PORT));
conns = new HashSet<>();
}
#Override
public void onOpen(WebSocket conn, ClientHandshake handshake) {
conns.add(conn);
conn.send("hello!!");
System.out.println("New connection from " + conn.getRemoteSocketAddress().getAddress().getHostAddress());
}
#Override
public void onClose(WebSocket conn, int code, String reason, boolean remote) {
conns.remove(conn);
System.out.println("Closed connection to " + conn.getRemoteSocketAddress().getAddress().getHostAddress());
}
#Override
public void onMessage(WebSocket conn, String message) {
System.out.println("Message from client: " + message);
for (WebSocket sock : conns) {
sock.send("SENDING BACK" + message);
}
}
#Override
public void onError(WebSocket conn, Exception ex) {
//ex.printStackTrace();
if (conn != null) {
conns.remove(conn);
// do some thing if required
}
System.out.println("ERROR from " + conn.getRemoteSocketAddress().getAddress().getHostAddress());
}
public static Set<WebSocket> getConns() {
return conns;
}
}
And launch the server from main() with new WebsocketServer().start();
client.js
var connection = new WebSocket("ws://127.0.0.1:6868");
connection.onopen = function () {
console.log("Connected!");
connection.send("Ping"); // Send the message 'Ping' to the server
};
// Log errors
connection.onerror = function (error) {
console.log("WebSocket Error " + error);
};
// Log messages from the server
connection.onmessage = function (e) {
console.log("Server: " + e.data);
};
And the dependency for the Java Web Socket:
<dependency>
<groupId>
org.java-websocket
</groupId>
<artifactId>
Java-WebSocket
</artifactId>
<version>
1.3.0
</version>
</dependency>

Getting 404 in WebSocket connection

I have a backend java code for websocket.
SessionEndpoint:
#ServerEndpoint("/session")
public class SessionEndpoint {
private static Set<SessionEndpoint> sessionEndpoints = new CopyOnWriteArraySet<>();
#OnMessage
public void onMessage(Session session, String sessionId) {
Map<String, Object> attributes = new HashMap<>();
attributes.put("sessionId", sessionId);
sessionEndpoints.forEach(endpoint -> {
synchronized (endpoint) {
try {
session.getBasicRemote().sendObject(attributes);
} catch (IOException | EncodeException e) {
e.printStackTrace();
}
}
});
}
}
Trying to connect to websocket from javascript, code is given below.
let webSocket = new WebSocket('ws://localhost:9999/session');
webSocket.onopen = () => webSocket.send('hello');
webSocket.onmessage = function(response) {
console.log(response);
};
I get 404 response code while connecting to websocket. How should I connect to webscoket from javascript ?

Why is this Cloud Function called more than once with an Android HTTP request trigger?

I have a function in an Android app which sends a POST request to an HTTP triggered Cloud Function. Whenever I click the button once to send the message, Firebase registers the event twice on the Firebase console. My application is built in such a way that the button to send a message disappears after the first click, so I'm not accidentally double clicking the button, and when I step through the debugger, the function to send the POST request is only called once. Can you guys help me? I don't know much about Firebase and can't find good documentation or other questions like this.
Here's the method which sends a message to my FCM cloud function:
public void sendPushToSingleInstance(final Context activity, final String message, final String myId, final String theirId) {
final String url = URL_TO_CLOUD_FUNCTION;
StringRequest myReq = new StringRequest(Request.Method.POST, url,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
Toast.makeText(activity, "Success", Toast.LENGTH_SHORT).show();
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
if (error.networkResponse != null)
Toast.makeText(activity, String.valueOf(error.networkResponse.statusCode), Toast.LENGTH_SHORT).show();
else
Toast.makeText(activity, "some error", Toast.LENGTH_SHORT).show();
}
}) {
#Override
public byte[] getBody() throws com.android.volley.AuthFailureError {
Map<String, String> rawParameters = new Hashtable<String, String>();
//not used
return new JSONObject(rawParameters).toString().getBytes();
};
public String getBodyContentType() {
return "application/json; charset=utf-8";
}
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
HashMap<String, String> headers = new HashMap<String, String>();
headers.put("from", myId);
headers.put("message", message);
headers.put("sendingTo", theirId);
return headers;
}
};
Volley.newRequestQueue(activity).add(myReq);
}
My JavaScript takes the HTTP request, cuts it up and send the message to a topic which contains the other user's id (I did mean to do this verses sending to a specific device).
Here's the JavaScript for my Cloud Function:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.sendMessage = functions.https.onRequest((request, response) => {
var topicId = request.get('sendingTo');
var color = request.get('color');
var from = request.get('from')
console.log('tried to push notification');
const payload = {
notification: {
title: from,
body: color,
sound: "default"
},
};
const options = {
priority: "high",
timeToLive: 60 * 60 * 24
};
admin.messaging().sendToTopic(topicId, payload, options);
});
Finally, here are the logs:
firebase console logs
Which say that the function was called twice.
I've tried many links for answers such as the standard,
https://firebase.google.com/docs/functions/http-events
and many StackOverflow posts. I haven't seen anyone else with the same problem.
From #mohamadrabee, "this from the documentation 'Always end an HTTP function with send(), redirect(), or end(). Otherwise, your function might to continue to run and be forcibly terminated by the system.' see firebase.google.com/docs/functions/http-events "
I added:
response.end();
after:
admin.messaging().sendToTopic(topicId, payload, options);
EDIT: After inserting this code, I still get the problem roughly 7% of the time. I had to change response.end(); to:
if (response.status(200)) {
response.status(200).end();
} else {
response.end();
}
I haven't had any problems since.

Spring WebSockets Stomp.subscribe not working

I've been trying to implement a basic Spring WebSockets application following the official Spring guide. The files I have are the following:
WebSocketConfig.java
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
#Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker("/chat");
registry.setApplicationDestinationPrefixes("/message");
}
#Override
public void registerStompEndpoints(StompEndpointRegistry stompEndpointRegistry) {
stompEndpointRegistry.addEndpoint("/ws-connect").setAllowedOrigins("*").withSockJS();
}
}
MessageController.java
#Controller
public class MessageController {
#MessageMapping(value = "/test")
#SendTo("/private")
public Message message(String messageText) {
Message message = new Message();
message.setMessage(messageText);r);
message.setTimestamp(new Date());
return message;
}
}
sockets.js
var stompClient = null;
function connect() {
var socket = new SockJS('http://localhost:8080/ws-connect');
stompClient = Stomp.over(socket);
stompClient.connect({}, function(frame) {
console.log('Connected: ' + frame);
stompClient.subscribe('/chat/private', function(message) {
console.log('Here');
console.log('Message is: ' + message);
});
console.log('Here2');
})
}
connect();
function sendMessage() {
stompClient.send('/message/test', {}, "Hello self!");;
}
I have a button in my index.html that when clicked calls the sendMessage function and I get a console log that the message has been sent, however I never get the reply in the subscribe function. The client successfully connects to the WebSocket server and I get this outputted in the console. What am I doing wrong?
Change /private to /chat/private
Change it like below :
#Controller
public class MessageController {
#MessageMapping(value = "/test")
#SendTo("/chat/private")
public Message message(String messageText) {
Message message = new Message();
message.setMessage(messageText);
message.setTimestamp(new Date());
return message;
}
}

SignalR js client wrong Server port

I'm starting with signalr but got some trouble, my test server run at http://localhost:22660/ and my web run at
http://localhost:61963/.I got this error when connect from client to server:
GET http://localhost:61963/signalr/negotiate?clientProtocol=1.4&connectionData=%5B%7B%22name%22%3A%22chathub%22%7D%5D&_=1496809403215 404 (Not Found)
I already config: $.connection.hub.url = 'http://localhost:22660/signalr'; but not work, this my js code:
var connection = $.hubConnection();
$.connection.hub.url = 'http://localhost:22660/signalr';
var chatHub = connection.createHubProxy('ChatHub');
connection.start()
.done(function () { console.log('Now connected, connection ID=' + connection.id); })
.fail(function () { console.log('Could not connect'); });
Server:
namespace test
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.Map("/signalr", map =>
{
map.UseCors(CorsOptions.AllowAll);
var hubConfiguration = new HubConfiguration
{
EnableJSONP = true
};
map.RunSignalR(hubConfiguration);
});
}
}
}
namespace SignalRChat
{
public class ChatHub : Hub
{
public void Send(string name, string message)
{
// Call the addNewMessageToPage method to update clients.
Clients.All.addNewMessageToPage(name, message);
}
}
}
I dont sure, but i think because i using different version of signalr (2.1.2 and 2.2.0). Using same version solved my problem.

Categories

Resources