How do you send data to socket with different emit? - javascript

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"

Related

Why am I getting ReferenceError: db is not defined

For some reason I cannot get axios to connect to the DB. Its is a MSQL server and when I use app.get in the server file I can get data returned but when using express DB connection just doesn't persist. In postman I can return a result with all my code on server.js receiving the entire table. This is what I want. When moving everything to axios and routing it to have less code on my server nothing returns anymore. nothing is broken except i get ReferenceError: db is not defined in nodemon.
HomePage
const express = require('express')
const app = express()
const mysql = require('mysql')
const morgan = require('morgan')
//middleware
app.use(express.json())
app.use(morgan('dev'))
//Connect to DB
const db = mysql.createConnection({
user : 'root',
password : '******',
database : 'avengers'
})
db.connect((err) => {
if(err){
console.log(err)
}
console.log('MySql Connected...')
})
//Routes
app.use('/avengers', require('./routes/avengerRouter.js'))
//error handling
app.use((err, req, res, next) => {
console.log(err)
return res.send({errMsg: err.message})
})
app.listen(9000, () => {
console.log("The server is running on port 9000")
})
Server.js
import React, {useState, useEffect} from 'react'
import axios from 'axios'
import AvengersTable from './AvengerTable.js'
function delay(time) {
return new Promise(resolve => setTimeout(resolve, time));
}
export default function Main(){
const [tableState, setTableState] = useState('')
useEffect(() => {
async function getTableData() {
axios.get('/avengers')
await delay(300)
.then(res => {
// setTableState(res.data)
console.log(res)
})
.catch(err => console.log(err.response.data.errMsg))
} getTableData()
}, [])
return (
<div className="Main">
{/* <AvengersTable tableState={tableState}/> */}
</div>
)
}
avengerRouter.js
const express = require('express');
const avengerRouter = express.Router();
function delay(time) {
return new Promise(resolve => setTimeout(resolve, time));
}
avengerRouter
// all data from avengers table http://localhost:9000/avengers
.get('/', (req, res) => {
let sql = 'SELECT * FROM avengers.avengers'
db.query(sql, (err, result) => {
if(err) console.log(err)
console.log(result)
})
})
module.exports = avengerRouter;
Create a file named db.js that includes a DB connection.
const mysql = require('mysql')
const db = mysql.createConnection({
user : 'root',
password : '******',
database : 'avengers'
});
export default db;
Usage of db at top of your HomePage
const db = require('./db.js');
db.connect((err) => {
if(err){
console.log(err)
}
console.log('MySql Connected...')
});
// Other codes goes below
...
And finally usage in your avengerRoute.js
const express = require('express');
const avengerRouter = express.Router();
// Forgotten line here
const db = require('./db.js');
function delay(time) {
return new Promise(resolve => setTimeout(resolve, time));
}
avengerRouter
// all data from avengers table http://localhost:9000/avengers
.get('/', (req, res) => {
let sql = 'SELECT * FROM avengers.avengers'
db.query(sql, (err, result) => {
if(err) console.log(err)
console.log(result)
})
})
module.exports = avengerRouter;

Integrating websocket at React client

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");
});
});

The content-type is not JSON compatible

With the following code Im trying to create a accessToken with the simple-oauth2 library in node.
I have the server.js and the app.js files. The problem is that every time I try to call the getToken method it returns the following error The content-type is not JSON compatible. Im calling the /token endpoint with postman where the request´s Content-Type is set to application/json.
Has anyone encountered this problem before?
server.js
'use strict';
const app = require('express')()
const bodyParser = require('body-parser')
app.use(bodyParser.json())
const port = 3000;
module.exports = (cb) => {
app.listen(port, (err) => {
if (err) return console.error(err);
console.log(`Express server listening at http://localhost:${port}`);
return cb({
app
});
});
};
app.js
const createApplication = require('./server');
const simpleOauthModule = require('simple-oauth2');
require('dotenv').config()
const credentials = {
client: {
id: process.env.CLIENT_ID,
secret: process.env.CLIENT_SECRET
},
auth: {
tokenHost: 'http://localhost:3000/test'
}
};
createApplication(({ app }) => {
app.post('/token', async (req, res) => {
const oauth2 = simpleOauthModule.create(credentials);
var contype = req.headers['content-type']; // <-- application/json
const tokenConfig = {
username: "test",
password: "1234"
};
try {
const result = await oauth2.ownerPassword.getToken(tokenConfig); //Error occuress
const accessToken = oauth2.accessToken.create(result);
console.log('Access Token: ', accessToken);
} catch (error) {
console.log('Access Token Error', error.message);
}
});
app.post('/test', async (req, res) => {
});
});

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

No response from node js (mongoose)

I send request from React with:
export const loadItems = () => async dispatch => {
await axios
.get("http://localhost:8000/api/users")
.then(response => {
console.log(response.users);
dispatch(dataLoaded(response.users));
})
.catch(err => {
dispatch(dataLoadFailed(err));
});
};
But there is no response, and the server does not take request, here is my server app code:
server.js
// a lot of requires
const todoRoutes = require("./routes/serverRoute");
const url = "mongodb://localhost:27017/taskManager";
const app = express();
mongoose.Promise = global.Promise;
mongoose.connect(
url,
{ useNewUrlParser: true },
function(err) {
if (err) {
console.log(err);
} else console.log("Database connected");
}
);
app.get("/", (req, res) => {
res.sendFile(path.join(__dirname, "/public/index.html"));
});
// cors allow
app.use("/api", todoRoutes);
app.listen(8000, () => {
console.log("API started");
});
And this is a controller I use, it's all good with Schema and DB, I checked with output to console from the node, users is defined and contains data
const mongoose = require("mongoose");
const User = require("../models/UserModel");
module.exports = {
getUsers(req, res) {
User.find().exec((err, users) => {
if (err) {
console.log(err);
return res.send({ err });
} else {
console.log(users);
return res.send({ users });
}
});
}
};
And this is my router:
module.exports = router => {
router.get('/users', userController.getUsers);
}
Ok, I got it on my own. Problem was here:
router.get('/users', userController.getUsers);
It supposed to be like this:
router.get('/users', userController.getUsers());

Categories

Resources