ExpressJs - SocketIo.client - emit not working - node.js

I am trying to connect to the crypto compare's api websockets to get the up to date prices for crypto currencies. I am using expressjs for my server and socketio to connect to crypto compare.
However after logging connected nothing else seems to happen.
This is my first time trying to play with sockets so I am a little lost as to why the io.emit function is not triggering anything.
Also there seems to be an issue in the callback of connect as socket is undefined!
Why does emit not seem to be doing anything?
My app.js file:
const express = require('express');
const app = express();
const clientIo = require('./lib/client-socket/crytpto-compare-socket');
clientIo.connect();
app.disable('x-powered-by');
module.exports = app;
Crypto-compare-socket.js
const io = require('socket.io-client');
const configs = require('./../config/configs');
const crytpCompareConfigs = configs.get('CRYPTO_COMPARE_API');
const cryptoCompareEndpoint = crytpCompareConfigs.ENDPOINT;
const cryptoCompareSocket = io(cryptoCompareEndpoint, {reconnect: true});
cryptoCompareSocket.on('connect', (socket) => { // socket here is undefined
console.log('Connected');
cryptoCompareSocket.emit('SubAdd', { subs: crytpCompareConfigs['LIST_OF_ITEMS']});
});
cryptoCompareSocket.on('SubAdd', (from, msg) => {
console.log('Hello');
console.log(from);
console.log('*******');
console.log(msg);
});
module.exports = cryptoCompareSocket;

The code you are using is client side code. This code does not return a socket in the callback because the client already knows the socket its connected with.
You are subscribing to a socket service, but you do not have any code that responds to data sent from that service.
When crypto compare returns data it sends the "m" event. So you need to respond to "m".
An example
cryptoCompareSocket.on("m", function(message) {
console.log(message);
});

Related

How to prevent people from connecting to any id with sockeIO?

I just set up SocketIO in my PHP project. I am completly new to websockets at all so bear with me.
I am defining the socketIO variable globally
let socketIO = io("http://localhost:3000");
When people are logging in to my application, they are connected to it with their ID comming from the database. The login script just gives back true which redirects the user in very simplified terms:
// get component
$.get(url, data, (data) => {
if (data.status) {
// connect with Node JS server
socketIO.emit("connected", data.user_id);
// redirect
load_new_page("/users/" + data.user_id);
}
});
My concern here now is that people could just go and change the data.user_id to anything they want and receive what ever the chosen id would receive.
My server.js:
// initialize express server
var express = require("express");
var app = express();
// create http server from express instance
var http = require("http").createServer(app);
// include socket IO
var socketIO = require("socket.io")(http, {
cors: {
origin: ["http://localhost"],
},
});
// start the HTTP server at port 3000
http.listen(process.env.PORT || 3000, function () {
console.log("Server started running...");
// an array to save all connected users IDs
var users = [];
// called when the io() is called from client
socketIO.on("connection", function (socket) {
// called manually from client to connect the user with server
socket.on("connected", function (id) {
users[id] = socket.id;
});
});
});
How can I prevent something like this?

socketio, client can connect to server if hosted locally, but returns error when trying to connect to server hosted on seperate vserver

I am trying to make a simple server with socket.io and express and connect to it through a website.
when i followed a tutorial on socketio with localhost, everything worked fine, but when i put the server on a vserver, and tried to connect to it, i got this error:
Failed to load resource: net::ERR_SSL_PROTOCOL_ERROR
as well as:
GET https://54.53.0.254:47185/socket.io/?EIO=4&transport=polling&t=O09jjrs net::ERR_SSL_PROTOCOL_ERROR
here is my server code:
const express = require('express');
const app = express();
const server = app.listen(47185);
const socket = require('socket.io');
const io = socket(server)
console.log('server running on port 47185');
io.sockets.on('connection', newConnection);
function newConnection(socket) {
console.log('new connection: ' + socket.id);
socket.on('input', inputLog)
function inputLog(data) {
socket.broadcast.emit('input', data);
console.log(data);
}
}
and here is my client code (this is all that relates to socket.io, the rest is just for the website)
var options = {
rejectUnauthorized:false
}
var socket;
socket = io.connect('89.58.0.199:47185', options);
socket.on('input', foreignInput)
function foreignInput(data) {
terminal_animate('\n' + data)
}
i have tried many different fixes and googled everything i can think of, and i'm just not sure what the problem is.
can anyone help me out with this issue? thanks in advance.
In the documentation, according to the Client Initialization part, in node.js you should provide the protocol when connecting to the server.
// the following forms are similar
const socket = io("https://server-domain.com");
const socket = io("wss://server-domain.com");
const socket = io("server-domain.com"); // only in the browser when the page is served over https (will not work in Node.js)
The first two example shows the secure https/wss as protocol, for that you need to serve the required files from the server, example in the documentation.
With http/ws as protocol it should work, but the communication will not be secure.
The Server Initialization / With Express shows an example to call .listen on the return value of createServer from the http module, with the app given as a parameter.
const express = require("express");
const { createServer } = require("http");
const { Server } = require("socket.io");
const app = express();
const httpServer = createServer(app);
const io = new Server(httpServer, { /* options */ });
io.on("connection", (socket) => {
// ...
});
httpServer.listen(3000);
With a caution that says:
Using app.listen(3000) will not work here, as it creates a new HTTP server.

Broadcast a basic event to all clients

How would I go about broadcasting alert("Hello World!"); on all clients currently avaible?
I have gone through these links:
https://socket.io/get-started/chat
https://socket.io/docs/v3/client-api/
https://socket.io/docs/v3/emit-cheatsheet/
And NONE of them helped. Can someone please help me?!
Solutions I have tried:
// Script.js:
var socket;
function onload(){
socket = io();
}
function test(){
socket.emit("broadcast");
}
socket.on('broadcast', function() {
alert("Hello World!");
});
// index.js:
const express = require("express");
const socketio = require("socket.io");
const path = require("path");
const app = express();
const http = require("http");
const io2 = require("socket.io-client");
const directory = path.join(__dirname, "html");
const httpserver = http.Server(app);
const io = socketio(httpserver);
app.use(express.static(directory));
httpserver.listen(3000);
To broadcast a message to all connected clients from your server, you do:
io.emit('bulletin', someMsg);
To listen for that message in the client, you do this:
socket.on('bulletin', someMsg => {
console.log(someMsg);
});
The message name 'bulletin' can be anything you want it to be (any string that doesn't conflict with a built-in message name).
You cannot trigger a broadcast directly from the client. But, you can send the server a custom message that you design and have the server, upon receipt of that message, then do a broadcast to all connected clients.

Implement socket.io in node.js application controller

good afternoon. I am new to programming sockets in node.js and I need to implement socket.io in a controller of my application. The architecture I have is the following:
The file that starts the server is index.js
const express = require('express');
const app = express();
const port = 3000;
const socketRouter = require('./routes/socket')
app.use(express.json());
//Route
app.use('/socket', socketRouter);
app.listen(port, () => {
console.log(`Server connection on http://127.0.0.1:${port}`); // Server Connnected
});
The file where I define the routes is socket.js
const { Router } = require('express');
const { showData } = require('../controllers/socket');
const router = Router();
router.post('/send-notification', showData);
module.exports = router;
And my controller is:
const { response } = require('express');
const showData = (req, res = response) => {
const notify = { data: req.body };
//socket.emit('notification', notify); // Updates Live Notification
res.send(notify);
}
module.exports={
showData
}
I need to implement socket.io in this controller to be able to emit from it but I can't get it to work. Could you tell me how to do it?
Thanks a lot
CLARIFICATION: if I implement socket.io in the main file it works, but I want to have some order and separate things. This is how it works:
const express = require('express');
const app = express();
const port = 3000;
app.use(express.json());
app.post('/send-notification', (req, res) => {
const notify = { data: req.body };
socket.emit('notification', notify); // Updates Live Notification
res.send(notify);
});
const server = app.listen(port, () => {
console.log(`Server connection on http://127.0.0.1:${port}`); // Server Connnected
});
const socket = require('socket.io')(server);
socket.on('connection', socket => {
console.log('Socket: client connected');
});
Move your socket.io code to its own module where you can export a method that shares the socket.io server instance:
// local socketio.js module
const socketio = require('socket.io');
let io;
modules.exports = {
init: function(server) {
io = socketio(server);
return io;
},
getIO: function() {
if (!io) {
throw new Error("Can't get io instance before calling .init()");
}
return io;
}
}
Then, initialize the socketio.js module in your main app file:
const express = require('express');
const app = express();
const port = 3000;
app.use(express.json());
const server = app.listen(port, () => {
console.log(`Server connection on http://127.0.0.1:${port}`); // Server Connnected
});
// initialize your local socket.io module
const sio = require('./socketio.js');
sio.init(server);
// now load socket.io dependent routes
// only after .init() has been called on socket.io module
const socketRouter = require('./routes/socket')
app.use('/socket', socketRouter);
Then, anywhere you want to access the socket.io server instance, you can
require("./socketio.js") and use the .getIO() method to get the socket.io instance:
// use correct path to socketio.js depending upon where this module
// is located in the file system
const io = require("../../socketio.js").getIO();
// some Express route in a controller
const showData = (req, res) => {
const notify = { data: req.body };
// send notification to all connected clients
io.emit('notification', notify);
res.send(notify);
};
module.exports= {
showData
};
Note: A typical socket.io usage convention on the server is to use io as the server instance and socket as an individual client connection socket instance. Please don't try to use socket for both. This makes it clear that io.emit(...) is attempting to send to all connected clients and socket.emit() is attempting to send to a single connected client.
Also note that if your route is triggered by a form post where the browser itself sends the form post, then that particular client will not receive the results of io.emit(...) done from that form post route because that browser will be in the process of loading a new web page based on the response of the form post and will be destroying its current socket.io connection. If the form post is done entirely via Javascript using an Ajax call, then that webpage will stay active and will receive the results of the io.emit(...).
You can use the same socket and app (if you need to expose APIs as well) in other files if you want to separate socket messages and REST endpoints by functionality or however you choose to organize it. Here's an example of how this can be done:
Create a new file, let's say controller1.js:
function initialize(socket, app) {
socket.on('some-socket-message', socket => {
// Whatever you want to do
});
app.get('/some-endpoint', (req, res) => {
// whatever you want to do
});
}
module.exports = {initialize}
And then add the following to your controller.js
const controller1 = require('path/to/controller1');
...
// At some point after socket and app have been defined
controller1.initalize(socket, app);
This will be the bases of separating your controller however you want, while still using the same socket connection and API port in all of your controllers. You can also refactor the initialize method into different methods, but that would be at your own discretion and how you want to name functions, etc. It also does not need to be called initalize, that was just my name of preference.

Using Socket.io in Express.js Project

I'm making some single page web application with Node.js, Express and Socket.io. I want to display how works are going to browser. In IDE, There is console, so I can check program process in console window. Like, I want to show these process to browser. All I want to is just 'emit'.
When I use socket.io in app.js file, there is no problem. but this is limited for me. I want to display many sentences in realtime as running. How can I use socket.io in not only app.js but controller.js? I red Use socket.io in controllers this article, but I can't understand. Please help me with a simple solution.
app.js
var app = express();
var server = http.createServer(app);
var io = require('socket.io').listen(server);
module.exports.io = io;
...
controller.js
var io = require('./app').io;
// some task
console.log('Task is done!'); // it would be seen in console window
io.sockets.emit('Task is done!'); // Also I want to display it to broswer
Result (error)
TypeError: Cannot read property 'sockets' of undefined
Edit 2---
Follwoing Ashley B's comments, I coded like this.
controller.js
module.exports.respond = function(socket_io) {
socket_io.emit('news', 'This is message from controller');
};
app.js
var app = express();
var server = http.createServer(app);
var io = require('socket.io').listen(server);
var controller = require('./controller');
io.sockets.on('connection', controller.respond );
It works well, But what I wonder is... When I want to several socket_emit, What Should I do? Should I call everytime? If you don't understand. see below :
//first task is done
module.exports.respond = function(socket_io) {
socket_io.emit('news', 'First task is done!');
};
//second task is done
module.exports.respond = function(socket_io) {
socket_io.emit('news', 'Second task is done!');
};
//third task is done
module.exports.respond = function(socket_io) {
socket_io.emit('news', 'Third task is done!');
};
But It is wrong way, right? only last api is implemented in app.js. There are a lot of console.log in my controller, I want to convert it to socket.emit How can I do this?
I have worked on this using socket.io and nodejs events. The idea is to handle the emission of the socket only from the app.js, and emit nodejs events from controllers, which will be captured in app.js and then issued by the socket.
app.js
const app = express();
const http = require('http');
const server = http.createServer(app);
const io = require('socket.io')(server);
const events = require('events');
io.on('connection', function(socket) {
console.log("Someone has connected");
var eventEmitter = new events.EventEmitter();
eventEmitter.on("newEvent", (msg) => { // occurs when an event is thrown
socket.emit("news", msg);
});
exports.emitter = eventEmitter; // to use the same instance
});
myController.js
const app = require('../app');
.....
if (app.emitter) // Checking that the event is being received, it is only received if there is someone connected to the socket
app.emitter.emit("newEvent", "First task is done!");
.....
if (app.emitter)
app.emitter.emit("newEvent", "Second task is done!");

Resources