How detect changes of an api - javascript

I have a api that returns if the building is open and how much peapole are in there.
Now i want my Discord Bot to send a message when the Building opens.
How do i do that?
if the api recives a request the response is looks this :
state: {
open: false/true
}

It may be helpful to clear out the terminology: the "API" in this context is the endpoints exposed by the server and their request/response schemas (you can think of it as the fields you send and receive back). Now, this doesn't change in your case: it's the same endpoint, and the same fields. What changes is the value.
Now, you are probably doing a HTTP request to a given URL, where the server is. And in HTTP world, we say that we are requesting a resource. The resource behind https://stackoverflow.com is the homepage of this website. The resource behind the endpoint you are calling is a building's state. This resource changes overtime, it may open or closed at any time, people going in and out. But the API doesn't change in this case.
Let's reword your question, so it can be clearer: How can a client know when a HTTP resource changes? If your server only exposes this endpoint to know the state of the building, the answer is a sad "it can't". Let's say that I close the building, the server knows it somehow and now the building's state is {"open": false}. But the server doesn't have any mechanism to say to your client that the state changed, the server just waits for the client to ask what the state is, and returns. Allowing a server to send data to your client without the client requesting first adds some complexity to your architecture, and although there's a bonus (the client will know of state changes as soon as possible), in your case, it may not be necessary.
One alternative is long polling, in long polling your client makes a request to the server and the server doesn't respond immediately, it... waits. Waits for an update, like a change in building's state. When an update happens, then it sends a response. The client, in turn, requests again! And waits for the server to send an update... In practice, the client will keep up with the server state. The mentioned article for long polling gives a good example: https://javascript.info/long-polling#regular-polling
The one caveat is that the server must also support long polling. If the server just returns whatever the resource's state is, then the client will keep receiving the same state over and over. Another valid solution is instead of waiting for updates, the client keeps requesting the server for every few seconds. You may miss some updates! But in some cases, it's fine to lose track of a few updates.
Ok, enough theory. What about your case? If you want to know if a door is open or closed, but don't care to know when it happens, you can just request the server every five seconds or so:
In some pseudo javascript code, and very inspired by the long polling article mentioned before:
async function subscribe() {
let buildingState = null
while (true) {
const response = await fetch("/subscribe")
if (response.status != 200) {
// An error - let's show it
showMessage(response.statusText)
}
// Get and show the message
const message = await response.json()
// a function that returns true/false if the state is different
if (stateChanged(message, buildingState)) {
updateDiscordBot(message)
buildingState = message
}
// wait five seconds and repeat
await new Promise(resolve => setTimeout(resolve, 5000));
}
}
subscribe();
This works fine. But if you want for your client to immediately know when a door is opened or closed, this is not enough: opening and closing a door is a quite fast action, and even if you request the server every second, you may lose updates. In this case, the server needs to change. Either by implementing long polling, or something like websockets... you didn't mention that the server is in your control, but if it doesn't, it may be helpful to talk with who maintains it to work out a solution.

If you only have pull access to that API then the only way to detect state change is to periodically send a request, store response, and trigger your bot on stored response change.

Related

How to notify without websocket

I want to integrate a simple notification system in my react application. I want to notify for example:
- new post (when the user post the system need time to transcode the media attached and the publication)
- missing settings (the user need to compile some information)
- interesting posts etc..
There is a simple way to add a websocket, like socket.io, to a reactjs app with an aws lambda backend?
All the notification not need to be read in real time, maybe an ajax call every 2 minutes can solve my problem, but, in this case, someone can help me avoid ajax call if the app isn't used(like if the app remain opened in a foreground tab...)
componentDidMount() {
this.liveUpdate()
setInterval(this.liveUpdate, 120000);
}
liveUpdate() {
axios.get(endpoint.posts+'/live/', cfg)
.then(res => {
// ...
});
}
This code is in the footer component, the call happen every 120 seconds, but the call will still happen also if a user leave the application opened in the browser and not use it, this on a lambda backend mean a waste of money.
There are 3 main ways of notifying that I can think of at the moment...
Long polling (using ajax etc)
Websocket
Push Notification
Push (though) requires permission from the user

Wait for an event to trigger inside Node.js process

First of all, I am well aware that Node.js is non-blocking before anything else, but in this very specific case, it must be blocking and waiting here.
I have an authentication process that works that way (using APIs, I didn't design this so I cannot modify the way the auth works):
I send a PUT request to a REST API, I get a HTTPResponse code that determines if the API understood the request.
The server I just requested through its API sends the full response (including error codes, etc) through an XMPP protocol.
This means, when I send the request, I cannot know what happened next, and must wait for the XMPP event to trigger (basically, an on("message", callback) event).
I'd like to know how to work with this with Node.js.
Two more things to know:
1) I'm working on a client/server architecture, and my Node.js server is doing this authentication process, and sending a response through the websocket to the client and waiting for a socket answer is out of the question (not my call, but my boss wants this process to be done in one pass).
2) It must not be done with the client socket and must go through the full Node.js process for various reasons.
Thanks a lot for your help people! \o/
Sorry for not answering previously, we had some severe hardware failure at work.
Anyway, I'm not answering one of your comments directly because I found a solution I prefer, even if I thank you for your help. I've decided to use a promise and to wait for its answer to be sure to get a proper response.
Here is the code:
var answer = await new Promise((accept, reject) => {
// If there are no stanza in 30 seconds, then the process failed or the stanza got missed.
setTimeout(() => {
reject("timed out");
}, (30 * 1000));
// Waiting for the xmpp event to trigger.
xmpp.on("stanza", function(stanza) {
// Processing of the received stanza goes here.
});
});
#gkatzioura solution was interesting, but this looked a little bit heavy on bandwidth and we are working on a large scale applications, or maybe I didn't fully understand it, then it is my mistake.
#pspi solution was also interesting but this would be a problem considering the XMPP event listener is inside the request, and the PUT request needs to send a body on its end() event and here it wouldn't really work for what I want to do. I think that's because the original post I made was somewhat unclear.
Thanks a lot for your help guys! :]
I don't know enough XMPP, but would this just be case of "putting dependent logic inside callback".
request.put(..., function () {
// dependent xmpp logic inside request callback
xmpp.on(..., function () {
// xmpp and put response received, now talk back to socket client
socket.send(...);
});
});
In your case I would proceed with the event emitter (or anything in a publish subscribe fashion).
Fire your http call and inside the handler add an emitter listener with a check if the events is for the corresponding authentication.
Meanwhile your xmpp connection once it receives the authorization it shall emit a message.
The listener will receive the message successfully and will use the callback of the http call.

Correct way to handle Websocket

I've a client to server Websocket connection which should be there for 40 seconds or so. Ideally it should be forever open.
The client continually sends data to server and vice-versa.
Right now I'm using this sequence:
var socket;
function senddata(data)
{
if (!socket)
{
socket = new WebSocket(url);
socket.onopen = function (evt) {
socket.send(data);
socket.onmessage = function (evt) {
var obj = JSON.parse(evt.data);
port.postMessage(obj);
}
socket.oneerror = function (evt) {
socket.close();
socket = null;
}
socket.onclose = function(evt){
socket = null;
}
}
}
else
{
socket.send(data);
}
}
Clearly as per current logic, in case of error, the current request data may not be sent at all.
To be frank it sometimes gives error that websocket is still in connecting state. This connection breaks often due to networking issues. In short it does not work perfectly well.
I've read a better design : How to wait for a WebSocket's readyState to change but does not cover all cases I need to handle.
Also I've Googled about this but could not get the correct procedure for this.
So what is the right way to send regular data through Websockets which handles well these issues like connection break etc?
An event you don't seem to cover is onclose. Which should work really well, since it's called whenever the connection terminates. This is more reliable than onerror, because not all connection disruptions result in an error.
I personally use Socket.IO, it enables real-time bidirectional event-based communication between client and server.
It is event driven. Events such as
on connection :: socket.on('conection',callback);
and
on disconnect :: socket.on('disconnect',callback);
are built in with socket.io so it can help you with your connection concerns. Pretty much very easy to use, check out their site if you are interested.
I use two-layer scheme on client: abstract-wrapper + websocket-client:
The responsibilities of the websocket-client are interacting with a server, recovering the connection and providing interfaces (event-emitter and some methods) to abstract-wrapper.
The abstract-wrapper is a high-level layer, which interacts with websocket-client, subscribes to its events and aggregating data, when the connection is temporary failed. The abstract-wrapper can provide to application layer any interface such as Promise, EventEmitter and so on.
On application layer, I just work with abstract-wrapper and don't worry about connection or data losing. Undoubtedly, it's a good idea to have here information about the status of connection and data sending confirmation, because it's useful.
If it is necessary, I can provide some code for example
This apparently is a server issue not a problem in the client.
I don't know how the server looks like here. But this was a huge problem for me in the past when I was working on a websocket based project. The connection would continuously break.
So I created a websocket server in java, and that resolved my problem.
websockets depend on lots of settings, like if you're using servlets then servlet container's settings matter, if you're using some php etc, apache and php settings matter, for example if you create a websocket server in php and php has default time-out of 30 seconds, it will break after 30 seconds. If keep-alive is not set, the connection wont stay alive etc.
What you can do as quick solution is
keep sending pings to a server after a certain amount of time (like 2 or 3 seconds, so that if a websocket is disconnected it is known to the client so it could invoke onclose or ondisconnect, I hope you know that there is no way to find if a connection is broken other than failing to send something.
check server's keep-alive header
If you have access to server, then it's timeouts etc.
I think that would help

Will ajax in beforeunload reliably execute?

I have a HTML5 application that needs to send a disconnect ajax request when the user changes/refreshes the page. I am currently using this code:
window.addEventListener("beforeunload", function(event) {
$.ajax({
url: api_disconnect,
data: { identifier: token },
method: "GET"
});
});
I don't need to process the response, or even ensure that the browser receives a response. My question is, can I rely on the server receiving the request?
And if not, how can I accomplish this? Currently I have the app send an "I'm alive!" request every 15 seconds (which already feels like too much). I want the server to know the second the user disconnects.
To clarify, I know that if the browser/computer crashes there's nothing I can do about that. That's what the heartbeat is for. I just mean in a normal use case, when the user closes/changes/refreshes the page.
You cannot 100% rely on the ajax call getting through. You can test many browsers and operating systems and determine which ones will usually get the ajax call sent before the page is torn down, but it is not guaranteed to do so by any specification.
The heartbeat like you are using is the most common work-around. That will also cover you for a loss in network connection or a power-down or computer sleep mode or browser crash which the beforeunload handler will not.
Another work-around I've seen discussed is to use a socket.io connection to the server. Since the socket.io connection has both a small, very efficient heartbeat and the server will see the socket get closed when the page is closed, you kind of get the best of both worlds since you will see an abnormal shut-down via the heartbeat and you will see a normal shut-down immediately via the webSocket connection getting closed.

Is there anyway in flex to get the status of server?

we have an application where button click in flex side restarts the server and makes the client logged out. once after logout, If user logs in it gives error since the server is not up by the time. In our scenario the server takes time to restart because of the stuff(like back up). I want the user to be notified of the webserver status if he tries to log in.
is there any way to monitor the status of server in Flex side. or Will javascript help in finding whether the server is up or not?.
Also I tried redirecting to html page using external interface but I am not sure how to automatically redirect it again to the swf file when the server becomes active.the server downtime is not known(may be 2 or 5 or 10 minutes.)
So what would be the best approach.Any help would be of greatly appreciated.
Using URLLoader you can try to download a file on the server and listen to ioError or httpStatus.
private var testLoader:URLLoader;
private var testRequest:URLRequest;
...
testRequest = new URLRequest("http://server/testFile");
testLoader = new URLLoader(request);
testLoader.addEventListener(HTTPStatusEvent.HTTP_STATUS, onStatus);
private function onStatus(HTTPStatusEvent:event):void
{
//test the status, if the server is up, reconnect, else...
testLoader.load(testRequest);
}
Interesting problem. When you mean restart, do you mean just a specific service like Apache or like an actual reboot of the server? I ask because it would mean different scenarios. I'm not exactly sure what you're doing, but I'll assume that you're rebooting the server.
One of the problems here is that the client logs out, which is something we do not want. What I would do is have a second server which it's sole purpose would be authentication and giving status on the other server. This is a 'man in the middle' approach where this server doesn't log you out, but all calls are redirected to the other server.
From the Flex side, you can have it calls the 'man in the middle' to see what's the status. Depending on the technology you're using (polling vs pushing), you can get the data needed and show the user the status.

Categories

Resources