Flask socketIO emit series of events - reactjs

I would like server to emit series of events to client (React) after connection is established, Ive tried:
#socketio.on('connect')
def test_connect():
for i in range(10):
emit('my response', {'data': 'Connected ' + str(i)})
time_module.sleep(2)
but events shows in web browser console at the same time, like they arrived at the same moment, in react I use :
useEffect(() => {
const socket = socketIOClient(ENDPOINT);
socket.on('my response', function (data) {
console.log('my response: ', data.data);
})
})

There are two potential problems in your server code.
First of all, what is time_module in your example? I suspect that is a blocking sleep that you are doing. Instead, I suggest you sleep properly with socketio.sleep(2).
The second problem is that you are doing this in the connect event handler. The Socket.IO server waits until you return from the connect handler to decide if the client is accepted or rejected, so in general you do not want this handler to take a long time to run, because the connection isn't fully established until you return. I suggest you move this logic to a background function instead.
The following code addresses both issues:
def initial_events():
for i in range(10):
emit('my response', {'data': 'Connected ' + str(i)})
socketio.sleep(2)
#socketio.on('connect')
def test_connect():
socketio.start_background_task(initial_events)

Related

Request Deferrer with Service Worker in PWA

I am making a PWA where users can answer the forms. I want it to make also offline, so when a user fills out a form and does not have the internet connection, the reply will be uploaded when he is back online. For this, I want to catch the requests and send them when online. I wanted to base it on the following tutorial:
https://serviceworke.rs/request-deferrer_service-worker_doc.html
I have managed to implement the localStorage and ServiceWorker, but it seems the post messages are not caught correctly.
Here is the core function:
function tryOrFallback(fakeResponse) {
// Return a handler that...
return function(req, res) {
// If offline, enqueue and answer with the fake response.
if (!navigator.onLine) {
console.log('No network availability, enqueuing');
return;
// return enqueue(req).then(function() {
// // As the fake response will be reused but Response objects
// // are one use only, we need to clone it each time we use it.
// return fakeResponse.clone();
// });
}
console.log("LET'S FLUSH");
// If online, flush the queue and answer from network.
console.log('Network available! Flushing queue.');
return flushQueue().then(function() {
return fetch(req);
});
};
}
I use it with:
worker.post("mypath/add", tryOrFallback(new Response(null, {
status: 212,
body: JSON.stringify({
message: "HELLO"
}),
})));
The path is correct. It detects when the actual post event happens. However, I can't access the actual request (the one displayed in try or fallback "req" is basically empty) and the response, when displayed, has the custom status, but does not contain the message (the body is empty). So somehow I can detect when the POST is happening, but I can't get the actual message.
How to fix it?
Thank you in advance,
Grzegorz
Regarding your sample code, the way you're constructing your new Response is incorrect; you're supplying null for the response body. If you change it to the following, you're more likely to see what you're expecting:
new Response(JSON.stringify({message: "HELLO"}), {
status: 212,
});
But, for the use case you describe, I think the best solution would be to use the Background Sync API inside of your service worker. It will automatically take care of retrying your failed POST periodically.
Background Sync is currently only available in Chrome, so if you're concerned about that, or if you would prefer not to write all the code for it by hand, you could use the background sync library provided as part of the Workbox project. It will automatically fall back to explicit retries whenever the real Background Sync API isn't available.

Meteor redirect client from server-side method

Meteor 1.6, React, React Router
Interfacing with Paypal billing-agreements
Client onClick event:
subPayPal(){
Meteor.call('paypal.getToken', this.props.user_id, (error, response) => {
if(error) {
console.warn(error);
}else{
console.log(response);
}
}
}
I'm calling the method on the server rather than on the client because I'm dealing with privileged info (usernames, passwords, tokens, etc). No problem here.
Server methods:
Meteor.methods({
'paypal.getToken': function getOauthToken(uid){
// simplified a bit
// check if current token valid
// set vars here, then go get token
axios.post(ppAPI, data, config)
.then( function(response) {
// save oAuth token
})
.catch( function(error){
// stuff here
})
// prepare another axios.post(), with oauth Token, to get a payment token
// and approval_url and execute_url from paypal
// call axios.post() and use data in response:
// with the approval_url in this reponse, I need to redirect
// the browser to the approval_url on paypal.com so that the user
// can sign into paypal, and ok the subscription agreement.
// once user 'ok' in paypal, the browser comes back to my site,
// where I render a 'cart' with a final 'ok, purchase' button.
return approval_url;
}
})
So, once I have the approval_url, I can send it back to the client, and when the client "sees" it, it can then call the React Router to the paypal.com site.
PROBLEM
The client's onClick method is obviously async and as soon as I click the initial onClick(), the console.log outputs undefined for process which makes perfect sense.
TRIAL 1
So, I tried using Meteor.apply in the client trying to make it synchronous, waiting for the server-side method to return the approval_url to no avail:
subPayPal(){
Meteor.apply('paypal.getToken', [{uid:user_id}], {
onResultReceived: (error, response) => {
if(error) console.warn(error.reason);
if(response) console.log('server response', response);
}
});
}
I also tried Meteor.call('paypal.getToken').then({ console.log(response) }).catch... to no avail either, as it is still async.
I've also tried try/catch blocks in the server-side method, to no avail. Whatever I try, the server-side code always runs as expected (with exception of the Meteor.call().then().catch() which just plain failed). I just can't seem to promise it, or return it.
TRIAL 2
The next thought would be not caring about the response on the client, if I could get the server-side method, with approval_url defined, to somehow call the React Router on the client and push the unique approval_url to it, but that doesn't make much sense to me how to wire that up.
THOUGHT 1
I guess I could use some "temporary" database collection, which is reactive, so that when the server-side method completes, it'll update (or insert/create) a document, and when the client 'sees' that, it could then call the React Router to redirect the browser to paypal.com. The collection document would have to hold the approval_url URI, which would then be passed down to the client. Not too sure how I'd wire the client to tell the Router when it sees the approval_url "appear".
Sooooo....
Any ideas? Is there more than one solution (and if so, what would be the best?).
I read somewhere that the app should logout the user, then the Router could redirect to paypal, but that doesn't help, as paypal.com redirects back to me, and I wouldn't want the user to have to log back in again.
THANKS.

Does it make sense to create promise from StompClient SEND request?

I want to make additional request to server after SEND message through StompClient was successfully maintained.
function sendActivity() {
connected.promise.then(function () {
stompClient
.send('/app/activity',
{},
angular.toJson(/*some data*/));
}).finally(function () {
/*additional Rest request to Server */
});
}
It's currently working on my local machine but i'm not sure that operations are working synchronously as i wanted.
Could you please assist with my sitiation?
Not really. It's better to wait for ack from server for your 'app/activity' message and then do other stuffs.

send multiple responses to client via nodejs

i am using nodejs and i want to send back multiple responses to client.And my code is below
//addwork
var agenda = require('../../schedules/job-schedule.js')(config.db);
exports.addwork = function(req, res) {
var work = new Work(req.body);
work.user = req.user._id;
var user=req.user;
work.save(function(err) {
if (err) {
return res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
} else {
console.log('created work....'+work);
console.log('dateeeeeeeeeeeee'+work.created);
console.log('calling agenda job now, user is: '+ JSON.stringify(req.user));
console.log('supervisor-------------------------'+JSON.stringify(user.supervisor));
agenda.now('Work_To_Supervisior_Notify', {supervisor:user.supervisor,title:work.title,details:work.details});
res.jsonp(work);
res.send({message:'An email has been sent to ' + user.supervisor + ' with further instructions.'});
}
});
};`
//job-schedule.js
var Agenda = require("agenda");
var emailJob = require('./jobs/email-job.js');
module.exports = function(agendaDb) {
var agenda = new Agenda({db: { address: agendaDb}});
emailJob.sendWorkToSupervisiorEmail(agenda);
agenda.start();
return agenda;
}
//email-job.js
exports.sendWorkToSupervisiorEmail = function(agenda){
agenda.define('Work_To_Supervisior_Notify',{priority: 'high', concurrency: 10}, function(job, done){
console.log('Send works to supervisior ' + JSON.stringify(job.attrs.data.supervisor)+' ,title '+job.attrs.data.title+' ,details '+job.attrs.data.details);
var smtpTransport = nodemailer.createTransport(config.mailer.options);
var mailOptions = {
to: job.attrs.data.supervisor,
from: config.mailer.from,
subject: 'work done by user',
html: '<b>work title : '+job.attrs.data.title+' <br/>work details : '+job.attrs.data.details+'</b>'
};
smtpTransport.sendMail(mailOptions, function(err) {
if (!err) {
console.log('An email has been sent to ' + job.attrs.data.supervisor + ' with further instructions.');
res.send({message:'An email has been sent to ' + user.supervisor + ' with further instructions.'});
}
});
done();
})
}
Here i want response either from agenda or from res.send() message in addwork function
If i use res.send in addwork function it shows ERROR as "can't set headers after they sent".And if i use res.send message in sendWorkToSupervisiorEmail() it show ERROR as "there is no method send".I am new to nodejs please help me with solution
A http request only gets a single http response. Using http, you only get one response. Some options for you:
1) Wait for everything to finish before replying. Make sure each part creates a result, success or failure, and send the multiple responses at once. You would need some control flow library such as async or Promises to make sure everything responded at the same time. A good choice if all parts will happen "quickly", not good if your user is waiting "too long" for a response. (Those terms were in quotes, because they are application dependent).
2) Create some scheme where the first response tells how many other responses to wait for. Then you'd have a different HTTP request asking for the first additional message, and when that returns to your client, ask for the second additional message, and so on. This is a lot of coordination though, as you'd have to cache responses, or even try again if they were not done yet. Using a memory cache like redis (or similar) could fulfill the need to holding responses until ready, with a non-existent meaning 'not ready'
3) Use an eventing protocol, such as WebSockets, that can push messages from the server. This is a good choice, especially if you don't know how long some events would occur after the trigger. (You would not want to stall a HTTP request for tens of seconds waiting for 3 parts to complete - user will get bored, or quit, or re-submit.). Definitely check out the Primus library for this option. It can even serve the client-side script, which makes integration quick and easy.

Using Request/Reply in SAGA NserviceBus

I'm creating a SAGA in NServiceBus. This saga is handling some string which has to be transformed then validated and finally imported. These three actions are separate services. I want the actions as separate handlers in NServiceBus. I'm using the Request/Reply functionality in NServiceBus. Like this:
Bus.Send<TransformRequest>("Backend", m =>
{
m.string = string;
m.MessageId = messageId;
})
.Register(i =>
{
Console.WriteLine("transform finished")
});
The transformationHandler is as follows.
public void Handle(TransformRequest message)
{
var transformationResult = _transformationService.Transform(message.string);
var response = new TransformResponse()
{
string= transformationResult,
messageId = message.messageId,
};
Bus.Reply(response);
}
My question is as follows. When a request is sent to the transformationHandler. A message is sent to the messagequeue. Then hypothetical, the server crashes. The server reboots, the server picks up the TransformationRequest, does it work and wants to do a reply to the Saga, but how? The saga is not alive anymore and can't handle the .Register. How do I handle this problem?
Thank you.
NServiceBus will find the saga instance using a header in the response message automatically for you.
As Sean mentions you need to skip .Register and add a handler for transform result in your saga. The reason is that callbacks using .Register is stored in memory and therefor won't survive a restart

Resources