Socket.io: Failed GET requests in the console - node.js

I am trying to add socket.io to my code, and the following failed GET request is repeatedly printed to the console whenever I run the website on my localhost.
GET http://localhost:4000/socket.io/?EIO=3&transport=polling&t=MMNC8I9 0 ()
I do not understand what is sending this request. The socket works, although not entirely in the way I intended it to*.
*I am trying to build a real-time application that works with several clients, and at the moment only one client is being updated at any given time. As I am still learning, I am not sure if this is a normal behaviour or not, but I want to fix the failed request error before I dive into that!
How do I fix the issue? Thank you in advance!
Code below:
server.js
const client=require("socket.io").listen(4040).sockets;
const app = express();
mongoose.connect('mongodb://localhost/<dbname>?replicaSet=rs');
mongoose.connect(config.db);
const db = mongoose.connection;
db.once("open", () => {
console.log(">>> 🖥️ MongoDB: Connection successful");
app.listen(9000, () => {
console.log('Node server running on port 9000');
});
// Connect to Socket.io
client.on("connection", function(){
let queries = db.collection('queries');
// Create function to send status
sendStatus = function(s) {
socket.emit("status", s);
}
});
});
app.post('/query', (req, res, next) => {
<some code omitted>
doc.save()
.then(result => {
socket.emit("query", res);
res.send({
result
});
}
});
Queries.js
constructor(props) {
...
var socket = io.connect("http://localhost:4000/");
if (socket!= undefined) {
socket.on("query", function() {
this.loadQueries();
});
}
index.html
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.0.4/socket.io.js"></script>

Related

How to establish connection to mongo db in a Node js express server using serverless?

I don't know how to establish connection to the mongo db for my node JS server in AWS Lambda using serverless on AWS. I've mentioned my question in the handler function below.
The code looks something like this:
import express from "express";
import mongoose from "mongoose";
import dotenv from "dotenv";
import cookieParser from "cookie-parser";
import serverless from "serverless-http";
const PORT = 1234;
dotenv.config();
mongoose.connect(
process.env.MONGO_URL,
() => {
console.log("connected to db");
},
(err) => {
console.log({
error: `Error connecting to db : ${err}`,
});
}
);
const app = express();
app.use(cookieParser());
app.use(express.json());
// this part has various routes
app.use("/api/auth", authRoutes);
app.use((err, req, res, next) => {
const status = err.status || 500;
const message = err.message || "Something went wrong";
return res.status(status).json({
success: false,
status,
message,
});
});
app.listen(PORT, () => {
console.log(`Server listening on port ${PORT}`);
});
export const handler = () => {
// how to connect to mongodb here?
return serverless(app);
};
Here handler is the AWS lambda's handler function. For each http request I'm reading/writing data from/to my DB in some way. After checking the cloudwatch logs, it was clear that the requests sent to the server result in timeout because the connection to mongodb hasn't been established. So how exactly do I use mongoose.connect here?
I tried doing this:
export const handler = () => {
mongoose.connect(
process.env.MONGO_URL,
() => {
console.log("connected to db");
}
);
return serverless(app);
};
But it didn't work possibly because it's asynchronous. So I'm not sure how to make this connection here.
EDIT:
One thing that I realised was that the database server's network access list had only my IP because that's how I set it up initially.
So I changed it to anywhere for now and made the following minor changes:
const connect_to_db = () => {
mongoose
.connect(process.env.MONGO_URL)
.then(() => {
console.log("Connected to DB");
})
.catch((err) => {
throw err;
});
};
app.listen(PORT, () => {
connect_to_db();
console.log(`Server listening on port ${PORT}`);
});
Now I can see "Connected to DB" in the logs but the requests sent still times out after 15 seconds (the timeout limit set currently).
My logs:
What am I doing wrong?
So I did some more digging and asked this around the community. Few things that made me understand what I was doing wrong:
It appeared I wasn't connecting the db and my app response
together. My app was handling the request fine, my db was connecting
fine. But there was nothing tying them together. It's supposed to be simple:
Requests comes in > App waits until db connection has been established > App handles request > App returns response.
Second, calling app.listen was another problem in my code. Calling listen keeps the process open for incoming requests and it ultimately is killed by Lambda on timeout.
In a serverless environment, you don't start a process that listens for requests but, instead, the listening part is done by AWS API Gateway (which I have used to have my Lambda handle http requests) and it knows to send request information to Lambda handler for processing and returning a response. The handler function is designed to be run on each request and return a response.
So I tried adding await mongoose.connect(process.env.MONGO_URL); to all my methods before doing any operation on the database and it started sending responses as expected. This was getting repetitive so I created a simple middleware and this helped me avoid lot of repetitive code.
app.use(async (req, res, next) => {
try {
await mongoose.connect(process.env.MONGO_URL);
console.log("CONNECTED TO DB SUCCESSFULLY");
next();
} catch (err) {
next(err);
}
});
Another important, but small change. I was assigning lambda's handler incorrectly.
Instead of this:
export const handler = () => {
return serverless(app);
};
I did this:
export const handler = serverless(app);
That's it I suppose, these changes fixed my express server on Lambda. If anything I've said is wrong in any way just let me know.

Extracting POST request data from Express in Nodejs

I have a fairly simple express server that is designed to take external client data and publish it via mqtt to a gateway. It works perfectly with a hardcoded variable but I can't figure out how to extract the actual data from the POST request, which is as follows (it prints to the console just fine):
const postData = app.post('/send-data', function (req, res) {
console.log('connected', req.body);
res.status(200).json(req.body)
});
I need to get the req.body data out of that and into the following code that publishes the data to the topic:
client.on('connect', function () {
console.log('connected!');
client.publish('iot-2/type/wtlType/id/channel100/evt/event/fmt/json', publishData);
client.end();
});
publishData will just be the stringified json response.
This is the create server code if that helps:
https.createServer(options, app).listen(30002, () => {
console.log('Listening')
});
If I understand correctly your question is about the logic of getting the req.body published by the client. If so, then something like this should work:
let connected = false;
client.on('connect', function () {
console.log('connected!');
connected = true;
});
const postData = app.post('/send-data', function (req, res) {
console.log('connected', req.body);
res.status(200).json(req.body)
client.publish('iot-2/type/wtlType/id/channel100/evt/event/fmt/json', JSON.stringify(req.body));
client.end(); // are you sure you want this? can there not be more messages to broadcast?
});

JSDOM - nodejs makes clean exit, doesn't load

I am following a tutorial on this site:
https://phasertutorials.com/creating-a-simple-multiplayer-game-in-phaser-3-with-an-authoritative-server-part-1/
I am trying to get the last step to work.
I tried this initially with my own code as I am begining to understand using node and express. I got the same error, so I did a clean start and followed the guide exactly as I thought I had made a mistake and couldn't find it. But now I think there is an issue in this function, I don't know of.
Everything works fine until I reach the last step- including this function:
function setupAuthoritativePhaser() {
JSDOM.fromFile(path.join(__dirname, 'authoritative_server/index.html'), {
// To run the scripts in the html file
runScripts: "dangerously",
// Also load supported external resources
resources: "usable",
// So requestAnimatinFrame events fire
pretendToBeVisual: true
}).then((dom) => {
dom.window.gameLoaded = () => {
server.listen(8081, function () {
console.log(`Listening on ${server.address().port}`);
});
};
}).catch((error) => {
console.log(error.message);
});
};
my nodemon makes a clean exit and waits for changes before restarting.
any ideas?
Your help is greatly appreciated.
I found my own answer. Apparently I am a fool, I removed the call of this function...
setupAuthoritativePhaser();
However, I am not getting the correct phaser tag in the console log, it should say Phaser .... (Headless | HTML5 Audio) but it still says Phaser v3.15.1 (WebGL | Web Audio), though in my node it says the correct phrase...
you need remove old code in server/index.js
server.listen(8081, function () {
console.log(`Listening on ${server.address().port}`);
});
and use
dom.window.gameLoaded = () => {
server.listen(8081, function () {
console.log(`Listening on the ${server.address().port}`);
});
};
finaly server/index.js look like
const express = require('express');
const app = express();
const server = require('http').Server(app);
const path = require('path');
const jsdom = require('jsdom');
const { JSDOM } = jsdom;
app.use(express.static(__dirname + '/public'));
app.get('/', function (req, res) {
res.sendFile(__dirname + '/index.html');
});
// server.listen(8081, function () {
// console.log(`Listening on ${server.address().port}`);
// });
function setupAuthoritativePhaser() {
console.log(__dirname)
JSDOM.fromFile(path.join(__dirname, '/authoritative_server/index.html'), {
// To run the scripts in the html file
runScripts: "dangerously",
// Also load supported external resources
resources: "usable",
// So requestAnimatinFrame events fire
pretendToBeVisual: true
}).then((dom) => {
dom.window.gameLoaded = () => {
server.listen(8081, function () {
console.log(`Listening on the ${server.address().port}`);
});
};
}).catch((error) => {
console.log(error.message);
});
}
setupAuthoritativePhaser();

how to get realtime data in nodejs mongodb and angularjs using SocketsJs?

i have a nodejs server which is getting list of a collection from mongodb . Here is its code . since am new to sockets so ..
const express = require("express");
const app = express();
const http = require("http").Server(app);
const socketio = require('socket.io');
after that iam simply getting data in a route . and one thing more all code is in one file and i do need express route as there are other routes in app. here is the mongodb code for getting list
app.post("/getAllOfferManagement",
async (req, res) => {
try {
MongoClient.connect(url,
function(err, db) {
if (err) throw err;
var dbo = db.db("realtime");
dbo
.collection("offer")
.find({})
.toArray(function(err,
result) {
if (err) throw err;
// console.log('getting it ');
res.send(result);
db.close();
});
});
} catch (err) {
res.send("error");
}
}); // its all working fine when i hit the route
http.listen(5000, function() {
console.log("Server Started!");
});
//serversidecode ends here
Now am getting the data through angular and here is the code for it
$scope.getAllOffer = function() {
$scope.mongoloader = true;
//nodejs api endpoint
$http.post("http://localhost:5000/getAllOffer").then(function(res) {
$scope.offersArray = res.data;
console.log('data here', res.data);
});
};
the above works fine . but i need to get data in realtime e.g when somone insert new doc in mongodb the the view get updates . am new to sockets so any help is appreciated. Thanks
For this u have to add an event to backend and as well as in frontend
Backend
io.on('connection', (socket) => {
    console.log(socket.id);
    socket.on('SEND_TITLE', function(data){
        io.emit('RECEIVE_TITLE', data);
        console.log('data',data)
    })
});
For frontend u have to use socket io client module
import io from "socket.io-client";
socket = io('your backend host url')
    socket.on('RECEIVE_TITLE', function(data)
      Console. Log(data);
  });
Frontend syntax could differ in angular.
As I am not familiar with angular
For more information visit.
Forclient side.
https://socket.io/docs/client-api/
For server.
https://socket.io/docs/server-api/

Webtracker using nodejs

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();

Resources