Is there a smart possibility to get API results without sending requests every second? [VueJS | Vuetify] - rest

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

Related

What is the best Socket.IO design for my application?

Realising this is gonna be a very general question but I am gonna try to be as specific as possible:
What is the best way to design/structure an Socket.IO app?
I have a NodeJS backend with React frontend, with authentication (user must log in). I have several REST endpoints, for example /foo, /bar, /baz.
I know you can use rooms and namespaces, and I know you can add authentication to the connect as middleware, but I have no idea what the best solution is to glue this all together. I will be using this socket for multiple purposes. For each purpose I am curious what the best way to go is (flow).
General CRUD messages: When someone posts a "foo" on the server side, it needs to also send this to that particular user. WHen someone deletes a "foo", it also needs to send something to this user. So this CRUD messaging should only be for one specific user (based on logged in user ID). How would structure those messages? Namespace for "foo"? Multiple event listeners: on "foo create", on "foo delete", on "foo update?" How to make sure you only send to this user?
I have multiple pages on the client side, for the respective CRUD endpoint. So when I am on the "foo" page, I need to get updates on the "foo" backend object. How can I accomplish this?
General server side messages: I will be running long-running scripts on the server side, started by a user (or by a time trigger). If I go to that page in react and if there are long running scripts active that belong to me, I need to see those logging. (but again, they are personal so those messages are only for me).
Thanks in advance if you need more clarification just ask me and I will add this to my question.
EDIT:
I think the CRUD part can better be created as having only an "listener for updates" (like the firebase onSnapshot). So on page foo, I will listen to updates in the foo database, but the updates or creations are dont through normal REST API. Is that indeed the better way?
You can authenticate socket.io connection in 'connection' event or using middleware - doc.
Also you can use some package from npm, for example this
After authentication store user data in socket object or as separate object in 'connection' event scope.
io.on('connection', (socket) => {
const handshake = socket.handshake;
const user = // fetch user obj according data in handshake, for example, from jwt token in header
});
So after you can use user object in other events for this connection.
Private messages according to your task I implemented in my project using rooms. Here abstract example:
// this is just a helper to get room name according to userId
getUserRoomName(userId) {
return `user_${userId}`;
}
// function to send data to user
sendToUser(userId, event, data) {
io.to(getUserRoomName(userId)).emit(event, data);
}
// in 'connection' event add join to user room
io.on('connection', (socket) => {
const handshake = socket.handshake;
const user = // fetch user obj according data in handshake, for example, from jwt token in header
// join to private room
socket.join(getUserRoomName(user.userId), () => {
// some logic
});
});
So, when the user connected to socket.io we join his connection to private user room. And every connection of same user will be joined to same room, so we can isolate data sending messages to this room.
Using sendToUser method you can send any type of data to all user connections from any part of your application:
sendToUser(userId, 'foo_create', data);
OR
sendToUser(userId, 'foo', {
action: 'create',
// some other data
});

How to synchronize backend timer with mobile app

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 :)

Real time model events in Sails.js 0.10-rc5

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");
}
}
}

Incoming Phone call to make a Popup inside of SugarCRM?

Hello I am trying to make a module that will make a popup window inside of SugarCRM when we receive a phone call. I have seen that some others have accomplished this already (expensive paid modules) and I am hoping to get some insight on the actual popup triggering part....
Our phone system has an API that sends an HTTP post to a URL when we have an incoming phone call.
Inside of SugarCRM, in my Modules code, I am not sure how I can use this HTTP POST from my Phone to do the Popup, the reason is I do not see how it can be fast enough, If I were to set a Cron job to check a page every 1 minute, that would still be too slow.
So does anyone have any ideas how the other similar Phone integration modules are doing it and having the Popup happen almost immediately as the phone call comes in?
Any ideas on how to do such a task? I am planning to do a Desktop application that just sits in the Tray and waits for the POST but seeing others have been able to get the same result inside of SugarCRM without a separate program really interests me.
I am working in a company that has created a expensive paid module to accomplished this, but I can give you hints for 2 ways to achieve this ;-)
1) With GenericHook
in custom/modules create a logic_hooks.php and a YOURCHOICEHERE.php
in the logic hooks create an after ui hook
$hook_array['after_ui_frame'] = Array();
$hook_array['after_ui_frame'][] = Array(1, 'Display Javascript for Telephone','custom/modules/YOURCHOICEHERE.php','GenericHooks', 'displayTelephoneJS');
and in YOURCHOICEHERE.php
class GenericHooks {
function displayTelephoneJS() {
if(!$_REQUEST['to_pdf']) echo '<div id=\"telephone_div\"></div>
<script type=\"text/javascript\" src=\"custom/somewherewhereyouwant/Telephone.js\"/></script>';
// you yould also add a stylesheet here
}
}
in the Telephone.js you can do what ever you want for example:
function Telephone_poll() {
$.post("some.php?poll=1,function(data){
if(data != 0)
{
var result= JSON.parse(data);
//HERE you can do manipulate your telephone_div and populate it with response data "result" from the call to some.php
$('#telephone_div').html("<span>HELLO<span>");
$('#telephone_div').show();
//Here you can also add styles and so on
}
setTimeout("Telephone_poll()", 1000); //restart the function every 1000ms
});
}
Telephone_poll(); //initial start of script
2) An other approach would be creating a demon/service from a php file that reruns itself.
Here you would need some way to identify users and Phones to ensure the popup is displayed for the correct user/phone.

Using Everyauth/Express and Multiple Configurations?

I'm successfully using Node.js + Express + Everyauth ( https://github.com/abelmartin/Express-And-Everyauth/blob/master/app.js ) to login to Facebook, Twitter, etc. from my application.
The problem I'm trying to wrap my head around is that Everyauth seems to be "configure and forget." I set up a single everyauth object and configure it to act as middleware for express, and then forget about it. For example, if I want to create a mobile Facebook login I do:
var app = express.createServer();
everyauth.facebook
.appId('AAAA')
.appSecret('BBBB')
.entryPath('/login/facebook')
.callbackPath('/callback/facebook')
.mobile(true); // mobile!
app.use(everyauth.middleware());
everyauth.helpExpress(app);
app.listen(8000);
Here's the problem:
Both mobile and non-mobile clients will connect to my server, and I don't know which is connecting until the connection is made. Even worse, I need to support multiple Facebook app IDs (and, again, I don't know which one I will want to use until the client connects and I partially parse the input). Because everyauth is a singleton which in configured once, I cannot see how to make these changes to the configuration based upon the request that is made.
What it seems like is that I need to create some sort of middleware which acts before the everyauth middleware to configure the everyauth object, such that everyauth subsequently uses the correct appId/appSecret/mobile parameters. I have no clue how to go about this...
Suggestions?
Here's the best idea I have so far, though it seems terrible:
Create an everyauth object for every possible configuration using a different entryPath for each...
Apparently I jumped the gun and wrote this before my morning cup of coffee, because I answered my own question, and it was quite easy to implement. Basically I just had to create my own custom express middleware to switch the everyauth configuration before the everyauth gets its grubby paws on the request, so...
var configureEveryauth = function()
{
return function configure(req, res, next) {
// make some changes to the everyauth object as needed....
next();
};
}
and now my setup becomes:
var app = express.createServer();
everyauth.facebook
.entryPath('/login/facebook')
.callbackPath('/callback/facebook');
app.use(configureEveryauth());
app.use(everyauth.middleware());
everyauth.helpExpress(app);
app.listen(8000);
Notice that I don't even bother fully configuring the everyauth Facebook object during the startup, since I know that the middleware will fill in the missing params.