Web interface (ofxHTTP, ofxJSONRPC)

Hi,

I am trying to create a web interface for an OF app.

What I want to achieve is:

  • Get video stream from OF displayed in the webpage,
  • Get webpage UI control (slider/buttons/checkboxes/…) to OF,
  • Set webpage UI control values from OF.

I started using ofxHTTP and got the video stream part done looking at “example_basic_ip_video_server”.

Now I am having hard time to understand how can I get access back and forth (OF <-> Webpage) to the UI elements…especially since my knowledge of Web/HTML is very limited :slight_smile:

Looking at this topic, @bakercp recommend to use ofxJSONRPC.
I tried it but couldn’t get the example to work because Xcode cannot find ‘json/json.h’. I installed json from here but without any success.

So I have some questions:

  1. Is ofxJSONRPC the way to go for what I want to do?
  2. Can I achieve what I want to do using only ofxHTTP?
    (to what I understand I need to send/receive GET or POST requests from the web page. Am I right?)

I looked at ofxHTTP “example_basic_post_server” but I don’t want to use forms. Also I couldn’t get both the video server and the POST server running at the same time (which I am not sure is a good idea anyway).

Any help is appreciated.

Meach

1 Like

This is totally possible to do! It’s how we made ofSketch. I can go into detail at the moment, but the first order of business is to make sure you are using ofxJSON. Secondly, could you post some screen shots and more errors so we can get it compiling? Thanks!

Do you mean using ofxJSON instead of ofxJSONRPC?

Also I think I made a mistake previously, I was using json-c and now tried with jsoncpp.
In Xcode, I added to the search path:
jsoncpp/include
jsoncpp/src

I also added ofxHTTP to the project (and required addons).

But then when compiling, I get errors related to json:

Do I need to compile json and add it to the project as well?

I tried again by adding ofxJSON to the project instead of jsoncpp and it is now compiling fine :slight_smile:

I will start to look at the example then and see if I can do what I want!

Super! Let me know how I can help and if you have questions …

Ok I think I am now going somewhere :slight_smile:
I had difficulties to understand how the OF app, the index.html and the main.js work together but I start to get it.

So far I managed to create some button, slider and dropdown elements on the webpage. I registered new method in the json server in OF. When I change the UI element, I have the correct function being called in OF and sending the UI element’s value correctly.

But I couldn’t understand how to do it the other way around:
How can I call some function in OF that would change the value of an item of my UI?

One questions about the registered method called in OF:
Is it possible to return more than 1 argument?
If for example I have several sliders on my webpage and want to call in OF a single getSlider() function: can I send the value and the name of the slider at once?

Thanks!

I tried to combine both the JSONRPC and the Video example in the same app but cannot get them to work at the same time together. I end up having 2 servers and only the one started before the other is working.

Is it possible to create somehow a server variable that can be of type both
ofx::HTTP::BasicJSONRPCServer and ofx::HTTP::BasicIPVideoServer?

I enclosed what I did so far:
simpleWebInterface.zip (599.5 KB)

Any help would be appreciated as I am getting lost in here.

Actually, I found a way to get both working at the same time.
First I set a different port number for each server (of course, so silly of me).

Then I created a second html file where I only put
<img src="/ipvideo"/>

In OF, I changed the default index for the BasicIPVideoServer to use this new html file:
settingsVideo.setDefaultIndex(“liveView.html”);

Then in the main “index.html” I added a function that I can call to display the “liveView.html” file. To do that, I put the address and port of the BasicIPVideoServer.

function load_liveView(){         document.getElementById("contentLiveView").innerHTML='<object type="text/html" width="661" height="540" data="http://127.0.0.1:7890" ></object>';
}

I am not sure if this is the best way to do it but it works for me :smile:
Now I only need to be able to change UI elements from OF and I would be all set!

@bakercp, I looked at ofSketch code to try to find out how to send messages from OF to the web page but couldn’t figure it out.
Any help would be great on that!

Hi there. Basic Http is a client driven protocol (get, post, head, delete messages), so every communication must be started by the client (the browser).

If you want to submit events initiated at the server (I understand that this is what you want, changing values from the server to the UI in the browser) the basic way to do it is to simulate push by polling. You shoud send a post periodically from the browser, like a keepalive message, and in the response from the server you would include data useful to the browser (in this case, UI data).

This approach has a lot of lag, and might put excessive stress on the server (responding to posts periodically from different clients, when there might not be data to transmit).

The modern eay to do it, and more efficient, is to manage communication through a websocket. A web socket is just like a tcp socket, but runs on top on http, it requires browser support, and server support. Luckily, there are a few addons that wrap libwebsocket lib that will allow you to set up a websocket server in your ofapp.

With the websocket established, you will be able to send and receive messages from client or server indistinctivley.

(You may be able to maintain most of your current architecture, since you can still send json through the websocket)

Hope this helps.

Cheers.

Hey Bolton,

Thank you for this explanation!
I also found some presentation that explained this same principle and the strength behind websockets, compared to basic http.

From the description of ofSketch, about ofxJSONRPC:

This is a JSONRPC 2.0 compliant server built on top of ofxHTTP. It allows
us to interact with the jquery jsonrpc client on the front end. It can
handle round trip JSONRPC requests and notifications over POST requests and
WebSockets (we are using the WebSockets exclusively).

So I am now trying to understand how to create json messages that can be sent from OF correctly. And also if for each json message I am sending, I need a function on the client side to catch it.

Hey @Meach sorry for the delay getting back to you.

Sending messages from the server to the client is a somewhat manual process at this point.

If the client calls a method (like the ping or pong in the example), the server will respond and the jquery.jsonrpcclient.js will take care of routing the responses back to the right callback. Thus, with the jsonrpc model, the only messages that are automatically handled are those that come as a response to the client’s direct request.

All other messages sent from the server to the client will end up in an onWebSocketMessage callback (defined when we instantiate the JSONRPC client javascript object here https://github.com/olab-io/ofSketch/blob/master/ofSketchApp/bin/data/DocumentRoot/js/ofSketch/ofSketch.js#L551-L557)

Here is the callback:

So, to send unsolicited messages from the server to the client (which we do when new connections are made, etc) we have to set up another protocol. Basically we define a “module” (for routing purposes) and a “method” and some “data” (in the form of some JSON) to send with it. We use this method to package it all up before sending from the server to the client:

Here is an example of a packet that we send to the client that includes the server’s version info, etc:

All of this version info is sent without being requested, so on the client side, we are prepared to parse it here …

First we look at the “module”

Then we pass it to the right handler, where the json is used:

Anyway, I hope this makes sense. It’s basically client-driven model (because of the GUI nature of it) with the JSONRPC calls only initiated by the client. Any information that you need to send from that server that is not explicitly requested by the client must be handled as I mentioned above.

Let me know if this helps …

1 Like

PS. I’m working on this stuff today and will hopefully have a clearer example of the mechanics of server-sent data. The ofSketch code has a lot of other stuff going on so it’s not a great way to learn …

I’ll post it here if/when I get it done today.

Thanks for the explanation bakercp, it definitely helps!

I will check this out very soon but I think I start to understand how things are working. I will try it out myself and will let you know if there are things that I don’t manage or if I am some questions.

I managed to get some messages sent correctly to the web page. I can at least control a slider now :slight_smile:
I will continue digging in this tomorrow.

Thanks!

Super!

I can now control all UI elements I have from OF, this is awesome!

But I realised that onWebSocketOpen function needs to be called before I can send anything from OF.
Is there any way to do this when the web page load directly?

One way to get the function called is to use some UI element at first on the page but it’s not super convenient.

Also, is there a way to send a JSON message with a vector as parameter? For example I have a dropdown element on the webpage that I would like to populate at once from a vector< string > in OF.
At the moment I am sending as many JSON messages as string in this vector but it would be much more convenient to be able to send them all at once.

Thanks

Great to hear! It’s pretty cool huh? :smile:

Anyway, right now the websocket does not open until the first jsonrpc call. So there are two options.

  1. Make an initial JSONRPC call when you load the page (for instance in the document ready portion of the javascript). You could have a method like “newClient” or something to start the conversation.

  2. Depending on how you configure your javascript, you can provide jquery.jsonrpcclient.js with a “getSocket” function if you want to own your own websocket (see https://github.com/Textalk/jquery.jsonrpcclient.js). Currently the websocket lives inside the jquery.jsonrpcclient.js class. If you initialize it elsewhere (and open it manually), then you can just instantiate the jquery.jsonrpcclient.js using the getSocket() method.

  3. To send a vector, just construct a json array from your std::vector<string> in oF. An array of strings might look like:

{
"arrayOfStrings":[ "one", "two", "three"] 
}

To create an array of strings using ofxJSON (aka jsoncpp) you can use the “append()” method.

See http://jsoncpp.sourceforge.net/class_json_1_1_value.html#7e49ac977e4bcf59745a09d426669f75

e.g.

Json::Value root;
Json::Value vectorNode;
vectorNode.append("one");
vectorNode.append("two");
vectorNode.append("three");
root["arrayOfStrings"] = vectorNode;

Thanks for your answer. Yes I love it, I think it’s really cool!
(besides javascript and html, which I still don’t understand much :blush:)

I chose the solution 1. to open the webSocket when the web page load and it works fine now. Same with the vector, works perfectly.

Only tiny problem I still have is the float value of my slider that I am sending from the client cannot be converted to float using asFloat() function. Might be something very trivial and I didn’t try to solve this for now.

If some people are interested, I enclosed my project to this post as well.

Thanks again @bakercp!

simpleWebInterface.zip (597.5 KB)

1 Like

Hi
Thank you for this!
Is it possible to establish a connection to the video- and json-server from the web?
In example, i’d like to have my webgui.html hosted on my webspace,
so if i browse mydomain.com/webgui.html i can send and receive data to and from the ofApp.

Greets
Oli