Node.JS + Socket.io, moving socket event handlers to external module? - javascript

I have a server.js file like this:
var express = require('express'),
app = express(),
server = require('http').createServer(app),
mongoose = require('mongoose'),
bodyParser = require('body-parser'),
apiRouter = require('./app/routes/api.js'),
io = require('socket.io')(server),
socketEvents = require('./app/modules/socketEvents.js')(io);
//Clears Node Console.
process.stdout.write('\033c');
console.log('Server starting!');
socketEvents.attachEventHandlers();
app.use(bodyParser.urlencoded({extended: true}));
app.use(bodyParser.json());
app.use('/api', apiRouter);
app.use(express.static('public'));
app.use('*', function(req, res, next) {
//All requests return single page angular application.
res.sendFile(__dirname + '/public/index.html');
});
mongoose.connect('localhost', 'triviaattack', function(err) {
if (err) {
console.log('An error occured when connecting to the MongoDB Database');
throw err;
}
});
server.listen(1337);
And socketEvents.js
module.exports = function(io) {
return {
attachEventHandlers: function() {
io.on('connection', function(socket) {
console.log('client connected');
socket.on('joinMatchMaking', function(data) {
//Every time a player joins the matchmaking queue, check if a game can be created.
matchMakingQueue.push(data);
var matchedPlayers = [];
for (i = 0; i < matchMakingQueue.length; i++) {
switch (data.gameType) {
case '1v1':
matchedPlayers.push(matchMakingQueue[i].username);
if (matchedPlayers.length == 2) {
socket.emit('matchFound', {players: matchedPlayers});
}
console.log('user joined 1v1 queue');
case '2v2':
matchedPlayers.push(matchMakingQueue[i].username);
if (matchedPlayers.length == 4) {
socket.emit('matchFound', {players: matchedPlayers});
}
console.log('user joined 2v2 queue');
}
}
console.log(data.username + ' joined the ' + data.gameType + ' matchmaking queue');
console.log('users in queue: ' + matchMakingQueue.length);
});
socket.on('leaveMatchMaking', function(username) {
matchMakingQueue.splice(matchMakingQueue.indexOf(username), 1);
console.log(username + ' left matchmaking queue.');
console.log('users in queue: ' + matchMakingQueue.length);
});
});
console.log('events attached');
}
}
};
When I load my site in my browser, the io.on('connection), function () {...}) event handler is not being called, which should output a console.log message whenever a client connects. I want to keep my socket.io events outside of my main server.js file because there will be alot of them and I wanted to separate them into their own module.

You need to have some socket code in the html file to connect.. can you include it as well?

I do this by stuffing all of my socket events in a middleware:
var io = require('socket.io');
// listen stuff
var SocketEvents = require('./socket-events.js')(io);
io.use(SocketEvents);
... and then in socket-events.js something like:
module.exports = function(io) {
return function(socket, next) {
// do stuff
return next();
}
}
I should add that in this case the on("connection") listener appears not to be necessary, as each middleware function is executed on each incoming socket connection already.

Related

Why combining Node Express and Redis can't set a simple Key-Value pair?

Basically, the below put service that should execute a simple Redis-cli> SET KEY VALUE can't work.
The get operations work well.
Using separately the redis module and calling the set function also works.
But when called from app.put() the KEY/VALUE pair isn't registered.
What's the hell???
// express setup
const REDIS_REST_PORT = 3000;
const express = require('express');
const router = express.Router();
const app = express();
const bodyParser = require('body-parser');
app.use(bodyParser.json());
// redis setup
const REDIS_CONNECTION_STRING = "redis://127.0.0.1:6379";
const RedisCli = require('redis').createClient(REDIS_CONNECTION_STRING);
RedisCli.on('connect', function() {
console.log('Connected to REDIS');
});
RedisCli.on('error', function(err) {
console.log('/!\ REDIS ERROR: ' + err);
});
// GET .../get/KEY (works well !!)
app.get('/get/:key', function(req, res) {
RedisCli.get( req.params.key, function (err, result) {
if (err) {
res.send(err,500);
} else {
res.send(result);
}
});
});
// PUT .../set/KEY + body (can't work KEY/VALUE never registered ??)
app.put('/set/:key', function(req, res) {
var value = "'" + JSON.stringify(req.body) + "'";
console.log("SET " + req.params.key + " " + value);
RedisCli.set( req.params.key, value,
function (err, result) {
if (err) {
res.send(err,500);
} else {
res.send(result);
}
});
});
// Start REST server
app.listen(REDIS_REST_PORT, () =>
console.log('Listening on port '+ REDIS_REST_PORT + '...'));
Eventually it used to work - don't understand how and why - see my comment.

Update user balance in realtime in the browser from private ethereum blockchain

I would like to have a website that updates live the user's wealth from a private Ethereum blockchain.
Current Solution (broken)
I opened a websocket to a private Ethereum blockchain that is mining, I would like to update my Coinbase balance on the front end. My code is as follow:
const express = require("express");
const Web3 = require("web3");
var app = express();
app.get("/", (req, res) => res.send("hello world from ping ether application"));
app.get("/ping-ether", function(req, res){
var web3 = new Web3(new Web3.providers.WebsocketProvider('ws://localhost:8546'));
var event_newBlockHeaders = web3.eth.subscribe("newBlockHeaders", function(err, result){
if (err){
console.log(err)
} else {
let acctPromise = web3.eth.getAccounts().then(function(accts){
let balance = web3.eth.getBalance(accts[0]).then(function(bal){
console.log("user: ", accts[0]);
console.log("balance: ", bal);
res.end("new balance for user: " + bal)
});
});
}
});
});
// run the server
app.listen(3000, () => console.log("web app listening on port 3000"));
Clearly this is not updating live in the frontend even though the inner most callback is firing constantly as I can confirm on the console. I would like three things:
How should I change this code so that the front end has a live ticker of the coinbase balance
The code in general just smells bad with its nested promises. How can I refactor it so that I do not have to establish a websocket connection each time I navigate to /ping-ether?
Untested, but something like this should work:
const express = require("express");
const Web3 = require("web3");
var app = express();
var web3 = new Web3(new Web3.providers.WebsocketProvider('ws://localhost:8546'));
var balance = -1;
web3.eth.getAccounts().then(accounts => {
return web3.eth.subscribe("newBlockHeaders", (err, result) => {
if (err) {
console.log(err);
} else {
web3.eth.getBalance(accounts[0]).then(bal => {
console.log("user: ", accounts[0]);
console.log("balance: ", bal);
balance = bal;
});
}
})
}).then(() => {
app.listen(3000, () => console.log("web app listening on port 3000"));
});
app.get("/", (req, res) => res.send("hello world from ping ether application"));
app.get("/ping-ether", function (req, res) {
res.end("new balance for user: " + balance);
});
The main idea is to set up the websocket connection and subscription once, and then just respond to incoming web requests with the current balance. I also tried to clean up the nested promises by returning the subscription promise.
Update: I ended up using websocket, here's the solution:
import * as Web3 from 'web3' ;
import * as express from 'express' ;
import * as socketIO from 'socket.io';
import * as http from 'http' ;
const CLIENT_PATH = 'path/to/directory'
var app = express();
var server = http.Server(app);
var io = socketIO(server);
var web3 = new Web3(new Web3.providers.WebsocketProvider('ws://localhost:8546'));
app.get('/', (req,res) => {
res.sendFile(CLIENT_PATH + '/index.html');
});
web3.eth.getAccounts().then(accounts => {
display_account(accounts)
})
function display_account(accounts){
var user_0 = accounts[0]
web3.eth.subscribe('newBlockHeaders', (err, ret) => {
if (err){
console.log("error: ", err)
} else {
web3.eth.getBalance(user_0).then(bal => {
var msg = 'Balance for user ' + user_0 + ' is ' + bal
io.emit('message-1', msg)
console.log('emitted message: ', msg)
})
}
})
}
// use this instead of app.listen
server.listen(3000, () => {
console.log('listening on 3000')
});
And this is index.html.
<html>
<head></head>
<body>
<div id="message"></div>
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io();
socket.on('message-1', function(msg){
console.log(msg);
document.getElementById("message").innerHTML = msg;
});
</script>
</body>
</html>

can't create a new directory using mongoose and express

Like the title entails.
I'm trying to make an application that when i put in certain info, it creates a link using mongoose _id. and express's app.get what i don't get is that to be able to join that directory i have to reload the whole server, which for the users and my sake a i don't want to do.
var mongoose = require("mongoose");
var express = require("express");
var app = express();
var http = require("http").Server(app);
var io = require("socket.io")(http);
var router = express.Router();
app.get("/", function (req, res) {
var ip = req.connection.remoteAddress;
res.sendFile(__dirname + "/index.html");
});
mongoose.connect("mongodb://localhost:27017/NEW_DB1");
console.log("Connection to database has been established");
var collectedData = new mongoose.Schema({
ipAddress: String,
name: {
type: String,
unique: false
}
});
var collectionOfData = mongoose.model("dataType", collectedData);
io.on("connection", function (socket) {
socket.on("name", function (e) {
var ip = socket.request.socket.remoteAddress;
var dataBase = mongoose.connection;
var Maindata = new collectionOfData({
ipAddress: ip,
name: e
});
Maindata.save(function (err, Maindata) {
if (err) {
return console.error(err);
} else {
console.dir(Maindata);
}
});
});
});
app.get("/mix", function (req, res) {
collectionOfData.find(function (err, data) {
res.send(data);
});
});
collectionOfData.find(function (err, data) {
data.forEach(function (uniqueURL) {
app.get("/" + uniqueURL._id, function (req, res) {
res.send("<h1>Hello " + uniqueURL.ipAddress + "</h1><p>" + uniqueURL.name + "</p>");
});
});
});
http.listen(10203, function () {
console.log("Server is up");
});
So what i'm trying to do is make it so i don't have to reload the whole server, and i'm able to just join the created directory when it's done being loaded.
figured i should put a quick example:
localhost:10203/55c2b2f39e09aeed245f2996
is a link a user just created the long
55c2b2f39e09aeed245f2996
is the effect of the _id, but when the user try's to connect to that site it won't work until i reload the server and obviously i'd like to avoid that haha.
I have a index.html file, but all that has is a socket.emit that sends "name" to the server
app.get("/", function (req, res) {
var ip = req.connection.remoteAddress;
res.sendFile(__dirname + "/index.html");
});
app.get('/:uniqueURL', function(req, res){
var id = req.params.uniqueURL;
res.send("Your requested id : " + id);
})
Try to use this above.
You are creating fix get path inside collectionData.find. That is the problem. So each time you have to reload the server by restarting.

TypeError: this.io is undefined socket.io.js:639

I try to connect from JavaScript to nodejs socket-server (for using webrtc in phonegap - PhoneRTC plugin)
I have server.js code:
var app = require('express')();
var server = require('http').createServer(app);
var webRTC = require('webrtc.io').listen(server);
var io = require('socket.io')(server);
var port = process.env.PORT || 1234;
server.listen(port);
app.get('/', function(req, res) {
res.sendfile(__dirname + '/index.html');
});
app.get('/style.css', function(req, res) {
res.sendfile(__dirname + '/style.css');
});
app.get('/fullscrean.png', function(req, res) {
res.sendfile(__dirname + '/fullscrean.png');
});
app.get('/script.js', function(req, res) {
res.sendfile(__dirname + '/script.js');
});
app.get('/webrtc.io.js', function(req, res) {
res.sendfile(__dirname + '/webrtc.io.js');
});
webRTC.rtc.on('chat_msg', function(data, socket) {
var roomList = webRTC.rtc.rooms[data.room] || [];
for (var i = 0; i < roomList.length; i++) {
var socketId = roomList[i];
if (socketId !== socket.id) {
var soc = webRTC.rtc.getSocket(socketId);
if (soc) {
soc.send(JSON.stringify({
"eventName": "receive_chat_msg",
"data": {
"messages": data.messages,
"color": data.color
}
}), function(error) {
if (error) {
console.log(error);
}
});
}
}
}
});
start it: node server.js
then i have client side code:
<script src="http://my-saite:1234/socket.io/socket.io.js"></script>
<script>
// Create SocketIO instance, connect
var socket = new io.Socket();
socket.connect('http://my-saite:1234');
// Add a connect listener
socket.on('connect',function() {
alert ('Client has connected to the server!');
});
// Add a connect listener
socket.on('message',function(data) {
alert ('Received a message from the server!',data);
});
// Add a disconnect listener
socket.on('disconnect',function() {
alert ('The client has disconnected!');
});
// Sends a message to the server via sockets
function sendMessageToServer(message) {
socket.send(message);
};
</script>
and when i open it in web-browser i get error: TypeError: this.io is undefined socket.io.js:639
http://my-saite.com:1234 and http://my-saite.com:1234/socket.io/socket.io.js load fine,
639 line in socket.io.js is
/**
* `Socket` constructor.
*
* #api public
*/
function Socket(io, nsp){
this.io = io;
this.nsp = nsp;
this.json = this; // compat
this.ids = 0;
this.acks = {};
/*639 line --->*/ if (this.io.autoConnect) this.open();
this.receiveBuffer = [];
this.sendBuffer = [];
this.connected = false;
this.disconnected = true;
this.subEvents();
}
If someone has faced a similar problem - help. I would be grateful for your advice!
Using version 1.1.0 I guess?
Change the creation of a Socket object
var socket = io.connect('http://my-saite:1234');
Then the rest shouldn't be a problem
// Add a connect listener
socket.on('connect',function() {
alert ('Client has connected to the server!');
});
// Add a connect listener
socket.on('message',function(data) {
alert ('Received a message from the server!',data);
});
// Add a disconnect listener
socket.on('disconnect',function() {
alert ('The client has disconnected!');
});
// Sends a message to the server via sockets
function sendMessageToServer(message) {
socket.send(message);
};

Node js displaying images from server

I am trying to display an image on a basic web page on a localhost w/ port 5000
here is main.js
var http = require('http');
var domain = require('domain');
var root = require('./root');
var image = require('./image');
function replyError(res) {
try {
res.writeHead(500);
res.end('Server error.');
} catch (err) {
console.error('Error sending response with code 500.');
}
};
function replyNotFound(res) {
res.writeHead(404);
res.end('not found');
}
function handleRequest(req, res) {
console.log('Handling request for ' + req.url);
if (req.url === '/') {
root.handle(req, res);
} else if (req.url === '/image.png'){
image.handle(req, res);
} else {
replyNotFound(res);
}
}
var server = http.createServer();
server.on('request', function(req, res) {
var d = domain.create();
d.on('error', function(err) {
console.error(req.url, err.message);
replyError(res);
});
d.run(function() { handleRequest(req, res); });
});
function CallbackToInit(){
server.listen(5000);
};
root.init(CallbackToInit);
Using callbacks I want the server to start listening(5000) only after the init function of the following code runs
var http = require('http');
var body;
exports.handle = function(req, res) {
res.writeHead(200, {
'Content-Type': 'image/png'
});
res.end(body);
};
exports.init = function(cb) {
require('fs').readFile('image.png', function(err, data) {
if (err) throw err;
body = data;
cb();
});
}
It's an assignment I can't use express
I am trying to get image.png to be displayed, I think body = data doesn't work because it can't hold an image like a string? I don't want to put any HTML into my js file.
Don't roll your own app server. Use one of the great web app frameworks like express or connect.
var express = require('express');
var app = express();
app.use(express.logger());
app.use(express.static(__dirname + '/public'));
app.listen(process.env.PORT || 5000);
Trust me, this is better.
Take a look at the node.js example for a simple http server or a tutorial/example, such as this, for serving static files through a simple server.

Categories