I have a simple authentication app to instagram. After I authenticate to instagram and receive user profile I would like to send the username from server side to reactjs client side. I tried using socket IO but I can't make it work.
Client side
componentDidMount() {
const { socket, provider } = this.props
console.log('component did mount')
socket.on(provider, user => { //provider is a string e.g 'instagram'
//receives data and update state.
this.setState({user})
})
}
startAuth() { //onclick function that opens up new window for auth
const {provider} = this.props
const width = 600, height = 600
const left = (window.innerWidth / 2) - (width / 2)
const top = (window.innerHeight / 2) - (height / 2)
const url = `https://localhost:5000/${provider}`
return window.open(url, '',
`toolbar=no, location=no, directories=no, status=no, menubar=no,
scrollbars=no, resizable=no, copyhistory=no, width=${width},
height=${height}, top=${top}, left=${left}`
)
}
Server side
//After successful authentication redirect here with username and provider as
//query string. Here I want to emit to my component and update component's state
app.get('/success', (req, res) => {
var provider = req.query.provider
var username = req.query.username
io.emit(provider, username); //this doesn't work
res.send('Auth to ' + provider + ' successful by ' + username)
})
What should I do in order for the emitted event in server side to get caught by the on inside componentDidMount()? I got no error messages whatsoever. I'm not even sure if the emitted event at /success got fired or not.
Socket connection works fine, I did the following code below and it works fine.
io.on('connection', (client) => {
client.on('subscribeToTimer', (interval) => {
console.log('client is subscribing to timer with interval', interval);
setInterval(() => {
client.emit('timer', new Date());
}, interval);
})
})
I faced a similar problem on a project I was working upon & the way I solved the problem was
Create file io.js
// singleton instance of socket.io that is stored here after the
// constructor function is called
let ioInstance;
module.exports = function(server) {
const io = require("socket.io")(server);
io.on("connection", socket => {
console.log("made socket connection", socket.id);
// Handle socket event
socket.on("eventTrigger", function(data) {
// console.log(data);
io.sockets.emit("chat", data);
});
});
// save in higher scope so it can be obtained later
ioInstance = io;
return io;
};
// this getIO method is designed for subsequent
// sharing of the io instance with other modules once the module has been initialized
// other modules can do: let io = require("./io.js").getIO();
module.exports.getIO = () => {
if (!ioInstance) {
throw new Error(
"Must call module constructor function before you can get the IO instance"
);
}
return ioInstance;
};
In file bin/www add below code
var app = require("../app");
var debug = require("debug")("express-sequelize");
var http = require("http");
var models = require("../models");
/**
* Get port from environment and store in Express.
*/
var port = normalizePort(process.env.PORT || "3000");
app.set("port", port);
/**
* Create HTTP server.
*/
var server = http.createServer(app);
//initialize io
require("../io")(server);
server.listen(port, function() {
debug("Express server listening on port " + server.address().port);
});
server.on("error", onError);
server.on("listening", onListening);
now in route file for an api call if I wanted to send socket data
#file app.js
app.get('/success', (req, res) => {
const io = require("./io").getIO();
....
io.sockets.emit("eventTrigger",data);
res.send('Auth to ' + provider + ' successful by ' + username)
})
Hope this approach helps in fixing the issue that you are facing.
Related
I'm running two apps that sends real-time messages to each other using websocket and also generate a random link using express.js, now i hosted the server with both react apps to my vps host and want to make the websocket connection secure (wss://) but i realize i'll have to get the express server on the same port too, so the ssl/tsl works for both - so how do i do that?
Here is my full code, all on the same file:
const webSocketServerPort = 8000;
const webSocketServer = require('websocket').server;
const http = require('http');
const server = http.createServer(); server.listen(webSocketServerPort); console.log('Listening on port 8000');
const wsServer = new webSocketServer({ httpServer: server })
//GEERTOOOO
const express = require('express'); const cors = require('cors'); const fs = require('fs'); const app = express();
app.use(cors({ origin: '*' }));
app.get('/', (req, res) => { // Generate a random 6-character string const linkId = Math.random().toString(36).substr(2, 6);
// Save the link in the lex.json file fs.readFile('lex.json', (err, data) => { if (err) { console.error(err); res.status(500).send('Error generating link'); return; }
const links = JSON.parse(data);
links[linkId] = {
destination: 'http://localhost:4000/',
expires: Date.now() + 1000 * 60 * 5 // expires in 5 minutes
};
fs.writeFile('lex.json', JSON.stringify(links), (err) => {
if (err) {
console.error(err);
res.status(500).send('Error generating link');
return;
}
// Send the link back to the client
res.send(`http://localhost:3000/${linkId}`);
});
}); });
app.get('/:linkId', (req, res) => {
fs.readFile('lex.json', (err, data) => {
if (err) { console.error(err); res.status(500).send('Error retrieving link');
return;
}
const links = JSON.parse(data);
const link = links[req.params.linkId];
if (!link) {
res.status(404).send('Link not found');
return;
}
// Check if the link has expired
if (link.expires < Date.now()) {
res.status(410).send('Link has expired');
return;
}
// Redirect to the destination
res.redirect(link.destination);
}); });
app.listen(3000, () => { console.log('Server listening on port 3000'); });
//GEERTOOOO
const clients = {};
const getUniqueID = () => { const s4 = () => Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1);
return s4() + s4() + '-' + s4(); }
wsServer.on('request', (request) => { var userID = getUniqueID();
const connection = request.accept(null, request.origin); clients[userID] = connection;
connection.on('message', (message) => {
if (message.type === 'utf8') {
for(var key in clients) {
if (clients[key] !== clients[userID]) {
clients[key].sendUTF(message.utf8Data);
console.log(`Sent Message to: ${clients[key]}`);
}
}
}
}) })
Note: the express server is on port 3000 and the websocket server runs on port 8000.
I,ve tried just changing the port to same thing but i get an error when trying to use the websocket server for messages.
THE PURPOSE OF ALL THIS IS JUST TO MAKE THE WEBSOCKET CONNECTION AND EXPRESS CONNECCTION SECURE SO MY APPS (with letsencrypt ssl) can connect to the servers
It is not possible to create two separate server instances, both listening on the same port. But, specifically for a webSocket, you can share one server instance between Express and the webSocket server code. This is possible because a webSocket connection always starts with an http request (thus it can be listened for using your Express http server. And, because these http requests that initiate a webSocket all contain identifying headers they can be separated out from the regular http requests for Express by looking at the headers. The webSocket server code already knows how to do that for you.
To do that, first capture the Express server instance:
const server = app.listen(3000, () => { console.log('Server listening on port 3000'); });
Then, use that server instance when you create your webSocket server.
const wsServer = new webSocketServer({ httpServer: server });
Then, remove this code because you don't want to create yet another http server instance for the webSocket server:
const server = http.createServer();
server.listen(webSocketServerPort);
console.log('Listening on port 8000');
I'm new to node.js and, having worked through the relevant parts of the Wexler book, I am trying to create a simple stream using socket.io.
Here is my node.js server code:
const port = 3000,
dataIntervalMillis = 5000,
express = require("express"),
app = express(),
crypto = require('crypto');
const server = app
// .get("/", (req, res) => {
// res.send("Run this project by typing in <b>nodemon</b> in the node.js command prompt.");
// })
.listen(port, () => {
console.log(`RNG Server running on port number ${port}`);
}),
io = require("socket.io")(server);
io.on("connection", client => {
console.log("RNG client connected.");
io.emit("New RNG client connection.");
client.on("disconnect", () => {
console.log("RNG client disconnected.");
io.emit("RNG client disconnected.");
});
});
I have built a standalone Java application to test the stream:
//import java.io.BufferedReader;
import java.io.InputStream;
//import java.io.InputStreamReader;
//import java.io.PrintStream;
import java.net.Socket;
public class SimpleSocketClientExample {
public static void main(String[] args) {
String server = "localhost";
int port = 3000;
try {
// Connect to the server
System.out.println("Connect to server " + server + " on port " + port + "...");
Socket socket = new Socket( server, port );
System.out.println("...connected.");
//BufferedReader in = new BufferedReader( new InputStreamReader( socket.getInputStream() ) );
InputStream in = socket.getInputStream();
System.out.println("Reading byte...");
int b = in.read();
System.out.println("...byte read.");
// Close our streams
if (in != null) {
in.close();
}
if (socket != null) {
socket.close();
}
}
catch( Exception e ) {
e.printStackTrace();
}
}
}
The problem is that this client code hangs on the in.read() line.
The only console log from the server is RNG Server running on port number 3000. There is no RNG client connected in the server log, which indicates that the client has not connected (or has connected to something else).
I've tested my node.js app using online socket testers, and they don't seem to connect either - indicating the problem probably lays with my node.js server app.
Can anyone advise what I may have missed?
Turns out socket.io doesn't create a standard TCP socket.
My solution was to leave my client code untouched and change the Node.js server code to use the net library instead.
In case it might help anyone else that runs into the same issue, here's my new code:
const port = 3000;
const { createServer } = require('net');
const server = createServer();
// A counter to facilitate assigning of socket.id.
let counter = 0;
// An array of connected client sockets that we will broadcast to.
let sockets = {};
server.on('connection', (socket) => {
socket.id = counter++;
console.log(`A client has connected: ${socket.id}`);
// Catch errors so they don't stop the application.
socket.on('error', function () {
console.log(`Client error: ${socket.id}`);
delete sockets[socket.id];
});
// Set character encoding.
socket.setEncoding('utf8');
// Add socket to array.
sockets[socket.id] = socket;
// When connection ends, remove socket from array.
socket.on('end', data => {
console.log(`${socket.id} has disconnected`)
delete sockets[socket.id];
});
});
server.listen(port, () => {
console.log(`RNG Server running on port number ${port}`);
});
I'm trying to create a webtracker to track what pages my users are seeing and how much time they are spending at each page, at the end they will make a registration and i will associate their navigation with the created user.
I want to use node because i can see when the user connect to the url and disconnect to calculate the time, i have tried that with pure javascript but i can see when the user leaves the page only on Chrome.
I have already managed to create some of what i need using the socket.io lib but i can't find a way to use it without creating an html page. What i need is to create something like google analytics where i will only incorporate the script. Is it possible?
I have managed to figure it out so i will post it to help others with the same problem:
Server
let socket = require('socket.io');
let http = require('http');
let serveStatic = require('serve-static');
let finalhandler = require('finalhandler');
var port = process.env.PORT || 1337;
let serve = serveStatic(__dirname, { 'index': ['client.js'] });
let server = http.createServer(function (req, res) {
serve(req, res, finalhandler(req, res));
});
let io = socket(server);
server.listen(port);
io.on('connection', client => {
console.log('new user connected!', client.id);
client.on('hello', data => {
console.log('data: ', data);
});
client.on('disconnect', () => {
console.log('user disconnected', client.id);
});
});
Client
(function (plugin) {
plugin.socket = null;
function loadDependencies() {
head.js(
{ socket: 'https://cdn.socket.io/socket.io-1.4.5.js' }
);
head.ready('socket', function() {
plugin.socket = io('http://localhost:1337');
setSocketHandlers();
});
}
function setSocketHandlers() {
plugin.socket.on('my-event', function(data){
console.log('called my event');
});
}
plugin.init = () => {
loadDependencies();
}
}(this.WebTracker = this.WebTracker || {}));
WebTracker.init();
I am using SocketIo with Nodejs, Express server and MongoDB, I followed the documentation . it works fine when connecting multiple clients they can send messages to each other without any problem . when I made an Http request, I cannot connect any new clients and get this error.
socket.io.js:7370 WebSocket connection to
'ws://localhost:28232/socket.io/?userId=userAmr&EIO=3&transport=websocket&sid=wNTTgrUD-PSeNaIcAAAF'
failed: Error during WebSocket handshake: Unexpected response code:
400
the other connected users before the Http request can continue sending messages without any problem.
I debugged the Socket library and found the client socket request go to connect function then fire errorCode:1
This this my code
/**
* Create Express server.
*/
const app = express();
// API endpoint
app.get('/api/test',(req,res)=>{
res.status(200).send({test:"test"});
});
/**
* Init socket
*/
// the following line not working too
// const server = require('http').createServer(app);
const server = require('http').Server(app);
const io = require('socket.io')(server);
io.on('connection', (socket) => {
// emit message to group
socket.on('emitMessage', (data) => {
io.emit('emitMessage', data);
});
});
The Client side code
import { Injectable } from '#angular/core';
import * as io from "socket.io-client/dist/socket.io.js"
import { BehaviorSubject } from 'rxjs';
#Injectable()
export class AppSocketService {
private url = 'http://localhost:28232';
private socket;
constructor() {
}
connect(){
this.socket = io(this.url,{
query:{userid:"123"},
forceNew:true,
'force new connection': true,
autoConnect: true,
reconnectionDelay: 1000,
timeout: 100000,
reconnectionDelayMax: 5000,});
this.socket.on('connect', () => {
console.log("connect",{"socketId":this.socket.id});
this.startListening();
});
}
startListening(){
this.socket.on('emitMessage', (data) => {
console.log(data);
});
}
emitMessage(message){
this.socket.emit('emitMessage', {message});
}
}
Client version:"socket.io-client": "^1.7.3"
Server version: "socket.io": "^1.7.3"
i found the problem, the package express-status-monitor making this wrong behavior .
try to remove it, and it will work perfectly
// comment these lines, as they making the issue
// const expressStatusMonitor = require('express-status-monitor');
// app.use(expressStatusMonitor());
The final code:
let app = require('express')();
// these two lines were making the problem, please comment them. if you want to reproduce the problem enable them again
// const expressStatusMonitor = require('express-status-monitor');
// app.use(expressStatusMonitor());
let http = require('http').Server(app);
let io = require('socket.io')(http);
let port = process.env.PORT || 3000;
app.get('/', function(req, res){
res.sendFile(__dirname + '/index.html');
});
app.get('/api/v0/availabilities',(req,res)=>{
res.status(200).send({test:"test"});
});
io.on('connection', (socket) => {
// emit message to group
socket.on('emitMessage', (data) => {
io.emit('emitMessage', data);
});
});
http.listen(port, function(){
console.log('listening on *:' + port);
});
After every page updating I have +1 socket connection..
module.exports = function(io, client) {
var GameController = {
gamePage: function(req, res) {
client.hget('games', 'game.' + req.params.id, function (err, result) {
if (err) return result(err);
var game = JSON.parse(result);
io.on('connection', function (socket) {
console.log('send');
console.log(socket.id);
io.emit('get_bets', game.players);
});
res.render('pages/game', {
title: 'Game - ' + req.params.id,
user: req.user,
game: game
});
});
};
return GameController;
});
route file:
module.exports = function(io, client) {
var express = require('express');
var router = express.Router();
var GameController = require('controllers/GameController')(io, client);
router.get('/:id', GameController.gamePage);
...
return router;
};
Client side on react:
var Game = React.createClass({
getInitialState: function() {
this.socket = io();
return {
bets: null
}
},
socketGetBets: function() {
var that = this;
this.socket.on('get_bets', function(data) {
console.log('get bets');
that.setState({ bets: data });
});
this.socket.on('rand', function(data) {
console.log(data);
});
},
...
But after debug I find what problem not in client side.
app.js file:
var socket_io = require('socket.io');
var io = socket_io();
app.io = io;
//route
var game = require('./routes/games')(io, client);
bin/www file:
var server = http.createServer(app);
var io = app.io;
io.attach( server );
After page updating, io.on("connection") event show me "send" message in console, after second page updating, I have "send" "send", third update - "send" "send" "send" etc. Than Memory leak warning appeared. Console log socked.id show the same value many time.
Every time you call on, whether it's io.on or socket.on, you are registering an event handler. This being the case, you probably don't want to be calling io.on('connection') inside of a route, as you will register a new connection handler every time that route is accessed. This is why you are seeing cumulative messages being logged in the console.
In fact, you probably don't want to mix express routing with socket functions at all, as they are different protocols and will work independent of each other.
// server side
// this should only be called once per connection.
io.on('connection', function (socket) {
// handle socket protocol stuff.. fetching server data, sending data
socket.on('fetch bets', function() {
// get game.players from server
// updating other sockets
io.emit('get_bets', game.players);
})
})
app.get('/route', function (req, res) {
// handle http protocol stuff.. fetching server data, sending data
// send data back to caller
res.json(data)
})
The same applies to socket.on in your client side. It looks like you're adding a new 'get_bets' event handler everytime you call socketGetBets.
Instead you probably want to register that event handler one single time, likely in componentDidMount or componentWillMount. Also, because a socket connection can be considered global for your application, you can create the connection above your app.
// client side
var socket = io()
var Game = React.createClass({
getInitialState: function() {
return {
bets: null
}
},
componentWillMount: function() {
var that = this
socket.on('get_bets', function(data) {
that.setState({ bets: data })
})
}
...