how to put websocket in to database (mongoDB/mongoose)?

Viewed 3389

when a player login, i put his websocket in database(mongoose mixed) and save it.however, after some testing i understand that if i put websocket in database , websocket becames a bunch of data and loses its websocket properties and cant send message to user. On the other hand, if i put websocket in array, i can totally send message. Is there anyway to cast that "bunch of data" to websocket again ? because i dont want to have one massive array that holds users websockets.

app.js (my server)

const express = require('express');
const { createServer } = require("http");
const mongoose = require('mongoose');
const config = require('./config');
const WebSocket = require('ws');
const activeUsers = require("./Models/ActiveUsersModel");
const app = express();

app.use(express.json());
app.use(express.urlencoded({ extended: true }));
const server = createServer(app);
app.locals.wsArray = [];
app.use("/RegisterApi", require("./Routes/RegisterApi/RegisterApi"));
app.use("/MatchMakingApi", require("./Routes/MatchMakingApi/MatchMakerApi"));

const wss = new WebSocket.Server({ server });



server.listen(config.PORT, function () {
    console.log(`im listening at ${config.PORT}`);
    mongoose.connect(config.MONGODB_URI, {
        useNewUrlParser: true, useUnifiedTopology: true, useCreateIndex: true,
        useFindAndModify: false
    })

});
//function to split parameters from url
function getVars(tempVars) {
    var userObject = {};
    tempVars.forEach((a) => {
        var splited = a.split("=");
        userObject[splited[0]] = splited[1];
    });
    return userObject;
}

wss.on("connection",async (ws, request) => {

    console.log("Total connected clients: ", wss.clients.size);
    var tempVars = request.url.split("?")[1].split("&");
    var userObject = getVars(tempVars);

    console.log(userObject);
    const currentUser = await activeUsers.findOne({ _id: userObject.parentID });
    console.log('user with id ' + currentUser.currentActiveUser._id + ' login');

    currentUser.webSocket = ws;
    await currentUser.markModified('webSocket');
    await currentUser.save();
    app.locals.wsArray.push(ws);


});


const db = mongoose.connection;

db.on('error', (err) => console.log(err))

active user schema


const ActiveUsers = new schema({

    currentActiveUser: Users.schema,
    webSocket: mongoose.Mixed,
    isSearchingGame: {
        type: Boolean,
        default: false
    },
    isInMatch: {
        type: Boolean,
        default: false
    }

});

const ActiveUsersModel = mongoose.model("ActiveUsers", ActiveUsers);
module.exports = ActiveUsersModel;

matchmaking api( middleware of server) where error occur

router.post('/searchMatch'/*,verifyToken*/, async (req, res) => {


    const currentUserData = await activeUsers.findOne({ _id: req.body.tempID });
    if (currentUserData.currentActiveUser.money < req.body.money) { res.send('insufficient money'); return; }

    req.app.locals.wsArray[0].send('aaaa'); // sends message
    await currentUserData.webSocket.send('aaaa'); // gets error " send() isnt a function"
});

1 Answers

You can't store Websocket connections: the objects you call ws as your first parameter to your wss.on('connection' ...) event handler. You can't store them in MongoDB, and you can't serialize them to JSON: they're not pure data, but rather an interface to your machine's network stack.

So, you need to maintain them in your nodejs program. The Websocket server (wss) has a clients object. You can do

     wss.clients.forEach(...)

to look at all the connections. You can add attributes to your connections, something like this:

wss.on("connection", async (ws, request) => {
    ws.locals = {}
    console.log("Total connected clients: ", wss.clients.size)
    var tempVars = request.url.split("?")[1].split("&")
    var userObject = getVars(tempVars)
    ws.locals.parentId = userObject.parentId
    const currentUser = await activeUsers.findOne({ _id: userObject.parentID })

    wss.on("message", function (event) {
        /* retrieve the user */
        currentUser = await activeUsers.findOne({ _id: this.locals.parentId})               
    })
})

This lets you get back to the user for a particular connection when you get an incoming message.

Related