Redis Store doesn't have a get method? - javascript

http://senchalabs.github.com/connect/middleware-session.html mentions....
"Every session store must implement the following methods: "
.get(sid,callback)
.set(sid, session, callback)
.destroy(sid, callback)
I'm using the following code to attempt to get the SID:
Node JavaScript, using Socket.io connection
io.sockets.on('connection', function(socket) {
var sid = socket.id;
if (sid) {
sessionStore.get(sid, function (error, session) {
console.log("Connect Sid: " + sid);
});
}
});
And i'm getting the following error:
TypeError: Object function RedisStore(options) {
options = options || {};
Store.call(this, options);
this.client = new redis.createClient(options.port || options.socket, options.host, options);
if (options.pass) {
this.client.auth(options.pass, function(err){
if (err) throw err;
});
}
if (options.db) {
var self = this;
self.client.select(options.db);
self.client.on("connect", function() {
self.client.send_anyways = true;
self.client.select(options.db);
self.client.send_anyways = false;
});
}
} has no method 'get'
Inclusion of redis
//Redis store for storage
var sessionStore = require('connect-redis')(express);
...
...
app.use(express.session({secret: "keyboard cat",store: new sessionStore}));

Looks like you forgot to type new when you instantiated the store perhaps?

Taken from: https://github.com/visionmedia/connect-redis
This means express users may do the following, since express.session.Store points to the connect.session.Store function:
This seems to work:
express.session.Store(sid, function(){ console.log("Connect Sid: " + sid); });

I do it like this:
var RedisStore = require('connect-redis')(express);
var sessionStore = new RedisStore;
...
app.use(express.session({secret: "keyboard cat",store: sessionStore}));
This way you can reference session data using the sessionStore object from socket.io code later if needed.

Related

About how the value is returned using app.set() and app.get()

I am releasing access to pages using connect-roles and loopback but I have a pertinent question about how I can collect the customer's role and through the connect-roles to read the session and respond to a route.
Example, when the client logs in I load a string containing the client's role and access it in a function that controls access to pages.
I have this doubt because I'm finalizing a large scale service that usually there are multiple client sessions that are accessed instantly using a same storage and check function.
It would be efficient to store the customer's role using app.set() and app.get()?
app.get('/session-details', function (req, res) {
var AccessToken = app.models.AccessToken;
AccessToken.findForRequest(req, {}, function (aux, accesstoken) {
// console.log(aux, accesstoken);
if (accesstoken == undefined) {
res.status(401);
res.send({
'Error': 'Unauthorized',
'Message': 'You need to be authenticated to access this endpoint'
});
} else {
var UserModel = app.models.user;
UserModel.findById(accesstoken.userId, function (err, user) {
// console.log(user);
res.status(200);
res.json(user);
// storage employee role
app.set('employeeRole', user.accessLevel);
});
}
});
});
Until that moment everything happens as desired I collect the string loaded with the role of the client and soon after I create a connect-roles function to validate all this.
var dsConfig = require('../datasources.json');
var path = require('path');
module.exports = function (app) {
var User = app.models.user;
var ConnectRoles = require('connect-roles');
const employeeFunction = 'Developer';
var user = new ConnectRoles({
failureHandler: function (req, res, action) {
// optional function to customise code that runs when
// user fails authorisation
var accept = req.headers.accept || '';
res.status(403);
if (~accept.indexOf('ejs')) {
res.send('Access Denied - You don\'t have permission to: ' + action);
} else {
res.render('access-denied', {action: action});
// here
console.log(app.get('employeeRole'));
}
}
});
user.use('authorize access private page', function (req) {
if (employeeFunction === 'Manager') {
return true;
}
});
app.get('/private/page', user.can('authorize access private page'), function (req, res) {
res.render('channel-new');
});
app.use(user.middleware());
};
Look especially at this moment, when I use the
console.log(app.get('employeeRole')); will not I have problems with simultaneous connections?
app.get('/private/page', user.can('authorize access private page'), function (req, res) {
res.render('channel-new');
});
Example client x and y connect at the same time and use the same function to store data about your session?
Being more specific when I print the string in the console.log(app.get('employeeRole')); if correct my doubt, that I have no problem with simultaneous connections I will load a new variable var employeeFunction = app.get('employeeRole'); so yes my function can use the object containing the role of my client in if (employeeFunction === 'Any Role') if the role that is loaded in the string contain the required role the route it frees the page otherwise it uses the callback of failureHandler.
My test environment is limited to this type of test so I hope you help me on this xD
Instead of using app.set you can create a session map(like hashmaps). I have integrated the same in one of my projects and it is working flawlessly. Below is the code for it and how you can access it:
hashmap.js
var hashmapSession = {};
exports.auth = auth = {
set : function(key, value){
hashmapSession[key] = value;
},
get : function(key){
return hashmapSession[key];
},
delete : function(key){
delete hashmapSession[key];
},
all : function(){
return hashmapSession;
}
};
app.js
var hashmap = require('./hashmap');
var testObj = { id : 1, name : "john doe" };
hashmap.auth.set('employeeRole', testObj);
hashmap.auth.get('employeeRole');
hashmap.auth.all();
hashmap.auth.delete('employeeRole');

How do I return data from a function in node?

I'm using Express and trying to teach myself node/javascript callbacks and I've stumbled across something.
I have a route that looks like this:
var express = require('express');
var router = express.Router();
var api = require('../api');
router.get('/',function(req, res, next){
var modulename = api.modulename;
modulename.methodname(res);
});
module.exports = router;
And then the module that is being called above looks like this:
var library = require('library');
var instances = {};
var modulename = {
getAllInstances: function(res) {
var request = new library.asyncMethod();
request.on('success', function(resp) {
instances = resp.data;
res.setHeader("Content-Type","application/json");
var returnInstances = {
id: instances[0].InstanceId,
state: {name: instances[0].State.Name, code: instances[0].State.Code}
};
res.send(returnInstances);
})
.on('error', function(resp){
console.log(resp);
})
}
};
module.exports = modulename;
As you can see I'm passing through the response parameter through to my module, but I'd rather pass back instances and then in the route return api.modulename.instances, like this:
var library = require('library');
var instances = {};
var modulename = {
getAllInstances: function() {
var request = new library.asyncMethod();
request.on('success', function(resp) {
var returnData = resp.data;
instances = {
id: returnData[0].InstanceId,
state: {name: returnData[0].State.Name, code: returnData[0].State.Code}
};
})
.on('error', function(resp){
console.log(resp);
})
.send();
}
};
module.exports = modulename;
However, when I do, it's coming through as the default value {} but if I run it as above, I do get output so I know that there should be data in there.
Let me know if I have misunderstood your issue. If you are saying you want to pass back objects from getAllInstances then you pass in a callback and call it from the event handler like this-
router.get('/',function(req, res, next){
var modulename = api.modulename;
modulename.getAllInstances(res, function(err, instances){
if(err){ ... }
else{
res.send(instances); //or however you want to use instances
}
});
});
and in getInstances
var modulename = {
getAllInstances: function(res, cb) {
var request = new library.asyncMethod();
request.on('success', function(resp) {
instances = resp.data;
var returnInstances = {
id: instances[0].InstanceId,
state: {name: instances[0].State.Name, code: instances[0].State.Code}
};
cb(null, instances);
})
.on('error', function(err){
cb(err, null));
});
//.send(); not sure what this is it seems to be request.send() ??
}
};
The problem here lies with when the response from the API call is available. The event loop in Node means code won't block until the API replies with a response. Hence a callback is needed to handle that response when it becomes available. You probably want to use the API response in your Express router response so there's a chain of dependency.
One strategy here would be to use promises and not callbacks, it would alleviate some of the pain you're experiencing with async response from the API call.
In your routes:
router.get('/',function(req, res, next){
var instances = [];
// The function below could be refactored into a library to minimise controller code.
var resolver = function (response) {
var data = JSON.parse(response);
instances.push({
name: data[0].State.Name,
code: data[0].State.Code
});
res.render('instances'. {instances : instances});
};
modulename.methodname(resolver);
});
And in your module:
var rp = require('request-promise'); // Also see q-io/http as an alternate lib.
var modulename = {
methodname: function (resolver) {
rp('http://the-inter.net')
.then(resolver)
.catch(console.error);
}
};
This might not cut-n-paste work but have a look at the request-promise examples for further clarification.

Create my own Model with node who allow new Model and Model.find()

I'm trying to create a Model with node and I want to be able to use it like that :
Require the models
var Example = require('./models/example');
Create new object
The model can create a new object using new
var example = new Example({ data:'example' });
Find
The model can find object using method
Example.find({ data: 'mongoQuery' }, function(err, examples) {});
Save
The model can help to find object using method, who return object with methods.
Example.findOne({ query: 'example' }, function(err, example) {
example.set({ data: 'another data' });
example.save();
});
Example of use
I want to be able to create, find (one or multiple), uptade and delete a token (for example) using the model like that. I'll use that on controller or lib for example.
var Token = require('./models/token);
// Create and save a new token
var new_token = new Token({ key: 'abcdef' });
new_token.save();
// find multiple tokens, update, and save
var token = Token.find({key: 'abcderf'}, function(tokens) {
for(var i in tokens) {
tokens[i].set({key: '123456'});
tokens[i].save();
}
});
I already try lots of thing, but I can't create a module who allow the new Example and Example.find() in the same time.
Backbone :
I have try using Backbone, the new Token({ /* attributes */ }) work but the find function return an error : TypeError: Object function (){ return parent.apply(this, arguments); } has no method 'find'
var Token = Backbone.Model.extend({
initialize: function(attributes) {
console.log("Token create");
console.log(" attributes : ", attributes);
},
find : function(query, callback) {
console.log("Token find");
console.log(" query : ", query);
callback(null, [ /* tokens */]);
}
});
module.exports = Token;
Object
When I'm trying to use an object, the find function work well, but I can't use it with new returning the error : TypeError: object is not a function
module.exports = {
find : function(query, callback) {
console.log("[Step] models/token.js - find");
console.log(" query : ", query);
callback(null, []);
}
};
What the best way to create a Model to handle all objects on controller ?
Thank for helping !
Here you go :
YourModule = function(data){
this.data = data; // this.data is now a property of the object you create with New.
};
YourModule.prototype.find = function(query, callback) {
console.log("[Step] models/token.js - find");
console.log(" query : ", query);
callback(null, []);
return this.data; // this.data is available here.
};
YourModule.prototype.save = function(data) {
this.data = data; // this.data is available here to.
};
module.exports = YourModule;
You cannot instantiate an object using new keyword, you can however do Object.create to do so. i prefer my example though.
So... I create a model base on the #Neta Meta reply :
./models/token.js
var Backbone = require('backbone');
var db = require('../lib/database');
var Token = Backbone.Model.extend({
initialize: function(attributes) {
},
save: function(callback) {
db.collection('tokens').insert(self.attributes, function(err) {
if (typeof callback === 'function') {
callback(err, self);
}
});
}
});
module.exports.create = function(attr, callback) {
callback(null, new Token(attr));
};
module.exports.findOne = function(query, callback) {
db.collection('tokens').findOne(query, function(err, result) {
callback(err, new Token(result));
});
};
So now I can use it like that :
./controllers/example.js
var Token = require('../models/token');
// Create one :
Token.create({key: 'new data'}, function(err, token) {
token.set({key: 'updated data'});
token.save();
});
// Find one :
Token.findOne({key: 'updated data'}, function(err, token) {
token.set({key: 're-updated data'});
token.save(function(err) {
console.log("Token saved");
});
});

outsource XXX.db.bson_serializer.ObjectID.createFromHexString(id) to a function?

I went through this express tutorial. I was wondering if it is possible to outsource the following call to a separate function, as it is very very long?
employee_collection.db.bson_serializer.ObjectID.createFromHexString(id)
This is the whole file where the statement is called:
var Db = require('mongodb').Db;
var Connection = require('mongodb').Connection;
var Server = require('mongodb').Server;
var BSON = require('mongodb').BSON;
var ObjectID = require('mongodb').ObjectID;
EmployeeProvider = function(host, port) {
this.db = new Db(
'node-mongo-employee',
new Server(host, port, {}),
{safe: true}
);
this.db.open(function(){});
};
...
// find an employee by id
EmployeeProvider.prototype.findById = function(id, callback) {
this.getCollection(
function(error, employee_collection) {
if( error )
callback(error)
else {
employee_collection.findOne(
{_id: employee_collection.db.bson_serializer.ObjectID.createFromHexString(id)},
function(error, result) {
if( error )
callback(error)
else
callback(null, result)
}
);
}
}
);
};
...
exports.EmployeeProvider = EmployeeProvider;
It's the controller of an express application. It's shortened, but should give you an idea of what it does. You can find the whole application on Github.
I tried
getid = function( employee_collection, id ) {
return employee_collection.db.bson_serializer.ObjectID.createFromHexString(id);
};
and called the function with
{_id: getid(employee_collection, id),
but I'm getting a very long ENOENT error with that one.
Presuming that you are working with the basic node.js mongodb driver here and that you have id essentially coming in as something like a request parameter, which means it's just a string and looks something like:
"53cfba87e248860d16e1f7e1"
Then the import you have used here:
var ObjectID = require('mongodb').ObjectID;
Gives you a direct function to use. Just do this:
employee_collection.findOne({ "_id": ObejctID(id) },function(err,result) {
// work in here
});
The ObjectID you are importing already implements this function.

Meteor insert uploaded into the console but not MongoDB

I've configured a FB graph call that would retrieve data from the API, however I'm having trouble inserting it into MongoDb. Right now if I run Photos.find().count(); in the browser it shows that there are photos, however if I run db.Photos.find().count(); in MongoDb it shows nothing. Also, if I run db.users.find(); in MongoDb it returns results from the FB user account, so MongoDb is talking to the API to some extent.
Any thoughts on what might be causing the issue?
Here is my code:
Client:
Template.test.events({
'click #btn-user-data': function(e) {
Meteor.call('getUserData', function(err, data) {
if(err) console.error(err);
});
}
});
Template.facebookphoto.helpers({
pictures: function () {
return Photos.find();
}
});
Server:
function Facebook(accessToken) {
this.fb = Meteor.require('fbgraph');
this.accessToken = accessToken;
this.fb.setAccessToken(this.accessToken);
this.options = {
timeout: 3000,
pool: {maxSockets: Infinity},
headers: {connection: "keep-alive"}
}
this.fb.setOptions(this.options);
}
Facebook.prototype.query = function(query, method) {
var self = this;
var method = (typeof method === 'undefined') ? 'get' : method;
var data = Meteor.sync(function(done) {
self.fb[method](query, function(err, res) {
done(null, res);
});
});
return data.result;
}
Facebook.prototype.getUserData = function() {
return this.query('me/photos');
}
Meteor.methods({
getUserData: function() {
var fb = new Facebook(Meteor.user().services.facebook.accessToken);
var data = fb.getUserData();
_.forEach(data.data, function(photo) {
if(Photos.findOne({id: photo.id})) return;
Photos.insert(photo, function(err) {
if(err) console.error(err);
});
});
}
});
Collection:
Photos = new Meteor.Collection('picture');
Thanks in advance!
Instead of db.Photos.find().count();, try db.picture.find().count();
Photos is just the name you gave to the JavaScript variable. The actual name of the collection in MongoDB is whatever you use when you initialized the Collection - in this case, picture.

Categories