I am making a chat app, but when I write a message and press send, my node server keep giving me:
TypeError: Cannot read property 'trim' of undefined
or
TypeError: Cannot read property 'room' of undefined
Then it crashes, I don't know why, everything else was working normally, only the server crashes. I've tried fixing it myself to no avail, without the server, you can probably guess what will happen.
Here's the code:
index.js:
var express = require ('express')
var http = require ('http')
var { addUser, removeUser, getUser, getUsersInRoom } = require ('./user')
var router = require ('./router')
var { callbackify } = require('util')
var PORT = process.env.PORT || 5000
var app = express()
var server = http.createServer(app)
var io = require('socket.io')(server, {
cors: {
origin: '*',
}
});
app.use(router)
io.on('connection', (socket) => {
socket.on('join', ({ name, room }, callback) =>{
var { error, user } = addUser({ id: socket.id, name, room })
if(error) return callback(error)
socket.emit('message', { user: 'admin', text: `Now, I- Oh, ${user.name}, welcome to room ${user.room},enjoy your time here!` })
socket.broadcast.to(user.room).emit('message',{user: 'admin', text:`Hey, just coming in to say ${user.name} joined, also, how you guys doin.`})
socket.join(user.room)
callback()
})
socket.on('sendMessage', (message, callback) => {
var user = getUser(socket.id)
io.to(user.room).emit('message', { user: user.name, text: message })
callback()
})
socket.on('disconnect', () => {
console.log('Aw they left :(');
});
});
server.listen(PORT, () => console.log (`This is Index, port ${PORT} secured, lots of unfixable bug`))
user.js(where the problem exist):
const users = []
const addUser = ({ id, name, room }) =>{
name = name.trim().toLowerCase()
room = room.trim().toLowerCase()
const existingUser = users.find((user) => user.room === room && user.name === name)
if(existingUser){
return {error: 'Username is already taken you dumbass'}
}
const user = {id, name, room}
users.push(user);
return{ user }
}
const removeUser = (id) =>{
const index = users.findIndex ((user) => user.id === id)
if(index !== -1) {
return users.splice(index, 1)[0]
}
}
const getUser = (id) => users.find((user) => user.id === id)
const getUsersInRoom = (room) => users.filter((user) => user.room === room)
module.exports = { addUser, removeUser, getUser, getUsersInRoom }
and router.js:
const express = require('express')
const router = express.Router();
router.get('/*', (req,res) =>{
res.send(`Server is up and running`)
})
module.exports = router;
That is all the server file because the problem comes from server, not client (there is not enough words in here so I have to do this)
Thanks in advance!
Both error is due to the application is trying to access a subfunction/subparameter of an undefined value.
Are you sure the client is sending the right param when emitting "join" ?
what you can do on the server side is do some validation and check if its undefined and set a default value if it is.
name = name ? name.trim().toLowerCase() : "default_name";
room = room ? room.trim().toLowerCase() : "default_room";
as for the Room of undefined error is most likely due to this part of the app
const existingUser = users.find((user) => user.room === room && user.name === name)
try checking if users.length, if it's 0 then don't bother doing .find(), or you can add validation inside the .find() function to check if user is undefined,then return false;
const existingUser = users.find((user) => user && user.room === room && user.name === name)
socket.on('join', ({ name, room }, callback) =>{
Where do you get name and room from?
Related
I want to find the socket instance using the socket id
I saw a solution on stackoverflow and tried it, but it didn't work.
Make specific socket leave the room is in
exports.removeParticipant = ({ data }) => {
const { roomId, toBeRemovedSocketId } = data;
const roomFound = rooms.find((room) => room.id === roomId);
if (roomFound) {
const user = roomFound.connectedUsers.find(
(user) => user.socketId === toBeRemovedSocketId
);
/* Removing the user from the room.connectedUserArray . */
roomFound.connectedUsers = roomFound.connectedUsers.filter(
(user) => user.socketId !== toBeRemovedSocketId
);
//i tried this but it throws error
let socket = io.sockets.connected[toBeRemovedSocketId];
socket.leave(roomId);
}
my own research led me to a solution.
let socket=io.sockets.sockets.get(toBeRemovedSocketId);
socket.leave(roomId)
I created a discord.js bot and after some time I wanted to add a servers list command
that sends a message with an embed for each server containing: Server Name, Member Count, Server Avatar (As The Embed Thumbnail), Server Owner ID and Most importantly I don't want anyone to be able to use this command except for me so maybe I add a constant with my ID?,
I can't really come up with a code for it, but anyways... here's the format of one of the commands:
if((args[0] === settings.prefix + "deletereactions" || args[0] === settings.prefix + "dr") && msg.member.hasPermission("ADMINISTRATOR")){
//deletereactions #channel
let channel = msg.mentions.channels.array()[0];
if(!channel) return;
let db = client1.db("rbot");
let collection = db.collection("reactions");
collection.deleteOne({channel : channel.id}, function(err){
if(err) console.log(err);
msg.reply("**✅ Done!**");
})
}
})
and here's my command handler:
const settings = require("./settings.json");
const Discord = require("discord.js");
const client = new Discord.Client();
const fs = require("fs");
const MongoClient = require("mongodb").MongoClient;
const url = "my_mongodb_url";
const mongoClient = new MongoClient(url, { useUnifiedTopology: true });
const moment = require("moment");
const { CommandCursor } = require("mongodb");
let client1;
client.login(settings.token);
client.on("ready", ready =>{
console.log("Ready");
mongoClient.connect(function(err, cli){
client1 = cli;
})
client.user.setActivity(`${settings.activity}`, { type: 'LISTENING' })
})
client.on("message", async msg =>{
let args = msg.content.split(' ');
if(msg.channel.type !== "text") return;
if(msg.channel.type === "text"){
let db = client1.db("rbot");
let collection = db.collection("reactions");
collection.findOne({channel : msg.channel.id}, function(err, result){
if(err) console.log(err);
if(result){
for(let i = 0; i < result.reactions.length; i++){
msg.react(result.reactions[i]).catch(err =>{
if(err) collection.deleteOne({channel : msg.channel.id}, function(err){
if(err) console.log(err);
})
});
In Your Command (Run Or Execute Function):
For 1 User:
if (message.author.id != "YOUR ID") return;
For 2+ Users:
let Owners = ["ID 1", "ID 2"];
if (!Owners.includes(message.author.id)) return;
Ex:
module.exports = {
name: "eval",
run: async (client, message, args) => {
if (message.author.id != "696969696969") return message.channel.send("Only Owners Can Use Eval Command!");
//...
}
};
Links:
User#id
Array
Issue
Custom validator not giving any response. I want to validate this below object in express-validator. The privilege key must be valid and exist in my array. If privilege object does not exist then the validation not working because it's optional but the value must be valid if the object exists
{
"email" : "john#gmail.com",
"privileges" : {
"topic" : true
}
}
user.js
const User = require('../../models/User');
const { check, validationResult } = require('express-validator');
let privilegesArray = ['topic'];
router.post(
'/',
[
check("privileges")
.custom(async (value, { req }) => {
Object.keys(value).forEach(function(key){
if(!privilegesArray.includes(key)){
return false;
}
if(value[key] === 'true' || value[key] === 'false' || value[key] === ''){
return false;
}
})
}).withMessage("Invalid privileges").optional({checkFalsy: true})
],
async (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
}
);
I am a beginner in node-js and not using any custom validator.
Okay, so there are few problems with your script:
Within the custom handler, you are iterating using forEach:
Object.keys(value).forEach(function(key){
if(!privilegesArray.includes(key)){
return false;
the problem is, however, that you are returning false from within the internal forEach handler, not the custom handler itself.
You shouldn't be returning by the way, according to documentation. You should throw an error instead.
You didn't provide handler if everything goes well, eg. return res.status(200).json({ errors: "[]" }); in case everything goes fine in route handler.
Most important I guess, you didn't register any bodyParser. I'm pretty sure express won't be able to understand application/json in the POST body: app.use(bodyParser.json());
After middleware parses input jsons, you shouldn't be comparing value[key] === 'true', as it's going to be boolean true.
Below is complete code which seems to meet your requirements, tested using fiddler:
const { check, validationResult } = require("express-validator");
const bodyParser = require("body-parser");
const express = require("express");
const app = express();
const port = 3000;
let privilegesArray = ["topic"];
app.use(bodyParser.json());
app.post(
"/",
[
check("privileges")
.custom(async (value, { req }) => {
var keys = Object.keys(value);
for (var k = 0; k < keys.length; k++) {
var key = keys[k];
if (!privilegesArray.includes(key)) continue;
if (
value[key] !== true &&
value[key] !== false &&
value[key] !== ""
) {
throw new Error("Topic is invalid.");
}
}
return true;
})
.withMessage("Invalid privileges")
.optional({ checkFalsy: true }),
],
async (req, res) => {
const errors = await validationResult(req);
console.log(errors);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
return res.status(200).json({ errors: "[]" });
}
);
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`);
});
I want to test a function that returns a user by ID from a list of users!!
There is a file responsible for working with the list of users:
const users = [];
const getUser = (id) => users.find((user) => user.id == id);
module.exports = { users, addUser, removeUser, getUser, getUsers };
Unfortunately, I did not find a solution on how to test this function. Expected result is undefined, because the users array is empty. I do not understand how I can replace an array of users for testing.
const { getUser } = require('../users');
describe('Socket', () => {
let socketId;
beforeEach(() => {
socketId = 'qwertyqwerty';
})
test('getUser', () => {
const user = getUser(socketId);
expect(user).toEqual({id: 'qwertyqwerty',user:{username: 'Max'}});
});
})
Conjured a decision!!! in short. used a babel-plugin-rewire. And here's how to implemen:
users.js
import Helper from './Helper';
const users = [];
const user = {
getUser: (id) => users.find((user) => user.id == id),
}
module.exports = user;
And test file:
const User = require('../users');
User.__Rewire__('users', [{id:'qwertyqwerty',user:{username: 'Max'}},{id:'asdfghasdfgh',user:{username: 'Andy'}}]);
describe('Socket', () => {
let socketId;
beforeEach(() => {
socketId = 'qwertyqwerty';
})
test('getUser is user error', () => {
const user = User.getUser(socketId);
expect(user).toEqual({id: 'qwertyqwerty',user:{username: 'Max'}});
});
})
Thanks to Always Learning, for the quick and correct answer )))
I have tried Firebase cloud function for sending a notification.My project structure
and this is the index.js,
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
exports.pushNotification = functions.database.ref('/messages').onWrite( event => {
console.log('Push notification event triggered');
const message = event.data.val();
const user = event.data.val();
console.log(message);
console.log(user);
const topic = "myTopic";
const payload = {
"data": {
"title": "New Message from " + user,
"detail":message,
}
};
return admin.messaging().sendToTopic(topic, payload);
});
The above code is misconfigured, when I deploy in Node.js, LOG in Function shows:
"TypeError: Cannot read property 'val' of undefined".
What Actually I am trying to do :
I am trying to extract info from snapshot load into that index.js so that when a new child gets added to Real-time database, it should trigger a notification payload with a title and body.
In Android, I use a child listener, for listening when a new record is added
FirebaseDatabase.getInstance().getReference().child("messages")
OnChildAdded(.....){
if (dataSnapshot != null) {
MessageModel messageModel = dataSnapshot.getValue(MessageModel.class);
if (messageModel != null) {
// do whatever
}
}
But in index.js, I could not able to parse that.
A bit guidance how to fixate index.js according to my database structure would be immensely appreciated.
PS- I have never done coding in JS
If you want more context, I'd be happy to provide it.
Change this:
exports.pushNotification = functions.database.ref('/messages').onWrite( event => {
const message = event.data.val();
const user = event.data.val();
});
to this:
exports.pushNotification = functions.database.ref('/messages').onWrite(( change,context) => {
const message = change.after.val();
});
Please check this:
https://firebase.google.com/docs/functions/beta-v1-diff#realtime-database
The cloud functions were changed and now onWrite has two parameters change and context
The change has two properties before and after and each of these is a DataSnapshot with the methods listed here:
https://firebase.google.com/docs/reference/admin/node/admin.database.DataSnapshot
'use strict'
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.sendNotification = functions.database.ref('/NOTIFICATIONS/{UserId}/{{notification_id}').onWrite((change, context) =>
{
const UserId = context.params.UserId;
const notification = context.params.notification;
console.log('The user Id is : ', UserId);
if(!change.after.exists())
{
return console.log('A Notification has been deleted from the database : ', notification_id);
}
if (!change.after.exists())
{
return console.log('A notification has been deleted from the database:', notification);
return null;
}
const deviceToken = admin.database().ref(`/USER/${UserId}/device_token`).once('value');
return deviceToken.then(result =>
{
const token_id = result.val();
const payload = {
notification : {
title : "Friend Request",
body : "You've received a new Friend Request",
icon : "default"
}
};
return admin.messaging().sendToDevice(token_id, payload).then(response => {
console.log('This was the notification Feature');
});
});
});