0

I'm using the fetch api to post and retrieve user data which works great, but I also want to implement sioket.io into fetch to emit and broadcast my selected data from mysql database.

server-side:

var server = require('http').createServer(app);
var io = require('socket.io')(server);


app.use(function(request, result, next) {
    result.setHeader("Access-Control-Allow-Origin", "*");
    next();
})



dotenv.config({ path: './.env' });


var sqlDatabase = mysql.createConnection({
    host: process.env.DATABASE_HOST,
    user: process.env.DATABASE_USER,
    password: process.env.DATABASE_PASSWORD,
    database: process.env.DATABASE,

});


app.set('view engine', 'hbs');

app.use(express.urlencoded({ extended: false }));
app.use(express.json());
app.use(cookieParser('key cat'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(expressValidator());
app.use(cors());


const publicDirectory = path.join(__dirname, './public')
app.use(express.static(publicDirectory));

var options = {
    host: process.env.DATABASE_HOST,
    user: process.env.DATABASE_USER,
    password: process.env.DATABASE_PASSWORD,
    database: process.env.DATABASE,

};

var sessionStore = new MySQLStore(options);


app.use(session({
    secret: 'key cat',
    resave: false,
    saveUninitialized: false,
    store: sessionStore,
    cookie: {
        httpOnly: true,
        secure: false,
        maxAge: 60000
    }
}));

app.use(passport.initialize());
app.use(passport.session());




sqlDatabase.connect((err) => {
    if (err) {
        console.log(err);
    } else {
        console.log('mysql is connected')
    }
});

io.on('connection', (socket) => {
    console.log('socket connect successful');
    socket.on('new_message', function(results) {
        console.log('Client says', results);


    })


    app.get("/get_messages", function(request, result) {
        sqlDatabase.query("SELECT users.username, comments.comments, comments.date FROM users INNER JOIN comments ON users.user_id=comments.user_id",
            function(error, results) {
                io.emit('new_message', JSON.stringify(results))

            });
    });
});




app.use((req, res, next) => {
    res.locals.isAuthenticated = req.isAuthenticated();
    next();
});

where the problem is I think:

io.on('connection', (socket) => {
    console.log('socket connect successful');
    socket.on('new_message', function(results) {
        console.log('Client says', results);


    })


    app.get("/get_messages", function(request, result) {
        sqlDatabase.query("SELECT users.username, comments.comments, comments.date FROM users INNER JOIN comments ON users.user_id=comments.user_id",
            function(error, results) {
                io.emit('new_message', JSON.stringify(results))

            });
    });
});

If I use

result.end(JSON.stringify(results));

the results are fine, except that I also want to emit and broadcast data, which is why I'm using sioket.io.

client-side:

function loadcomments() {
    fetch('http://localhost:5502' + '/get_messages')

    .then(response => {
            if (response.ok) {
                console.log('success')
                console.log(response);
            } else {
                console.log('failure')
            }
            return response.json();
        })
        .then(function(data) {

                output.innerHTML = '';

                data.forEach(function(user) {

                    io.emit("new_message", comments.value)


                    io.on("new_message", function(results) {
                        console.log("Server says", results);

                        var newUser = document.createElement("div");
                        var newName = document.createElement("h5");
                        var newDate = document.createElement("h5");
                        var newMessage = document.createElement("h6");

                        var display_username = document.createTextNode(JSON.stringify(user.username));
                        var display_date = document.createTextNode(JSON.stringify(user.date));
                        var display_comments = document.createTextNode(JSON.stringify(user.comments));


                        newName.appendChild(display_username);
                        newDate.appendChild(display_date);
                        newMessage.appendChild(display_comments);

                        newUser.appendChild(newName);
                        newUser.appendChild(newDate);
                        newUser.appendChild(newMessage);
                        output.appendChild(newUser);

                        console.log(data);

                    }).catch(function(error) {
                        console.log(error)

Been going around in circles on this one. I checked out similar questions, but I know I'm doing something, just don't know what.

I'm a noob, by the way. Any help is appreciated. Thank you in advance.

Answer altered: After making some adjustments, the only output I get is the first data entry. Also, when I submit a comment, multiple responses of the first data entry is returned: [![enter image description here][1]][1]

Here's where I changed the code:

 .then(function(data) {

            output.innerHTML = '';
            data.forEach(function(user) {

                io.emit("new_message", comments.value)

                io.on("new_message", function(data) {
                    console.log("Server says", data);

                    var newUser = document.createElement("div");
                    var newName = document.createElement("h5");
                    var newDate = document.createElement("h5");
                    var newMessage = document.createElement("h6");

                    var display_username = document.createTextNode(JSON.stringify(user.username));
                    var display_date = document.createTextNode(JSON.stringify(user.date));
                    var display_comments = document.createTextNode(JSON.stringify(user.comments));
    ```


  [1]: https://i.stack.imgur.com/i0bsd.jpg
  • First of all, move that `app.get("/get_messages")` out of the `io` callback. `app.get()` is express setup that tells the server how to reply to the `fetch("/get_messages")` request, and this happens independently of io. –  Jul 29 '20 at 05:41
  • How exactly do you want this to work? The main point of socket.io is to be able to refresh a client if something happens on the server, so if you want to refresh the comments for all clients if one of them adds a comment, what I would do is simply call `io.emit("refresh", comments)` when a client posts something. –  Jul 29 '20 at 05:51
  • Okay so, I did what you said, which I had actually done before posting. The issue I'm having is that onload and on the submit btn, the only thing that gets output is the first comment entry in my database, and the response is duplicated on a single button submit, –  Jul 29 '20 at 07:22
  • ,Please have I look above where I added the changes with the image. –  Jul 29 '20 at 07:27
  • Nevermind, I solved the problem by restructuring. –  Jul 29 '20 at 07:50
  • Cool; if this is solved, feel free to remove the question –  Jul 29 '20 at 07:59
  • Nah, can't remove questions, when people have already put in inputs. SO doesn't allow. Besides, this may help someone down the line. Thanks for your input by the way. –  Jul 29 '20 at 08:02
  • @ChrisG I did some more reading and I appreciate you pointing out a couple of insufficiencies (problems) in my approach. I tried to better understand what could be the problem and I found this particular answer very informative (https://stackoverflow.com/questions/51448297/share-server-from-socket-io-between-files). This is something I seemed to be struggling with before - a bit different scenario to the above question (using the socket in different places in the backend). My apologies for taking so much of your time and honestly thanks for that. I hope we are good. – Jakub A Suplicki Jul 30 '20 at 00:59
  • @JakubASuplicki Hey, no worries, we're good :) –  Jul 30 '20 at 06:15

1 Answers1

0

server side:

io.on('connection', (socket) => {
    console.log('socket connect successful');

    socket.on('new_message', function(message) {
        console.log('Client says', message);
        io.emit('new_message', message)


    })
})


app.get("/get_messages", function(request, result) {
    sqlDatabase.query("SELECT users.username, comments.comments, comments.date FROM users INNER JOIN comments ON users.user_id=comments.user_id",
        function(error, results) {
            result.end(JSON.stringify(results));
        });
});

client-side

function loadcomments() {
    fetch('http://localhost:5502' + '/get_messages')

    .then(response => {
            if (response.ok) {
                console.log('success')
                console.log(response);
            } else {
                console.log('failure')
            }
            return response.json();
        })
        .then(function(data) {
            io.emit("new_message", data)
            io.on("new_message", function(data) {
                console.log("Server says", data);
                output.innerHTML = '';
                data.forEach(function(user) {

                    var newUser = document.createElement("div");
                    var newName = document.createElement("h5");
                    var newDate = document.createElement("h5");
                    var newMessage = document.createElement("h6");

                    var display_username = document.createTextNode(JSON.stringify(user.username));
                    var display_date = document.createTextNode(JSON.stringify(user.date));
                    var display_comments = document.createTextNode(JSON.stringify(user.comments));


                    newName.appendChild(display_username);
                    newDate.appendChild(display_date);
                    newMessage.appendChild(display_comments);

                    newUser.appendChild(newName);
                    newUser.appendChild(newDate);
                    newUser.appendChild(newMessage);
                    output.appendChild(newUser);

Please be aware of how I structure this part:

  .then(function(data) {
            
            io.emit("new_message", data)
            io.on("new_message", function(data) {
                
                console.log("Server says", data);
                output.innerHTML = '';
                data.forEach(function(user) {

                    var newUser = document.createElement("div");

The problem I was having is that I kept getting first entry in database as output and duplicated. Placing this

io.emit("new_message", data);
io.on("new_message", function(data) {

above this:

output.innerHTML = '';
data.forEach(function(user) {

solved the problem.