9

In the latest Meteor release (version 0.5.8), Session has been removed from the server-side code.

Previously I've used Session to store client-specific variables for the server; what is the replacement for this functionality?

Example case: User One opens a browser, User Two opens a browser. One calls a method on the server setting some token, the other calls a method on the server doing the same. I then need to access this when the client requests something. How do I differentiate between the two?

Christian Stewart
  • 15,217
  • 20
  • 82
  • 139
  • How did you use Session to identify each one? Wont an ordinary JS Object work just as well / theres no reactivity on the server so it would be the same as Session – Tarang Mar 13 '13 at 22:28
  • Normal Js object doesn't work because the objects are shared between sessions! I've tested this by logging to console whenever the objects are defined, it's always once on server startup. – Christian Stewart Mar 14 '13 at 01:00
  • Can you show the code you used in the previous version? – cmather Mar 16 '13 at 02:04
  • I can publish it probably... The thing is @cmather, the original implementation was a facebook app. Because of this, I was not integrating with the Auth api in Meteor, rather I was making my own token storage and user tracking. I was using `Session.set` and `Session.get` server-side for client-specific variables. – Christian Stewart Mar 16 '13 at 05:43
  • Thanks Christian. I think I understand what you're trying to do with tracking a specific browser session. The breakdown in understanding for me is how Session on the server helped. Maybe I'm missing something - where seeing some code would help. But Session is just a fancy object wrapper that is reactive - invalidates contexts when its data changes. It doesn't know anything about user or browser sessions. So I'm thinking you had some other piece of code where you were using Session in combination with something else to do something. – cmather Mar 16 '13 at 19:44
  • @cmather I'm just doubting that it worked correctly right now... I thought Session server-side separated variables based on which *session* was connected... Is there any functionality to do what I describe? – Christian Stewart Mar 16 '13 at 19:47
  • 1
    Session is an unfortunately named object because it really has nothing to do with what we traditionally think of as "session." To do what you're mentioning in your post I think a little more use case context would help. I abstractly understand the technical requirement, but maybe with a little more context around what you're enabling or doing would yield more options. – cmather Mar 16 '13 at 19:58
  • Basically, it would be good if we could have an object like `Session` to store data specific to the **browser window** accessing the page... I'm not sure if Meteor.uuid does this; perhaps I'll make a pull request to Meteor with this sort of functionality. – Christian Stewart Mar 16 '13 at 20:00

2 Answers2

7

You'll want to save your tokens to a collection in the database.

You could use a Session on the server if you wanted to simply by copying the session package into your application's packages directory and changing its package.js to also load on the server. But a Session is an in-memory data structure, and so won't work if you have multiple server instances; and you wouldn't be able to restart the server without losing your user's tokens.

If you store your tokens in the database they'll persist across server restarts, and will work with a future version of Meteor which is able to scale an application by adding more server instances when needed.

If you need to expire your tokens (so that your collection doesn't grow without bound), you could add a "lastUsed" Date field to your token collection, and periodically remove tokens that haven't been used for longer than your chosen expiration period.

Andrew Wilcox
  • 1,021
  • 6
  • 8
  • This is probably the best explanation for why Session was removed from the server – Tarang Apr 10 '13 at 21:37
  • @Akshat would you recommend this answer over your answer? – supertrue Oct 20 '13 at 21:22
  • @supertrue Both yes and no. Yes if you're using one server. You need to use something like Redis if you have more than 1 server. Or unless you use something like sticky sessions with your proxy server to make sure the same user always gets the same server – Tarang Oct 21 '13 at 09:21
2

You can use each one's session id which is unique to the tab too. Not too sure how to get the current session id but it should be there somewhere (you can see it in Meteor.default_server.sessions, so there is still a way:

Client js

Meteor.call("test", Meteor.default_connection._lastSessionId, function(err,result) {
    console.log(result);
});

Server side Js

Session = {
  set : function(key, value, sessionid) { 
      console.log(Meteor.default_server.sessions[sessionid]);
      if(!Meteor.default_server.sessions[sessionid].session_hash) Meteor.default_server.sessions[sessionid].session_hash = {};
      Meteor.default_server.sessions[sessionid].session_hash.key = value;
  },
  get : function(key, sessionid) {
      if(Meteor.default_server.sessions[sessionid].session_hash)
        return Meteor.default_server.sessions[sessionid].session_hash.key;
  },
  equals: function(key, value, sessionid) {
      return (this.get(key, sessionid) == value)
  },
  listAllSessionids: function() {
      return _.pluck(Meteor.default_server.sessions, "id");
  }  
};


Meteor.methods({
    test:function(sessionid) {

        if(!Session.get("initial_load", sessionid)) Session.set("initial_load", new Date().getTime(), sessionid);

        return Session.get("initial_load", sessionid);
    }
});

I hook into Meteor.default_connection._sessions to store the values so that theres some type of garbage collection involved when the session isn't valid anymore (i.e the user has closed his tabs) to prevent memory being wasted. In livedata_server.js these old sessions get destroyed after 1 minute of no activity on the DDP wire (like the heartbeat).

Because the server can see everyone's session you can use the sessionid to access another user's session data. and listAllSessionids to give out an array of all the sessionids currently active.

Automatically set session like this.userId in a Method without using a param in a call

It looks like there is functionality for this this but its not fully hooked up. The session id would be stored in this.sessionData but its likely still unfinished. Its there to be called in method but theres nowhere that its being set yet (in livedata_connection.js & livedata_server.js)

Tarang
  • 75,157
  • 39
  • 215
  • 276
  • Can't there be a way to extend meteor to do this on default? This seems like a really clunky implementation :) – Christian Stewart Apr 10 '13 at 18:29
  • How is it clunky perhaps I can iron it out? Do you mean the need provide a sessionid? It looks like it needs to be provided in the livedata files so this.sessionData but theres nothing to set it yet in livedata_server files – Tarang Apr 10 '13 at 18:54
  • I mean passing that id every time you call something. Furthermore, how would you do reactive subscriptions with something like this? Allow rules? – Christian Stewart Apr 11 '13 at 00:14
  • Reactive subscriptions can be done by running something in the setter the same way reactivity works on the client. The id is something that needs to be sorted in the livedata server file which basically needs a custom meteor if it were used at the moment so this is what would let it be used in the publish function/allow/deny rules. Are you using it in these too? – Tarang Apr 11 '13 at 05:48