Vue Socket.io Not Receiving Data - node.js

I currently have a Python Flask SocketIO application that will be connecting to a Vue app using this socket.io library. The Vue app (currently) will poll the Python application using socket.io on a button press. I can correctly receive the data sent from Vue; however, Vue is not receiving the data. Currently, my actions/mutations looks like this:
const actions = {
fbCommentsPerPost: (context) => {
console.log('fb comments per post sent!')
socket.emit('fb comments per post', { post_id: '123' })
// socket.on('data', function (resp) {
// console.log(resp)
// })
},
socket_connectResp: (context, message) => {
console.log(message)
},
socket_fbData: (context, message) => {
console.log(message)
}
}
// mutations
const mutations = {
SOCKET_FB_DATA: (state, status) => {
console.log('comments!!!!')
}
}
Using the README for this project, the socket_fbData should be receiving the data from the Python app (the backend is emitting 'fb data'). When I run a simple client in node using socket.io-client, this works and I can properly receive data. Moreover, when I uncomment the socket.on block in fbCommentsPerPost, I can at least console log the data. Is there something I'm missing here?

vue-socket.io has an issue with converting socket events to actions and mutations. It kind of works but not as expected. Check issue #117
A few months ago there was few PRs with a fix for this issue but some edge cases are not covered. So you can try the latest version or just move to vue-socket.io-extended instead.

Related

Socket.io listener getting skipped on the client-side while there is an emitted event

I am facing this weird issue. I am not a veteran of using Socket.io. I have been exploring this library as the app I am building needs a remote playing feature wherein players create invitations to other players so that they can use those invitations to join the game remotely. I am using React on the front end (client-side), and on the server side, I am using the Nodejs Express framework with Socket.io. I have also installed client-side Socket.io for React. The basic implementation is all working fine. When there is a new user accessing the client-side app, Server-side socket.io listens to the connection. Any events triggered by the client also get reported on the server side. I am also able to broadcast the events back to all the connected clients using the socket.broadcast.emit() method.
I am trying to store the past events (basically, these are the invitations created by the currently connected players) in an array and then emit the stored array for the new connections so that the new users will see the past events(invitations). Below is my implementation on the server side:
//Array to store previously emitted events
const activeInvites = [];
//SocketIO connections
io.on("connection", (socket) => {
console.log(`⚡: ${socket.id} user just connected!`);
//Listen to the new invites
socket.on("newInvite", (invite) => {
activeInvites.push(invite);
socket.broadcast.emit("newPrivateInvites", invite);
});
//Publish all previously created invites to the new connections
io.emit("activeInvites", activeInvites); //new connections emit this event however the client won't listen to "activeInvites" event
socket.on("disconnect", () => {
console.log(`🔥: ${socket.id} user disconnected`);
destroy();
});
function destroy() {
try {
socket.disconnect();
socket.removeAllListeners();
socket = null; //this will kill all event listeners working with socket
//set some other stuffs to NULL
} catch (ex) {
console.error("Error destroying socket listeners:", ex.message);
}
}
});
And, below is my client-side implementation:
useEffect(() => {
socket.on("activeInvites", (invite) => {
console.log(invite);
}); //a new connection client skips listening to this event. Can't understand why.
socket.on("newPrivateInvites", (invite) => {
setPrivateInvites((existingInvites) => [...existingInvites, invite]);
});
//I have commented below code. Even if I uncomment it, no difference
// return () => {
// socket.off("newPrivateInvites");
// socket.off("activeInvites");
// socket.removeAllListeners();
// };
}, [socket, privateInvites]);
//Below is the handler function I use to open up a Sweetalert2 dialog to create an invite
const createMyGameInviteHandler = () => {
swalert
.fire({
title: "New Invite",
text: "This will create a new game invite and unique joining code that you can share with your friends",
iconHtml: '<img src="/images/invite.png" />',
showCancelButton: true,
confirmButtonColor: "#3085d6",
cancelButtonColor: "#d33",
confirmButtonText: "Yeh! Let's Go!",
customClass: {
icon: "no-border",
},
})
.then((result) => {
if (result.isConfirmed) {
player.gameId = "1234";
setMyGameInvite(player);
socket.emit("newInvite", player); //This is where I create a new invitation event
}
});
};
In the above code, the "activeInvites" event is getting skipped by the new client even after socket.io on the server side triggers a new event after the new connection is created. Note that I am using io.emit() to emit the event to all the connected clients. So, even new clients should also listen. I am not able to see where the problem is. Could you please help me with this?
I tried to store the events generated by the client and consumed by the server in the past so that I could serve those events to the new clients when they establish the connection. I was expecting that io.emit() method would emit the event that will be consumed by all the clients including the new clients. However, new clients are skipping listening to this event. I am using useEffect hook in a react component.

pubnub integration in react js frontend and nodejs backend

i want to integrate pubnub with reactjs frontend and node js backend.My system consist of websocket . I want to replace websocket with pubnub connection .I have installed pubnub using npm in node js its works fine.But in front end side when i run npm start i see only below screen.
The problem with web socket is when connection lost i didnt get back my card details(poker game cards)
Did i do something wrong?if please let me know correct way to do it.
i have replaced websocket connection of existing system with pubnub.see code below.
import PubNub from 'pubnub';
import { PubNubProvider, usePubNub } from 'pubnub-react';
// import CountDownBgTask from "./containers/CountDownBgTask";
const pubnub = new PubNub({
publishKey: 'xxxxxxxxxxxxxxxxx',
subscribeKey: 'xxxxxxxxxxxxxxxxx'
});
componentDidMount() {
if (isMobile) {
setTimeout(() => {
this.setState({
isOpen: true
});
window.scrollTo(0,1);
},1000)
}
window.onbeforeunload = closingCode;
// Read res from service via Socket IO
// socket.on("message", receiveMsg);
pubnub.on("message", text => {
let params = text.split("|"); //.map(p => Base64.Decode(p)); // we are not using b64 now
let message = params.shift(); // message, eg. playerSitOut, clearTable
this.receiveMsg.push(message);
this.props.updateMessage({ message, params });
});
}

Socket.io: Other client only updates when being interacted

I'm trying to set up a realtime application using socket.io in Angular and node.js, which is not working as intended.
Whenever a client is making a new post, the other clients won't update until you interact with the client (e.g. clicking somewhere on the page, or clicking on the browsers tab).
However, having console open in the browser, I can see the new post in the console when I log the posts/objects - without the need to interact with the clients.
Angular:
import io from 'socket.io-client';
const socket = io('http://localhost:3000');
posts: Post[] = [];
...
// Inside ngOnInit:
socket.on('data123', (res) => {
console.log('Updating list..', res);
this.postService.getPosts();
this.postsSub = this.postService.getPostUpdateListener()
.subscribe((posts: Post[]) => {
this.posts = posts;
});
});
Displaying in the template:
<... *ngFor="let item of posts">
Inside PostsService:
getPosts() {
this.http.get<{ message: string, posts: Post[] }>('http://localhost:3000/api/posts')
.subscribe((postData) => {
this.posts = postData.posts;
this.postsUpdate.next([...this.posts]);
});
}
Node.js - this socket.io solution is not yet sending the actual list:
const io = socket(server);
io.sockets.on('connection', (socket) => {
console.log(`new connection id: ${socket.id}`);
sendData(socket);
})
function sendData(socket){
socket.emit('data123', 'TODO: send the actual updated list');
setTimeout(() => {
console.log('sending to client');
sendData(socket);
}, 3000);
}
What worked as intended:
Using setInterval instead "socket.on(..)" on the front-end gave the intended result, meaning the clients will update automatically without the need of interacting. I'm fully aware this solution is horrible, but I assume this pinpointing that it's something wrong with socket solution above in Angular part.
wait, every time when socket.on('data123', (res) => {... you are creating new subscribe? it's wrong way...you must create subscribe in your socket connect feature

Updating Amazon DDB table from node on now after response to request sent

I want to add row to Amazon DDB table from node app deployed on Zeit-now every time I get a post reqest but after sending response to post request. My ddb.putItem stops as pending promise and no errors are logged. I don't understand why.
The app is a slack bot. I get a message from slack api and it fires response by my bot. I want to quickly send 200 to slack to avoid getting message sent again.
I tried different approaches, using EventEmitter or res.on('finish'...
I did test that the module sending update to table in ddb works as when I fire it from command line node it works.
But neither from now dev or deployed now app it does not.
I made a simplified test case in this repository:
https://github.com/halas/now-test-case
Basically entrypoint for node app looks like this:
const send = require('./send.js');
module.exports = (req, res) => {
res.on('finish', send);
res.end(`Hello from Node.js on Now 2.0!`);
console.log('still here'); // this gets logged
};
And the send module:
[ require aws-sdk and set credentials ]
const ddb = new AWS.DynamoDB({apiVersion: '2012-08-10'});
module.exports = () => {
let params = {
TableName: 'now-test-case',
Item: {
'id': { N: String(Date.now()) },
'message': { S: 'hello World' },
}
};
console.log('hello'); //we get here
try {
console.log('try'); //we get here
const data = ddb.putItem(params).promise();
console.log(data); //this is pending promise now
data
.then((data) => {console.log(data)})
.catch((error) => {console.log(error)});
// and it never gets resolved or rejected
} catch(e) {
console.log(e); //and no error catched here either
}
};
As suggested by Rob Evans on Zeit Spectrum chat, I prepared the version
with async-await (on branch in test repo), but results are the same.
I would expect to get the update on DynamoDB (resolved promise).
While I get only pending promise and now resolve or reject.

Using socketio with react redux

Im building a small chat application using react,redux,socketio and node with mongoose. Normally redux flows through actions (which makes API calls and receive data) and dispatch the data. But in my case the socket will emit to a certain event but it would not return data until we manually emit the data from the back-end. so to achieve the proper redux flow should i add a socket event on actions to retrieve the data (coming from back-end) and then dispatch it or is there any other proper way to achieve this?
Here is a sample code of what i'm planing to do in
Actions file
function sendMessage(data) {
return {
type: SEND_MESSAGE,
payload: data
};
}
export const sendNewMessage = (socket,data) => {
return dispatch => {
socket.emit("send message",data);
socket.on("new message",function(data){
dispatch(sendMessage(data));
});
};
};
That seems perfectly reasonable to me. I would suggest using thunk's "extra argument" for this such that your components do not need to know about the actual socket object:
const store = createStore(
reducer,
applyMiddleware(thunk.withExtraArgument({ socket }))
)
export const sendNewMessage = (data) =>
(dispatch, getState, { socket }) => {
socket.emit("send message", data)
socket.on("new message", (data) => {
dispatch(sendMessage(data))
})
}

Resources