Can anyone provide successful implementation of Stomp using the latest version of ActiveMQ 5.x using the React N? How to connect and publish to the queue?
I have below questions:
I have to retrieve the data from consumer and do some add some boolean value and send it to publish.
How can I keep the connection alive because continuously I will get message in queues.
How can I implement this in React.js in simple manner (any plugins)
I tried with JavaScript, and it works as expected.
consumer.js
const Stomp = require("stomp-client");
const stompClient = new Stomp("127.0.0.1",61613);
stompClient.connect( function(sessionId){
console.log("consumer connected");
stompClient.subscribe("/queue/<name>",function(body){
console.log(body);
});
});
producer.js
const Stomp = require("stomp-client");
const stompClient = new Stomp("127.0.0.1",61613);
stompClient.connect( function(sessionId){
console.log("producer connected");
stompClient.publish("/queue/<name>",function(body){
console.log(body);
console.log(typeof(body));
//JSON.stringify(body);
});
stompClient.disconnect();
});
This is what I tried in React.JS (which failed): here i can able to connect and after that if i call subscribe with que name it is not giving any response
import './App.css';
import React,{useEffect} from 'react';
import { Client, Message } from '#stomp/stompjs';
function App() {
const clientdata = new Client();
useEffect(() => {
clientdata.configure({
brokerURL: 'ws://localhost:61614/stomp',
onConnect: (frame) => {
console.log('onConnect');
console.log(frame);
clientdata.subscribe('/queue/<quename>',info => {
console.log(info);
})
console.log(subscription);
},
// Helps during debugging, remove in production
debug: (str) => {
// console.log(new Date(), str);
}
});
client.activate();
}, []);
return (
<div >
</div>
);
}
export default App;
When i tried the above code I am getting only connected log and I'm not able to subscribe any thing and not seeing anything.
Related
I am trying to update a variable whenever I receive data from udp. The connection is working fine and when I send some data I am getting it in the console correctly. But seems the variable is not being updated. I want to use the variable from a svelte component that will update in the browser. i am using sveltekit.
import { writable } from 'svelte/store';
import dgram from 'dgram';
const Socket = () => {
const server = dgram.createSocket({type:"udp4",reuseAddr:true});
server.bind(4444);
const temperature = writable(0);
const getTemperature = () => {
return temperature;
}
server.on('message', (msg, rinfo) => {
var data = JSON.parse(msg);
temperature.set(data.message);
console.log(temperature);
});
return { getTemperature };
};
export default Socket;
I am trying to convert my code from Nuxt 2 to Nuxt 3, and I have run into an issue with creating a websocket server in Nuxt 3.
It works perfectly fine in Nuxt 2 using this code:
// Nuxt 2: modules/socket.js
import http from 'http'
import socketIO from 'socket.io'
export default function () {
this.nuxt.hook('render:before', () => {
const server = http.createServer(this.nuxt.renderer.app)
const io = socketIO(server)
this.nuxt.server.listen = (port, host) => new Promise(resolve => server.listen(port || 3000, host || 'localhost', resolve))
this.nuxt.hook('close', () => new Promise(server.close))
io.on('connection', (socket) => {
console.log("CONNECTED")
})
})
}
// Nuxt 2: plugins/socket.client.js
import io from 'socket.io-client'
const socket = io('http://localhost:3000')
export default ({}, inject) => {
inject('socket', socket)
}
<!-- Nuxt 2: pages/index.vue -->
<template>
<div>
<p>Check socket status in Vue devtools...</p>
</div>
</template>
<script>
export default {
computed: {
socket() {
return this.$socket ? this.$socket : {};
}
}
}
</script>
However, in Nuxt 3 I cannot access this.nuxt.renderer.app in the modules/socket.js file (for http.createServer(...)), and I cannot figure out how to access the correct renderer.app elsewhere in a Nuxt3 module. My Nuxt 3 code looks like this:
// Nuxt 3: modules/socket.js
import http from 'http'
import socketIO from 'socket.io'
export default (_, nuxt) => {
// Note that I use the 'ready' hook here - render:before is apparently not included in Nuxt3.
nuxt.hook('ready', renderer => {
// nuxt.renderer is undefined, so I've tried with renderer.app instead, with no luck.
const server = http.createServer(renderer.app)
const io = socketIO(server)
nuxt.server.listen = (port, host) => new Promise(resolve => server.listen(port || 3000, host || 'localhost', resolve))
nuxt.hook('close', () => new Promise(server.close))
io.on('connection', () => {
console.log("CONNECTION")
})
})
}
// Nuxt 3: plugins/socket.client.js
import io from 'socket.io-client'
export default defineNuxtPlugin(() => {
const socket = io('http://localhost:3000')
return {
provide: {
socket: socket
}
}
})
<!-- Nuxt 3: app.vue -->
<template>
<div>
<p>Check socket status in Vue devtools...</p>
</div>
</template>
<script setup>
const { $socket } = useNuxtApp()
</script>
I would make a codesandbox link for you, but every time I try, it breaks before I even add any code. I think it does not correctly work with Nuxt3 yet.
Has anyone successfully established a websocket server in a Nuxt 3 module yet? Or can anyone see what I am missing?
I am interested in any working solution, it does not necessarily have to be socket.io.
I figured it out!
Digging deep into the Nuxt 3 code, it turns out that they have a listen hook which provides the server parameter that I needed to set up the server. This information is really hard to find though.
I also managed to simplify the script a bit.
Here's the updated modules/socket.js:
import { Server } from 'socket.io'
export default (_, nuxt) => {
nuxt.hook('listen', server => {
const io = new Server(server)
nuxt.hook('close', () => io.close())
io.on('connection', () => {
console.log("CONNECTION")
})
})
}
Everything else can remain the same
thx anbork I'm use ws it the same method create file "modules/wsserver.ts"
import { WebSocketServer } from "ws"
export default (_: any, nuxt: any) => {
nuxt.hook("listen", (server: any) => {
const wss = new WebSocketServer({ server })
nuxt.hook("close", () => wss.close())
wss.on("connection", function connection(ws) {
ws.on("message", function message(data) {
console.log("received: %s", data)
})
ws.send("something")
})
})
}
then register at nuxt.config
modules: ["./modules/wsserver"],
Based on #ahbork's response and a addition from the Nuxt 3 docs, I got this on Vue 3 + Nuxt 3 + Typescript:
import { Server } from 'socket.io'
import { defineNuxtModule } from '#nuxt/kit'
export default defineNuxtModule({
setup(options, nuxt) {
nuxt.hook('listen', (server) => {
console.log('Socket listen', server.address(), server.eventNames())
const io = new Server(server)
nuxt.hook('close', () => io.close())
io.on('connection', (socket) => {
console.log('Connection', socket.id)
})
io.on('connect', (socket) => {
socket.emit('message', `welcome ${socket.id}`)
socket.broadcast.emit('message', `${socket.id} joined`)
socket.on('message', function message(data: any) {
console.log('message received: %s', data)
socket.emit('message', { data })
})
socket.on('disconnecting', () => {
console.log('disconnected', socket.id)
socket.broadcast.emit('message', `${socket.id} left`)
})
})
})
},
})
I am using the following server code to retrieve data from a postgres db:
const express = require('express')
const app = express()
const server = require('http').createServer(app);
const pool = require("postgresql");
const WebSocket = require('ws');
const wss = new WebSocket.Server({ server:server });
const getTempData = async () => {
try {
const tempData = await pool.query("select country, temp from my_temp_table");
return JSON.stringify(tempData.rows)
} catch(err) {
console.error(err.messasge);
}
}
wss.on('connection', async (webSocketClient) => {
console.log('A new client Connected!');
const tempDetails = await getTempData();
webSocketClient.send(tempDetails);
webSocketClient.on('message', (message) => {
console.log('received: %s', message);
});
});
server.listen(3000, () => console.log(`Listening on port :3000`))
Now on the client side, I have created the following websocket connection to localhost 3000.
When first rendering the below client code, the data displays where I also get all the console log messages, i.e. ws opened, getting data.... and finally console logging the actual data.
isPaused is also set to false.
The problem I'm facing and unsure what the issue is, is that I expected to see my client page update the country/temp data (no page refresh), when I updated the country/temp values in my_temp_table database table, but it didn't.
The result that I expected was that via the websocket, anytime my table on the server-side updated, the client would update the tempData, via the second useEffect hook below.
I basically would like the client to pull in and display changes from the server via websocket when the data changes in the backend db table.
import React, { useState, useEffect, useRef } from 'react';
export default function Temperature() {
const [isPaused, setPause] = useState(false);
const [tempData, setTempData] = useState([]);
const [name, setName] = useState(null);
const ws = useRef(null);
useEffect(() => {
ws.current = new WebSocket("ws://localhost:3000");
ws.current.onopen = () => {
console.log("ws opened");
}
ws.current.onclose = () => console.log("ws closed");
return () => {
ws.current.close();
};
}, []);
useEffect(() => {
if (!ws.current) return;
ws.current.onmessage = e => {
if (isPaused) return;
console.log("getting temp data....");
const data = JSON.parse(e.data);
setTempData(data)
console.log("data: ",data);
};
}, [isPaused]);
return (
<div>
<button onClick={() => setPause(!isPaused)}>
{isPaused ? "Resume" : "Pause"}
</button>
{ tempData?
tempData.map((data, i) => (
<div>
<span>{data.country}</span>
<span>{data.temp}</span>
</div>
))
: null }
</div>
)
}
The code is executing only once because there are no recurrying calls to the web socket send event. When the web socket is created it gets the data from the database and sends it, and thats it.
You probably want some kind of action that triggers this event multiple times. For example, in your code:
wss.on("connection", async webSocketClient => {
console.log("A new client Connected!");
setInterval(() => {
const timeNow = Date.now();
webSocketClient.send(
JSON.stringify([
{ country: "country-a", temp: timeNow },
{ country: "country-b", temp: timeNow },
])
);
}, 1000);
webSocketClient.on("message", message => {
console.log("received: %s", message);
});
});
I see you are using some package to pool from a PostgreSQL db. Take a look at this other example.
How would your clients know if there is any change in database on server side ?
You can create an event that triggers each time a particular data changes and listen to those event on your client sockets. Like you did with onmessage event in your current code.
You can render the react component based on this event.
There's various answers to this question, but either they're outdated (I don't think the "reconnect" event exist anymore?) or just doesn't work for me.
I have a ton of data that the client is waiting for from the server via socket.io sockets. It's fine until 10-15 minutes later with over 1600 results that the socket reconnects. After the reconnection happens, I do not get anymore of the data that the server emits, which I assume is because I've lost the events from the original socket connection.
I have to refresh to continue getting that data.
How do I reconnect to socket.io after every reconnection?
Client:
socket.js (context)
import { createContext } from 'react';
import io from 'socket.io-client';
export const socket = io('http://localhost:5000');
export const SocketContext = createContext();
Layout.js
import { socket, SocketContext } from '../context/socket'
function MyApp({ Component, pageProps }) {
return <SocketContext.Provider value={socket}>
<Layout>
<Component {...pageProps} />
</Layout>
</SocketContext.Provider>
}
page (next.js)
import { SocketContext } from '../context/socket';
...
const socket = useContext(SocketContext);
useEffect(() => {
socket.emit('joined', socketChannel);
socket.on(socketChannel, handleStream);
}, []);
Server:
index.js (Uses fastify-socket.io)
fastify.io.on('connection', socket => {
socket.on('joined', (channel) => {
socket.join(channel);
})
});
redis.subscriber.on('message', (channel, message) => {
io.to(channel).emit(channel, message);
});
Socket.io will automatically leave the rooms when you have a disconnect.
Rooms are left automatically upon disconnection.
in useEffect(), you are joining the room once:
socket.emit('joined', socketChannel);
socket.on(socketChannel, handleStream);
Two options:
Automatically join at connect on client:
useEffect(() => {
socket.on(socketChannel, handleStream);
// connect fires when connected, also after reconnected
socket.on('connect', () => {
console.log('connect', socket.connected);
// automatically join the room
socket.emit('joined', socketChannel);
});
}, []);
Automatically join at the server, but this assumes all clients join the relevant room which may not be suitable:
io.on('connection', (socket) => {
console.log(`${socket.id} connected`);
// automatically join the room
socket.join(socketChannel);
...
I've been looking for a way to handle web socket disconnects in my React app with Apollo subscriptions and have not found a way to do so. The other examples I see in the apollo documentation show the below method for catching a reconnect:
const wsClient = process.browser ? new SubscriptionClient(WSendpoint, {
reconnect: true,
}) : null;
const wsLink = process.browser ? new WebSocketLink(wsClient) : null;
if (process.browser) {
wsLink.subscriptionClient.on(
'reconnected',
() => {
console.log('reconnected')
},
)
}
There are two issues with the above method:
is that is does not catch when the user disconnects from their internet (only from when the server restarts for whatever reason)
that the reconnect is triggered outside of my React apps components.
What I would like to be able to do is to is reload my "chat" component if the user either disconnects from their internet or if my express server goes down for any reason. For this to happen I would need my chat component to completely reload which i'm not sure would be possible from outside my component tree.
Is there a method in the Query or Subscription Apollo components to be able to capture this event and handle it accordingly from the component?
There are a few ways I can think of to handle these cases but none of them are a one-shot solution, each case needs to be handled independently.
Setup a online/offline listener (ref)
Setup an Apollo middleware to handle network errors from your server (ref)
Create a variable in your store, isOnline for example, which can hold a global reference of your app's state. Whenever the above two methods trigger, you could update the value of isOnline
Finally, to bundle all of it together. Create a react HOC which uses isOnline to handle the network state for each component. This can be used to handle network error messages, refresh components once network is restored.
You can use SubscriptionClient callbacks from subscriptions-transport-ws, like this:
const ws = require("ws");
const { SubscriptionClient } = require("subscriptions-transport-ws");
const { WebSocketLink } = require("apollo-link-ws");
const { ApolloClient } = require("apollo-client");
const { InMemoryCache } = require("apollo-cache-inmemory");
const subClient = new SubscriptionClient(
'ws://localhost:4000/graphql',
{ reconnect: true },
ws
);
subClient.onConnected(() => { console.log("onConnected") });
subClient.onReconnected(() => { console.log("onReconnected") });
subClient.onReconnecting(() => { console.log("onReconnecting") });
subClient.onDisconnected(() => { console.log("onDisconnected") });
subClient.onError(error => { console.log("onError", error.message) });
const wsLink = new WebSocketLink(subClient);
const client = new ApolloClient({
link: wsLink,
cache: new InMemoryCache()
});
I'm using this for Node.js, but it will probably work for React too.