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;
Related
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.
Frameworks used: Next.js, Socket.io, React
I am making a simple messaging app. I am basically just emitting a message someone types, sending that message to the server, which is then "broadcasted" back through an event called "receive-chat-message". The issue I'm having is when the response is handled on the front end with "receive-chat-message", the [messages] state is not appending a new message to display, it's just overwriting the state.
My goal is to send a message to the server; the server then sends the message back to the client. I then append the new message on the client, sent from the server, to the [messages] state on the client, and then render the state of [messages]. The problem is it's only overwriting the [messages] state, and not appending new messages to it.
Code that sends message to the server
const [message, setMessage] = useState("");
const handleChange = (e) => {
setMessage(e.target.value);
};
const submitMessage = async () => {
// socket.io
const socket = io();
socket.emit("send-chat-message", message, user);
setMessage("");
};
Front-End Code
const [messages, setMessages] = useState([]);
useEffect(() => {
const socket = io();
socket.on("receive-chat-message", handleSetMessage);
return () => socket.disconnect();
}, []);
const handleSetMessage = (data) => {
/* data prop is the new message - it has a {message: "message", user: "name"}
sent from server.
THIS IS THE PROBLEM IN THE CODE WHERE IT DOESN'T APPEND
NEW MESSAGES TO THE [messages] STATE, IT JUST OVERWRITES
THE CURRENT STATE WITH THE NEW MESSAGE. */
setMessages([...messages, data]);
};
Back-End Code
export default async function handler(req, res) {
if (!res.socket.server.io) {
const io = new Server(res.socket.server);
res.socket.server.io = io;
io.on("connection", async (socket) => {
socket.on("send-chat-message", async (message, user) => {
socket.broadcast.emit("recieve-chat-message",
{
message,
name: user && user.name,
});
});
});
}
}
I solved this by setting messages through the functional method like:
setMessages((messages) => [...messages, data]);
Instead of:
setMessages([...messages, data])
I think we need this because I was updating the state from a function called within a socket.io listener and was never actually grabbing the previous state; so I had to direct it to the previous state and then merge the values.
I recently updated a weather dashboard project that I was working on to have a server backend, that I could just pull the API json values from said server page (in order to hide the api key I need to utilize the weather api). Since my React project requires entering a searched city value or zipcode and the API request being made requires said searched value to be submitted into the site request, I am struggling with how to get said value from the client side to the server side. Whenever I have tried to connect a callback function which can just grab the value from the React component after the user enters it, I get a React error that states
"Module not found: You attempted to import which falls outside of the project src/ directory. Relative imports outside of src/ are not supported"
My question is, how am I meant to connect this?
Below is my code for the component collecting the search value, overview.js, where the function getSearch receives the value from a child component:
import React from 'react';
import './overview.css';
import { RecentSearches } from '../Recent Searches/recentSearches';
import { Hourly } from '../Hourly/hourly';
import { Fiveday } from '../5 Day Forecast/fiveday';
export function Overview() {
// this callback function receives the searched city entered from recentSearches and applies it to fetchForecast
const getSearch = async (searchedCity) => {
console.log(searchedCity);
fetchForecast(searchedCity);
};
async function fetchForecast(city) {
var BASE_URL = `localhost:8000/forecast`;
const response = await fetch(BASE_URL);
const data = await response.json();
// collects all of the current weather info for your search
const currentTempInfo = {
city: data.location.name,
state: data.location.region,
epochDate: data.location.localtime_epoch,
message: data.current.condition.text,
wicon: data.current.condition.icon,
currentTemp: data.current.temp_f,
currentHighTemp: data.forecast.forecastday[0].day.maxtemp_f,
currentLowTemp: data.forecast.forecastday[0].day.mintemp_f,
feelsLike: data.current.feelslike_f,
humidity: data.current.humidity,
rainLevel: data.current.precip_in,
// hourlyTemps is an array, starts from midnight(index 0) and goes every hour until 11 pm(index 23)
hourlyTemps: data.forecast.forecastday[0].hour.map((entry) => {
let epochTime, temp;
[epochTime, temp] = [entry.time_epoch, entry.temp_f];
return [epochTime, temp];
})
};
// console.log(currentTempInfo);
const daycardInfo = [];
// this for loop triggers and creates an array with all necessary values for the
function daycardForLoop() {
for (let x=0; x < 3; x++) {
const fcDayDates = data.forecast.forecastday[x].date_epoch;
const dayInfo = data.forecast.forecastday[x].day;
const dayValues = {
dates: fcDayDates,
message: dayInfo.condition.text,
wicon: dayInfo.condition.icon,
maxTemp: dayInfo.maxtemp_f,
minTemp: dayInfo.mintemp_f,
avgTemp: dayInfo.avgtemp_f
};
// pushes dayValues object into daycardInfor array
daycardInfo.push(dayValues);
};
};
daycardForLoop();
// this updates the state with the forecast for the city entered
const newData = {
currentTempInfo: currentTempInfo,
daycardInfo: daycardInfo
};
// this spits out the newly created forecast object
return newData;
};
return (
<div>
<div className='jumbotron' id='heading-title'>
<h1>Welcome to <strong>Weathered</strong>!</h1>
<h3>A Simple Weather Dashboard </h3>
</div>
<div className='container-fluid' id='homepage-skeleton'>
<div className='d-flex' id='center-page'>
<RecentSearches getSearch={getSearch}/>
<Hourly />
</div>
</div>
<Fiveday />
</div>
)
};
Here is my server code, index.js, where you can see that I need to fill in the params value of "q" that you can find in the get request for the "/forecast" page:
const PORT = 8000;
const express = require('express');
const cors = require('cors');
const axios = require('axios');
require('dotenv').config();
const app = express();
// this callback function receives the searched city entered from recentSearches and applies it to fetchForecast
// update: this callback function now passes the search to the backend for the url search to parse the new data
// export const getSearch = async (searchedCity) => {
// fetchForecast(searchedCity);
// };
app.get('/', (req, res) => {
res.json('hi');
});
app.get('/forecast', (req, res) => {
const options = {
method: 'GET',
url: `http://api.weatherapi.com/v1/forecast.json?key=${process.env.REACT_APP_API_KEY}`,
params: {
q: "*** I need to get the search value here ***",
days: 3,
api: "no",
alerts: "no"
}
};
axios.request(options).then((response) => {
res.json(response.data);
}).catch((error) => {
console.log(error);
});
});
app.listen(PORT, () => console.log(`Server running on PORT ${PORT} `))
Apologies if the message itself is convoluted. Any help/tips/comments are much appreciated!
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.
I'm using websocket in react. This is the code for the component:
import React, { useState, useEffect } from "react";
export default function Component(props) {
const [socket, setSocket] = useState();
const parseMessage = (msg) => {
if (msg[0] !== "R") sendMessage("123"); // ignore the very first message from the socket.
};
const sendMessage = (msg) => socket.send(msg); // error at this line
useEffect(() => {
const socket = new WebSocket("wss://ws.ifelse.io/");
socket.addEventListener("message", ({ data }) => {
if (socket) parseMessage(data);
});
setSocket(socket);
}, []);
const sendMsg = () => {
socket.send("test");
};
return <button onClick={() => sendMsg("clicked")}>send msg</button>;
}
I'm getting this error: TypeError: Cannot read properties of undefined (reading 'send') at the marked line. The WebSocket is just an echo server, it sends back the same thing you send it.
If I wrap the socket.send in a try-catch block, I can still send and receive messages from the WebSocket using the button, but the error still occurs at that line in sendMessage.
It's clear that the socket variable is not undefined as I'm able to send and receive messages before and after the error occurs.
So my question is why is the socket variable undefined only for the brief period after receiving a message, and what is the fix for this issue.
Better solution would be to initialize the socket outside
import React, { useState, useEffect } from "react";
const socket = new WebSocket("wss://ws.ifelse.io/")
export default function Component(props) {
const ws = useRef(socket)
useEffect(() => {
ws.current?.addEventListener("message", ({ data }) => {
parseMessage(data);
});
return () => {
ws.current?.removeAllListeners()
}
}, [])
const parseMessage = (msg) => {
if (msg[0] !== "R") sendMessage("123"); // ignore the very first message from the socket.
};
const sendMessage = (msg) => ws.current?.send(msg);
const sendMsg = () => {
ws.current?.send("test");
};
return <button onClick={() => sendMsg("clicked")}>send msg</button>;
}
The useEffect runs just once and in that moment the socket is still undefined. Function sendMessage references undefined socket when the effect runs. When the socket is set using setSocket, component will rerender, but the new instance of sendMessage (now referencing the existing socket) will never be used, because the effect will not run again.
It is better to use ref in this case.
export default function Component(props) {
const socket = useRef();
const sendMessage = (msg) => socket.current.send(msg);
useEffect(() => {
socket.current = new WebSocket("wss://ws.ifelse.io/");
socket.current.addEventListener("message", ({ data }) => {
parseMessage(data);
});
return () => {
... release resources here
}
}, []);
...
}
When you use useState you create a state variable with an update state function. You also provide the initial value of the state variable in useState(initialState).
In your case you are not passing anything (i.e. you are telling React it's undefined, that's why at this line:
const sendMessage = (msg) => socket.send(msg); // error at this line
your code cannot use socket.send because socket is undefined.
Your useEffect runs after the return function and then the socket instance is created as well as set to socket state variable.
You need to make sure that you are only sending message over socket after socket is created.
For more on useEffect you can read this post:
https://jayendra.xyz/2019/06/17/how-useeffect-works/
You need to wait for the socket to be established first and then set the socket using setSocket in the open event. The way you are doing it now expects the first message to be sent by the server and then you setSocket, if the server does not send a message before you click on the button, the socket instance is not set in your state.
Do this instead:
socket.addEventListener('open', function (event) {
setSocket(socket);
});
Here is the full code
import React, { useState, useEffect } from "react";
export default function Component(props) {
const [socket, setSocket] = useState();
const [disabled, setButtonDisabled] = useState(true);
const parseMessage = (msg) => {
if (msg[0] !== "R") sendMessage("123"); // ignore the very first message from the socket.
};
const sendMessage = (msg) => socket.send(msg); // error at this line
useEffect(() => {
const socket = new WebSocket("wss://ws.ifelse.io/");
socket.addEventListener('open', function (event) {
setSocket(socket);
setButtonDisabled(false);
});
socket.addEventListener("message", ({ data }) => {
if (data) parseMessage(data);
});
return ()=>{
socket.close();
};
}, []);
const sendMsg = () => {
if(socket) socket.send("test");
};
return <button disabled={disabled} onClick={() => sendMsg("clicked")}>send msg</button>;
}