Cannot read property `xxx` of undefined - javascript

I'm working with NodeJS in an attempt to make a basic Socket.IO server for the fun of it and I've ran into an issue that's confusing me to no ends.
Here's my Server code. Fairly short, only one event.
// Create the server and start listening for connections.
var s_ = require('socket.io')(5055);
var Session = require('./Session');
var connections = [];
var dummyID = 0;
// Whenever a connection is received.
s_.on('connection', function(channel) {
connections[channel] = new Session(channel, ++dummyID);;
console.log("Client connected with the ID of " + dummyID);
// Register the disconnect event to the server.
channel.on('disconnect', function() {
delete connections[channel];
console.log("A Client has disconnected.");
});
channel.on('login', function(data) {
if(data.username !== undefined && data.password !== undefined) {
var session = connections[channel];
if(session !== undefined) {
session.prototype.authenticate(data.username, data.password);
}
}
});
});
The error is thrown on this line:
session.prototype.authenticate(data.username, data.password);
Saying that "authenticate" cannot be called on undefined, meaning the prototype of session is undefined. Session itself is not undefined, as per the check above it. Here is Session.js
var Session = function(channel, dummyID) {
this.channel = channel;
this.dummyID = dummyID;
};
Session.prototype = {
authenticate: function(username, password) {
if(username == "admin" && password == "admin") {
this.channel.emit('login', {valid: true});
} else {
this.channel.emit('login', {valid: false});
}
}
};
module.exports = Session;
As you can see the prototype is clearly there, I'm exporting the Session object, and I'm really confused as to what the issue is. Any help would be greatly appreciated.

just call the function you added to the objects prototype
session.authenticate(data.username, data.password);

This article explains the prototype inheritance chain very clearly, especially with the graph.
And one more tip of myself: everything object in javascript has a __proto__ property in the inheritance chain, keep that in mind helps a lot.

Related

Why does my database attribute keep getting reset in IndexDB?

I'm a student and I've been tasked with creating a todo application with clientside authentication using IndexedDB.
I'm trying to store account data, but my database attribute keeps setting itself back to null even after working during the onupgradeneeded method. I've been using debuggers and it doesn't actually show my code running the onupgradeneeded method, though it does as it creates the correct stores on Firefox.
Any help will be appreciated!
Many thanks
class DatabaseConnection
{
constructor(name="todoapp", version=1) {
this.name = name;
this.version = version;
this.database = null;
// Normalise IndexedDB by switching versions depending on browser
var indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
// If the browser does not support IndexedDB, do not load
if(!indexedDB) document.write("Your browser does not support IndexedDB. Please try another browser.");
else console.log(`Database [${name}] successfully loaded.`);
/* Instead of using anonymous functions in the constructor, I'm going to use private methods in the class
for organisational and performance purposes */
var request = indexedDB.open(name, version);
request.onerror = this._onerror;
request.onsuccess = this._onsuccess;
request.onupgradeneeded = this._onupgradeneeded;
}
/* Account methods
=================== */
registerAccount() {
console.log(this);
let tx = this.database.transaction(["accounts"], "readwrite");
let account = {
username: "George",
password: "Test"
};
tx.objectStore("accounts").add(account);
}
/* Private methods
=================== */
_onerror(event) {
alert("[ERROR] :: " + event.target.error);
}
_onsuccess(event) {
this.database = event.target.result;
}
_onupgradeneeded(event) {
this.database = event.target.result;
// Defining the data used in the database
this.database.createObjectStore("todos", {
keyPath: "id",
autoIncrement: true
});
this.database.createObjectStore("accounts", {
keyPath: "id",
autoIncrement: true
});
}
}
The callbacks aren't "bound", so they will be called with a different value for this than you are expecting.
If you do console.log(this) from inside your callbacks, you'll see what's going on, and why this.database = ... isn't working as you expect.
Try this:
request.onsuccess = this._onsuccess.bind(this);
request.onupgradeneeded = this._onupgradeneeded.bind(this);
... which turns your function into one that automagically has this set to what you want.

Socket undefined, send don't send if undefined

Hello I wrote the following function to get someone his socket;
var getSocket = function(persId){
var socketid = users[persId].socket;
if(io.sockets.connected[socketid]){
return io.sockets.connected[socketid];
}
}
They are being emitted like so;
getSocket(372).emit({ ... });
Now if an user has disconnected before the socket is sent out it will result in a undefined socket error, which may cause issues.
is there any way by modifying the function (without having to check for if getSocket(372)) to make it not throw out an error? it's causing problems right now.
Thanks!
What you should do instead, is use socket.io function, that will check for that already.
io.to(room).emit()
On connection just join the user to a room named 372 (I believe that's the user id), and then emit to it:
io.on('connection', socket => {
const room = 372; // Get user id somehow
socket.join(room);
});
// Somewhere
io.to(372).emit(..)
Answering your specific question, you can return an object with an emit nop method. Also you have to check if the user exist before accessing to .socket. You can do that using destructuring.
const { socket: socketId } = users[persId] || {};
The full function should be:
const getSocket = function(persId){
const { socket: socketId } = users[persId] || {};
if(socketId && io.sockets.connected[socketId]){
return io.sockets.connected[socketId];
}
return { emit: () => {} }
}
And now you don't have to perform a check, since .emit will always exist.
getSocket(23123213).emit(); // Will no throw if 23123213 doesn't exist

SOCKET.IO - Usage of socket.id in two different browsers for same logged in user

This is more of a question regarding what to do in the scenario where you want to trigger a socket event for one user, that might be logged into another browser.
I've got a couple of functions that update a users' workstack real-time (in a queue of other workstacks that are assignable by other users); however, if the user is logged into another browser at the same time, and do an update in one browser, it doesn't update in the other (as they have a different socket.id).
I'm not sure what to do with this... I could do it based on the user ID of the person logged in, but at present my socket code does not have scope of any session variables and although there are modules such as session-socket - I'm not sure if that's the right path to go down.
Can anyone advise a way I might approach this please?
If you don't use any cluster you can follow the approach I had in my Miaou chat : I simply set the user as a property of the socket object and I iterate on sockets when necessary. This allow for a few utilitarian functions.
Here's the (simplified) related code.
io.on('connect', function(socket){
...
var userId = session.passport.user;
if (!userId) return die("no authenticated user in socket's session");
...
var shoe = new Shoe(socket, completeUser) // <=== bindind user socket here
// socket event binding here
The Shoe object :
// A shoe embeds a socket and is provided to controlers and plugins.
// It's kept in memory by the closures of the socket event handlers
function Shoe(socket, completeUser){
this.socket = socket;
this.completeUser = completeUser;
this.publicUser = {id:completeUser.id, name:completeUser.name};
this.room;
socket['publicUser'] = this.publicUser;
this.emit = socket.emit.bind(socket);
}
var Shoes = Shoe.prototype;
// emits something to all sockets of a given user. Returns the number of sockets
Shoes.emitToAllSocketsOfUser = function(key, args, onlyOtherSockets){
var currentUserId = this.publicUser.id,
nbs = 0;
for (var clientId in io.sockets.connected) {
var socket = io.sockets.connected[clientId];
if (onlyOtherSockets && socket === this.socket) continue;
if (socket && socket.publicUser && socket.publicUser.id===currentUserId) {
socket.emit(key, args);
nbs++;
}
}
return nbs;
}
// returns the socket of the passed user if he's in the same room
Shoes.userSocket = function(userIdOrName) {
var clients = io.sockets.adapter.rooms[this.room.id],
sockets = [];
for (var clientId in clients) {
var socket = io.sockets.connected[clientId];
if (socket && socket.publicUser && (socket.publicUser.id===userIdOrName||socket.publicUser.name===userIdOrName)) {
return socket;
}
}
}
// returns the ids of the rooms to which the user is currently connected
Shoes.userRooms = function(){
var rooms = [],
uid = this.publicUser.id;
iorooms = io.sockets.adapter.rooms;
for (var roomId in iorooms) {
if (+roomId!=roomId) continue;
var clients = io.sockets.adapter.rooms[roomId];
for (var clientId in clients) {
var socket = io.sockets.connected[clientId];
if (socket && socket.publicUser && socket.publicUser.id===uid) {
rooms.push(roomId);
break;
}
}
}
return rooms;
}
// returns the first found socket of the passed user (may be in another room)
function anyUserSocket(userIdOrName) {
for (var clientId in io.sockets.connected) {
var socket = io.sockets.connected[clientId];
if (socket.publicUser && (socket.publicUser.id===userIdOrName||socket.publicUser.name===userIdOrName)) {
return socket;
}
}
}
// closes all sockets from a user in a given room
exports.throwOut = function(userId, roomId, text){
var clients = io.sockets.adapter.rooms[roomId];;
for (var clientId in clients) {
var socket = io.sockets.connected[clientId];
if (socket.publicUser && socket.publicUser.id===userId) {
if (text) socket.emit('miaou.error', text);
socket.disconnect('unauthorized');
}
}
}
Real code
Now, with ES6 based node versions and WeakMap, I might implement a more direct mapping but the solution I described is robust and efficient enough.

CometD taking more time in pushing messages

I am trying to implement CometD in our application. But it is taking more time compared to the existing implementation in our project. The existing system is taking time in milliseconds where as CometD is taking 2 seconds to push the message.
I am not sure where I am going wrong. Any guidance will help me lot.
My code:
Java script at client side
(function($)
{
var cometd = $.cometd;
$(document).ready(function()
{
function _connectionEstablished()
{
$('#body').append('<div>CometD Connection Established</div>');
}
function _connectionBroken()
{
$('#body').append('<div>CometD Connection Broken</div>');
}
function _connectionClosed()
{
$('#body').append('<div>CometD Connection Closed</div>');
}
// Function that manages the connection status with the Bayeux server
var _connected = false;
function _metaConnect(message)
{
if (cometd.isDisconnected())
{
_connected = false;
_connectionClosed();
return;
}
var wasConnected = _connected;
_connected = message.successful === true;
if (!wasConnected && _connected)
{
_connectionEstablished();
}
else if (wasConnected && !_connected)
{
_connectionBroken();
}
}
// Function invoked when first contacting the server and
// when the server has lost the state of this client
function _metaHandshake(handshake)
{
if (handshake.successful === true)
{
cometd.batch(function()
{
cometd.subscribe('/java/test', function(message)
{
$('#body').append('<div>Server Says: ' + message.data.eventID + ':'+ message.data.updatedDate + '</div>');
});
});
}
}
// Disconnect when the page unloads
$(window).unload(function()
{
cometd.disconnect(true);
});
var cometURL = "http://localhost:8080/cometd2/cometd";
cometd.configure({
url: cometURL,
logLevel: 'debug'
});
cometd.addListener('/meta/handshake', _metaHandshake);
cometd.addListener('/meta/connect', _metaConnect);
cometd.handshake();
});
})(jQuery);
Comet service class
#Listener("/service/java/*")
public void processMsgFromJava(ServerSession remote, ServerMessage.Mutable message)
{
Map<String, Object> input = message.getDataAsMap();
String eventId = (String)input.get("eventID");
//setting msg id
String channelName = "/java/test";
// Initialize the channel, making it persistent and lazy
bayeux.createIfAbsent(channelName, new ConfigurableServerChannel.Initializer()
{
public void configureChannel(ConfigurableServerChannel channel)
{
channel.setPersistent(true);
channel.setLazy(true);
}
});
// Publish to all subscribers
ServerChannel channel = bayeux.getChannel(channelName);
channel.publish(serverSession, input, null);
}
Is there any thing I need to change in server side code.
You have made your channel lazy, so a delay in message broadcasting is expected (that is what lazy channels are all about).
Please have a look at the documentation for lazy channels.
If you want immediate broadcasting don't set the channel as lazy.

Javascript pattern for maintaining state and creating nested objects that provide additional functionality

I am writing a Javascript API library that provides consumers with an interface that enables them to interact with our backend web services. It is envisioned that a consumer will be writing a javascript client web application that draws heavily on the API provided for by the library.
I have come up with this "pattern" for maintaining state and making functionality "available" as certain criteria are met (for example, an authenticated user is logged in client-side).
Is this an appropriate way to achieve that end? Or am I unwittingly breaking some convention or best practice that will bite me later on?
// file: clientApi.js (library)
ClientObject = function () {
this.objectname = "a client class";
}
ClientObject.prototype.loginUser = function(name) {
this.loggedin = true;
if (typeof this.User === 'undefined') {
this.User = new ClientObject.User(name);
}
}
ClientObject.User = function (name) {
this.username = name;
}
ClientObject.User.prototype.getProfile = function() {
return 'user profile';
}
// file: app.js (consuming application)
var testClient = new ClientObject();
console.log('testClient.User = ' + (typeof testClient.User)); // should not exist
testClient.loginUser('Bob'); // should login 'bob'
console.log('testClient.User = ' + (typeof testClient.User)); // should exist
console.log(testClient.User.username); // bob
testClient.loginUser('Tom'); // should not do anything
console.log(testClient.User.username); // bob still
console.log(testClient.User.getProfile()); // tada, new functionality available
My question: is this approach valid? Is there a pattern that I'm touching on that might offer a better explanation or method of achieving my end goal?
I asked a similar question here with a bunch of other ones, unfortunately the above code was somewhat lost in the noise: Javascript: creation of object from an already instantiated object versus the prototype
Your API should have some secrets. That's why do not make all your functions public. Let's analyze some parts of your code:
testClient.loginUser('Tom'); // should not do anything
But your implementation allows client to do next:
testClient.User = new ClientObject.User(name);
Now user will be changed to "Tom".
Let's change your clientApi.js code, using revealing prototype pattern:
ClientObject = function () {
this.objectname = "a client class";
this.username;
this.User;
this.loggedin;
}
ClientObject.prototype = function() {
var loginUser = function(name) {
this.loggedin = true;
if (typeof this.User === 'undefined') {
this.User = new User(name);
}
};
var User = function (name) {
this.username = name;
};
User.prototype.getProfile = function() {
return 'user profile';
};
return {
loginUser : loginUser
}
}()
Now client cannot change logged in User like in first version of the library. You can use some variations, but that's the idea.

Categories

Resources