failure using eventSourceSubscription
jesperldk opened this issue · 5 comments
I really would like to use autorest with SSE.
I am trying to use bits from this sample in my project. I am using XhrResourceBuilder.eventSourceSubscription unchanged, but I get a series of the following error when trying to connect:
ConsoleLogger.java:55 Exception: com.google.gwt.core.client.JavaScriptException: (TypeError) : this$static_0_g$.handleEvent is not a function
ConsoleLogger.java:32 TypeError: this$static_0_g$.handleEvent is not a function
at Wwx_g$ (JsEventListener.java:42)
at Nzw_g$ (JsElementalMixinBase.java:326)
at EventSource.<anonymous> (JsElementalMixinBase.java:271)
at Dp_g$ (Impl.java:239)
at Gp_g$ (Impl.java:291)
at EventSource.<anonymous> (Impl.java:77)
I am clueless about what is happening, and would appreciate any help, thank you a lot! :-)
Ah, Ignacio gave the answer elsewhere: GWT compiler param "-generateJsInteropExports".
Thank you!
But please, put this in an Autorest release ;-)
Nice. But, what do you mean with 'put this in AutoREST'? hehe about the generateJsInteropExport, I think this is a bug because should not be required in this cases, this is still a problem in 2.8.0? and in HEAD-SNAPSHOT? https://groups.google.com/forum/#!topic/google-web-toolkit/n20KWzUQpVY
The second option, which makes more sense, do you mean that I should add this XhrResourceBuilder? I don't think this is a good idea, first, the library is not stable enough but second and more important, I really think and encourage that users of AutoREST should create it's own ResouceBuilder visitor, using these proposals as templates. This makes the library super-flexible, much more simple, clean so maintainable. I created AutoREST based on the super complete and nice library RestyGWT, but I conclude that the complexity added to the custom RequestBuilder used in RestyGWT to make it customizable don't worth it. If you create your own copy, the code is not complex, makes it trivial to customize and at the end, makes the user much more conscious of what it actually happening. It is so simple that you can even copy paste any of this template and adapt to JRE, Android or GWT with minor/trivial changes as demonstrated here (https://github.com/ibaca/autorest-nominatim-example). This is a bit exaggerated but, hehe you should note that all these classes in this and sub-packages (https://github.com/resty-gwt/resty-gwt/tree/master/restygwt/src/main/java/org/fusesource/restygwt/client) is covered just in this one class XhrResourceBuilder.
Anyways, I think I'm going to release now to include the consumes/produces metadata, hehe because the previous solution was pretty ugly, I check the path name to know if this method is the method used as SSE because I haven't any other data 😞.
Ok, I respect that.
I do however think you could just add eventSourceSubscription from XhrResourceBuilder to the standard RequestResourceBuilder and call it in the standard as(), and that would still be clean and simple and quite general.
Also, I think that with Jersey the server side can be quite simple.
With an shared API like
@AutoRestGwt @Path("api") @Consumes(MediaType.APPLICATION_JSON)
public interface Api {
@GET @Produces(SseFeature.SERVER_SENT_EVENTS) Observable<Evnt> listen();
}
I do a straight forward implementation on the server
public class ResourceApi implements Api {
@Override public Observable<Evnt> listen() { return myEventGeneratingObservable; }
}
Unfortunately this can not be registered directly with Jersey, so instead I have to make the following trivial boilerplate and register that instead.
@Path("api") @Consumes(MediaType.APPLICATION_JSON)
public class ResourceApiSse extends SseRessource {
private Api api = new ResourceApi();
@GET @Produces(SseFeature.SERVER_SENT_EVENTS) public EventOutput listen() { return asEventOutput(Evnt.class, api.listen()); }
}
SseRessource is generic and can be just something like
public abstract class SseRessource {
protected <T> EventOutput asEventOutput(Class<? extends T> cls, Observable<T> o) {
final EventOutput eventOutput = new EventOutput();
final OutboundEvent.Builder eventBuilder = new OutboundEvent.Builder();
eventBuilder.mediaType(MediaType.APPLICATION_JSON_TYPE);
o.subscribe(new Subscriber<T>() {
@Override public void onStart() { request(1); }
@Override public void onCompleted() { close(); }
@Override public void onError(Throwable e) { close(); }
@Override public void onNext(T t) {
eventBuilder.data(cls,t);
try {
eventOutput.write(eventBuilder.build());
} catch (Throwable e) {
close();
Exceptions.propagate(e);
}
request(1);
}
void close() { if (!eventOutput.isClosed()) try { eventOutput.close(); } catch (Throwable t) {}}
});
return eventOutput;
}
}
ADDED for anybody else who stumble on this.
On the client side you just use AutoRest GWT and the XhrResourceBuilder from this project, then you can use the above API without further ado like for example this:
Api api = new Api_RestServiceModel(() -> new XhrResourceBuilder().path(myUrl));
FlowPanel history = new FlowPanel(); panel.add(history);
api.listen()
.doOnNext(evnt -> history.add(new Label(evnt.textattribute)))
.subscribe();
Neat!!
Oh! 😮 I need more time, in general sound good and reasonable. In the meantime, did you upload this to github? I don't see it in your profile? I need more testing with this builder, and I really don't like to mix incomplete elemental1 + jsni + jsinterop all in once. But I hope we found a bit nicer implementation so it can be included.
sorry, a bit embarrassing, but I am not yet using git(hub). I have been totally off programming for 6 years, and before that I worked for years with others who would handle all tooling. So I am on a steep curve where I try to prioritize my own project. Java 8, GWT, reactive, rest - hadn't used it ever until 8 weeks ago ;-) Git(hub) is on the list, but will not be before 3-4 weeks or so.
But there really isn't more than what is included above ;-) I would guess that the elemental1+jsni could quite easily be changed to jsinterop? Might give that a look next week, unless you beat me to it ;-)