koajs / koa.io

[MAINTAINERS WANTED] Realtime web framework combine koa and socket.io.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

How would I send a callback styled response to a client side event emitter

knowthen opened this issue · comments

I just noticed koa.io today, pretty slick!
I think I will do a screencast on this soon.

I was looking for a way to do a callback in response to an event.
With normal socket.io it would be done like below 'cb'

socket.on('someEvent', function (data, cb) {
  // do something with data...
  cb(null, 'client done processing data...');
});

I looked through the code and it doesn't seem to be possible, unless I'm missing something.

It would be pretty cool to be able to do something like

app.io.route('someEvent', function *(next, data){
  // do something with data...
  this.body = 'client done processing data...';
});

and have the message 'client done processing data...' get sent back as the callback to the clientside emitter.

Your thoughts?

Thanks!

I'm wondering the same thing. This is a bit of a dealbreaker if it's not possible, because it would require refactoring all of my client code.

Is this project still active? I'll be happy to give this issue a go and look into how to implement it, I was working on a similar idea then found your repository, that, while not exactly what I'm looking for, seems quite useful and I would be happy to contribute back

commented

I currently solve this problem like this: https://github.com/rashfael/koa.io/commit/3caf742fb1c3163335f3f5eee9cfbe0b1c629e7c

I can then do:

app.io.route('someEvent', function *(next, data) {
  // do something with data...
  this.ack('client done processing data...');
 });

This is not the koa/generators way, and @knowthen's proposal sounds much better and looks doable, but I started digging into ES6 and koa just days ago and haven't figured out all the bits yet.

Well, few weeks of node under the belt here, so not really an expert... Said that, I think that what @knowthen propose is doable.
Based on your change in the router file, you just need to add a setter function in the socket object created by koa.io. Something like:

Socket.prototype.__defineSetter__('body', function (ack_params) {
  this.ack(ack_params);
});

then, you should be able to do this in your app:

app.io.route('someEvent', function *(next, data){
  // do something with data...
  this.body = 'client done processing data...';
});

I will update my github fork when I got access to my dev box. Please bear in mind that I have no idea of performance or other consequences of this approach, but it does seem in line with the logic in the rest of the koa.io code

commented

Using a setter is a good idea, but I think we should not directly invoke the socket.io ack in the setter. I just had a look into the response handling in koa, and it looks like it is solved as a privileged middleware (https://github.com/koajs/koa/blob/0ad06c9810079174660fa4948ca183d9b90efd3c/lib/application.js#L179-L220), it always gets invoked first. We probably should adapt the same approach.

commented

I prototyped this here: https://github.com/rashfael/koa.io/commit/153f1c8c5c25729f3cefeb77888db92b8d2fca55
While implementing this, I noticed that co.gen is used differently than in koa, and because of this, control wasn't returned to routes after a yield? Can someone verify if this is indeed a bug introduced by 6abce9e, or am I just holding it wrong?

cool. It's the same approach taken in the app.callback() function of koa, so design wise seems spot on.
I think you are right about the bug, looking at the code and the co library wiki, now co.wrap return a promises and the callback should be called with .then(). But, this is just reading the code, so some koa/co expert should really confirm this

@bambalaus co.wrap returns a function that returns a promise, that function takes an argument which is the resolved value of the promise it returns.

@hallas do you mean that it does the same? As mentioned I'm not a nodejs expert at all, but If this is the case I think that it would be better to stick to the usage pattern as defined in the official co wiki (with .then()), as it is used in koa.js as well. It would make it easier to understand.

Any progress on implementing this support in some form? Without this functionallity is is a bit of a dealbreaker for me as well.

@mattiasrunge: Not AFAIK, but I will try to got to it soon, probobly this weekend or next

Ok, this will defiantly be in v0.1.0. Here's what I'm thinking of, syntax wise (I'm open to suggestions though):

app.io.route('getStatus', function* (next, data) {

    // do something

    this.body = 'awesome';
});
commented

The parameters for the acknowledgment in socket.io are in an array. Callbacks accept multiple parameters. I often use the (error, data) pattern.

To reflect this, should this.body be an array?

this.body = [null, {_id: 3, text: 'some content'}];

For usability, we could automatically wrap a single value into an array.

@rashfael PRs welcome and we can continue discussion there?