vue-socket.io fail to trigger event when url route is present - vue.js

I have a Python Flask backend that listens at port 8000 (at '/') and keeps emitting digest event after receiving a connection. At the Vue frontend, I setup the connection as
Vue.use(
new VueSocketIO({
debug: false,
connection: "http://localhost:8000",
})
);
and in a component, I have
sockets: {
connect() {
console.log('connected');
},
afterConnect(data) {
console.log(data);
},
// get digest from backend
digest(data) {
console.log(data)
},
}
The digest function here will be triggered correctly.
However, when I change the setup to
Vue.use(
new VueSocketIO({
debug: false,
connection: "http://localhost:8000/abc", // add whatever route here
})
);
I can still receive correct data packets through the socket, but digest function is simply not triggered. The abc in the route can be anything, it won't break the connection.
Any help is appreciated! Thanks!

Related

ICE failed on firefox but peerJs's exemple work fine

I try to make a simple chat with peerJs to learn how to use peer to peer
when I try to connect two clients, this error happens on both client
WebRTC: ICE failed, your TURN server appears to be broken, see about:webrtc for more details
PeerJS: iceConnectionState is failed, closing connections
the peerJs demo work fine on Firefox (even when i run it locally)
and my code seem to work correctly on edge
I try in private with disabled add-on
my media.peerconnection.ice.proxy_only is set to false.
Any setting related to ice or peer is set to default
My code
both client have the same code, they try to connect to the client in the url
exemple:
i open http://localhost:5173/room who get an peerId and rename itselfhttp://localhost:5173/room?roomId=198ec396-1691-48cf-b6ea-16d2102c4917 then i copy paste this link to another tab
<script lang="ts">
import { page } from '$app/stores';
import { Peer } from 'peerjs';
import { onMount } from 'svelte';
let peer: Peer;
onMount(() => {
const url = $page.url.searchParams;
peer = new Peer({ debug: 3 });
peer.on('open', function (id) {
console.log('open| id :', id);
if (url.has('roomId')) {
let conn = peer.connect(url.get('roomId')!, {
reliable: true
});
conn.on('open', function () {
console.log('test 1');
conn.send('test send 1');
});
}
// change url to be easily copied
window.history.replaceState({}, '', 'room?roomId=' + id);
});
peer.on('connection', function (connexion) {
console.log('test 2');
connexion.send('test send 2');
});
});
</script>
firefox log
edge log (seem to connect but test's send() not logged)

server does not connect to the right port for my DB when it makes a request

I am running a node/express react app, with mongoDB as my database, its being served on a EC2 instance AWS. I am using MobaXterm to ssh into my server. The problem I am encountering, when I go to signUp/Login, and it makes the http request, its not sending the Request to port:8081 where my DB is. My front end is being hosted on port:3000, as seen here url with port.
The home page of my app show display public content, but instead it shows this should display my content, instead displays html syntax. I am using PM2 to run both the front end and back end , they are 2 separate instances. Here is my ecosystem.config.js file that gets called to start the front end
module.exports = {
apps: [
{
name: 'frontend',
script: 'npx',
args: 'serve -s build -l 3000 -n',
interpreter: 'none',
env: {
NODE_ENV: 'production',
},
},
],
}
Here is my http-common.js file that sets up axios
import axios from 'axios';
const apiUrl = process.env.NODE_ENV === 'production' ? process.env.REACT_APP_PRODUCTION : process.env.REACT_APP_DEV;
export default axios.create({
baseURL: apiUrl,
headers: {
"Content-type": "application/json"
}
});
Here is where my public content on my home page is called
import http from '../http-common';
import authHeader from './auth-header';
class UserService {
getPublicContent() {
return http.get('api/test/all');
};
getUserBoard() {
return http.get('api/test/user', { headers: authHeader() });
};
getModeratorBoard() {
return http.post('api/test/mod', { headers: authHeader() });
};
getAdminBoard() {
return http.put('api/test/admin', { headers: authHeader() });
};
}
export default UserService;
and my .env.production file
REACT_APP_PRODUCTION=http://EC2-INSTANCE-URL-NOT-REAL:8081/
And you can see here that instead of the REQUEST using port:8081 it sends the request to port:3000
GET request to wrong port
**** Also my ports are open on 8081 , on the security group for the EC2 instance ***
Im new to the backend so im not sure what to do , or how to continue, I really want to have my project CI/CD working before I try to make any more progress.

VueSocketIO offer fallback connection url

I am using Vuetify together with Vuex and VueSocketIO for my WebApp and here is an example Part of the code:
Vue.use(new VueSocketIO({
reconnection: true,
debug: true,
connection: SocketIO(`http://${process.env.ip}:4000`),
vuex: {
store,
actionPrefix: 'SOCKET_',
},
}));
If I understand it correctly, using Vuex and VueSocketIO together makes it only possible to use one Socket like this at the same time.
In some cases Vue might not be able to connect to the socket specified at connection.
I was wondering if there was a possibility to first let Vue try to connect to one socket (also with some number of reconnection attempts) but to switch to another connection value and try with that one afterwards as a fallback?
Thank you in advance!
Final solution
const options = {
reconnection: true,
reconnectionAttempts: 2,
reconnectionDelay: 10,
reconnectionDelayMax: 1,
timeout: 300,
};
let connection = new SocketIO(`http://${process.env.ip}:4000`, options);
const instance = new VueSocketIO({
debug: true,
connection,
vuex: {
store,
actionPrefix: 'SOCKET_',
},
options,
});
const options2 = {
reconnection: true,
reconnectionAttempts: 4,
};
connection.on('reconnect_failed', () => {
connection = new SocketIO(`http://${process.env.fallback}:4000`, options2);
instance.listener.io = connection;
instance.listener.register();
Vue.prototype.$socket = connection;
});
To specify the number of reconnection attempts you can set reconnectionAttempts option.
Example Code:
const url = `http://${process.env.ip}:4000`
const options = {
reconnectionAttempts: 3
}
Vue.use(new VueSocketIO({
debug: true,
connection: new SocketIO(url, options),
vuex: { ... }
}))
But switching to another connection is not easy as both of vue-socket.io and socket.io-client it was not designed for that.
First we have to listen on reconnect_failed event which will fires when reconnection attempts is exceeded.
Then we have to create a new connection to connect to the fallback url.
The VueSocketIO instance have two important properties which emitter and listener we cannot create the new emitter since it might already used in some components (with subscribe function) so we have to use old emitter but new listener.
Unfortunately, we cannot import Listener class directly from vue-socket.io package. So we have to use old listener but change the io property to the new connection then manually call register method.
Binding Vue.prototype.$socket to the new connection for the future use.
Example Code:
const url = `http://${process.env.ip}:4000`
const fallbackUrl = `http://${process.env.ip}:4001`
const options = {
reconnectionAttempts: 3
}
const connection = new SocketIO(url, options)
const instance = new VueSocketIO({
debug: true,
connection,
vuex: {
store,
actionPrefix: 'SOCKET_'
},
options
})
connection.on('reconnect_failed', error => {
const connection = new SocketIO(fallbackUrl, options)
instance.listener.io = connection
instance.listener.register()
Vue.prototype.$socket = connection;
})
Vue.use(instance)

Vue-Socket Mutation Listener

I recently changed over to connecting to a namespace on the socket.
Previously the connection was working fine and my Vuex mutations were catching the emission from the server.
After switching to the namespace I have verified that the connection is being made and the correct event is firing on the socket, but my Vuex mutation is no longer firing.
Here is the applicable code:
Server Side
const complianceNamespace = IO.of("/compliance");
complianceNamespace.on("connection", function (socket) {
socket.on("UPDATE_REQUEST_SERVICE", function (requestService) {
IO.emit("UPDATE_REQUEST_SERVICE", requestService);
});
socket.on("ADD_REQUEST_SERVICE", function (requestService) {
IO.emit("ADD_REQUEST_SERVICE", requestService)
});
});
Client Side
const SocketInstance = process.env.NODE_ENV === 'development' ? socketio('http://localhost:3001/compliance') : socketio('https://real.address.com/compliance');
Vue.use(new VueSocketIO({
debug: false,
connection: SocketInstance,
vuex: {
store,
actionPrefix: 'SOCKET_',
mutationPrefix: 'SOCKET_'
}
}));
// Mutation
SOCKET_UPDATE_REQUEST_SERVICE(state, requestService) {
// some code runs
}
Again, I have verified that the socket is getting to UPDATE_REQUEST_SERVICE, but the mutation is never being run when the socket emits, it worked when not using namespace.
I am thinking that the prefix is altered or doesn't work when using a namespace?
Answer: mistake within the namespace connection event listeners.
I was setting up a connection with the namespace (complianceNamespace) then emitting events to a different connection (IO).
Correction code:
complianceNamespace.on("connection", (socket) => {
socket.on("SOME_EVENT", function(user) {
complianceNamespace.emit("SOME_EVENT", user);
}
});

Node.js + socket.io + node-amqp and queue binginds when "re" connecting thru socket.io

I have one scenario which is very close to this sample:
One main screen:
this screen (client side) will connect to the socket.io server thru server:9090/scope (io.connect("http://server:9090/scope)) and will send one event "userBindOk" (socket.emit("userBindOk", message)) to the socket.io server;
the server receives the connection and the "userBindOk". At this moment, the server should get the active connection to rabbitmq server and bind the queue to the respective user that just connected to the application thru socket.io. sample:
socket.on("connection", function(client){
//client id is 1234
// bind rabbitmq exchange, queue, and:
queue.subscribe(//receive callback);
})
So far, no problem - I can send/receive messages thru socket.io without problems.
BUT, If I refresh the page, all those steps will be done again. As consequence, the binding to the queue will occur, but this time related to another session of the socket.io client. This means that if I send a message to the queue which is related to the first socket.io session (before the page refresh), that bind should (I think) receive the message and send it to a invalid socket.io client (page refresh = new client.id on the socket.io context). I can prove this behaviour because every time I refresh the page I need to send x times more messages. For instance: I`ve connected for the first time: - so, 1 message - one screen update; refresh the page: I need to send 2 messages to the queue and only the second message will be received from the "actual" socket.io client session - this behaviour will occur as many as I refresh the page (20 page refreshs, 20 messages to be sent to a queue and the server socket.io "last" client will send the message to the client socket.io to render into the screen).
The solutions I believe are:
Find a way to "unbind" the queue when disconnecting from the socket.io server - I didn`t see this option at the node-amqp api yet (waiting for it :D)
find a way to reconnect the socket.io client using the same client.id. This way I can identify the client that is coming and apply some logic to cache the socket.
Any ideas? I tried to be very clear... But, as you know, it`s not so eaey to expose your problem when trying to clarify something that is very specific to some context...
tks
I solved it like this:
I used to declare the rabbitMq queue as durable=true,autoDelete=false,exclusive=false and in my app there was 1 queue/user and 1 exchange(type=direct) with the routing_key name=queueName, my app also used the queue for other client diffent to browsers like android app or iphone app as push fallback, so i use to crear 1 queue for earch user.
The solution to this problem was to change my rabbitMQ queue and exchange declaration. Now i declare the exchange/user as fanout and autoDelete=True, and the user is going to have N queues with durable=true, autoDelete=true, exclusive=true (No. queue = No. clients) and all the queues are bind to the user-exchange(multicast).
NOTE: my app is wirten in django, and i use node+socket+amqp to be able to comunicate with the browser using web.scokets, so i use node-restler to query my app api to get the user-queue info.
thats the rabbitMQ side, for the node+amqp+socket i did this:
server-side:
onConnect: the declaration of the user exchange as fanout, autoDelete, durable. then declaration of the queue as durable, autodelete and exclusive, then the queue.bind to the user-exchange and finaly the queue.subscribe and the socket.disconnect will destroy the queue so there are going to exist queue as client connected the app and this solve the problem of the refresh and allow the user to have more than 1 window-tab with the app:
Server-side:
/*
* unCaught exception handler
*/
process.on('uncaughtException', function (err) {
sys.p('Caught exception: ' + err);
global.connection.end();
});
/*
* Requiere libraries
*/
global.sys = require('sys');
global.amqp = require('amqp');
var rest = require('restler');
var io = require('socket.io').listen(8080);
/*
* Module global variables
*/
global.amqpReady = 0;
/*
* RabbitMQ connection
*/
global.connection = global.amqp.createConnection({
host: host,
login: adminuser,
password: adminpassword,
vhost: vhost
});
global.connection.addListener('ready',
function () {
sys.p("RabbitMQ connection stablished");
global.amqpReady = 1;
}
);
/*
* Web-Socket declaration
*/
io.sockets.on('connection', function (socket) {
socket.on('message', function (data) {
sys.p(data);
try{
var message = JSON.parse(data);
}catch(error){
socket.emit("message", JSON.stringify({"error": "invalid_params", "code": 400}));
var message = {};
}
var message = JSON.parse(data);
if(message.token != undefined) {
rest.get("http://dev.kinkajougames.com/api/push",
{headers:
{
"x-geochat-auth-token": message.token
}
}).on('complete',
function(data) {
a = data;
}).on('success',
function (data){
sys.p(data);
try{
sys.p("---- creating exchange");
socket.exchange = global.connection.exchange(data.data.bind, {type: 'fanout', durable: true, autoDelete: true});
sys.p("---- declarando queue");
socket.q = global.connection.queue(data.data.queue, {durable: true, autoDelete: true, exclusive: false},
function (){
sys.p("---- bind queue to exchange");
//socket.q.bind(socket.exchange, "*");
socket.q.bind(socket.exchange, "*");
sys.p("---- subscribing queue exchange");
socket.q.subscribe(function (message) {
socket.emit("message", message.data.toString());
});
}
);
}catch(err){
sys.p("Imposible to connection to rabbitMQ-server");
}
}).on('error', function (data){
a = {
data: data,
};
}).on('400', function() {
socket.emit("message", JSON.stringify({"error": "connection_error", "code": 400}));
}).on('401', function() {
socket.emit("message", JSON.stringify({"error": "invalid_token", "code": 401}));
});
}
else {
socket.emit("message", JSON.stringify({"error": "invalid_token", "code": 401}));
}
});
socket.on('disconnect', function () {
socket.q.destroy();
sys.p("closing socket");
});
});
client-side:
The socket intance with options 'force new connection'=true and 'sync disconnect on unload'= false.
The client side use the onbeforeunload and onunload windows object events to send socket.disconnect
The client on socket.connect event send the user token to node.
proces message from socket
var socket;
function webSocket(){
//var socket = new io.Socket();
socket = io.connect("ws.dev.kinkajougames.com", {'force new connection':true, 'sync disconnect on unload': false});
//socket.connect();
onSocketConnect = function(){
alert('Connected');
socket.send(JSON.stringify({
token: Get_Cookie('liveScoopToken')
}));
};
socket.on('connect', onSocketConnect);
socket.on('message', function(data){
message = JSON.parse(data);
if (message.action == "chat") {
if (idList[message.data.sender] != undefined) {
chatboxManager.dispatch(message.data.sender, {
first_name: message.data.sender
}, message.data.message);
}
else {
var username = message.data.sender;
Data.Collections.Chats.add({
id: username,
title: username,
user: username,
desc: "Chat",
first_name: username,
last_name: ""
});
idList[message.data.sender] = message.data.sender;
chatboxManager.addBox(message.data.sender, {
title: username,
user: username,
desc: "Chat",
first_name: username,
last_name: "",
boxClosed: function(id){
alert("closing");
}
});
chatboxManager.dispatch(message.data.sender, {
first_name: message.data.sender
}, message.data.message);
}
}
});
}
webSocket();
window.onbeforeunload = function() {
return "You have made unsaved changes. Would you still like to leave this page?";
}
window.onunload = function (){
socket.disconnect();
}
And that's it, so no more round-robing of the message.