2012-04-21 11 views

Respuesta

18

Una técnica es implementar un método "keepalive" que cada cliente llama regularmente. Esto supone que tiene un user_id en cada cliente Session.

// server code: heartbeat method 
Meteor.methods({ 
    keepalive: function (user_id) { 
    if (!Connections.findOne(user_id)) 
     Connections.insert({user_id: user_id}); 

    Connections.update(user_id, {$set: {last_seen: (new Date()).getTime()}}); 
    } 
}); 

// server code: clean up dead clients after 60 seconds 
Meteor.setInterval(function() { 
    var now = (new Date()).getTime(); 
    Connections.find({last_seen: {$lt: (now - 60 * 1000)}}).forEach(function (user) { 
    // do something here for each idle user 
    }); 
}); 

// client code: ping heartbeat every 5 seconds 
Meteor.setInterval(function() { 
    Meteor.call('keepalive', Session.get('user_id')); 
}, 5000); 
+0

Después de mucho buscar, creo que esta es la mejor solución por el momento. ¡¡Gracias!! – greggreg

+6

Esto es casi un pseudocódigo, ya que no está funcional como está: el primer setInterval no tiene un intervalo especificado. Además, el comando Connections.update no especifica la actualización {'user_id': user_id}. Puede haber otros errores. Sin embargo, es un buen comienzo. –

+3

@debergalis ¿Sigue siendo esta la manera recomendada de ver si los clientes están muertos? – user2602152

1

si está utilizando autenticación tiene acceso al ID del usuario en el Método y Publicado funciones, se podría implementar su seguimiento no .. por ejemplo, podría establecer un "visto por última vez" habitación cuando el usuario cambia:

Meteor.publish("messages", function(roomId) { 
    // assuming ActiveConnections is where you're tracking user connection activity 
    ActiveConnections.update({ userId: this.userId() }, { 
     $set:{ lastSeen: new Date().getTime() } 
    }); 
    return Messages.find({ roomId: roomId}); 
}); 
13

creo que mejor forma de hacerlo es ponerse al zócalo evento de cierre en función de publicar.

Meteor.publish("your_collection", function() { 
    this.session.socket.on("close", function() { /*do your thing*/}); 
} 

ACTUALIZACIÓN:

reciente versión de meteoritos utiliza _SESSION así:

this._session.socket.on("close", function() { /*do your thing*/}); 
+0

Eso es genial. Pero luego aparentemente me encuentro con este problema: http://stackoverflow.com/questions/10192938/meteor-code-must-always-run-within-a-fiber-when-calling-collection-insert-on-s – huyz

+0

Gracias . Esta es la respuesta a mi pregunta: [Meteor observa ejecutarse para siempre] (http://stackoverflow.com/q/12902392/599991) – zVictor

+3

Uso el meteorito 0.6.1 y para esta línea 'this.session.socket.on (" close ", function() {/ * haz lo tuyo * /});' mi servidor devuelve _TypeError: no se puede leer la propiedad 'socket' de undefined_ Pero cuando lo corrijo a 'this._session.socket.on (" close ", function() {/ * haz lo tuyo * /}); 'funciona genial, gracias – fantom

2

he implementado un paquete inteligente Meteor que rastrea todas las sesiones conectadas de diferentes sesiones y detecta tanto en la sesión de cierre de sesión y desconecta eventos, sin un mantenimiento caro.

https://github.com/mizzao/meteor-user-status

para detectar eventos de desconexión/cierre de sesión, sólo puede hacer lo siguiente:

UserStatus.on "connectionLogout", (info) -> 
    console.log(info.userId + " with session " + info.connectionId + " logged out") 

También se puede utilizar de forma reactiva. ¡Echale un vistazo!

EDIT:v0.3.0 de estado de usuario ahora también rastrea a los usuarios que están inactivos!

+0

¿Se puede hacer esto por página y no a través de toda la aplicación? – Scalahansolo

+0

Sí, aunque eso aún no está implementado. Abra una solicitud de función! –

-1

Estoy usando Iron Router y llamo a mi código de limpieza en el evento unload de mi controlador principal. Seguro que esto no va a coger el caso de un cierre de pestaña, pero todavía se siente lo suficientemente bueno para muchos casos de uso

ApplicationController = RouteController.extend({ 
    layoutTemplate: 'root', 
    data: {}, 
    fastRender: true, 
    onBeforeAction: function() { 
     this.next(); 
    }, 
    unload: function() { 
     if(Meteor.userId()) 
      Meteor.call('CleanUpTheUsersTrash'); 
    }, 
    action: function() { 
     console.log('this should be overridden by our actual controllers!'); 
    } 
}); 
Cuestiones relacionadas