Integrating websocket at React client - javascript

I am trying to connect a backend layer running on localhost, below is the source code:
const { createServer } = require("http");
const cors = require("cors");
const photos = require("./photos");
const app = require("express")();
const WebSocket = require("ws");
app.use(cors());
app.get("/", (req, res) => {
res.status(200).json({});
});
app.get("/photos", (req, res) => {
res.status(200).json({ photos });
});
const clients = new Set();
app.post("/photos/:id", (req, res) => {
const photo = photos.find((p) => {
return p.id === req.params.id;
});
photo.status= "PENDING";
// Send back an approval
const timeout = (3 + Math.floor(Math.random() * 4)) * 1000;
setTimeout(() => {
photo.status = "APPROVED";
clients.forEach((ws) => {
ws.send(JSON.stringify({ event: "APPROVED", photo }));
});
}, timeout);
res.status(200).json({ photo });
});
const port = process.env.PORT || 3001;
const server = createServer(app);
server.listen(port, () => {
console.log(`Starting server on port ${port}`);
});
const wss = new WebSocket.Server({ path: "/ws", server });
wss.on("connection", (ws) => {
clients.add(ws);
console.log("WebSocket connection established");
ws.on("close", () => {
clients.delete(ws);
console.log("WebSocket connection closed");
});
});
As on react client we can't use "ws" so I tried using both "websocket" package but I am not able to connect to "http" as it is not supported. Below is the source code:
import React from "react";
import { w3cwebsocket as W3CWebSocket } from "websocket";
const client = new W3CWebSocket('http://localhost:3001/ws');
// const client = new W3CWebSocket('ws://localhost:3001');
function App() {
React.useEffect(
() => {
client.onopen = () => {
console.log('WebSocket Client Connected');
};
client.onmessage = (message) => {
console.log(message);
};
}, []
)
return null
}
Need help at client level to connect to 'http://localhost:3001/ws' to establish and listen connection.

You are connecting to the wrong url. In following line on the server, you specify a path as /ws .
const wss = new WebSocket.Server({ path: "/ws", server });
So you need to connect to the specified path.
const client = new W3CWebSocket('ws://localhost:3001/ws');
If you remove the path: "/ws" from your createServer, the url ws://localhost:3001 (notice, no /ws path.. )should also work as expected.
Here's an example which worked on my machine ( without react, it's for showing socket connection.)
Client
var W3CWebSocket = require('websocket').w3cwebsocket;
const client = new W3CWebSocket('ws://localhost:3001/ws');
client.onopen = () => {
console.log('WebSocket Client Connected');
};
client.onmessage = (message) => {
console.log(message);
};
client.onerror = function() {
console.log('Connection Error');
};
Server
const { createServer } = require("http");
const cors = require("cors");
const app = require("express")();
const WebSocket = require("ws");
app.use(cors());
const port = process.env.PORT || 3001;
const server = createServer(app);
server.listen(port, () => {
console.log(`Starting server on port ${port}`);
});
const wss = new WebSocket.Server({ path: "/ws", server });
wss.on("connection", (ws) => {
console.log("WebSocket connection established");
ws.on("close", () => {
console.log("WebSocket connection closed");
});
});

Related

How do you send data to socket with different emit?

I want to send data to 2 different components using socket.io, now the first emit works but the second isn't even activated, I tried to invert the order of them inside io.on function and only the first written one works. Is the second waiting for the first emit to end? How can I make them work in parallel?
This is my code:
import {createServer} from "http";
import socketIo from "socket.io";
import express from "express";
import cors from "cors";
import mongoose from "mongoose";
import { MONGODB_URL } from "./config/config";
import jwt from "jsonwebtoken";
import { watchLeaves } from "./database/controllers/LeaveControllers";
import { watchCalendars } from "./database/controllers/calendarControllers";
const port = process.env.PORT || 3333;
mongoose.connect(MONGODB_URL, {
useNewUrlParser: true,
useUnifiedTopology: true,
});
const db = mongoose.connection;
db.on("error", console.error.bind(console, "connection error:"));
db.once("open", () => {
console.log("Connected to database");
});
const app = express();
app.use(cors());
app.get("/", (req, res) => {
res.send({ response: "I am a websocket!" }).status(200);
});
const verifySocketAuth = (header) => new Promise((resolve, reject) => {
if (typeof header !== "undefined") {
const headerArray = header.split(" ")
const token = headerArray[1]
return jwt.verify(token, "Bearer", (err, auth) => {
if (err) reject(new Error(err))
else resolve(auth)
})
}
})
const server = createServer(app);
const io = socketIo(server, {
cors: {
origin: "*",
methods: ["GET", "POST"],
}
});
io.use(async (socket, next) => {
const header = socket.handshake.headers["authorization"];
await verifySocketAuth(header)
console.log("token", await verifySocketAuth(header))
next()
});
const getLeavesAndEmit = async (socket) => {
const lastRecord = await watchLeaves();
socket.emit("FromLeaves", lastRecord);
};
const getCalendarsAndEmit = async (socket) => {
const lastRecord = await watchCalendars();
console.log("last record calendars==>", lastRecord);
socket.emit("FromCalendars", lastRecord);
};
io.on("connection", async (socket) => {
console.log("Client connected");
await getLeavesAndEmit(socket);
await getCalendarsAndEmit(socket);
socket.on("disconnect", () => {
console.log("Client disconnected");
});
});
server.listen(port, () => console.log(`Soket Server listening on ${port}`));
I guess socket.emit doesn't return a Promise, so when you do await getLeavesAndEmit(socket) you are awaiting something that will never resolve. After socket.emit try to return something static from your async function, like return "done"

http.createserver and net.createserver in node.js together

I have 2 scripts in node js. One uses 'http' and other uses 'net'. I want to make these scripts together in one script. My 'http' script are as below:
const http = require('http');
const hostname = 'localhost';
const port = 3000;
const server = http.createServer((req, res) => {
console.log(req.headers);
res.statusCode = 200;
res.end('<html><body><h1>Hello, World!</h1></body></html>');
})
server.listen(port, hostname);
'net' script:
var net = require('net');
var client = new net.Socket();
client.connect(4352, 'x.x.x.x', function() {
console.log('Connected');
client.write('%1POWR 1\r\n');
});
client.on('data', function(data) {
console.log('Received: ' + data);
client.destroy(); // kill client after server's response
});
client.on('close', function() {
console.log('Connection closed');
});
My purpose is to run the 'net' script once I start the 'http' script.
Wrap the whole net script in a exported function:
var net = require('net');
module.exports = () => {
var client = new net.Socket();
client.connect(4352, 'x.x.x.x', function() {
console.log('Connected');
client.write('%1POWR 1\r\n');
});
client.on('data', function(data) {
console.log('Received: ' + data);
client.destroy(); // kill client after server's response
});
client.on('close', function() {
console.log('Connection closed');
});
}
Import and execute the exported function in http script:
const http = require('http');
const hostname = 'localhost';
const port = 3000;
require('path/to/net/script')() //Add to anywhere you like
const server = http.createServer((req, res) => {
console.log(req.headers);
res.statusCode = 200;
res.end('<html><body><h1>Hello, World!</h1></body></html>');
})
server.listen(port, hostname);

SOCKET.IO LISTEN HTTPS

i had my app with http, but i want add https, but i don't know how enable https on socket.io. The problem when i replaced http in 'require('socket.io)(https ....)' socket.io launch 404 error.
const http = require('http').Server(app);
const io = require('socket.io')(http, { pingInterval: 2000, pingTimeout: 7000,});
var https = require('https');
var fs = require('fs');
io.on('connect', socket => {
socket.on('ask', function(msg) {
search
.query(msg, socket.user, socket.token)
.then(result => {
socket.emit('response', result);
})
.catch(err => {
console.log(err);
socket.emit('response', {
msg: { text: "Lo siento, no puedo entender eso " },
type: 'error',
});
});
});
skills.registerClient(socket, socket.user).catch(err => {
console.warn('Failed to register client', err);
});
});
const port = await global.db.getGlobalValue('port');
http.listen(port, () => {
console.log(`Server started on http://localhost:${port}`);
});
const sslPort = '1443';
const server = https.createServer(httpsOptions, app)
.listen(sslPort, () => {
console.log(`Https server on https://localhost:${sslPort}`);
});
I am Currently using this:
const fs = require('fs');
const options = {
rejectUnauthorized: true,
key: fs.readFileSync('<SSL KEY PATH>/privkey.pem'),
cert: fs.readFileSync('<SSL CERT PATH>/fullchain.pem')};
const app = require('https').createServer(options);
const io = require('socket.io')(app);
io.on('connection', socket => {
console.log("New Connection");
socket.on('ask', function(msg) {
//your code here
});
});
app.listen(<PORT>); //e. g. 8080, Integer
First, you need to create cert and key for ssl.
After key and cert are generated, you can code like the following:
const express = require('express')
const https = require('https')
const fs = require('fs')
const port = 8888
const cert = fs.readFileSync('/path/to/your_cert.cert')
const key = fs.readFileSync('/path/to/your_key.key')
const SSLOption = {
key, cert
}
app = express()
let server = https.createServer(SSLOption, app)
server.listen(port, () => {
console.log('server started on port: ' + port)
})
app.get('/', (req, res) => {
res.send('Working good...')
})
const io = require('socket.io')(server)
io.on('connection', (socket) => {
console.log(socket)
})
enter image description here
This is the error.
var httpsOptions = {
key: fs.readFileSync(path.join(__dirname + '/ssl/localhost-key.pem')),
cert: fs.readFileSync(path.join(__dirname + '/ssl/localhost.pem'))
};
This is my httpsOptions.

How to make a Server for Websocket secure with node.js

My websocket server, based on node.js, works for ws:// but not for wss://
The server runs on my Raspberry Pi B 3+. Now that I have changed ws:// to wss:// in my JavaScript file, it does not work anymore.
The node.js server:
const WebSocket = require('ws');
var wss = new WebSoket.Server({ port: 4445 });
wss.on('connection', function connection(ws) {
console.log("New client connected.");
ws.on('message', function incoming(data) {
console.log(data);
ws.close();
});
ws.on('close', function close() {
console.log("Client disconnected.");
});
});
The JavaScript client:
var connection = new Websocket('wss://myDomain:4445');
connection.onopen = function () {
connection.send("Hello");
connection.close();
}
connection.onerror = function (error) {
console.log(error);
connection.lose();
}
'myDomain' is a subdomain that refers to the IP of the Raspberry Pi via dns.
I get the following error:
WebSocket connection to 'wss://myDomain:4445/' failed: Error in
connection establishment: net::ERR_CONNECTION_CLOSED
Maybe it will help you
Example:
Node server.js
const express = require("express");
const http = require("http");
const socketIo = require("socket.io");
const axios = require("axios");
const port = process.env.PORT || 4445;
const index = require("./routes/index");
const app = express();
app.use(index);
const server = http.createServer(app);
const io = socketIo(server);
let interval;
io.on("connection", socket => {
console.log("New client connected");
if (interval) {
clearInterval(interval);
}
interval = setInterval(() => getApiAndEmit(socket), 10000);
socket.on("disconnect", () => {
console.log("Client disconnected");
});
});
const getApiAndEmit = async socket => {
try {
const res = await axios.get(
"https://b.application.com/api/v1/scores?expand=createdBy"
);
socket.emit("FromAPI", res.data); // Emitting a new message. It will be consumed by the client
} catch (error) {
console.error(`Error: ${error.code}`);
}
};
server.listen(port, () => console.log(`Listening on port ${port}`));
Client in React
import socketIOClient from "socket.io-client";
class App extends Component {
constructor (props) {
super(props);
this.state = {
scores: []
endpoint: "http://127.0.0.1:4445"
}
}
componentDidMount() {
const { endpoint } = this.state;
const socket = socketIOClient(endpoint);
socket.on("FromAPI", data => this.setState({ scores: data }));
}
render () {
<div>
</div>
)
}
}
export default App;

The socket.io connection returns an empty array. Ways to receive data in React without reloading the page?

I create a chrome extension in React. I am trying to download data via socket.io. I didn't get any errors, but the array is empty.
I should set the header and token, but I do not know where to do it in the app.js server. Where can I set:
const token = '12345'
headers: {
  'Authorization': `Bearer $ {token}`
}
How can I set port in server app.js and endpoint in client app.jsx if I create chrome extension?
Is there any other way (other than socket.io) to receive data in the method componentDidMount() in React without reloading the page?
When I go to the address http://127.0.0.1:4001, the console.log displays to me New client connected and Error: undefined
Server
//app.js
const express = require("express");
const http = require("http");
const socketIo = require("socket.io");
const axios = require("axios");
const port = process.env.PORT || 4001;/How port in `chrome extension?`
const index = require("./routes/index");
const app = express();
app.use(index);
const server = http.createServer(app);
const io = socketIo(server); // < Interesting!
const token = "12345";
let interval;
io.on("connection", socket => {
console.log("New client connected");
if (interval) {
clearInterval(interval);
}
interval = setInterval(() => getApiAndEmit(socket), 10000);
socket.on("disconnect", () => {
console.log("Client disconnected");
});
});
const getApiAndEmit = async socket => {
try {
const res = await axios.get(
"https://b.application.com/api/v1/scores?expand=createdBy"
); // Getting the data from DarkSky
socket.emit("FromAPI", res.data); // Emitting a new message. It will be consumed by the client
} catch (error) {
console.error(`Error: ${error.code}`);
}
};
server.listen(port, () => console.log(`Listening on port ${port}`));
//index.js
const express = require("express");
const router = express.Router();
router.get("/", (req, res) => {
res.send({ response: "I am alive" }).status(200);
});
module.exports = router;
Client
//app.jsx
import socketIOClient from "socket.io-client";
class App extends Component {
constructor (props) {
super(props);
this.state = {
scores: []
endpoint: "http://127.0.0.1:4001" /How endpoint in `chrome extension`?
}
}
componentDidMount() {
const { endpoint } = this.state;
const token = "12345";
const socket = socketIOClient(endpoint);
socket.on("FromAPI", data => this.setState({ todos: data }));
}
render () {
<div>
</div>
)
}
}
export default App;
I solved it:
const getApiAndEmit = async socket => {
try {
const res = await axios.get(
"https://b.application.com/api/v1/scores?expand=createdBy",
headers: {
Authorization: `Bearer ${token}`
}
);
socket.emit("FromAPI", res.data); // Emitting a new message. It will be consumed by the client
} catch (error) {
console.error(`Error: ${error.code}`);
}
};
-----------Try Replacing app.js:- -----------------
const express = require("express");
const http = require("http");
const socketIo = require("socket.io");
const axios = require("axios");
const port = process.env.PORT || 4001;/How port in `chrome extension?`
const index = require("./routes/index");
const app = express();
app.use(index);
const server = http.createServer(app);
const io = socketIo(server); // < Interesting!
const token = "12345";
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
let interval;
io.on("connection", socket => {
console.log("New client connected");
if (interval) {
clearInterval(interval);
}
interval = setInterval(() => getApiAndEmit(socket), 10000);
socket.on("disconnect", () => {
console.log("Client disconnected");
});
});
const getApiAndEmit = async socket => {
try {
const res = await axios("https://b.application.com/api/v1/scores?expand=createdBy", {
method: 'GET',
headers: {
'Content-Type': 'application/json',
"Access-Control-Allow-Origin": "*",
'token': token
}
}); // Getting the data from DarkSky
console.log("res.data:- "+JSON.stringify(res.data,null,4));
socket.emit("FromAPI", res.data); // Emitting a new message. It wil be consumed by the client
} catch (error) {
console.error(`Error: ${error.code}`);
}
};
server.listen(port, () => console.log(`Listening on port ${port}`));
Try modifying app.jsx as:
import socketIOClient from "socket.io-client";
class App extends Component {
constructor(props) {
super(props);
this.state = {
scores: [],
receivedData:[],
endpoint: "https://b.application.com/api/v1/scores?expand=createdBy",
token: "12345"
}
this.onDataReceived = this.onDataReceived.bind(this);
this.socket = socketIOClient(this.state.endpoint, {
extraHeaders: {
Authorization: `Bearer ${this.state.token}`
}
});
this.socket.on("FromAPI", this.onDataReceived);
}
onDataReceived(receivedData) {
console.log("receivedData ", receivedData);
this.setState({
receivedData: receivedData
});
}
render() {
return(
<div></div>
)
}
}
export default App;
Try modifying app.js: function getApiAndEmit
replace the line: socket.emit("FromAPI", res.data);
io.emit("FromAPI", res.data);

Categories

Resources