I am developing a app that chooses a user and has a 15 sec. timer for that user to respond. The user app queries the db every 5 sec to see if that user is chosen. If so The mobile app begins a 15 sec. timer. The problem is that the timers will never match up because the user app can be on a different timer cycle that the backend and can query the db at a later time. I use Angular, NodeJS, and expressJS + MongoDB to develop this app.
any suggestion on how I can get the timers to be synchronized?
You don't need to have two timers running at the same time. Start a timer on the front-end, then let the back-end know when the timer on the front-end started. As long as you treat one side as the single source of truth, the other side will be able to infer whether the timer has finished or not.
Although the timers might not be synchronized, time should be the same everywhere. If the back-end knows that the front-end timer started at 12:01:00, it also knows that the timer will end at 12:01:15. In this way, it can just continue to check whether the current time is before or after 12:01:15.
This is definitely a job for websockets! Websockets unlike HTTP enable two way data flow so your server and client can talk in real-time. Socket.io is a really popular framework for enabling this type of interaction and hooks really seamlessly into node/express.
http://socket.io/
Here is a tutorial to get your started http://socket.io/get-started/chat/.
The basic flow will be
Open a socket between the user and the server.
When the user is chosen (I assume on the server-side) then do a io.emit('user chosen', { userId: '<the user id>' });. This will send a message over the socket to all attached applications.
Start the timer on the server and send info that the period is over. Something like this should work. setTimeout(() => socket.emit('user chosen end', { userId: '<the user id>' }), 15000);
In your app you will be listening for the 'user_chosen' event and can check if the logged in user has the same id as the one sent over the socket. If the user id's match enable the text input for the user to set the input. Something like this: socket.on('user chosen', function(msg){ /* Enable the input */ });
The app will also be listening for the 'user_chosen_end' event and if the ids of the user again match, disable the text input or do whatever else you need to do. Again this will look like: socket.on('user chosen end', function(msg){ /* Disable the input & do anything else */ });
Hope this helps :)
Related
So I made a website to show which services on my server are running and which are offline.
The site is an Vuetify App running in a docker container. My services are monitored via UptimeRobot.
Currently I use:
created: function () {
this.interval = setInterval(() => this.getStatuses(), 1000);
},
To trigger my API request function every second to update the status of my services.
But is there some smarter possibility to only update on change and not request every second to see if something happened?
Like I send one request to get the status and then receive a message when something changed? I hope you can understand, whats my problem. It's hard to decribe.
Yes you can by firing an event. for example:
in your app.js
window.Fire = new Vue();
For example here you create a user then you want to update table after creating a new user, Follow these steps:
createUser(){
// FireUpdate is your fire name, you can give it any name you want!
// Call this after you post something to specific route.
Fire.$emit('FireUpadte');
}
Then you will load new users using this approach:
created(){
// Load new Users after created.
Fire.$on('FireUpadte', () => { this.createUser(); });
}
For more information check this video: https://www.youtube.com/watch?v=DHuTkJzH2jI&list=PLB4AdipoHpxaHDLIaMdtro1eXnQtl_UvE&index=20
What you're looking for are websockets. You establish a websocket connection and it stays open, allowing the server to notify the web app when something changes.
You can run your own socket.io server on a Node.js backend or use a service like Pusher.com (very cheap, free tier is pretty big).
I highly recommend going the Pusher.com route, they also have great tutorials ; )
https://pusher.com
I've been playing around with building some realtime functionality using Sails.js version 0.10-rc5 (currently the #beta release).
To accomplish anything, i've been following the sweet SailsCast tutorial on this subject (sailsCast link)
It talks about subscribing to a model via a 'subscribe' action within the model's controller. Then listening to it at the client side, waiting for the server to emit messages. Quite straightforward, although I do not seem to receive any messages.
I'm trying to do this to get real-time updates on anything that changes in my User models, or if new ones get created.. So I can display login status etc. in real time. Pretty much exactly the stuff that's explained in the sailsCast.
In my terminal i'll get two things worth noticing, of which the first is the following:
debug: Deprecated: `Model.subscribe(socket, null, ...)`
debug: See http://links.sailsjs.org/docs/config/pubsub
debug: (⌘ + double-click to open link from terminal)
debug: Please use instance rooms instead (or raw sails.sockets.*() methods.)
It seems like the 'subscribe' method has been deprecated. Could anybody tell me if that's correct, and tell me how to fix this? I've been checking out the reference to the documentation in the debug message, although it just points me to the global documentation page. I've been searching for an answer elsewhere, but haven't found anything useful.
The second message I'm getting is:
warn: You are trying to render a view (_session/new), but Sails doesn't support rendering views over Socket.io... yet!
You might consider serving your HTML view normally, then fetching data with sockets in your client-side JavaScript.
If you didn't intend to serve a view here, you might look into content-negotiation
to handle AJAX/socket requests explictly, instead of `res.redirect()`/`res.view()`.
Now, i'm quite sure this is because I have an 'isAuthenticated' policy added to all of my controllers and actions. When a user is not authenticated, it'll redirect to a session/new page. Somebody must log in to be able to use the application. When I remove the 'isAuthenticated' policy from the 'subscribed' action, the warnings disappear. Although that means anyone will get updates via sockets (when I get it to work), even when they're logged out. - I don't really feel like people just sitting at the login screen, fishing out the real time messages which are intended only for users who are logged in.
Can anyone help me getting the real time updates to work? I'd really appreciate!
As far as the socket messages not being received, the issue is that you're following a tutorial for v0.9.x, but you're using a beta version of Sails in which PubSub has gone through some changes. That's covered in this answer about the "create" events not being received.
Your second issue isn't about sockets at all; you'll just need to reconsider your architecture a bit. If you want to to use socket requests to sign users in, then you'll have to be more careful about redirecting them because, as the message states, you can't render a view over a socket. Technically you could send a bunch of HTML back to the client over a socket, and replace your current page with it, but that's not very good practice. What you can do instead is, in your isAuthenticated policy, check whether the request is happening via sockets (using req.isSocket) and if so, send back a message that the front end can interpret to mean, "you should redirect to the login page now". Something like:
module.exports = function (req, res, next) {
if ([your auth logic here]) {
return next();
}
else {
if (req.isSocket) {
return res.json({status: 403, redirectTo: "/session/new"});
} else {
return res.redirect("/session/new");
}
}
}
I am using play 2.0 for a realtime web application that connects to a backend socket in order to listen for data on that stream.
The following example does what I want but I don't know how to disconnect the socket if the clients webpage is closed or page has changed.
def comet = Action {
val out = Enumerator.imperative[String]()
val socketClient = new SocketClientModel("localhost", "testclient",
Option("username"), "password", out)
socketClient.listen
Ok.stream(out &> Comet(callback = "console.log"))
}
The problem that I am having is figuring out how to call socketClient.disconnect when the page has been closed or changed. Currently when I close the browser session I can still see the connection is established and data is being received on the server side.
A hacky solution could be for you to have a ping call in the other direction (client to server):
You setup a timer that will destroy the connection if it hasn't been canceled before 10 seconds (you can always setup a longer period):
var timer;
def comet = Action {
timer = Akka.system.scheduler.scheduleOnce(10 seconds) {
socketClient.disconnect
}
...
}
You setup an Action that receives pings and setup a timer in the javascript code to send requests to that route every 9 seconds:
def keepAlive = Action {
cancel.cancel
timer = Akka.system.scheduler.scheduleOnce(10 seconds) {
socketClient.disconnect
}
}
When the user goes to another page, or cancel the connection to the comet Action, then it should also cancel the ping timer on the client side (if the user change page, this should be automatic, but you will have to have some health check on the comet connection if you stay in the same page, etc.). When the client stops pinging your action, the timer will eventually kill the socket.
It's really ugly as you need to use a var that is shared between your two actions and it's not really thread safe. It also would only be able to support one client. But the code example you have given is the same I guess. You would need to track which session has open which socket to support multiple client. You would loose stateless behaviour though.
A cleaner solution would be to use a small actor system to encapsulate this behaviour:
- you have a SocketActor that, when it receives a Start message, opens a socket and pushes things on a PushEnumerator, it keeps doing this as long as it doesn't receive a Stop message.
- you also have a KeepAliveActor that will after a given amount of time send a Stop message to the SocketActor, unless it has received a KeepAlive message before (so, what's going on here).
When you receive a comet connection, you spawn two new actors (you should have a manager actor to hide the two actors and relay the messages, etc.) and keep a ref to them linked to the session. The keepalive action would then fetch the ref for the right session and send KeepAlive messages to the actor.
The SocketActor would, when it receive a Stop message close the socket and destroy the actors that were linked to him.
It's a bit more involved coding, so I am not including snippets, but it would be a simple AKKA system, so you should be able to set it up by checking out the AKKA tutorials if you are not yet used to it.
im a newbie both in spring security and spring-security-facebook and in an app that we are building we have to couple them.Everything is working well i will need to know the way to listen to the facebook login success event. is there some one that already did a stuff that impose him to catch the facebook event success?? I need that because in the begining of the app (before adding the spring -security-Facebook plugin ); we have a special behaviour attached to the "grails.plugins.springsecurity.onInteractiveAuthenticationSuccessEvent" event (configured in the config.groovy file) and we have to execute the same special behaviour when the user connect with facebook account. Is there an event (extending springsecurity kinds of events) that we have to listen to?
any idea ??
Ps: when searching for solution we found a way to catch the FB js Events and work around to reach what we want as result but we would as possible to want to not go that way ....
The problem with it that current Spring Security Facebook authenticates user on each request (by listening to FB cookie, transparently), so you'll get this event on each request. Probably it's not what you want, right? It the same as having a filter on each request.
Btw, you can handle situation when user login into your app first time, but implementing onCreate(user, token) or afterCreate(user, token) in service FacebookAuthService (you have to create such service at this case)
Example:
File grails-app/services/FacebookAuthService.groovy:
class FacebookAuthService {
void afterCreate(def user, def token) {
log.info("New user!") //or any code there
}
}
I'm writing a Catalyst application that's required to have a fairly short session expiration (15 minutes). I'm using the standard Catalyst framework authentication modules, so the user data is stored in the session -- i.e., when your session expires, you get logged out.
Many of the uses of this application will require >15 minutes to complete, so users will frequently submit a form only to find their session state is gone and they're required to log back in.
If this happens I want to preserve the original form submission, and if they log in successfully, continue on and carry out the form submission just as if the session had not expired.
I've got the authentication stuff being handled by an auto() method in the controller -- if you request an action that requires authentication and you're not currently logged in, you get redirected to the login() method, which displays the login form and then processes it once it's submitted. It seems like it should be possible to store the request and any form parameters when the auto method redirects to the login(), and then pull them back out if the login() succeeds -- but I'm not entirely sure of the best way to grab or store this information in a generic/standard/reusable way. (I'm figuring on storing it in the session and then deleting it once it's pulled back out; if that seems like a bad idea, that's something else to address.)
Is there a standard "best practices" or cookbook way to do this?
(One wrinkle: these forms are being submitted via POST.)
I can't help thinking that there's a fundamental flaw in mandating a 15 minute timeout in an app that routinely requires >15 minutes between actions.
Be that as it may, I would look at over-riding the Catalyst::Plugin::Session->delete_session method so that any contents of $c->request->body_parameters are serialised and saved (presumably to the database) for later recovery. You would probably want some rudimentary check of the POST arguments to ensure they're what you're expecting.
Similarly, create_session needs to take responsibility for pulling this data back out of the database and making it available to the original form action.
It does seem like a messy situation, and I'm inclined to repeat my first sentence...
UPDATE:
Whether you use delete_session or auto, the paradoxical issue remains: you can't store this info in the session because the time-out event will destroy the session. You've got to store it somewhere more permanent so it survives the session re-initialization. Catalyst::Plugin::Session itself is using Storable, and you should be able to with something along these lines:
use Storable;
...
sub auto {
...
unless (...) { #ie don't do this if processing the login action
my $formitems = freeze $c->request->body_parameters;
my $freezer = $rs->update_or_create(
{user => $c->user, formitems => $formitems} );
# Don't quote me on the exact syntax, I don't use DBIx::Class
}
...
my $formitems = $c->request->body_parameters
|| thaw $rs->find({$user => $c->user})->formitems
|| {} ;
# use formitems instead of $c->request->body_parameters from here on in
The underlying table probably has (user CHAR(x), formitems TEXT) or similar. Perhaps a timestamp so that nothing too stale gets recovered. You might also want to store the action you were processing, to be sure the retrieved form items belong to the right form. You know the issues for your app better than me.
I would store the form data as some sort of per user data in the model.
Catalyst::Plugin::Session::PerUser is one way of doing that (albeit somewhat hackishly). I would reccomend using the session plugin only for authentication and storing all the state info in the model that stores your user data instead.
And I totally agree with RET's opinion that the 15 minute limit seems really counter productive in this context.
I came across this whilst searching CPAN for something entirely unrelated.
Catalyst::Plugin::Wizard purports to do exactly what you need. The documentation suggests it can redirect to a login page whilst retaining the state of the previous action.
NB: I haven't used it, so can't vouch for its effectiveness.
In the end, we ended up grabbing the pending request (URL+params) in the auto(), serializing and encrypting it, and passing it via a hidden form element on the login page. If we got a login request with the hidden element populated, we decrypted and deserialized it and then redirected appropriately (making sure to pass through the standard "can this user do this thing" code paths).
You could always have some javascript on the client that keeps the session from expiring by making a small request every few minutes.
Or you could have AJAX check for an active session before posting the form and presenting the user with a new login box at that time if needed.