I am setting up a peer to peer server for a blockchain project which leverages the Node JS ws websocket client. For whatever reason, the arrow function in my server.on(...) call does not execute. When I change the keyword to 'listen' however, the function executes. Please help :P.
p2p-server.js:
const Websocket = require('ws');
const P2P_PORT = process.env.P2P_PORT || 5001;
const peers = process.env.peers ? process.env.PEERS.split(',') : [];
// HTTP_PORT=3002 P2P_PORT=5003 PEERS=ws://localhost:5001,ws://localhost:5002 npm run dev
// HTTP_PORT=3002 P2P_PORT=5002 PEERS=ws://localhost:5001 npm run dev
class P2pServer {
constructor (Blockchain) {
this.blockchain = Blockchain;
this.sockets = [];
}
listen() {
const server = new Websocket.Server({ port: P2P_PORT });
// server.on('connection', socket => this.connectSocket(socket));
server.on('connection', socket => this.connectSocket(socket));
// this.connectToPeers();
console.log(`Listening for peer-to-peer connections on: ${P2P_PORT}`);
}
// connectToPeers() {
// peers.forEach(peer => {
// const socket = new Websocket(peer);
// socket.on('open', () => this.connectSocket(socket));
// });
// }
connectSocket(socket) {
this.sockets.push(socket);
console.log('Socket connected.')
}
}
module.exports = P2pServer;
index.js:
// REST API
const express = require('express');
const bodyParser = require('body-parser');
const BlockChain = require('../blockchain');
const P2pServer = require('./p2p-server');
const HTTP_PORT = process.env.HTTP_PORT || 3001;
const app = express();
const bc = new BlockChain();
const p2pServer = new P2pServer(bc)
app.use(bodyParser.json());
app.get('/blocks', (req, res) => {
res.json(bc.chain);
});
app.post('/mine', (req, res) => {
const block = bc.addBlock(req.body.data);
console.log(`New block added: ${block.toString()}`);
res.redirect('/blocks');
})
app.listen(HTTP_PORT, () => console.log(`Listening on port ${HTTP_PORT}`));
p2pServer.listen();
simple syntax error messed me up in line 3.
This...
const peers = process.env.peers ? process.env.PEERS.split(',') : [];
should have been this...
const peers = process.env.PEERS ? process.env.PEERS.split(',') : [];
Related
I found a nice npm package by the name of Express Async Errors which according to the documentation, it's really nice to use.
However, if I implement it, the server will crash.
Here is my Route handler code
Controller
const { Genre } = require("../models");
const { StatusCodes } = require("http-status-codes");
const getGenre = async (req, res) => {
const genre = await Genre.findById({ _id: req.params.id });
if (!genre) {
return res.status(StatusCodes.BAD_REQUEST).json({
message: "The genre with the given ID was not found.",
});
}
res.status(StatusCodes.OK).json({ status: "success", data: genre });
};
*router*
const express = require("express");
const { authenticate, admin } = require("../middleware");
const router = express.Router();
const { schemaValidator } = require("../middleware");
const validateRequest = schemaValidator(true);
const { genres } = require("../controllers");
const { getAllGenres, getGenre, createGenre, updateGenre, deleteGenre } =
genres;
.route("/genres")
.get(getAllGenres)
Main Application Entry
require("express-async-errors");
//Routers
const routers = require("./router");
const connectDB = require("./DB/connect");
const express = require("express");
const app = express();
app.use(config.get("URI"), routers);
app.use(notFoundMiddleware);
const start = async () => {
const port = process.env.PORT || 3000;
const connectionString = config.get("mongoDB.connString");
await connectDB(connectionString)
.then(() => DBdebug(`Connected to MongoDB: ${connectionString}`))
.catch(() => console.log("MongoDB connection failure"));
app.listen(port, () => debug(`Listening on port ${port}...`));
};
start();
Above code is imported into index.js together with express-async-errors.
According to the document, if I create an error, express-async-errors has to handle this without crashing the application. My question is what I'm doind wrong???
I shut down the Mongo-driver just to create a scenario that the server is down with a status 503.
MongooseServerSelectionError: connect ECONNREFUSED 127.0.0.1:27017
at Function.Model.$wrapCallback (/Volumes/Seagate/lib/model.js:5087:32)
at /Volumes/Seagate/lib/query.js:4510:21
at /Volumes/Seagate/node_modules/mongoose/lib/helpers/promiseOrCallback.js:32:5
From previous event:
at promiseOrCallback (/Volumes/Seagate/node_modules/mongoose/lib/helpers/promiseOrCallback.js:31:10)
at model.Query.exec (/Volumes/Seagate/node_modules/mongoose/lib/query.js:4509:10)
at model.Query.Query.then (/Volumes/Seagate/node_modules/mongoose/lib/query.js:4592:15)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
Instead of above error, I should see "Something went wrong" as the default message in Postman without crashing the application.
Can someone point me to the right direction?
NB: The link which I had used us is https://www.npmjs.com/package/express-async-errors
Thank you very much in advanced.
After two days of researching my problem, I finally convinced my self that the problem was me and found a solution for this particular matter.
I have created an ErrorHandlerMiddleware and in the particular middleware I check if the error is an instance of MongooseError object, if this is the case, I just send for now an custom message.
See code below:
const { StatusCodes } = require("http-status-codes");
const { CustomApiError } = require("../errors");
const Mongoose = require("mongoose");
const errorHandlerMiddleware = (err, req, res, next) => {
console.log("errorMiddleWare");
if (err instanceof CustomApiError) {
return res.status(err.statusCode).json({ message: err.message });
}
if (err instanceof Mongoose.Error) {
return res.status(StatusCodes.INTERNAL_SERVER_ERROR).json({
message: "There is a technical problem, please try again later",
});
}
};
module.exports = { errorHandlerMiddleware };
In main application entry, I just pass errorHandlerMiddleware as a argument reference in app.use.
See code below
require("express-async-errors");
//Routers
const routers = require("./router");
const connectDB = require("./DB/connect");
const express = require("express");
const app = express();
app.use(config.get("URI"), routers);
app.use(notFoundMiddleware);
app.use(errorHandlerMiddleware);
const start = async () => {
const port = process.env.PORT || 3000;
const connectionString = config.get("mongoDB.connString");
await connectDB(connectionString)
.then(() => DBdebug(`Connected to MongoDB: ${connectionString}`))
.catch(() => console.log("MongoDB connection failure"));
app.listen(port, () => debug(`Listening on port ${port}...`));
};
start();
And this is the final result in PostMan:
If there are any comments regarding this solution, feel free to do this.
By comments and can learn more!!!
Thank you in advanced and keep coding!!!!
I'm having trouble connecting 4 arduinos using serialports and NodeJs.
When I connect all the ports only one is actually working and collecting the data message while all the others are ignored.
If I declare the serial ports separately they all work fine so the problem is not the Arduino code.
Here's how i declare all the serialports:
// Load HTTP module to create server, handle requests and send back static files (html, css, js)
const http = require('http');
// Load file system module to load files from computer
const fs = require('fs');
// Load path module to read paths from urls
const path = require('path');
// Load serialport module to communicate with arduino
const SerialPort = require('serialport');
// Open up connection with Arduino board
const serial = new SerialPort('/dev/cu.usbserial-1411140', {
baudRate: 115200
}, function() {
console.log('1411140 ready');
})
const SerialPort1 = require('serialport');
const serial1 = new SerialPort1('/dev/cu.usbserial-141120', {
baudRate: 115200
}, function() {
console.log('141120 ready');
})
const SerialPort2 = require('serialport');
const serial2 = new SerialPort2('/dev/cu.usbmodem-1411301', {
baudRate: 115200
}, function() {
console.log('1411301 ready');
})
const SerialPort3 = require('serialport');
const serial3 = new SerialPort3('/dev/cu.usbserial-1411130', {
baudRate: 115200
}, function() {
console.log('1411130 ready');
})
// Define port on which the webpage will be served from
const port = 8080;
This is how i read the arduino data
const io = require('socket.io')(server);
// do stuff when a client connects
io.on('connection', (socket) => {
console.log('a new client connected');
// let the client know that it's connected
socket.emit('greetings', 'You are now connected to the server through Socket IO');
// when receiving data from Arduino, tell the client what to do accordingly
serial.on('data', forwardMessage);
// log if an user disconnects
socket.on('disconnect', () => {
console.log('client disconnected');
// remove listener from Node EventEmitter
serial.removeListener('data', forwardMessage);
});
function forwardMessage(data) {
let message = data.toString().replace(/\n*/, '');
//riceve messaggi dal device corrispondente. Attenzione al nome messo anche sul codice Arduino
if (message.includes('Coinv')) {
socket.emit('CoinvChange', message.substring(7));
}
if (message.includes('Impor')) {
socket.emit('ImporChange', message.substring(7));
}
if (message.includes('Piace')) {
socket.emit('PiaceChange', message.substring(7));
}
if (message.includes('Cresc')) {
socket.emit('CrescChange', message.substring(7));
}
if (message.includes('Press')) {
socket.emit('PressChange', message.substring(7));
}
}
});
And finally this is how i use the message
const socket = io();
// log on browser console when socket is connected to server
socket.on('greetings', (message) => {
console.log(message);
});
// Caricamento Petali
socket.on('CoinvChange', (message) => {
console.log('coinv');
if(message<=6){
getFlowerObject ("petali", 1);
}
if(message>7 && message <=9) {
getFlowerObject ("petali", 2);
}
if(message>12) {
getFlowerObject ("petali", 3);
}
});
// Caricamento Sepali
socket.on('ImporChange', (message) => {
console.log('Impor');
if(message<=2){
getFlowerObject ("sepali", 1);
}
if(message>3 && message <=7) {
getFlowerObject ("sepali", 2);
}
if(message>8) {
getFlowerObject ("sepali", 3);
}
});
Thank you for your help!
Well, in the second snipped, you call just serial.on('data', forwardMessage);, and serial just refers to the firt one.
If you want to interact with the other ones, you have to call the same method also on serial1, serial2 and serial3, which you never use, instead.
As a sidenote, it's enugh to use const SerialPort = require('serialport'); just at the beginning (of the first snippet), then you can do
const serial1 = new SerialPort(...)
...
const serial2 = new SerialPort(...)
...
I'm new to node and trying to create a server with socketio to send messages to front (react). But when I run the server and many connections begin to be established it shows something like this :
Listening on port 3000
client connectedLv3LqI9EhmYTLBIIAAAA
client connectedrKLlxRPDkRs20L43AAAB
client connectedHAUuOADubCigGNTzAAAC
client connectedFF1dTRFe-HFublfgAAAD
Here is my code :
var express = require("express");
var app = express();
const http = require("http");
const SocketIO = require("socket.io");
//database connections
let user;
const MongoClient = require("mongodb").MongoClient;
const uri = "mongodb://localhost:27017/?replicaSet = rs01";
const client = new MongoClient(uri, {
useNewUrlParser: true,
useUnifiedTopology: true,
});
client.connect().then((db) => {
let requests = 0;
let responses = 0;
let transactions = 0;
const changeStream = client
.db("gardesh_pay_silk")
.collection("silk_profile")
.watch();
changeStream.on("change", (next) => {
console.log(next);
});
const silkProfileQueries = client
.db("gardesh_pay_silk")
.collection("silk_profile_queries")
.watch();
silkProfileQueries.on("change", (next) => {
console.log(next);
});
const silkSQLQueries = client
.db("gardesh_pay_silk")
.collection("silk_sqlquery")
.watch();
silkSQLQueries.on("change", (next) => {
console.log(next);
transactions += 1;
});
const silkRequest = client
.db("gardesh_pay_silk")
.collection("silk_request")
.watch();
silkRequest.on("change", (next) => {
console.log(next);
user.broadcast.emit("requested", next);
requests++;
});
const silkResponse = client
.db("gardesh_pay_silk")
.collection("silk_response")
.watch();
silkResponse.on("change", (next) => {
console.log(next);
responses += 1;
});
console.log(requests);
});
const server = http.createServer(app);
const io = SocketIO(server);
io.on("connection", (client) => {
user = client;
console.log("client connected"+client.id);
client.on("disconnect", () => {
console.log("user disconnected");
});
});
const port = process.env.PORT || 3000;
server.listen(port, () => console.log('Listening on port'+port));
I think that the problem is in this part of code:
const server = http.createServer(app);
const io = SocketIO(server);
io.on("connection", (client) => {
user = client;
console.log("client connected"+client.id);
client.on("disconnect", () => {
console.log("user disconnected");
});
});
and here is my connection in client side :
import { socketIOClient, io } from "socket.io-client";
import { type } from "jquery";
class Again extends React.Component {
timing=()=> {
this.props.req_changer(this.requests);
this.props.res_changer(this.responses);
this.props.trans_changer(this.transactions);
this.requests = 0;
this.responses = 0;
this.transactions = 0;
}
constructor(props) {
super(props);
this.state = {
endpoint: "http://127.0.0.1:4000",
requested: "undefined",
};
}
componentDidMount() {
this.count = setInterval(this.timing, 1000);
}
componentWillUnmount() {
clearInterval(this.count);
}
render() {
const socket = socketIOClient(this.state.endpoint);
socket.on("requested", (object) => {
if (object.ns.coll == "silk_request") {
this.requests++;
}
if (object.ns.coll == "silk_response") {
this.responses++;
}
if (object.ns.coll == "silk_sqlquery") {
this.transactions++;
}
});
return <div></div>;
}
}
export default Again;```
There is some issues in your code.
A) Client side:
Don't put the const socket & socket.on into the render method. The render method should contain only the visualizations (UI if you want)...
The creation of the socket constant -can be- in the class's constructor, or, outside of the class:
const socket = socketIOClient(this.state.endpoint);
class Again extends React.Component {
.
.
.
}
The listening of the sockets requests should be under the componentDidMount() function:
componentDidMount() {
socket.on("requested", (object) => {
if (object.ns.coll == "silk_request") {
this.requests++;
}
if (object.ns.coll == "silk_response") {
this.responses++;
}
if (object.ns.coll == "silk_sqlquery") {
this.transactions++;
}
});
}
B) Server side:
this is the important issue, the 'Client' attribute you used is a socket:
io.on("connection", (socket) => {
.
.
});
Every socket has a session. So for the same client we can have multiple sessions at the same time (for example, for every refreshing of the application). So you need to save the client's sessions. To do it, you can use the express session middleware:
io.use((socket, next) => {
app.sessionMiddleware(socket.request, {}, next);
});
io.on("connection", (socket) => {
const session = socket.request.session;
session.save();
});
You need also to save all sessions (if the client use multiple navigators for exemple, the server should send the requests for all of them, bu sockets), and then to delete them when client disconnecting:
var onlineClients = {};
var socketToClient = {};
io.on('connection', (socket) => {
const session = socket.request.session;
session.save();
if(onlineClients[session.clientID] === undefined){
onlineClients[session.clientID] = {
sockets: []
}
}
socketToClient[socket.id] = session.clientID;
onlineClients[session.clientID].sockets.push(socket);
.
.
.
socket.on('disconnect', () => {
let clientId = socketToClient[socket.id]
if(clientId){
let clientSockets = onlineClients[clientId].sockets
clientSockets = clientSockets.filter(s => socket.id !== s.id)
onlineClients[clientId].sockets = clientSockets
if(clientSockets.length === 0){
delete onlineClients[clientId]
}
}
});
Conclusion: your question title should be: multiple sessions established to socket io
Hope it can help you!
here is my node server code :
var app = express();
const http = require("http");
const SocketIO = require("socket.io");
// database connections
let user;
const MongoClient = require("mongodb").MongoClient;
const uri = "mongodb://localhost:27017/?replicaSet = rs01";
const client = new MongoClient(uri, {
useNewUrlParser: true,
useUnifiedTopology: true,
});
client.connect().then((db) => {
let requests = 0;
let responses = 0;
let transactions = 0;
const changeStream = client
.db("gardesh_pay_silk")
.collection("silk_profile")
.watch();
changeStream.on("change", (next) => {
console.log(next);
});
const silkProfileQueries = client
.db("gardesh_pay_silk")
.collection("silk_profile_queries")
.watch();
silkProfileQueries.on("change", (next) => {
console.log(next);
});
const silkSQLQueries = client
.db("gardesh_pay_silk")
.collection("silk_sqlquery")
.watch();
silkSQLQueries.on("change", (next) => {
console.log(next);
transactions += 1;
});
const silkRequest = client
.db("gardesh_pay_silk")
.collection("silk_request")
.watch();
silkRequest.on("change", (next) => {
console.log(next);
user.broadcast.emit("requested", next);
requests++;
});
const silkResponse = client
.db("gardesh_pay_silk")
.collection("silk_response")
.watch();
silkResponse.on("change", (next) => {
console.log(next);
responses += 1;
});
console.log(requests);
});
const server = http.createServer(app);
var onlineClients = {};
var socketToClient = {};
const io = SocketIO.listen(4000);
io.use((socket, next) => {
app.sessionMiddleware(socket.request, {}, next);
});
io.on('connection', (socket) => {
const session = socket.request.session;
this.user = socket;
session.save();
if (onlineClients[session.clientID] === undefined) {
onlineClients[session.clientID] = {
sockets: []
}
}
socketToClient[socket.id] = session.clientID;
onlineClients[session.clientID].sockets.push(socket);
socket.on('disconnect', () => {
let clientId = socketToClient[socket.id]
if (clientId) {
let clientSockets = onlineClients[clientId].sockets
clientSockets = clientSockets.filter(s => socket.id !== s.id)
onlineClients[clientId].sockets = clientSockets
if (clientSockets.length === 0) {
delete onlineClients[clientId]
}
}
});
});
const port = process.env.PORT || 3000;
server.listen(port, () => console.log(`Listening on port ${port}`));
it is just a very simple server that watch's for changes in mongodb...
Allright we are trying to make a chatbot, but we need it to recognize dutch language, this is the code we have so far, but we don't know how to add dutch language support. We already tried alot but we dont seem to get it working!
const builder = require('botbuilder');
const express = require('express');
const fs = require('fs');
const { Recognizer,LangNl } = require('node-nlp');
const modelName = './smalltalk.nlp';
const excelName = './smalltalk.xls';
// Creates a connector for the chatbot
const connector = new builder.ChatConnector({
appId: null,
appPassword: null,
});
// Creates a node-nlp recognizer for the bot
const recognizer = new Recognizer();
if (fs.existsSync(modelName)) {
recognizer.load(modelName);
} else {
recognizer.loadExcel(excelName);
recognizer.save(modelName);
}
// Creates the bot using a memory storage, with a main dialog that
// use the node-nlp recognizer to calculate the answer.
const bot = new builder.UniversalBot(connector, (session) => {
recognizer.nlpManager.addLanguage("nl","Nl","NL")
recognizer.recognize(session, (err, data) => {
session.send(data.answer || 'I don\'t understand');
session.endDialog();
});
}).set('storage', new builder.MemoryBotStorage());
recognizer.setBot(bot, false);
// Creates the express application
const app = express();
const port = process.env.PORT || 3000;
app.post('/api/messages', connector.listen());
app.listen(port);
console.log(`Chatbot listening on port ${port}`);
I have an API endpoint in my Node/Express app. The endpoint is responsible to upload files. There are several stages involved in the upload process. like image conversion, sending images to another third party API, etc. I am using socket.io to tell the client about the current stage of upload.
The problem is, The socket connection works fine in the first call, but in my second call to the endpoint, the socket connection runs twice and retains the data which I sent in the previous call.
Here's my code:
server.js
import ClientsRouter from './api/routes/clients';
import express from 'express';
import http from 'http';
import io from 'socket.io';
const port = process.env.PORT || 3000;
const app = express();
const server = http.Server(app);
const socket = io(server);
app.set('socket', socket);
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.set('view engine', 'ejs');
app.use(express.static('dist'))
app.use('/uploads', express.static('uploads'));
app.use('/api/clients', ClientsRouter);
server.listen(port, () => console.log(`Server Listening on ${process.env.URL}`));
api/routes/clients.js
import express from 'express';
import ClientsController from '../controllers/clients';
ClientsRouter.post('/uploadClientData/', clientDataUpload.array('client_data'), ClientsController.uploadClientData);
controllers/clients.js
const uploadClientData = async (req, res) => {
try {
const files = req.files
const clientFolder = req.body.client_folder
const { dbxUser } = req;
const team_member_id = req.body.team_member_id;
const data = req.files.map( i => ({team_member_id, destination: i.destination.substring(1), filename: i.filename, status: 1 } ))
const io = req.app.get("socket");
console.log("Outside Socket", data); //This contains my currently passed data
io.on('connection', async socket => {
console.log("Socket Connection established");
console.log("Inside Socket", data); //But This contains my current data aling with the data that I passed in previous call
await uploadQueue.collection.insertMany(data)
socket.emit('upload stage', { upload_stage: 2, progress: 33 })
await helpers.convertImagesToWebResolution(team_member_id, req.body.dpi, req.body.resolution);
socket.emit('upload stage', { upload_stage: 3, progress: 66 })
await helpers.uploadImagesToDropbox(team_member_id, dbxUser, clientFolder)
socket.emit('upload stage', { upload_stage: 4, progress: 100 })
})
res.status(200).json({message: "Uploaded"});
} catch (error) {
console.log(error)
res.status(500).json({
error
});
}
}
And in my front-end react component
componentDidMount(){
const { currentFolder } = this.props;
this.setState({ client_folder: currentFolder }, () => this.afterFileSelect())
}
componentDidUpdate(prevProps){
const { selectedFiles } = this.props;
if(prevProps.selectedFiles !== selectedFiles){
this.afterFileSelect()
}
}
afterFileSelect = async () => {
const { selectedFiles, setSelectedFiles, currentFolder, user, uploadSettings} = this.props;
let formData = new FormData()
formData.append('client_folder', currentFolder)
formData.append('team_member_id', user.team_member_id)
formData.append('resolution', uploadSettings.resolution.split("x")[0])
formData.append('dpi', uploadSettings.dpi)
for(let selectedFile of selectedFiles){
formData.append('client_data', selectedFile)
}
let uploadResp = uploadSettings.convert_web_res ? await uploadClientData(formData) : await dropboxDirectUpload(formData)
const endpoint = uploadResp.config.url;
const host = endpoint.substring(0, endpoint.indexOf("api"));
const socket = socketIOClient(host);
socket.on("upload stage", data => {
this.setState({upload_stage: data.upload_stage, progress: data.progress})
data.upload_stage === 4 && this.setState({client_folder: ""})
})
}
Also I want to know if this is the correct way to to track upload progress?