I have a problem with socket.io. The client can emit message to server for connecting, but if I leave the connection and then try to reconnect, socket io doesn't emit the message ('joinPerformance'). Only if I refresh the page then I can emit messages.
#CLIENT
function loginSuccess(easyrtcid, noMedia) {
selfEasyrtcid = easyrtcid;
console.log('loginSuccess',selfEasyrtcid);
//arm socket events only once
if(!socket){
socket = easyrtc.webSocket;
streaming.armEvents(socket);
}
settings.isStarted=true;
if(typeof settings.bindings.loginSuccess==='function')
settings.bindings.loginSuccess(easyrtcid);
if(settings.isInitiator===true){
console.log('Telling server to start performance');
socket.emit('startPerformance', {performanceID: settings.performanceID});
}else{
console.log('Telling server to join performance');
socket.emit('joinPerformance', {performanceID: settings.performanceID});
}
}
#SERVER
socket.on('joinPerformance', function (data) {
console.log('joinPerformance', data);
if(validateData(data, socket))
onJoinPerformance(data, socket);
});
function onJoinPerformance(data, socket) {
console.log('Join performance', data.performanceID);
console.log('rooom info',socket.adapter.rooms[data.performanceID]);
if(!socket.adapter.rooms[data.performanceID] || !socket.adapter.rooms[data.performanceID][socket.id] )
socket.join(data.performanceID);
if (!streamingPerformances[data.performanceID]) {
console.log('No such performance is streaming');
error(socket, 'No such performance is streaming');
} else {
console.log('joined performance');
streamingPerformances[data.performanceID].activeViewers[data.userID] = data;
streamingPerformances[data.performanceID].activeViewersCount++;
socket.emit('joinedPerformance', streamingPerformances[data.performanceID]);
socket.broadcast.to(data.performanceID).emit('performanceState', streamingPerformances[data.performanceID]);
}
}
Related
I am getting the event emitter leak after using my code 10 times essentially. I understand the default of event emitter auto sending out a warning in the console. My question is what in this code is directly creating the event listeners? Is it poor coding on my part or is it just how the websockets are stacked onto each other?
I'll explain the code a bit. I have one websocket within another and I figured it would serve the data to a web page essentially flowing from Twitch to a localhost site. However, if I use the keywords more than 10 times, I get the error. I do not understand enough about WebSockets to really understand why my code creates a new listener with each msg.text received so anyone with a bit more understanding please help!
I believe me issue to be similar to this though I am having a hard time conceptualizing my own code here
const { paintballShot } = require('./JavaScript/paintballGunFire');
const { readPin } = require('./JavaScript/readPin');
const ws = require('ws');
const express = require('express');
const app = express();
//CONNECT TO TWITCH
let client = new ChatClient({
connection: {
type: "websocket",
secure: true,
}
});
//connected?
client.on("ready", () => console.log("Successfully connected to chat"));
client.on("close", (error) => {
if (error != null) {
console.error("Client closed due to error", error);
}
});
//create headless websocket
const wsServer = new ws.Server({ noServer: true });
wsServer.on('connection', function connection(socket) {
//call other websocket connected to Twitch from inside the new websocket
client.on("PRIVMSG", (msg, error) => {
if (msg.messageText === "right") {
socket.send(JSON.stringify(`${msg.displayName}: ${msg.messageText}`));
}
if (msg.messageText === "left") {
socket.send(JSON.stringify(`${msg.displayName}: ${msg.messageText}`));
}
if (msg.messageText === "fire") {
socket.send(JSON.stringify(`${msg.displayName}: ${msg.messageText}`));
paintballShot();
}
if (msg.messageText === "pin") {
readPin();
}
process.on('uncaughtException', function (err) {
console.log(err);
});
});
client.connect();
client.join("channel");
socket.on('message', message => console.log(message));
});
// `server` is a vanilla Node.js HTTP server
const server = app.listen(3000);
server.on('upgrade', (request, socket, head) => {
wsServer.handleUpgrade(request, socket, head, socket => {
wsServer.emit('connection', socket, request);
});
});
process.on('uncaughtException', function (err) {
console.log(err);
});
To wrap this up, the library I am using (Dank TwitchIRC) does have a connection rate limiter that seems to work if you add it to your chat client in the beginning. If I set it low enough, depending on the messages received from Twitch, it will end connections just as fast, meaning no memory leak.
I am building a very basic chat system between two clients. While the server can receive a message from the client, it cannot send the message to the client (the receiveMessage event is not triggered when the server sends the message to the client). Below is my code client-side:
$("#send-msg").submit(function(e) {
e.preventDefault();
socket.emit("sendMsg", [$("#msg-text").val(), chattingWith]);
});
socket.on("receiveMessage", receiveMsg);
function receiveMsg(data) {
console.log("received msg"); // NOT OUTPUTTED
}
Below is my code server-side:
var socket = io.connect();
var io = socket(server, { pingTimeout: 63000 });
io.sockets.on("connection", userConnect);
function userConnect(user) {
user.on("sendMsg", sendMsg);
function sendMsg(msgData) {
var msgContent = msgData[0];
var receiverId = msgData[1];
console.log("received message from " + receiverId); // ACTIVATED
io.to(receiverId).emit("receiveMessage", [msgContent, receiverId]);
}
}
I think you should change a little your code:
Client side (I assume that chattingWith is a unique room or chat id):
$("#send-msg").submit(function(e) {
e.preventDefault();
socket.emit("send message", $("#msg-text").val(), chattingWith);
});
socket.on("send Message", receiveMsg);
function receiveMsg(data) {
console.log(data); //An array should be an output
}
Server side code:
io.on('connection', function(socket){
socket.on('send message', function(data, id){
socket.join(id)
io.sockets.in(id).emit('sendMessage', {
data: data,
})
})
})
Anytime I call the session.disconnect() method to remove clients from the session, I get this warning: "OpenTok:Publisher:warn Received connectivity event: "Cancel" without "Attempt"
and this error: "OpenTok:Subscriber:error Invalid state transition: Event 'disconnect' not possible in state 'disconnected'"
Could someone please explain to me what that error means? Thanks in advance.
// Initialize the session
var session = OT.initSession(data['apikey'], data['session_id']);
console.log(session);
// Initialize the publisher for the recipient
var publisherProperties = {insertMode: "append", width: '100%', height: '100%'};
var publisher = OT.initPublisher('publisher', publisherProperties, function (error) {
if (error) {
console.log(`Couldn't initialize the publisher: ${error}`);
} else {
console.log("Receiver publisher initialized.");
}
});
$('#session-modal').modal("show");
// Detect when new streams are created and subscribe to them.
session.on("streamCreated", function (event) {
console.log("New stream in the session");
var subscriberProperties = {insertMode: 'append', width: '100%', height: '100%'};
var subscriber = session.subscribe(event.stream, 'subscriber', subscriberProperties, function(error) {
if (error) {
console.log(`Couldn't subscribe to the stream: ${error}`);
} else {
console.log("Receiver subscribed to the sender's stream");
}
});
});
//When a stream you publish leaves a session, the Publisher object dispatches a streamDestroyed event:
publisher.on("streamDestroyed", function (event) {
console.log("The publisher stopped streaming. Reason: "
+ event.reason);
});
//When a stream, other than your own, leaves a session, the Session object dispatches a streamDestroyed event:
session.on("streamDestroyed", function (event) {
console.log("Stream stopped. Reason: " + event.reason);
session.disconnect();
console.log("called session.disconnect().");
});
session.on({
connectionCreated: function (event) {
connectionCount++;
if (event.connection.connectionId != session.connection.connectionId) {
console.log(`Another client connected. ${connectionCount} total.`);
}
},
connectionDestroyed: function connectionDestroyedHandler(event) {
connectionCount--;
console.log(`A client disconnected. ${connectionCount} total.`);
}
});
// Connect to the session
// If the connection is successful, publish an audio-video stream.
session.connect(data['token'], function(error) {
if (error) {
console.log("Error connecting to the session:", error.name, error.message);
} else {
console.log("Connected to the session.");
session.publish(publisher, function(error) {
if (error) {
console.log(`couldn't publish to the session: ${error}`);
} else {
console.log("The receiver is publishing a stream");
}
});
}
});
// Stop the publisher from streaming to the session if the user dismiss the modal
const stopSession = document.getElementById('stop-session');
stopSession.addEventListener("click", (event) => {
event.preventDefault();
session.disconnect();
});
I see this is kind of old, but wanted to share my solution to avoid this error. I'm not sure what the error means, but I call publisher.destroy() before calling session.disconnect() to avoid the error.
openTokPublisher.destroy();
openTokSession.disconnect();
I highly doubt you can disconnect the client with JavaScript. Here what I did.
// Connect to the session
session.connect(token, function connectCallback(error) {
// Get the connectionId
connectionId = session.connection.connectionId;
and use one of their SDK on the backend
https://tokbox.com/developer/sdks/server/
// Disconnect session
function disconnectSession() { // eslint-disable-line no-unused-vars
if (sessionId && connectionId) {
$.ajax({
url: '/OpenTok/DisconnectSession',
type: 'POST',
data: 'sessionId=' + sessionId + '&connectionId=' + connectionId,
});
}
}
I want to try run websockets in serviceWorker.
I write code for register serviceWorker:
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register(
GetDataForUser.settings.service_worker + "?version=" + GetDataForUser.settings.service_worker_version,
{scope: './'}
)
.then(() => navigator.serviceWorker
.ready
.then((worker) => {
console.log(worker);
worker.sync.register('syncdata');
})
)
.catch((err) => console.log(err));
navigator.serviceWorker.addEventListener('message', event => {
console.log('++++++++++++++++++++', event.data.msg, event.data.url);
});
}
And write serviceWorker code:
var ws = null;
self.addEventListener('install', (event) => {
console.log('Install');
});
self.addEventListener('activate', (event) => {
console.log('Activate');
ws = new WebSocket('ws://local.ll:8880');
ws.onopen = function() {
console.log("Open");
};
// On message receive
ws.onmessage = function (event) {
console.log("Message receive " + event.data);
console.log(event);
event.ports[0].postMessage({'test': 'This is my response.'});
};
// On error connection
ws.onerror = function (error) {
console.log("Error " + error.message);
};
// On close connection
ws.onclose = function (event) {
if (event.wasClean) {
console.log('clean closed');
} else {
console.log('broken connection');
}
console.log('Code: ' + event.code + ' reason: ' + event.reason);
};
});
self.addEventListener('fetch', (event) => {});
self.addEventListener('message', function (evt) {
console.log('postMessage received', evt.data);
ws.send('121212');
});
I try to send data to serviceWorker next:
navigator.serviceWorker.controller.postMessage({'hello': 'world'});
But receive an error:
Uncaught TypeError: Cannot read property 'postMessage' of null
console.log(navigator.serviceWorker);
ServiceWorkerContainer {controller: null, ready: Promise, oncontrollerchange: null, onmessage: null}
Trying to send message from serviceWorker to client next:
event.ports[0].postMessage({'test': 'This is my response.'});
But event.ports is empty.
Whats wrong?
How to transfer data between client and serviceWorker.
To fix your error of controller being null, you need to add the activate event listener
self.clients.claim()
Without that, when the service worker is activated, the page is not controlled by it until the next navigation. This allows the service worker to take control of the pages as soon as it's active.
But I don't think it's your only problem. Looking at your code I think you're confusing WebSocket and MessageChannel. You seem to try to use WebSocket to send messages between client and service worker where you should be using MessageChannel for that.
For exemple if we want to send messages from the client to the SW and allow the SW to respond to those messages, we create a MessageChannel, and we send a port of this channel allong with the message for the SW to use in his response.
in the client :
var msg = new MessageChannel();
msg.port1.onmessage = function(event){
//Response received from SW
console.log(event.data);
};
// Send message to SW
navigator.serviceWorker.controller.postMessage("hello", [msg_chan.port2]);
in the SW :
self.addEventListener('message', function(event){
//Message received from client
console.log(event.data);
//Send response to client using the port that was sent with the message
event.ports[0].postMessage("world");
});
Correct and worked example, only for understanding, not for production:
https://github.com/Shkarbatov/WebSocketInServiceWorkerJS
I am writing on a web-application where I want to send JSON-Code from the client-side to the server-side over Tornado WebSockets with SSL. When I want to build a connection, Google Chrome shows in the console-log the error:
Uncaught InvalidStateError: Failed to execute 'send' on 'WebSocket': Still in CONNECTING State.
My python server looks like this:
from tornado import websocket, web, ioloop
import json
from sqlite3functions import *
class SocketHandler(websocket.WebSocketHandler):
def on_message(self, message):
handleRequest(self, json.loads(message), True)
print(message)
def handleRequest(obj, message, isWebsock):
...
def writeResponse(obj, message, isWebsock):
if (isWebsock):
obj.write_message(message)
else:
print(message)
obj.write(message)
print('msg sent')
app = web.Application([
(r'/w', SocketHandler)
])
if __name__ == "__main__":
app.listen(8888)
ioloop.IOLoop.instance().start()
My client:
var ws;
function connect() {
ws = new WebSocket('wss://127.0.0.1:8888/w');
ws.onopen = function()
{
ws.send("Message to send");
};
}
$(document).ready(function() {
connect();
$("#Button").on('click', function() {
...
ws.send(data);
});
});
Thanks
Don't let your socket send data until its ready state is connected.
These functions may help:
function sendMessage(msg) {
waitForSocketConnection(nvWS, function() {
ws.send(msg);
});
};
function waitForSocketConnection(socket, callback){
setTimeout(
function(){
if (socket.readyState === 1) {
if(callback !== undefined){
callback();
}
return;
} else {
waitForSocketConnection(socket,callback);
}
}, 5);
};