meteormeteor-accounts

How do you know when a resume login attempt is being made or was completed?


On the client:

  1. Can you tell on page load whether a resume login attempt will be made?
  2. Is there a hook for when the attempt returns? Can I listen for the right DDP message?

EDIT: Looks like Meteor.userId() is defined on page load when a resume login attempt will be made, which takes care of #1.


Solution

  • Here are a couple solutions:

    Watch DDP on client

    Unfortunately by the time the stream handler is called with the result of the login method, Meteor.connection._methodInvokers has been cleared – hence the search function. It would be nice if there was a different / more efficient way to know resumeMethodId. A few possibilities:

    .

    resumeAttemptComplete = (success) ->
      console.log 'resumeAttemptComplete', success
    
    resumeMethodId = null
    
    searchForResumeMethodId = ->
      for id, invoker of Meteor.connection._methodInvokers
        sentMessage = invoker._message
        if sentMessage.method is 'login' and sentMessage.params[0].resume?
          resumeMethodId = id
    
    if Meteor.isClient
      Meteor.connection._stream.on 'message', (messageString) ->
        unless resumeMethodId
          searchForResumeMethodId()
    
        message = JSON.parse messageString
    
        if message.id is resumeMethodId and message.msg is 'result'
          resumeAttemptComplete !message.error
    

    _methodInvokers definition: https://github.com/meteor/meteor/blob/de74f2707ef34d1b9361784ecb4aa57803d34ae8/packages/ddp-client/livedata_connection.js#L79-L83

    Server onLogin sends event to client

    // server:
    
    // map of connection ids -> publish function contexts
    let onResumePublishers = {}
    
    Meteor.publish('onResume', function () {
      onResumePublishers[this.connection.id] = this
    
      this.ready()
    
      this.onStop(() => {
        delete onResumePublishers[this.connection.id]
      })
    })
    
    let handleLoginEvent = function({connection, type}, loggedIn) {
      if (type === 'resume') {
        let publisher = onResumePublishers[connection.id]
        if (publisher)
          publisher.added('onResume', connection.id, {loggedIn}})
      }
    }
    
    Accounts.onLogin(function (loginAttempt) {
      handleLoginEvent(loginAttempt, true)
    })
    
    Accounts.onLoginFailure(function (loginAttempt) {
      handleLoginEvent(loginAttempt, false)
    })
    
    // client: 
    
    let resumeExpires = new Date(localStorage.getItem('Meteor.loginTokenExpires'))
    let resumeAttemptBeingMade = resumeExpires && resumeExpires > new Date()
    
    let OnResume = new Mongo.Collection('onResume')
    
    let onResumeSubscription = Meteor.subscribe('onResume')
    
    OnResume.find(Meteor.connection.id).observeChanges(
      added(id, {loggedIn}) {
        onResumeSubscription.stop()
        onResumeAttemptCompleted(loggedIn)
      }
    })
    
    let onResumeAttemptCompleted = function(success) {
      // ...
    }