Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Session hooks #1611

Closed
wants to merge 23 commits into from
Closed

Session hooks #1611

wants to merge 23 commits into from

Conversation

awwx
Copy link
Contributor

@awwx awwx commented Nov 15, 2013

Add Meteor.server.onConnection API.

Move handling of login tokens from livedata to accounts.

of connections can be closed without waiting for the close callbacks
on one connection to return before closing the other connections.

Underscore internal Session field `_closeCallbacks`.

Update comment to explain the cause of the problem requiring the use
of `Meteor.bindEnvironment` with Meteor's public API.

// sessionId -> SessionHandle
var sessionHandles = {};

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note an alternative is if Meteor.server had an API to get the session from a session id, accounts wouldn't need to maintain its own mapping here.

`closeSessionsForTokens` doesn't need to clone `sessionsByLoginToken`
because `onClose` callbacks are deferred.

Simplify `closeTokensForUser` by using `_.pluck`.
@@ -1,3 +1,70 @@
// token -> list of session ids
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code organization for easy reading: this should go in the "RECONNECT TOKENS" or "TOKEN EXPIRATION" section, not at the top of the file.

@n1mmy
Copy link
Contributor

n1mmy commented Nov 19, 2013

This is looking good! Some comments inline.

Also, can you please add some docs for the new public APIs? I think users will be really excited to use them!

Poll instead of using Deps.autorun in server test.

When polling the client connection, tests don't have a chance to
disconnect before the stream client automatically reconnects, so add
an option to disable retries for testing.

Callers of `Meteor.bindEnvironment` often have the `onException`
argument print the exception stack trace.  To allow for less code
duplication, let the argument be a string providing the context
(e.g. "connection closed callback"), and then on an exception print
the context and the exception stack trace.
{{#dtdd name="onClose" type="Function"}}
Register a callback to be called when the session is closed.

When session reconnections are implemented, the client closing the
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe condense both sections on "when there is session reconnect" into a single {{note}}?

session id.

Make _sessionData available in a nested method invocation on the
server.
Document `Meteor.onConnection` instead of `Meteor.server.onConnection`.

Condense sections about when there is a session reconnect into a
single {{note}}.

Document the `stop` handle returned by `onConnect`.

Document `this.session` in Meteor.methods section.
fn = Meteor.bindEnvironment(
fn,
function (err) {
Meteor._debug(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto String form.

Pull out the session object into its own documentation section.
when the error callback only needs to print the exception.

Replace unsafe references to `err.stack` with
`err && err.stack || err`.  This avoids throwing a secondary exception
if the original exception in `err` isn't an object (`throw(null)` and
`throw(undefined)` are legal in JavaScript), and also displays the
error object if the stack trace wasn't included.
Add tests to check that account data is cleaned up after a session
closes.

Make `establishConnection` available to account tests.

Remove code duplication between `poll` (now called `simplePoll`) and
the async_multi `pollUntil`.
@n1mmy
Copy link
Contributor

n1mmy commented Nov 28, 2013

Looks great! Will merge. Nice work.

@timhaines
Copy link
Contributor

Hey guys, just read up a little on this (not thoroughly). It looks like methods and publish functions are getting access to a server side session object that represents the DDP session? This is completely different to the Session on the client side, right?

If I've understood correctly, would this server side session object be a good place to hold the client's accepted languages, hostname, user agent, IP address etc? (for use within methods and publish functions)

@n1mmy
Copy link
Contributor

n1mmy commented Nov 28, 2013

Yup!

@timhaines
Copy link
Contributor

That's pretty damn exciting. Seems like a very nice approach.

sockjs/sockjs-node@c3970d0
#786

@n1mmy
Copy link
Contributor

n1mmy commented Nov 28, 2013

Hrm. I ran our many-browser tests and this patch seems to cause issues. http://test-results-pr-1611-2-20131128-001934.meteor.com/

I've seen this pattern of failures (mostly accounts emails tests, some changing userid reruns subscriptions) before. In that case it was triggered by something closing the main DDP connection between the client and the server and it reconnecting mid-test. Could something in the new tests be causing a reconnect mid-test run?

I'll look into this early next week, unless you beat me to it @awwx =)

@awwx
Copy link
Contributor Author

awwx commented Nov 29, 2013

That's strange. The hash-login-tokens PR does add some extra steps to the client login token tests that could be doing something, but the session-hooks tests are all server-only (making a DDP connection from the server to the server), so I don't know why it would be affecting the main DDP connection between the client and server. Unless of course one of the server tests is closing the main connection accidentally :) But I didn't see anything.

I'd need a way to reproduce this to investigate myself... are the many-browser tests something I could run? Or are the many-browser tests running multiple tests in parallel, and perhaps I'd be able to see the same thing if I run the unit tests in a loop from multiple browser windows?

@n1mmy
Copy link
Contributor

n1mmy commented Dec 2, 2013

@awwx unfortunately, I can't give you access to the automated test repo. It's a private repo and has API keys and account details. But I think it should replicable without the cross-browser component -- I don't think the individual browsers make much of a difference. Deploying a test site (meteor test-packages --deploy foo.meteor.com) and pointing many browser tabs at it will hopefully do the trick.

@estark37
Copy link
Contributor

estark37 commented Dec 2, 2013

@n1mmy @timhaines Unless I'm missing it, I think we still don't have the actual plumbing to get the IP/headers/etc. associated with a session, though session handles will certainly be part of that plumbing. Should we add that in?

Client IP seems like a good thing to add (and is part of the current login hooks design: https://meteor.hackpad.com/Login-hooks-design-notes-o0809sK58jX), but I'm not sure if HTTP headers is an elegant thing to have on a session, because it kind of intermingles DDP with HTTP. Maybe this is just a matter of naming the field nicely (like session.transportInfo = { transport: 'sockjs', headers: <http headers> } or something though that looks kind of clunky now that I write it out).

@timhaines
Copy link
Contributor

@estark37 re: "not sure if HTTP headers is an elegant thing to have on a session" - you'd agree that it's beneficial to have at least a subset of the headers available from within methods and publish functions though right?

@estark37
Copy link
Contributor

estark37 commented Dec 2, 2013

@timhaines Absolutely! Headers, query parameters, all sorts of things that are very HTTP-ish... I think it's just a matter of figuring out the right way to expose it that doesn't tie the concept of a DDP session to HTTP.

@awwx
Copy link
Contributor Author

awwx commented Dec 2, 2013

Unless I'm missing it, I think we still don't have the actual plumbing to get the IP/headers/etc. associated with a session

Correct.

you'd agree that it's beneficial to have at least a subset of the headers available from within methods and publish functions though right?

Right, I suspect what we want is to have information derived from the headers (instead of necessarily the headers themselves).

For example, if the client is connecting to a load balancer which is forwarding connections to the Meteor server, the IP address of the client is available in the X-Forwarded-For header. On the other hand, if the client is connecting to the Meteor server directly, the X-Forwarded-For header must be ignored (since otherwise the client could forge it). So ideally the session would get the "client IP" supplied to it, without the developer using the session having to worry about how to dig it out of the headers etc.

@awwx
Copy link
Contributor Author

awwx commented Dec 2, 2013

@n1mmy oops, http://test-results-pr-1611-2-20131128-001934.meteor.com/ got cleared. Do you happen to remember which test was failing?

I suspect running tests from multiple browser tabs (as opposed to multiple browsers) won't work because the accounts-password client tests login and logout. Firefox however has the option to run with different user profiles, so it's possible to run multiple instances of Firefox on a computer.

I tried running a bunch of simultaneous tests using both test-in-console and using multiple Firefox instances. I am seeing an expireTokens method error on the server, but it doesn't seem to cause a test failure for some reason, so I don't think that's the same one as you saw.

Exception while invoking method 'expireTokens' Error: Bad test. Must specify both oldestValidDate and userId.
I20131202-16:22:08.137(-5)?     at Object.Accounts._expireTokens (packages/accounts-base/accounts_server.js:211)
I20131202-16:22:08.137(-5)?     at Meteor.methods.expireTokens (packages/accounts-password/password_tests_setup.js:45)
I20131202-16:22:08.137(-5)?     at maybeAuditArgumentChecks (packages/livedata/livedata_server.js:1371)
I20131202-16:22:08.138(-5)?     at packages/livedata/livedata_server.js:545
I20131202-16:22:08.138(-5)?     at _.extend.withValue (packages/meteor/dynamics_nodejs.js:35)
I20131202-16:22:08.139(-5)?     at packages/livedata/livedata_server.js:544
I20131202-16:22:08.139(-5)?     at _.extend.withValue (packages/meteor/dynamics_nodejs.js:35)
I20131202-16:22:08.139(-5)?     at _.extend.protocol_handlers.method (packages/livedata/livedata_server.js:543)
I20131202-16:22:08.139(-5)?     at packages/livedata/livedata_server.js:443

@awwx
Copy link
Contributor Author

awwx commented Dec 2, 2013

@n1mmy ack, I wasn't in the session-hooks branch :) Let me try again...

@awwx
Copy link
Contributor Author

awwx commented Dec 2, 2013

@n1mmy when you run the many-browser tests, how many browsers are you typically running at once? Are you testing all packages?

@awwx
Copy link
Contributor Author

awwx commented Dec 2, 2013

@n1mmy OK, this time I managed to checkout the session-hooks branch... :-) I ran 10 simultaneous phantomjs instances in a loop against test-in-console; and then 4 simultaneous instances of Firefox with test-in-browser hacked to keep running tests over and over; both running against accounts-base, accounts-password, and livedata tests.

No luck, I do get the expireTokens error message occasionally but no actual test failures. Without a successful reproduction I'm not getting much forwarder...

@mitar
Copy link
Contributor

mitar commented Dec 6, 2013

Great stuff! Two questions:

  • Is there a hook to hook into login step? So that when userId is set, you can additionally set something else into session? And when userId is unset to clear?
  • Will that be available through Meteor.connection() as well? In the same manner that Meteor.userId() is? In this manner it would be possible to use connection inside collection.deny and collection.allow?

I completely agree that browser headers and IP should be exposed in some way, if HTTP was used for DDP. Because this would be really useful for example to determine the language of the user, timezone, geo location and so on.

@n1mmy
Copy link
Contributor

n1mmy commented Dec 9, 2013

Merged in b5cd66d

@n1mmy n1mmy closed this Dec 9, 2013
@n1mmy
Copy link
Contributor

n1mmy commented Dec 9, 2013

@mitar: yes, we'll have login hook eventually too. design ongoing at https://meteor.hackpad.com/Login-hooks-design-notes-o0809sK58jX. Also client IP eventually.

We still need to figure out how to make this available in more places, eg, allow / deny. Unfortunately, allow/deny callbacks take explicit positional arguments which make it hard to extend. We might want to make them take some sort of options hash to allow for extensibility.

@mitar
Copy link
Contributor

mitar commented Dec 9, 2013

@n1mmy: You could just provide Meteor.connection(). In general, Meteor.userId() works inside allow / deny anyway, so having that positional argument is a bit redundant.

@n1mmy
Copy link
Contributor

n1mmy commented Dec 9, 2013

Unfortunately, the name Meteor.connection is already taken on the client to mean the default DDP connection to the server. Having Meteor.connection mean one thing on the client and Meteor.connection() mean something else on the server sounds kinda confusing.

@mitar
Copy link
Contributor

mitar commented Dec 10, 2013

Oh, true. :-( But the name is not so important, the concept of having a function you call in a similar fashion as Meteor.userId(). But it is true that it should be named the same. So maybe it could be Meteor.serverConnection() and this.serverConnection inside publish?

BTW, but they are not so different concepts, no? On the client, Meteor.connection() gives you information about your connection to the server, on the server, Meteor.connection() gives you information to the client. In both cases you could store some additional information into it, which would preferably be synced automatically between client and server.

@mizzao
Copy link
Contributor

mizzao commented Dec 17, 2013

This seems super useful. Time to rewrite https://github.com/mizzao/meteor-user-status...

However, the previous method of tracking connections allowed for reading the IP address. How can we do this with the Meteor.onConnection callback now?

@awwx awwx deleted the session-hooks branch March 31, 2016 15:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants