horizon
horizon copied to clipboard
Spec out and build a presence API (i.e. is this user logged in?)
TBD
I think you'll have to begin by designating that a table is going to be used for storing users (and/or?) presences.
I'm kind of partial to Slack's presence API
var fusion = new Fusion("localhost:31420");
var chatRoomPresence = fusion.collection("chatRoomPresence", {presence: true});
var user1 = chatRoomPresnce.find(id, 1);
user1.getPresence();
// {
// presence: "active" | "away",
// online: <boolean> (This would have to be maintained by Fusion Server and the current active WebSocket connections)
// last_activity: <timestamp>
// }
user1.setActive()
// Now presence set to active.
//Subscribe to presence changes
user1.subscribePresence().on("active", <function>).on("away", <function>)
//Change to your own automatic set away timeout.
chatRoomPresence.setAwayTimeOut(< Integer | Time in seconds >)
Subscribe to all user input events to run .setActive()
From here, it'd be nice to make it really stupid easy to allow the developer to make all interactivity events such as key[up|down|*], mouse[down|up], etc to run user1.setActive().
Bring your own timeHandler
As well, maybe when creating the table we'd want to allow them to do their own time checking like, fusion.collection("chatRoomPresence", {presence: true, timeHandler: <function>}), but by default we'd just start a setInterval that ran every second? Not sure the how to do this the most effectively.
I think this API should feel more distinct from the collections API:
var fusion = new Fusion("localhost:31420");
var presence = fusion.presence(); // use some default collection name
var presence = fusion.presence('chat', { activityTimeout: <Number | function> }); // full options
@coffeemug @dalanmiller @mglukhovsky @Tryneus I am putting this in subsequent (vs. initial release), but it hasn't come up in discussions much, so I may have been getting the wrong read on how important it is
Copied discussion from #51 :
@ha1331
Say I wanted to implement the "user so and so is typing" feature. I could update or insert a document and use subscribe() to get that info. I wouldn't need that "user was typing information" for anything and so updating/inserting would actually be waste of I/O. Having a mechanism for passing just that kind of information might be useful. Tho if RethinkDB implements memory tables, that could be used for this purpose nicely, I think.
@dalanmiller :
Totally agree @ha1331 that doing it that way would be rather kludgey. We have the intention of having a presence feature set for Fusion which should include this functionality and have a much nicer API.
@coffeemug :
:+1: -- we should add an interface for volatile messaging. Under the hood we can implement it via memory tables, but from the perspective of a fusion user this is an abstraction, and we can do it in other ways too. This probably won't make it into v1, but I definitely think this should be one of the services fusion eventually provides.
I think it's reasonable to put this in subsequent. We're getting close to release date (we'll talk about it together this week), so for now I'd like to limit the scope of the project instead of expanding it. I still think this is pretty important; once we launch we'll know pretty quickly if we need to put this in v1 or if it can wait a little bit longer.
We just started prototyping with Horizon, and would love the ability to hook into some type of presence API.
Well my company thought it would be the simplest use case to integrate into our applications.
Unfortunately I have been hitting walls after wall on how to handle this properly. When the user just alt+f4 his browser my only options seems to catch the window.upload event, BUT any async operation afterwards will just get cancelled. If I send synchronous AJAX to my back end then It is no longer "write apps without any backend" deal. That is why I went to try and implement extra routes in the express wrapper for the server but then... I have to figure how to hook everything correctly with the api... :(
@telammaite: what about creating a simple "heartbeat" solution for each user. When they have logged in to your application, send a ping to Horizon with a timestamp. Then you could write a simple query for users with a heartbeat ping in the last 30s (or minute)? This should satisfy to situation when the browser is closed.
Just a thought...we're looking at some kind of presence API as well.
@ericodom Thanks a lot for the nice idea! I guess your point is to write the heartbeat update query on the frontend. I guess it will send the user browser timestamp? To get updates I will watch for a timestamp with some offset as a changefeed let say 30 seconds.
What will happen if user A and user B browser timestamps are different more than 30 seconds. My guess user A could never see for example user B as online?
What do you think about it ? Is there a way to get the Horizon.server timestamp which should be a constant across all clients? Is there another build in timestamp that I could use?
Sorry for the volume of questions but your idea might work perfectly!
@telemmaite If you want to rely on the client timestamp convert it to universal time and that way it's gonna be the same. Otherwise you said that you are making extra routes for that - can't you take a timestamp from the server? @ericodom it's a pretty good idea actually 👍
I really like how Firebase handles presence, so made a quick stab at adding it to Horizon:
https://github.com/zwily/horizon/commit/0b1f169af8d13b733441ef816c1ca890bf55841f
Basically, it lets you specify commands to run server-side when your client disconnects. The commit above includes an example of how to use it in the react-chat example. I'm going to add some tests and submit a PR, but this is my first look at Horizon source so I may have missed a bunch of things. This feature does let me transition a bunch of my Firebase projects to Horizon though.