I am creating a node.js app with a react client and an express/socketio backend and passport authentication. I'm trying to emit a socketio event from the client and then have the backend respond but it seems that the request is getting lost somewhere between when it's emitted to when the backend processes it.
Below are all the files I thought relevant to the problem at hand.
Backend is on localhost:5000 and client is on localhost:3000
As I said, everything goes well until the line marked in Organization.js. But at/after that line, the event is presumably sent but none of the corresponding routes in socket.js are hit.
Backend start file - app.js
'use strict';
import express from 'express'
import { createServer } from 'http'
import path from 'path'
import { fileURLToPath } from 'url';
import logger from 'morgan'
import cookieParser from 'cookie-parser'
import index from './routes/index.js'
import session from 'express-session'
import passport from './src/auth.js'
import { Server } from 'socket.io'
import { CrashCollector } from 'crashcollector'
new CrashCollector('crash_logs', (err, exit) => {
console.log('Cleaning up...')
console.log('Saving some stuff...')
// Calls callback funtion executing process.exit()
// You can also just write process.exit() here
exit()
})
const app = express();
const server = createServer(app)
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const io = new Server(server, {
cookie: { maxAge: 24 * 60 * 60 * 1000 },
cors: {
origin: 'http://localhost:3000',
credentials: true
}
})
const sessionMiddleware = session({
secret: "changeit", resave: false,
saveUninitialized: false
});
// uncomment after placing your favicon in /public
//app.use(favicon(__dirname + '/public/favicon.ico'));
app.use(sessionMiddleware)
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use(passport.initialize());
app.use(passport.session());
app.use('/', index);
// catch 404 and forward to error handler
app.use(function (req, res, next) {
let err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handlers
// development error handler
if (app.get('env') === 'development') {
app.use(function (err, req, res, next) {
console.log('dev error handler')
res.status(err.status || 500);
res.end()
});
}
// production error handler
// no stacktraces leaked to user
app.use(function (err, req, res, next) {
console.log('prod error handler')
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});
app.set('port', process.env.PORT || 3000); //process.env.PORT = 5000
server.listen(app.get('port'), _ => {
console.log(`Server listening on port ${app.get('port')}`)
})
export {
io,
sessionMiddleware
}
Backend - socket.js
import { io, sessionMiddleware } from '../app.js'
import passport from '../src/auth.js'
import { getSequel } from '../src/database.js'
const wrap = middleware => (socket, next) =>
middleware(socket.request, {}, next);
io.use((_, next) => {
console.log('connection attempt')
next()
})
io.use(wrap(sessionMiddleware));
io.use(wrap(passport.initialize()));
io.use(wrap(passport.session()));
io.use((con, next) => {
console.log('socket check', !!con.request.user)
if (con.request.user) {
next()
} else {
next(new Error('unauthorized'))
}
});
io.on('connection', (con) => {
console.log(`new connection ${con.id}`);
con.on('confirm', cb => {
cb(con.request.user.name);
});
con.on('eventTable', _ => {
console.log('eventTable')
con.emit(con.request?.user?.getEvents()?.map(e => e.toJSON()))
})
});
Client start file - index.js
import React from 'react'
import { createRoot } from 'react-dom/client';
import { BrowserRouter } from 'react-router-dom';
import './index.css';
import App from './App/App';
import { io } from 'socket.io-client'
import configs from '../package.json'
const container = document.getElementById('root');
const root = createRoot(container);
export const socket = io.connect(configs.proxy, { //configs.proxy = http://localhost:5000
withCredentials: true
})
socket.on('connect', _ => {
console.log('socket connect', socket.id)
})
socket.on('connect_error', _ => {
console.log('socket connect_error')
})
socket.on('disconnect', _ => {
console.log('socket disconnect')
})
socket.prependAny((eventName, ...args) => {
console.log(eventName, args)
})
root.render((
<React.StrictMode>
<BrowserRouter>
<App />
</BrowserRouter>
</React.StrictMode>
));
Client - App.js
import React from 'react'
import { Route, Routes } from 'react-router-dom'
import './App.css'
import Login from './pages/Login'
import Home from './pages/Home'
import LoginCheck from './helper/LoginCheck'
const App = () => {
console.log('app')
return (
<Routes>
<Route exact path="/" element={<LoginCheck />} >
<Route index element={<Home />} />
</Route>
<Route path="/login" element={<Login />} />
</Routes>
)
}
export default App;
Client - Home.js
import React, { useState } from 'react';
import Org from './Organization'
const Home = () => {
console.log('home')
return localStorage.getItem('isOrg') ? (
<Org />
) : (
'Employee'
)
}
export default Home;
Client - Organization.js
import React, { createElement, useEffect, useState } from 'react';
import { useNavigate } from 'react-router-dom'
import Countdown from 'ds-countdown'
import { socket } from '../../index'
const Org = () => {
console.log('org')
const setTable = (raffles) => {
console.log('cb eventTable')
JSON.parse(raffles).forEach(raffle => {
const row = createElement('tr')
const name = createElement('td')
name.append(raffle.name)
const num = createElement('td')
num.append(raffle.num)
const started = Date.parse(raffle.start) >= Date.now()
const countdown =
<><td>
<p style={{ color: started ? 'red' : 'green' }}>
{started ? 'Starts' : 'Ends'} in:
<div id={`timer${raffle.id}`} />
</p>
</td></>
const action = createElement('td')
const edit = createElement('button')
edit.addEventListener('click', e => {
//goto edit at raffle.id
alert('edit')
})
const end = createElement('button')
end.addEventListener('click', e => {
//set timer to 0
alert('start/end')
})
action.append(edit)
action.append(end)
row.append(name)
row.append(num)
row.append(countdown)
row.append(action)
document.getElementById('eventTable').append(row)
new Countdown({
id: `timer${raffle.id}`,
targetTime: started ?
raffle.end : raffle.start
})
})
}
useEffect(() => {
console.log('useEffect')
**socket.emit('eventTable')** //THIS IS WHERE IT BREAKS
socket.on('eventTable', setTable)
return () => {
socket.off('eventTable', setTable)
}
})
return (<>
<h1 style={{ textAlign: 'center' }}>
{localStorage.getItem('name')}
</h1>
<table style={{ marginLeft: 'auto', marginRight: 'auto' }}
border="1"><caption>
<h3>Scheduled Raffles</h3>
</caption>
<tbody id="eventTable">
<tr>
<th>Name</th>
<th>Num Participants</th>
<th>Countdown</th>
<th>Action</th>
</tr>
<tr>
<td>Test</td>
<td>10</td>
<td>10:10:04</td>
<td><button> Edit </button> <button> End Now </button> <button> Stop </button></td>
</tr>
</tbody>
</table>
</>);
}
export default Org;
I get no errors on the front end. In fact, the client says that a connection has been established, thanks to the socket.on('connect') in index.js. None of the console.logs in the socket.js file are getting activated, so I have reason to believe that the route isn't getting hit. I also activated Debugging on socket but the logs there don't help me very much:
Server listening on port 5000
socket.io:server incoming connection with id 1wpATq-xiQ1jHttwAAAA +2s
socket.io-parser decoded 0 as {"type":0,"nsp":"/"} +0ms
socket.io:client connecting to namespace / +0ms
socket.io:namespace adding socket to nsp / +0ms
socket.io:socket socket connected - writing packet +0ms
socket.io:socket join room f6lna-kbntjuwffpAAAB +3ms
socket.io-parser encoding packet {"type":0,"data":{"sid":"f6lna-kbntjuwffpAAAB"},"nsp":"/"} +7ms
socket.io-parser encoded {"type":0,"data":{"sid":"f6lna-kbntjuwffpAAAB"},"nsp":"/"} as 0{"sid":"f6lna-kbntjuwffpAAAB"} +1ms
POST /login 200 653.887 ms - 37
socket.io-parser decoded 2["eventTable"] as {"type":2,"nsp":"/","data":["eventTable"]} +3s
socket.io:socket got packet {"type":2,"nsp":"/","data":["eventTable"]} +3s
socket.io:socket emitting event ["eventTable"] +0ms
socket.io:socket dispatching an event ["eventTable"] +1ms
socket.io-parser decoded 2["eventTable"] as {"type":2,"nsp":"/","data":["eventTable"]} +15ms
socket.io:socket got packet {"type":2,"nsp":"/","data":["eventTable"]} +2ms
socket.io:socket emitting event ["eventTable"] +0ms
socket.io:socket dispatching an event ["eventTable"] +1ms
The server side socket.emit call should have an event name as the first argument.
con.emit('eventTable', con.request?.user?.getEvents()?.map(e => e.toJSON()))
The problem was I was starting the server before initializing the sockets.js routes. I had to do some reconfiguring on the backend, but basically the way I fixed it was making an express router in sockets.js, importing said router to app.js, then doing app.use('/socket', sockets), BEFORE calling server.listen(PORT). Below is the final state of my backend:
new Backend file - init.js:
import express from 'express'
import { createServer } from 'http'
import session from 'express-session'
import { Server } from 'socket.io'
import { CrashCollector } from 'crashcollector'
new CrashCollector('crash_logs', (err, exit) => {
console.log('Cleaning up...')
console.log('Saving some stuff...')
// Calls callback funtion executing process.exit()
// You can also just write process.exit() here
exit()
})
const app = express();
const server = createServer(app)
const io = new Server(server, {
cookie: { maxAge: 24 * 60 * 60 * 1000 },
cors: {
origin: 'http://localhost:3000',
credentials: true
}
})
const sessionMiddleware = session({
secret: "changeit", resave: false,
saveUninitialized: false
});
export {
server,
app,
io,
sessionMiddleware
}
app.js:
'use strict';
import express from 'express'
import path from 'path'
import { fileURLToPath } from 'url';
import logger from 'morgan'
import cookieParser from 'cookie-parser'
import index from './routes/index.js'
import passport from './src/auth.js'
import { server, app, sessionMiddleware } from './init.js'
import sockets from './routes/sockets.js'
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
// uncomment after placing your favicon in /public
//app.use(favicon(__dirname + '/public/favicon.ico'));
app.use(sessionMiddleware)
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use(passport.initialize());
app.use(passport.session());
app.use('/', index);
*app.use('/sockets', sockets)* //This is the bit I was missing
// catch 404 and forward to error handler
app.use(function (req, res, next) {
let err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handlers
// development error handler
if (app.get('env') === 'development') {
app.use(function (err, req, res, next) {
console.log('dev error handler')
res.status(err.status || 500);
res.end()
});
}
// production error handler
// no stacktraces leaked to user
app.use(function (err, req, res, next) {
console.log('prod error handler')
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});
app.set('port', process.env.PORT || 3000);
server.listen(app.get('port'), _ => {
console.log(`Server listening on port ${app.get('port')}`)
})
sockets.js:
import { io, sessionMiddleware } from '../init.js'
import passport from '../src/auth.js'
import { getSequel } from '../src/database.js'
import { Router } from 'express'
const router = Router()
const wrap = middleware => (socket, next) =>
middleware(socket.request, {}, next);
io.use((_, next) => {
console.log('connection attempt')
next()
})
io.use(wrap(sessionMiddleware));
io.use(wrap(passport.initialize()));
io.use(wrap(passport.session()));
io.use((con, next) => {
console.log('socket check', !!con.request.user)
if (con.request.user) {
next()
} else {
next(new Error('unauthorized'))
}
});
io.on('connection', (con) => {
console.log(`new connection ${con.id}`);
con.on('confirm', cb => {
cb(con.request.user.name);
});
con.on('eventTable', cb => {
con.request.user.getEvents()
.then(events => events.map(e => e.JSON()))
//I switched to a callback here, rather than emitting a new event
.then(mappedArray => cb(mappedArray))
})
});
export default router
Related
Im using a Express server and trying to implement Socket.io for the first time, and I keep getting this whenever I open it:
GET /socket.io/?EIO=4&transport=polling&t=OKgNATB 404 0.526 ms - 149
GET /socket.io/?EIO=4&transport=polling&t=OKgNBww 404 0.332 ms - 149
GET /socket.io/?EIO=4&transport=polling&t=OKgNDOV 404 0.411 ms - 149
app.ts:
import express from 'express';
import morgan from 'morgan';
import favicon from 'serve-favicon';
import path from 'path';
import cors from 'cors';
import { errorManager } from './middlewares/errors_middleware.js';
import { ordersRouter } from './routers/OrdersRouter.js';
import { usersRouter } from './routers/UsersRouter.js';
import { createServer } from 'http';
import { Server } from 'socket.io';
export const app = express();
const httpServer = createServer(app);
const io = new Server(httpServer, {
cors: {
origin: '*',
},
});
io.on('connection', (socket) => {
console.log('HELLO');
});
app.use(favicon(path.join('.', 'public', 'favicon.ico')));
app.use(cors());
app.use(morgan('dev'));
app.use(express.json());
app.get('/', (_req, res, next) => {
res.send('H');
next();
});
Routers
app.use('/orders', ordersRouter);
app.use('/users', usersRouter);
app.use(errorManager);
index.ts:
import http from 'http';
import createDebug from 'debug';
import { app } from './app.js';
import { dbConnect } from './dbconnect/dbconnect.js';
const debug = createDebug('StoryLine:INDEX');
const port = 3300;
const server = http.createServer(app);
server.on('listening', () => {
const addr = server.address();
if (addr === null) return;
let bind: string;
if (typeof addr === 'string') {
bind = 'pipe ' + addr;
else {
bind =
addr.address === '::'
? `http://localhost:${addr?.port}`
: `port ${addr?.port}`;
}
debug(`SERVER: Listening on: ${bind}`);
});
server.on('error', (error: Error, response: http.ServerResponse) => {
response.write(error.message);
response.end();
});
dbConnect()
.then((mongoose) => {
debug(
'Database connection -> SUCCESSFUL: ',
mongoose.connection.db.databaseName
);
server.listen(port);
})
.catch((error) => {
debug('Database connection -> COULD NOT CONNECT');
server.emit(error);
});
I simply want to get a console.log telling me that a user is connecting. I have tried following the Socket.io docs for express but its not working for me.
I've created a MERN application and I'm trying to deploy it to heroku. When I try to build the application and test it with 'heroku local', everything seems to work, the local server starts and the database connects, however the initial page '/' is a blank screen. But if I type a different route like '/rankings/', it will work.
Below is a copy of my express server
// all imports below
const express = require("express");
const mongoose = require('mongoose');
const fileUpload = require("express-fileupload")
const p4pBoxingRankings = require("./p4pBoxingRankings")
const divisionalRankings = require("./divisionalRankings.js")
const ufcP4pRankings = require("./ufcRankings.js")
const ufcDivisionalRankings = require("./ufcDivisionalRankings.js")
let bodyParser = require('body-parser');
let cors = require('cors');
const app = express();
const path = require('path');
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(fileUpload());
app.use(cors());
app.use(express.static('public'));
app.set('port', (process.env.PORT || 8080));
// code to connect datbase below
const URI = process.env.MONGODB_URI || "mongodb+srv://skunk_hunnt:P#cquiaop4p224#cluster0.4cqzd.mongodb.net/Fight_Auction?retryWrites=true&w=majority"
mongoose.connect(URI, { useNewUrlParser: true })
.then(() => {
console.log('Database connected...')
}).catch((err) => {
console.log(err);
})
// code to stringify items below
const ItemSchema = new mongoose.Schema({
itemDescription: { type: String },
askingPrice: { type: String },
itemDetails: { type: String },
pictures: {type: String}
});
const fightItem = mongoose.model('Item', ItemSchema);
// all axios requests below
app.get("/items", function(req, res){
//make a DB query and send back all the items
fightItem.find({},(err, data)=>{
res.send(data)
})
})
app.get("/rankings", async(req, res) => {
res.send(p4pBoxingRankings);
})
app.get("/rankings/divisions", async(req, res) => {
res.send(divisionalRankings);
})
app.get("/rankings/divisions/ufcp4p", async(req, res) => {
res.send(ufcP4pRankings);
})
app.get("/rankings/divisions/ufcp4p/ufcdivisions", async(req, res) => {
res.send(ufcDivisionalRankings);
})
app.post("/items", function(req, res){
let item = new fightItem();
item.itemDescription = req.body.item.itemDescription
item.askingPrice = req.body.item.askingPrice
item.itemDetails = req.body.item.itemDetails
item.pictures = req.body.item.pictures
item.save((err,res)=>{
})
});
app.post('/upload', (req, res) => {
if (req.files === null) {
return res.status(400).json({ msg: 'No file uploaded' });
}
const file = req.files.file;
file.mv(`${__dirname}/public/${file.name}`, err => {
if (err) {
console.error(err);
return res.status(500).send(err);
}
res.json({ fileName: file.name, filePath: `/public/${file.name}` });
});
});
// if (process.env.NODE_ENV === 'production') {
// // Serve any static files
// app.use(express.static(path.join(__dirname, 'build')));
// // Handle React routing, return all requests to React app
// app.get('*', function(req, res) {
// res.sendFile(path.join(__dirname, '/build/index.html'));
// });
// }
app.use("", express.static(path.join(__dirname, 'build')));
// Handle React routing, return all requests to React app
app.get('*', function(req, res) {
res.sendFile(path.join(__dirname, '/build/index.html'));
});
app.listen(app.get('port'), function() {
console.log('Server started on port '+app.get('port'));
});
Here is my react router.
import React from "react";
import { BrowserRouter, Route, Switch, } from "react-router-dom";
import BrowseItemsPage from "../components/BrowseItemsPage.jsx";
import HomePage from "../components/HomePage.jsx";
import NewsAndRankings from "../components/NewsAndRankingsPage.jsx";
import NotFoundPage from "../components/NotFoundPage.jsx";
import SellItemPage from "../components/SellItemPage.jsx";
const AppRouter = () => (
<BrowserRouter>
<div>
<Switch>
<Route path="/" component={HomePage} exact={true}/>
<Route path="/browse-items" component={BrowseItemsPage}/>
<Route path="/sell-items" component={SellItemPage}/>
<Route path="/rankings" component={NewsAndRankings}/>
<Route component={NotFoundPage}/>
</Switch>
</div>
</BrowserRouter>
);
export default AppRouter;茀
So I have spent hours trying to figure out why express-fileupload is not working for me.. I have also tried using multer, but I keep getting req.files as either undefined or null. From looking around, it seems like it may have to do with my middleware bc the form is multipart data. I still can't figure out how to get this to work though. Forgive me if it's a stupid mistake.
express app (index.js)
const path = require('path')
const express = require('express')
const morgan = require('morgan')
const compression = require('compression')
const session = require('express-session')
const passport = require('passport')
const SequelizeStore = require('connect-session-sequelize')(session.Store)
const db = require('./db')
const sessionStore = new SequelizeStore({db})
const PORT = process.env.PORT || 8080
const app = express()
const socketio = require('socket.io')
const fileUpload = require('express-fileupload')
var methodOverride = require('method-override');
var multipart = require('multipart');
module.exports = app
// This is a global Mocha hook, used for resource cleanup.
// Otherwise, Mocha v4+ never quits after tests.
if (process.env.NODE_ENV === 'test') {
after('close the session store', () => sessionStore.stopExpiringSessions())
}
/**
* In your development environment, you can keep all of your
* app's secret API keys in a file called `secrets.js`, in your project
* root. This file is included in the .gitignore - it will NOT be tracked
* or show up on Github. On your production server, you can add these
* keys as environment variables, so that they can still be read by the
* Node process on process.env
*/
if (process.env.NODE_ENV !== 'production') require('../secrets')
// passport registration
passport.serializeUser((user, done) => done(null, user.id))
passport.deserializeUser(async (id, done) => {
try {
const user = await db.models.user.findByPk(id)
done(null, user)
} catch (err) {
done(err)
}
})
const createApp = () => {
// logging middleware
app.use(morgan('dev'))
// body parsing middleware
app.use(express.json())
app.use(express.urlencoded({extended: true}))
//file uploads
app.use(fileUpload()); //express-fileupload
// app.use(multer({dest:'./uploads/'})); //multer
// compression middleware
app.use(compression())
// session middleware with passport
app.use(
session({
secret: process.env.SESSION_SECRET || 'my best friend is Cody',
store: sessionStore,
resave: false,
saveUninitialized: false
})
)
app.use(passport.initialize())
app.use(passport.session())
// auth and api routes
app.use('/auth', require('./auth'))
app.use('/api', require('./api'))
// static file-serving middleware
app.use(express.static(path.join(__dirname, '..', 'public')))
// any remaining requests with an extension (.js, .css, etc.) send 404
app.use((req, res, next) => {
if (path.extname(req.path).length) {
const err = new Error('Not found')
err.status = 404
next(err)
} else {
next()
}
})
// sends index.html
app.use('*', (req, res) => {
res.sendFile(path.join(__dirname, '..', 'public/index.html'))
})
// error handling endware
app.use((err, req, res, next) => {
console.error(err)
console.error(err.stack)
res.status(err.status || 500).send(err.message || 'Internal server error.')
})
}
const startListening = () => {
// start listening (and create a 'server' object representing our server)
const server = app.listen(PORT, () =>
console.log(`Mixing it up on port ${PORT}`)
)
// set up our socket control center
const io = socketio(server)
require('./socket')(io)
}
const syncDb = () => db.sync()
async function bootApp() {
await sessionStore.sync()
await syncDb()
await createApp()
await startListening()
}
// This evaluates as true when this file is run directly from the command line,
// i.e. when we say 'node server/index.js' (or 'nodemon server/index.js', or 'nodemon server', etc)
// It will evaluate false when this module is required by another module - for example,
// if we wanted to require our app in a test spec
if (require.main === module) {
bootApp()
} else {
createApp()
}
app.post('/photos/upload', async (req, res, next) => {
try {
console.log(req.files, 'req.files ------')
if (req.files === null) {
res.status(400).send("no file uploaded");
}
console.log(req.files, 'req.files!!!----')
const file = req.files.file;
file.mv(`${__dirname}/client/public/uploads/${file.name}`, err => {
if(err) {
console.error(err);
return res.status(500).send(err);
}
res.json('hello')
// res.json({ fileName: file.name, filePath: `uploads/${file.name}`});
})
// const {name, data} = req.files.picture;
// await knex.insert({name: name, img: data}).into('picture');
} catch (err) {
next(err)
}
}
)
File upload form (CreateListingTest.js)
import React, {useEffect, useState} from 'react'
import {connect} from 'react-redux'
import {useForm} from 'react-hook-form'
import {addNewListing} from '../store/listings'
import axios from 'axios'
/**
* COMPONENT
*/
export const CreateListing = props => {
// const {register, handleSubmit, errors} = useForm()
const [file, setFile] = useState('');
const [filename, setFilename] = useState('Choose File')
const [uploadedFile, setUploadedFile] = useState({});
const onChange = (e) => {
setFile(e.target.files[0]);
setFilename(e.target.files[0].name);
console.log('onChange' , file, filename)
}
const onSubmit = async e => {
e.preventDefault();
const formData = new FormData();
formData.append('files', file);
try {
const res = axios.post('/photos/upload', formData, {
headers: {
'Content-Type' : 'multipart/form-data'
}
});
console.log(res.data, 'res.data in test')
const { fileName, filePath } = res.data;
setUploadedFile({ fileName, filePath });
} catch(err) {
console.log(err, 'error')
}
}
return (
<div className="create-listing">
<h2>Create New Listing</h2>
<div className="all-listings">
<form className="create-listing-form" onSubmit={onSubmit} action="/upload" method="POST">
<input
type="file"
id="img"
name="file"
accept="image/*"
onChange={onChange}
/>
<label>{filename}</label>
<div className="create-listing-form-section">
<input type="submit" value="Upload"/>
</div>
</form>
</div>
</div>
)
}
/**
* CONTAINER
*/
const mapState = state => {
return {
// myListings: state.listings.myListings,
user: state.user
}
}
const mapDispatch = (dispatch, state) => {
return {
addNewListing: (userId, listing) => dispatch(addNewListing(userId, listing))
}
}
export default connect(mapState, mapDispatch)(CreateListing)
I have a problem connecting to my front end server socket on my back end
in my front end ( react ) i have this:
import React, { Component } from 'react';
import {Form,FormGroup, Label, Input, Button, Alert} from 'reactstrap';
import Header from '../../components/header';
import io from 'socket.io-client';
export default class Login extends Component {
constructor(props) {
super(props)
console.log(this.props);
this.state = {
message: this.props.location.state?this.props.location.state.message: '',
};
}
signIn = () => {
let socket = null;
async function connect () {
socket = io.connect('http://localhost:8080/');
}
connect();
}
render(){
return(
<div className="col-md-6">
<Header title="ReactJS Login"/>
<hr className="my-3"/>
<Button color="primary" onClick={this.signIn}> Entrar </Button>
</div>
);
}
}
in my back end:
const usersRouter = require('./routes/userRoutes');
const postRouter = require('./routes/post');
const matchRouter = require('./routes/matchRoutes');
const app = express();
const router = express.Router();
const socket = require('socket.io');
const server = app.listen(
port,
console.log(`Server running in ${process.env.NODE_ENV} mode on port ${port}`)
);
let io = require('socket.io')(server);
app.set("io", io);
io.on('connection', socket => {
require('./routes/socket')(socket);
});
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(cors());
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});''
app.use(express.json());
app.use('/', router);
module.exports = app;
in my router folder i have this:
const socketController = require ('../controllers/SocketController');
module.exports = (socket) => {
socket.on('myevent', (message) => {
console.log('bateu aq');
socket.emit('myEvent', {message: 'hello world'});
});
};
I am also wondering how I could add a jwt validate middleware to my route that I have
I also don't know if this is the best code structure I can have to work with socket using routes and controllers, if anyone can help me how to improve it.
There is no code in your example that is actually interacting with the server. Please update the code as follows to determine the connections and events are working as per the question comments.
React:
async function connect () {
socket = io.connect('http://localhost:8080/');
socket.on('hello', (message) => {
console.log(message);
});
socket.on('myevent', message => {
console.log(message);
});
socket.emit('myevent', {foo: 'bar'});
}
Express:
module.exports = (socket) => {
socket.emit('hello', {data: 'this is a message'});
socket.on('myevent', (message) => {
console.log(message);
socket.emit('myevent', {message: 'OK'});
});
};
I'm trying to log the user activity on my api to a mongo collection. The problem is, when I add a middleware above the routes, I can log the request. But at that time the middleware have no way to know whether the request is a success or a failure. If I add the middleware below the routes it won't get called.
Now I run res.send() at the end of each route function. If I remove this and try to set only the status, the api get's stuck (From the front it says pending and the api does nothing). Any idea how to do this?
My app.js:
import express from 'express';
import logger from 'morgan';
import bodyParser from 'body-parser';
import helmet from 'helmet';
import filter from 'content-filter';
import cors from 'cors';
import dotenv from 'dotenv';
import mongoose from 'mongoose';
import Raven from 'raven';
import { createFirebaseAuth } from 'express-firebase-auth';
import routes from './routes';
import { DB_CONFIG } from './config';
import firebase from './lib/firebase';
import permissions from './middleware/permissions';
import userLogs from './middleware/userLog';
// Setup environment config
dotenv.config();
// Initiate the app
const app = express();
// Connect to the database
mongoose.connect(DB_CONFIG.uri, DB_CONFIG.options);
mongoose.Promise = global.Promise;
// Configure error reporting
if (process.env.RAVEN_DSN) {
Raven.config(process.env.RAVEN_DSN).install();
app.use(Raven.requestHandler());
}
// Apply the middleware
app.use(filter());
app.use(helmet.xssFilter());
app.use(helmet.hidePoweredBy());
app.use(helmet.noSniff());
app.use(cors());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(logger('dev'));
// Add the firebase authenticatior
const firebaseAuth = createFirebaseAuth({
firebase,
checkEmailVerified: true,
checkEmailVerifiedIgnoredUrls: ['/users', '/users/updatepassword']
});
app.use(firebaseAuth);
// Add the permissions module
app.use(permissions);
// Add the routes
app.use('/', routes);
// Catch 404 and forward to error handler
app.use((req, res, next) => {
const err = new Error('Not Found');
err.status = 404;
next(err);
});
// The user logs module
app.use(userLogs);
// Configure error reporting
if (process.env.RAVEN_DSN) {
app.use(Raven.errorHandler());
}
// Error handler
app.use((err, req, res) => {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.send({ error: 'Something failed!' });
});
// Setup the ip and port
app.set('port', process.env.APP_PORT || 8000);
app.set('ip', process.env.APP_IP || '127.0.0.1');
// Start the app
app.listen(app.get('port'), () => {
/* eslint-disable no-console */
console.log('***************************************************************');
console.log(`Server started on ${Date(Date.now())}`);
console.log(`Server is listening on port ${app.get('port')}`);
console.log('***************************************************************');
});
module.exports = app;
The line app.use(userLogs); is where I attach the logs.
My routes file look like this:
const router = express.Router();
const routeHandler = ({ path, callback, method }) => {
router.route(path)[method](async (req, res, next) => {
try {
await callback(req, res, next);
} catch (error) {
next(error);
}
});
};
routeHandler({ path: '/companies', callback: createCompany, method: 'post' });
routeHandler({ path: '/companies', callback: updateCompany, method: 'put' });
Let's take the updateCompany function:
export const updateCompany = async (req, res) => {
const companyData = req.body;
// Get the data and update the company
res.send({ message: 'Success!' });
};
UserLogs middleware:
const userLogs = async (req, res, next) => {
console.log(req);
console.log('--------------------------------------------------------------------------');
};