Send data from a Javafx-Client over Websockets to EventBus - javafx

I have a Socket handler in Vert.x and I know how to send data through the EventBus in a client-to-server (from Web Browser to Web Server) and server-component-to-server-component fashions.
Now I have a JavaFX-Client connected to the Vert.x Socket handler through websockets:
public void start() {
vertx.createHttpClient()
.setHost(Main.SOCKET_SERVER)
.setPort(8080)
.connectWebsocket("/chat/service", new Handler<WebSocket>() {
#Override
public void handle(WebSocket websocket) {
ws = websocket;
websocket.dataHandler(new Handler<Buffer>() {
#Override
public void handle(Buffer data) {
System.out.println("Received Data");
}
});
//...
// use ws for authentification
ws.writeTextFrame("doAuthentification");
//...
}
}
}
The Socket is connected to "/chat/service".
Now I want to use this Websocket to call different Services from Vert.x. I know that EventBus is not working from JavaFX-Client.
On the server:
ws.dataHandler(new Handler<Buffer>() {
#Override
public void handle(final Buffer data) {
String text = data.toString();
if(text.contentEquals("doAuthentification")){
logger.info("doAuthentification()");
doAuthentification();
}
// ...
}
}
I can now send "commands" like doAuthentification through the WebSocket, then, on server side and when that command is received, I can use the EventBus to process it further.
What would be the correct way using it from a client. Ideas?

Since you application is packaged as a standalone application is not deployed as in a Vert.x instance, you won't be able to call the event-bus since it is a Vert.x specific feature.
Your method to go would be, as you already tyried, to communicate to your Vert.x application in a standard way, through socket, or http for example (I would recommend HTTP and a RESTful application style), and send messages through an entry point that will be later on transferred to the appropriate verticles.
You may need to configure many path based handlers, maybe using a regex capture group inside, and let each handler choose the appropriate schema to delegate events, instead of having a single handler based on hardcoded messages.

Related

SignalR - access clients from server-side business logic

I have a requirement to start a process on the server that may run for several minutes, so I was thinking of exposing the following hub method:-
public async Task Start()
{
await Task.Run(() => _myService.Start());
}
There would also be a Stop() method that allows a client to stop the running process, probably via a cancellation token. I've also omitted code that prevents it from being started if already running, error handling, etc.
Additionally, the long-running process will be collecting data which it needs to periodically broadcast back to the client(s), so I was wondering about using an event - something like this:-
public async Task Start()
{
_myService.AfterDataCollected += AfterDataCollectedHandler;
await Task.Run(() => _myService.Start());
_myService.AfterDataCollected -= AfterDataCollectedHandler;
}
private void AfterDataCollectedHandler(object sender, MyDataEventArgs e)
{
Clients.All.SendData(e.Data);
}
Is this an acceptable solution or is there a "better" way?
You don't need to use SignalR to start the work, you can use the applications already existing framework / design / API for this and only use SignalR for the pub sub part.
I did this for my current customers project, a user starts a work and all tabs belonging to that user is updated using signalr, I used a out sun library called SignalR.EventAggregatorProxy to abstract the domain from SignalR. Disclaimer : I'm the author of said library
http://andersmalmgren.com/2014/05/27/client-server-event-aggregation-with-signalr/
edit: Using the .NET client your code would look something like this
public class MyViewModel : IHandle<WorkProgress>
{
public MyViewModel(IEventAggregator eventAggregator)
{
eventAggregator.Subscribe(this);
}
public void Handle(WorkProgress message)
{
//Act on work progress
}
}

Vert.x publish HttpServerRequest to other module

if i receive a HttpServerRequest in a Handler, is it somehow possible to publish the request?
I want to implement a small demo website with an index.html and an unknown number of sub sites. At first there should be a main vert.x module, which starts the HttpServer. In this main module it should be possible to add other dependent modules. I will call them submodules now. I don't know how many submodules i will have later, but each submodule should contain the logic to handle the http response for a specific URL (the sub html files). I guess i have to do the same for the WebSocketHandler...
A small example of the code inside the start():
//My Main Module:
vertx.createHttpServer().requestHandler(new Handler<HttpServerRequest>() {
public void handle(HttpServerRequest req) {
vertx.eventBus().publish("HTTP_REQUEST_CONSTANT", req);
}
}).listen(8080);
// My submodule 1
vertx.eventBus().registerHandler("HTTP_REQUEST_CONSTANT", new Handler<HttpServerRequest>() {
#Override
public void handle(HttpServerRequest req) {
if (req.uri().equals("/")) {
req.response();
}
}
});
// Other submodules which handles other URLs
Or any other solutions? I just don't wanna have the logic for sub sites in the main module.
Edit: Or could i call the vertx.createHttpServer() method in each submodule?
I have a similar Vert.x based application and I ended up doing the following:
I have a HttpServerVerticle that is started from the MainVerticle. There I created an HttpServer with several matchers. Each matcher receives a request and forwards it to a dedicated verticle through theEventBus. Upon getting the response from a dedicated verticle it writes the answer to the response.
Here is a code snippet:
RouteMatcher restMatcher = new RouteMatcher();
EventBus eventBus = vertx.eventBus();
HttpServer httpServer = vertx.createHttpServer();
restMatcher.post("/your/url",
r -> {
r.bodyHandler(requestBody -> {
final int length = requestBody.length();
if(length == 0) {
//return bad request
r.response().setStatusCode(HttpResponseStatus.BAD_REQUEST.code());
r.response().end();
return;
}
eventBus.send("your.address.here",
requestBody.getString(0, length),
new Handler<Message<JsonObject>>(){
#Override
public void handle(Message<JsonObject> message) {
//return the response from the other verticle
r.response().setStatusCode(HttpResponseStatus.OK.code());
if (message.body() != null) {
r.response().end(message.body().toString());
}
else{
r.response().end();
}
}
});
});
});
httpServer.requestHandler(restMatcher);
httpServer.listen(yourPort,yourHost);
In the dedicated verticle you register a listener to the address:
vertx.eventBus().registerHandler("your.address.here", this::yourHandlerMethod);
The handler method would look something like the following:
protected void yourHandlerMethod(Message<String> message){
// do your magic, produce an answer
message.reply(answer);
}
This way you separate your logic from your HTTP mappings and can have different pieces of logic in separate verticles using multiple event bus addresses.
Hope this helps.

Get names of Online users connected to a Server

I am new to asp.net. I have gone through this link which has shown how to count the online users connected to a server using asp.net. (which is working when I tried)
My question is: What should I change in that code (Global.asax) so that It shows all the names of the connected users instead of counting them.
I created a chat application which stores the name of the connected user in a variable chatUsername in js file as shown below:
js file
var chatUsername = window.prompt("Enter Username:", "");
//
chat.client.addMessage = //Function
//
chat.server.send(chatUsername);
.aspx.cs file
//Using SignalR (I think this doesnt matter)
public class Chat : Hub
{
public void Send(string from)
{
// Call the addMessage method on all clients
Clients.All.addMessage(from);
}
}
You can find my complete code here
EDIT: Please provide a simple example related only to asp.net or signalr (no other technologies like MVC)
Please help.
Edit: following code refers to SignalR v0.5, not the latest 1.0Alpha2, but I believe the reasoning is the same
To do this you need to add several steps to your SignalR connection process, both in the server and in the client:
on the server side:
on application start-up, for example, you can instantiate a static in-memory repository (can be a dictionary of ) that will serve as the user repository to store all currently connected users.
In the hub you need to handle the Disconnect event (when a user disconnects, needs to be removed from the user repository as well) and notify all other clients that this user disconnected
In the hub you need to add two new methods (the names can be whatever you want) that will help client connect to the system and get the list of currently connected users:
GetConnectedUsers() that just returns a collection of connected users
Joined() where the Hub will create a new User, using the info stored in the round-trip state (the username selected by the client) and the SignalR connection ID, and add the newly created user to the in-memory repository.
on the client side:
First you need to instantiate the javascript object that relates to your server-side hub
var chat = $.connection.chat;
chat.username = chatUsername;
Then implements all the functions that will be called by the hub and finally connect to the hub:
// Step 1: Start the connection
// Step 2: Get all currenlty connected users
// Step 3: Join to the chat and notify all the clients (me included) that there is a new user connected
$.connection.hub.start()
.done(function () {
chat.getConnectedUsers()
.done(/*display your contacts*/);
});
}).done(function () {
chat.joined();
});
});
});
If you are asking why we need to add a stage like "chat.joined()" is because in the method on the Hub that is handling the connection event, the round-trip state is not yet available, so the hub cannot retrieve the username chosen by the user.
Anyway I made a blog post to show more in detail how to create a basic SignalR chat web application using Asp.Net MVC, and it is available at:
http://thewayofcode.wordpress.com/2012/07/24/chatr-just-another-chat-application-using-signalr/
In the post you will also find a link to the github repository where the source is published.
I hope this helps.
Valerio
Apparently, you are using Signal-R - so try tracking state of online users (i.e. connected clients) in java-script itself. Use Connected/Disconnected/Reconnected server side events to broadcast to all clients - from documentation:
public class Chat : Hub
{
public override Task OnConnected()
{
return Clients.All.joined(Context.ConnectionId, DateTime.Now.ToString());
}
public override Task OnDisconnected()
{
return Clients.All.leave(Context.ConnectionId, DateTime.Now.ToString());
}
public override Task OnReconnected()
{
return Clients.All.rejoined(Context.ConnectionId, DateTime.Now.ToString());
}
}
A global server side store (for example - a static dictionary) can be used to store state against the connection id - that way, this dictionary can give you users for needed connection ids. For example,
// dis-claimer: untested code - just to give the idea/hint/outline
public class Chat : Hub
{
// change to use Concurrent Dictionary (or do thread-safe access)
static Dictionary<string, User> _users = new Dictionary<string, User>()
// call from client when it goes online
public void Join(string name)
{
var connId = this.Context.ConnectionId;
__users.Add(connId, new User(connId, name));
}
public override Task OnConnected()
{
return Clients.All.joined(_users[Context.ConnectionId], DateTime.Now.ToString());
}
public override Task OnDisconnected()
{
var user = _users[Context.ConnectionId];
_users.Remove(Context.ConnectionId);
return Clients.All.leave(user, DateTime.Now.ToString());
}
public List<User> GetUsers()
{
return _users.Values.ToList()
}
}
I think this should work for you :-
void Application_Start(object sender, EventArgs e)
{
// Code that runs on application startup
Application["OnlineUsers"] = 0;
List<string> list = new List<string>();
}
//First check if it is Authenticated request:-
void Session_Start(object sender, EventArgs e)
{
if(Request.IsAuthenticated)
list.Add(User.Identity.Name);
//your rest of code .......
}
list will return you all the username who are online :-

How to call properly HTTP client from HTTP server request handler in netty?

I am developing custom HTTP server with netty 3.3.1.
I need to implement something like this
HTTP Server receives request
HTTP Server parses it and invokes HTTP request as a client to other machine
HTTP Server waits for the response of request sent in (2)
HTTP Server sends response to request from (1) based on what had received in (3)
It means that client request (2) has to behave as synchronous.
What I wrote is based on HttpSnoopClient example but it does not work, because I receive
java.lang.IllegalStateException:
await*() in I/O thread causes a dead lock or sudden performance drop. Use addListener() instead or call await*() from a different thread.
I've refactored the code from the example mentioned above and now it looks more less like this (starting from line 7f of HttpSnoopClient):
ChannelFuture future = bootstrap.connect(new InetSocketAddress(host, port));
future.addListener(new ChannelFutureListener() {
public void operationComplete(ChannelFuture future) {
if (!future.isSuccess()) {
System.err.println("Cannot connect");
future.getCause().printStackTrace();
bootstrap.releaseExternalResources();
return;
}
System.err.println("Connected");
Channel channel = future.getChannel();
// Send the HTTP request.
channel.write(request);
channel.close();
// Wait for the server to close the connection.
channel.getCloseFuture().addListener(new ChannelFutureListener() {
public void operationComplete(ChannelFuture future) {
System.err.println("Disconnected");
bootstrap.releaseExternalResources(); // DOES NOT WORK?
}
});
}
});
}
}
The run() command from the above example is invoked in the messageReceived function of my herver handler.
So it became asynchronous and avoid await* functions. Request is invoked properly. But - for uknown reason for me - the line
bootstrap.releaseExternalResources(); // DOES NOT WORK?
does not work. It throws an exception saying that I cannot kill the thread I am currently using (which sounds reasonable, but still does not give me an answer how to do that in a different way).
I am also not sure is this a correct approach?
Maybe you can recommend a tutorial of such event programming techniques in netty? How to deal - in general - with a few asynchronous requests that has to be invoked in specified order and wait for each other?
Thank you,
If you really want to release the bootstrap on close you can do it like this:
channel.getCloseFuture().addListener(new ChannelFutureListener() {
public void operationComplete(ChannelFuture future) {
System.err.println("Disconnected");
new Thread(new Runnable() {
public void run() {
bootstrap.releaseExternalResources();
}
}).start();
}
});

Apache Commons HTTPClient 3.x leaving connections open

I'm using HttpClient to execute a PostMethod against a remote servlet and for some reason a lot of my connections are hanging open and hogging up all of my server's connections.
Here's more info about the architecture
GWT client calls into a GWT Service
GWT service instantiates a HttpClient, creates a PostMethod and has the client execute the method
it then gets the input stream by calling method.getResponseBodyAsStream() and writes it out to a byte array
it then closes the input stream and flushes the byte array output stream, does a few more lines of code and then calls method.releaseConnection()
There has to be something obvious I'm overlooking that's causing this. If I perform a GET in a browser to the same service, the connections close immediately but something about HTTPClient is causing them to hang open.
You need to call HttpMethodBase#releaseConnection(). If you return a InputStream to be used later, a simple way is to wrap it by a anonymous FilterInputStream overwriting close():
final HttpMethodBase method = ...;
return new FilterInputStream(method.getResponseBodyAsStream())
{
public void close() throws IOException
{
try {
super.close();
} finally {
method.releaseConnection();
}
}
};

Resources