i am using vue.js for webrtc client. My system has multi servers so i need to pick one and connect. I am getting server list from my webservice. Everything is ok till here, i want user connect to best server so decided to make custom ping (its called rtt, i think).
to sum up my aim is send a udp packet to server(sendTime in long), then server receives this packet and now server sends my a packet(receiveTime in long) => this servers ping is receiveTime - sendTime
So i will do this for every server and choose best server.Is it posible to send and receive udp packet or anyone got better idea?
In my opinion the simplest way would be to make a get request to every url, then do a promise race on the requests, which one returns the fastest is the server you would use.
const urls = ['https://www.google.com/', 'https://www.facebook.com/', 'https://www.twitter.com/', 'https://www.instagram.com/'];
const serverPromises = [];
urls.forEach((url) => {
serverPromises.push(
new Promise((resolve, reject) => {
fetch(url, {
mode: 'no-cors'
}).then((response) => {
if ([400, 500, 404].includes(response.status)) {
return reject(null);
}
return resolve(url);
})
})
);
});
Promise.race(serverPromises).then((url) => {
if (url) {
console.log('URL to use: ', url);
}
});
Check it out, see if it suits your needs!
To me this seems to be the easiest, and quickest way, without any calculations, plus you get the result as soon as the first request resolves, this way you don't have to wait for every request to resolve.
Related
I am bulding a cloudflare worker and I want to cache a fetch request for at least 24 hours. This mean if I make the same request twice within 24h the fetch() should not be called and used the cached response.
I've written this script, but the remote website (unixtimestamp.com) it's called every time.
addEventListener("fetch", event => {
event.respondWith(handleRequest(event.request))
});
async function handleRequest(request) {
const url = 'https://www.unixtimestamp.com/'
let response = await fetch(url, {
cf: {
cacheTtlByStatus: { "200-299": 60*60*24, 404: -1, "500-599": -1 }
}
})
return response
}
Documentation: https://developers.cloudflare.com/workers/examples/cache-using-fetch
I'm wondering if Page rules is more efficient in this case than workers in your case ? (moreover, workers count calls can be limited depending on your plan)
I have done once in page rules (and is easily configurable) with Cache TTL by status code option.
When I paste and search this url
https://api.openweathermap.org/data/2.5/forecast?lat=39.48923&lon=-0.4780256&appid=b11fc49d6b14456d6aacedc8d0153072
it makes the request just fine:
But then on my code, when I want to fetch it and save this json it turns out with "Network request failed":
I have only used fetch() with local urls and it always worked.
This is my code (you can use my api key I can generate a new one later):
GetClima() {
//fetch(`${this.state.api.url}lat=${this.props.latitudDestino}&lon=${this.props.longitudDestino}&appid=${this.state.api.key}`)
fetch("https://api.openweathermap.org/data/2.5/forecast?lat=39.48923&lon=-0.4780256&appid=b11fc49d6b14456d6aacedc8d0153072")
.then(res => res.json())
.then(res => {
this.setState({
dataClima: res
})
})
}
This is because your emulator/simulator isn't connected to the internet. I can see your Wi-Fi icon in the status bar saying that it isn't connected to the internet.
It clearly says Type Error: Network Request Failed. Make sure that you have configured your virtual device properly and check your internet connection.
Having that said, make sure that you catch the errors properly using .catch() or using try-catch block if you're using async-await
I am using server sent events in MEAN stack.
I am able to push data from server to client whenever required.
But one thing i noticed that even if i am the only client hitting the server. There are multiple listeners for me and events are broadcast to say 40 listeners(if i wait long enough for the client to reconnect 40 times).
Multiple listeners are also created when user reloads.
How can i limit the listeners to say 1 listener to per event per client. Is this even possible with server sent events.
I am trying to keep the connection open as long as the user is using the website and close only when the browser/tab is closed or clients request a reload.
NOTE : stream is an EventEmitter object which I use to pass events so that the required changes can be monitored and appropriate data can be send through server sent events.
const function = async (request: Request, response: Response) => {
console.log("client connected to broadcasting channel")
console.log("listeners : " , stream.listenerCount('event-L'))
response.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
"X-Accel-Buffering": "no"
});
response.flushHeaders();
stream.on('event-L', (event, data) => {
console.log("Broadcasting event-L")
response.write('event: ' + event + '\n' + 'data:' + JSON.stringify(data) + '\n\n')
}
})
stream.on('event-U', (event, data) => {
console.log("Broadcasting event-U.")
response.write('event: ' + event + '\n' + 'data:' + JSON.stringify(data) + '\n\n')
}
})
response.on('close', () => {
console.log('client dropped me');
response.end();
})
}
When the client closes the socket, you must close the server side response object that was servicing it.
At least when using the http package directly, the code is something like this:
request.connection.on("close", function(){
response.end();
//Any other clean up, e.g. clearInterval() for any timers.
console.log("Client closed connection. Aborting.");
});
That was copied from p.25 of my book, Data Push Apps with HTML5 SSE.
At https://stackoverflow.com/a/59041709/841830 there is an example for Express.js, which they write it as:
response.on('close', () => {
console.log('client dropped me');
//Any other clean up
response.end();
});
Assuming request.connection and response are the same object, then this is the same code, and therefore not specific to Express at all.
UPDATE based on code in question
Your stream.on() calls are adding a listener to an event. They are therefore part of the "clean up" in you have to do when the client disconnects. I.e.
response.on('close', () => {
console.log('client dropped me');
response.end();
stream.off('event-L', eventLHandler);
stream.off('event-U', eventUHandler);
})
See https://nodejs.org/api/events.html#events_emitter_off_eventname_listener
Notice how you need to specify the event handler function, so cannot use anonymous functions. Refactor your code to have two event handlers (that take response as an arg).
I have a little problem with my application.
My architecture:
Angular 6 (front)
NodeJS + Express + MongoDB (back)
There is a part, in my NodeJS application, that communicates with a REST API.
When an user clicks on button on the Angular WebSite, I send a request to Express.
In my Express application, I send another request to the API to retrieve information.
But this process takes a lot of time. My request timeout
What is the best solution to keep my process working after the Express reply has been sent?
Should I do otherwise?
Assuming the problem is with timeout, you can increase the default timeout:
You may set the timeout either globally for entire server. Read more here:
var server = app.listen(app.get('port'), function() {
//Server is running
});
server.timeout = 1000; //1000 is one second.
or just for specific route. Read more here:
app.post('/xxx', function (req, res) {
req.setTimeout(500000);
});
You can also change the timeout for the other API request you are making. Read more here
//Assuming you are using request module.
var options = {
url: 'http://url',
timeout: 120000
}
request(options, function(err, resp, body) {});
In this document, it uses URL.createObjectURL to set the video source. (This is the code to answer a call).
var offer = getOfferFromFriend();
navigator.getUserMedia({video: true}, function(stream) {
pc.onaddstream = e => video.src = URL.createObjectURL(e.stream);
pc.addStream(stream);
pc.setRemoteDescription(new RTCSessionDescription(offer), function() {
pc.createAnswer(function(answer) {
pc.setLocalDescription(answer, function() {
// send the answer to a server to be forwarded back to the caller (you)
}, error);
}, error);
}, error);
});
I expected video.src to be the address to retrieve the remote video. So it should be fixed and given by the other side of the connection (whoever initiated the call). But the value of URL.createObjectURL is generated on the answerer's side, and it event depends on when the function is called. How it can be used to get the remote video stream?
Edit:
The result of URL.createObjectURL looks like blob:http://some.site.com/xxxx-the-token-xxxx. With this string, how does the video component know where to load the remote stream? Is there a hashmap of {url:stream} stored somewhere? If so, how does the video component access the hashmap?
A stream object does store a token string, which you can get with stream.toURL. But it is different from the result of URL.createObjectURL. The value of URL.createObjectURL depends on time. If you call it twice in a row, you get different values.
URL.createObjectURL(stream) is a hack. Stop using it. Efforts are underway to remove it.
Use video.srcObject = stream directly instead. It is standard and well-implemented.
This assignment of a local resource should never have been a URL in the first place, and is a red herring to understanding how WebRTC works.
WebRTC is a transmission API, sending data directly from one peer to another. No content URLs are involved. The remote stream you get from onaddstream is a local object receiver side, and is the live streaming result of the transmission, ready to be played.
The documentation you read is old and outdated. Thanks for pointing it out, I'll fix it. It has other problems: you should call setRemoteDescription immediately, not wait for the receiver to share their camera, otherwise incoming candidates are missed. Instead of the code you show, do this:
pc.onaddstream = e => video.srcObject = e.stream;
function getOfferFromFriend(offer) {
return pc.setRemoteDescription(new RTCSessionDescription(offer))
.then(() => navigator.getUserMedia({video: true}))
.then(stream => {
pc.addStream(stream);
return pc.createAnswer();
})
.then(answer => pc.setLocalDescription(answer))
.then(() => {
// send the answer to a server to be forwarded back to the caller (you)
})
.catch(error);
}
It uses srcObject, avoids the deprecated callback API, and won't cause intermittent ICE failures.
Because a WebRTC connection involves several steps and what you get from such a connection is a stream. But the src property of the video tag does not accept a stream, but a URL. And this is the way to "convert" a stream to a URL.