How to access the Session Object Inside event bus in Vertx? - vert.x

My Request handler
router.route("/clientController/*").handler(sockJSHandler);
and my event bus is
eb.consumer("chat.to.server",message->{
System.out.println("Getting Request in Client Controller Event Bus");
JsonObject data = (JsonObject) message.body();
String classifier = data.getString("classifier");
if(classifier.equals("loginUri")) {
System.out.println("Request for Login URI");
vertx.executeBlocking(future -> {
future.complete(OAuth.getOAuthParam());
}, res -> {
eb.publish("chat.to.client", res.result());
});
}
is it possible to access the session object inside event bus as we do the normal routing handler as routingContext.getSession()

Short answer, you can't. Routing context session is not related to the eventbus. The eventbus can be deployed without having a HTTP server while routing context is a very web specific thing.
If you need to have state on your eventbus then I'd say you need to pass the session id in your message headers, and only if the session is clustered then you might be able to retrieve it from the cluster store by id. By doing so you might also introduce inconsistency so i'd advice not to do it.
Alternative just put all your required session data in your message payload.

Related

Response not submitted when rxEnd is used in HTTP server

I have a two verticle server written in vert.x + reactive extensions. HTTP server verticle uses event bus to send requests to the DB verticle. After receiving the response from the DB verticle (through event bus) I send the response to the http client using rxEnd. However clients does not seem to receive this response and times out eventually. If I were to use end() instead, things work fine. I use postman to test this REST API. Please see below for the code which forward results from the DB verticle to client.
routerFactory.addHandlerByOperationId("createChargePoints", routingContext -> {
RequestParameters params = routingContext.get("parsedParameters");
RequestParameter body = params.body();
JsonObject jsonBody = body.getJsonObject();
vertx.eventBus().rxRequest("dbin", jsonBody)
.map(message -> {
System.out.println(message.body());
return routingContext.response().setStatusCode(200).rxEnd(message.body().toString());
})
.subscribe(res -> {
System.out.println(res);
}, res -> {
System.out.println(res);
});
});
The rxEnd method is a variant of end that returns a Completable. The former is lazy, the latter is not.
In other words, if you invoke rxEnd you have to subscribe to the Completable otherwise nothing happens.
Looking at the code of your snippet, I don't believe using rxEnd is necessary. Indeed, it doesn't seem like you need to know if the request was sent succesfully.

Feign REST Client: How to get the HTTP status?

I have Feign client setup with Hystrix and I am trying to log all the HTTP status codes that I get from my API calls into a database. So this means, if one of my calls give me a 201, I would want to log that into DB. If my call results in a failure, my fallback handler can obviously log that but I want to do the DB inserts in one place. Does feign have a way to get access to responses or some kind of general callback?
You have to provide custom decoder to get your response in ResponseEntity<Object>.
NotificationClient notificationClient = Feign.builder()
.encoder(new JacksonEncoder())
.decoder(customDecoder())
.target(Target.EmptyTarget.create(NotificationClient.class));
Here you define your custom decoder bean. You can define your own by implementing Decoder but I'm using spring decoder.
#Bean
public Decoder customDecoder() {
HttpMessageConverter jacksonConverter = new MappingJackson2HttpMessageConverter(customObjectMapper());
ObjectFactory<HttpMessageConverters> objectFactory = () -> new HttpMessageConverters(jacksonConverter);
return new ResponseEntityDecoder(new SpringDecoder(objectFactory));
}
Now collect your response in ResponseEntity<Object>
ResponseEntity<Object> response = notificationClient.notify();
int status = response.getStatusCodeValue();
Another option is to create your own feign.Logger implementation, overriding the logAndRebufferResponse method:
protected Response logAndRebufferResponse(
String configKey, Level logLevel, Response response, long elapsedTime);
This may be simpler than creating a Decoder and is guaranteed to be called when a response is received regardless of status. Decoders are only called if the request does not trigger an error.

How to write a http REST service asynchronously

What is the recommended way in vert.x to write an Asynchronous request handler?
In this service, a request processing typically involves calling DB, calling external services, etc. I do not want to block the request handling thread however. What is the recommended way to achieve this using vet.x? In a typical asynchronous processing chain, I would use the request handling thread to emit a message to the message bus with the request object. Another handler will pick this message and do some processing such as checking request params. This handler can then emit a new message to the bus which can be picked up by the next handler which will do a remote call. This handler emits a new message with the result of the call which can be picked up by the next handler which will do error checking etc. Next handler would be responsible for creating the response and sending it to the client.
How one can create a similar pipeline using vert.x?
Everything, comprising request handlers for HttpServer, is asynchronous, isn't it?
var server = vertx.createHttpServer(HttpServerOptions())
server.requestHandler { req ->
req.setExpectMultipart(true) // for handling forms
var totalBuffer = Buffer.buffer()
req.handler { buff -> b.appendBuffer(buff) }
.endHandler { // the body has now been fully read
var formAttributes = request.formAttributes()
req.response().putHeader("Content-type","text/html");
req.response().end("Hello HTTP!");
}
// the above is so common that Vertx provides: bodyHandler{totalbuff->..}
}.listen(8080, "127.0.0.1", { res -> if(res.succeeded()) ... });
You just need to (end) write on req.response() on your final handler of your pipeline.
For a more stream-like implementation (i.e., not callback-based), you may use Vert.x Rx/ReactiveStreams API. E.g., you may use Vert.x Web Client for making requests, possibly using its Rx-fied API.

How do I call a method on my ServiceWorker from within my page?

I have a ServiceWorker registered on my page and want to pass some data to it so it can be stored in an IndexedDB and used later for network requests (it's an access token).
Is the correct thing just to use network requests and catch them on the SW side using fetch, or is there something more clever?
Note for future readers wondering similar things to me:
Setting properties on the SW registration object, e.g. setting self.registration.foo to a function within the service worker and doing the following in the page:
navigator.serviceWorker.getRegistration().then(function(reg) { reg.foo; })
Results in TypeError: reg.foo is not a function. I presume this is something to do with the lifecycle of a ServiceWorker meaning you can't modify it and expect those modification to be accessible in the future, so any interface with a SW likely has to be postMessage style, so perhaps just using fetch is the best way to go...?
So it turns out that you can't actually call a method within a SW from your app (due to lifecycle issues), so you have to use a postMessage API to pass serialized JSON messages around (so no passing callbacks etc).
You can send a message to the controlling SW with the following app code:
navigator.serviceWorker.controller.postMessage({'hello': 'world'})
Combined with the following in the SW code:
self.addEventListener('message', function (evt) {
console.log('postMessage received', evt.data);
})
Which results in the following in my SW's console:
postMessage received Object {hello: "world"}
So by passing in a message (JS object) which indicates the function and arguments I want to call my event listener can receive it and call the right function in the SW. To return a result to the app code you will need to also pass a port of a MessageChannel in to the SW and then respond via postMessage, for example in the app you'd create and send over a MessageChannel with the data:
var messageChannel = new MessageChannel();
messageChannel.port1.onmessage = function(event) {
console.log(event.data);
};
// This sends the message data as well as transferring messageChannel.port2 to the service worker.
// The service worker can then use the transferred port to reply via postMessage(), which
// will in turn trigger the onmessage handler on messageChannel.port1.
// See https://html.spec.whatwg.org/multipage/workers.html#dom-worker-postmessage
navigator.serviceWorker.controller.postMessage(message, [messageChannel.port2]);
and then you can respond via it in your Service Worker within the message handler:
evt.ports[0].postMessage({'hello': 'world'});
To pass data to your service worker, the above mentioned is a good way. But in case, if someone is still having a hard time implementing that, there is an other hack around for that,
1 - append your data to get parameter while you load service-worker (for eg., from sw.js -> sw.js?a=x&b=y&c=z)
2- Now in service worker, fetch those data using self.self.location.search.
Note, this will be beneficial only if the data you pass do not change for a particular client very often, other wise it will keep changing the loading url of service worker for that particular client and every time the client reloads or revisits, new service worker is installed.

ASP.NET Web Api: Delegate after Request

I have a problem with streams and the web api.
I return the stream which is consumed by the web api. Currently, i put the socket into a pool after getting the stream. but this cause some errors.
Now, I must putthe socket into the pool AFTER the request ended. (The stream was consumed and is now closed).
Is there a delegate for this or some other best practises?
Example code:
public HttpResponseMessage Get(int fileId)
{
HttpResponseMessage response = null;
response = new HttpResponseMessage(HttpStatusCode.OK);
Stream s = GetFile(id);
response.Content = new StreamContent(fileStream);
}
GetFile(int id)
{
FSClient fs = GetFSClient();
Stream s = fs.GetFileStream(id);
AddFSToPool(fs);
return s;
}
GetFile uses a self-programmed FileServer-Client.
It has an option to reuse FileServer-Connections. This connections will be stored in a pool. (In the pool are only unused FileServer-connections). If the next request calls GetFSClient() it gets an connected one from the pool (and removes it from the pool).
But if another requests comes in and uses a FileServer-Connection which is in the pool (because unused), there is still the problem, that the Stream is possibly in use.
Now I want to do the "put the FSClint into the pool" after the request ended and the stream is fully consumed.
Is there an entry point for that?
Stream is seen as a volatile/temporary resource - no wonder it implements IDisposable.
Also Stream is not thread-safe since it has a Position which means if it is read up to the end, it should be reset back to start and if two Threads reading the stream they will most likely read different chunks.
As such, I would not even attempt to solve this problem. Re-using streams on a web site (inherently multi-user / multi-threaded) not recommended.
UPDATE
As I said, still think that the best option is to re-think the solution but if you need to register something that runs after request finishes, use RegisterForDispose on request:
public HttpResponseMessage Get(HttpRequestMessage req, int fileId)
{
....
req.RegisterForDispose(myStream);
}