rijs / fullstack

modern fullstack framework
242 stars 21 forks source link

Ripple Scope: Global & Session #11

Closed pemrouz closed 9 years ago

pemrouz commented 9 years ago

Rippling changes globally as far and wide as possible is the default, but sometimes this is not desired. For example, when a user logs in, you don't want to trigger an update to all connected clients - just the newly authorised user. This can now be achieved using ripple.emit(sessionID)(resource). This has the brilliant effect that if you have multiple login pages open, logging into one will log you into all of them, and logging out of one will automatically log you out of the others!

To achieve this you need a hollow resource:

ripple
  .resource('user', {}, { from: login, to: user, cache: null })

In the to-proxy, we can use the this.sessionID to pick out the session from the session store (this is the socket being sent data):

function user() {
  return [sessions[this.sessionID]]
    .filter(Boolean)
    .map(JSON.parse)
    .map(key('user'))
    .pop() || {}
}

In the from-proxy, we can receive a login attempt and update the user resource on that particular client on success:

function login(key, attempt) {
  var session = auth.login(attempt)
  if (!session) return log('login fail', attempt, this.sessionID)
  log('login success', session, this.sessionID)
  sessions.set(this, 'user', session)
  ripple.emit(this.sessionID)('user')
  return false
}

For the login page on the client, you should listen for updates and redirect accordingly:

ripple('user').username
    ? request('/dashboard')()
    : ripple('user')
        .once('response', check)

And the reverse for protected pages to automatically log them out:

!ripple('user').username
    ? request('/login')()
    : ripple('user')
        .once('response', check)

Morever, express and socket.io are set up to share sessions, so you can receive a traditional HTTP POST request to login and respond with a ripple.emit(req.sessionID).