mxCuBE as a web application

Matias Guijarro

3rd mxCuBE meeting, 10th April, 2013

Presenter Notes

What is a web application?

Presenter Notes

What is a web application?

  • an application accessed by users over a network
    • Internet or an intranet
  • Web browsers as clients

    • Firefox, Chrome, Safari, etc.
  • Raise of webapps since 2005

    • technological evolution: Javascript, AJAX, web 2.0, HTML 5...
    • coming up of smartphones, tablets, etc.
    • cloud computing

Presenter Notes

What is a web application?

  • Typical architecture

Presenter Notes

mxCuBE as a web app !?

Presenter Notes

Advantages of mxCuBE as a webapp

  • Remote Access-enabled by design

  • No graphical application to install

  • Enforced separation between front-end and back-end code

  • Multi-platform at no cost

    • no compilation, no binary packages to deal with
  • Long term support

    • web browsers have always provided backward compatibility
    • webapps are self-contained (if not using externally hosted files)

Presenter Notes

Feasibility study

Presenter Notes

Web application server

  • web server + application framework

  • Python WSGI: Web Server Gateway Interface

    • wrappers available for Apache, Microsoft IIS
    • many Python servers available
  • Dozens of application framework exist

    • Django, Pyramid
    • web.py, Bottle, Flask

Presenter Notes

Feasibility study choices

  • Web server shipped with gevent
    • implemented using standard Python HTTPServer module
    • runs the gevent loop
  • bottle micro-framework

    • tiny (1 single Python file !), simple to use
    • with HTML 5 websockets add-on

Presenter Notes

bottle "Hello World"

1 from bottle import route, run, template
2 
3 @route('/hello/:name')
4 def index(name='World'):
5     return template('<b>Hello {{name}}</b>!', name=name)
6 
7 run(host='localhost', port=8080)

Presenter Notes

Getting mxCuBE objects from bottle

Framework 2 Hardware Repository is a library

1 from HardwareRepository import HardwareRepository
2 
3 hwr = HardwareRepository.HardwareRepository('localhost:hwr')
4 hwr.connect()
5 
6 minidiff = hwr.getHardwareObject("/minidiff")
7 
8 print minidiff.phiMotor.getPosition()

Presenter Notes

Web application logic

  • bottle routes == Remote Procedure Calls
  • mxCuBE Hardware Objects are globals
    • initialized when application is loaded on the client side

Example: setting minidiff front light level

 1 @bottle.get("/set_light_level")
 2 def set_light_level():
 3   light_level = float(bottle.request.GET["light_level"])
 4 
 5   light_level_changed_event = gevent.event.Event()
 6   def set_level_changed(*args):
 7     light_level_changed_event.set()
 8 
 9   minidiff.lightMotor.connect("moveDone", set_level_changed)
10   minidiff.lightMotor.move(light_level)
11   light_level_changed_event.wait()
12   minidiff.lightMotor.disconnect("moveDone", set_level_changed)
13 
14   return minidiff.lightMotor.getPosition()

Presenter Notes

Websocket example

  • websocket is a HTML 5 feature providing full-duplex channels over a single TCP connection
  • designed to be implemented in web servers and web browsers
  • stream of messages
  • low-latency compared to AJAX or Comet

Presenter Notes

Websocket example

In the case of mxCuBE, the sample video display is the more demanding; let's use a websocket to convey frames to the client

 1 new_frame = gevent.event.AsyncResult()
 2 
 3 def new_frame_received(img, width, height, *args):
 4   raw_data = img.bits().asstring(img.numBytes())
 5   data = numpy.asarray(Image.fromstring("RGBX", (width, height), raw_data).convert("RGB"))
 6   image = Image.fromarray(numpy.roll(data, -1, axis=-1)) #roll converts BGR to RGB
 7   jpeg_buffer = cStringIO.StringIO()
 8   image.save(jpeg_buffer, "JPEG", quality=95)
 9   new_frame.set(base64.b64encode(jpeg_buffer.getvalue()))
10 
11 minidiff.camera.connect("imageReceived", new_frame_received)
12 
13 @bottle.get('/sample_video_stream', apply=[websocket])
14 def stream_video(ws):
15   while True:
16     if ws.receive():
17       jpeg_data = new_frame.get()
18       #print "sending",len(jpeg_data), "bytes"
19       ws.send(jpeg_data)
20     else:
21       break

Presenter Notes

Application front-end

  • Technology stack
    • jQuery
    • Twitter Bootstrap
  • Nice Model-View-Controller pattern

    • View: HTML + CSS
    • Controller: client-side Javascript code
    • Model: server-side Python code

Presenter Notes

Web application communication

AJAX requests

 1 function set_light_level() {
 2   $.ajax({
 3     error: function(XMLHttpRequest, textStatus, errorThrown) { alert(textStatus) },
 4     url: 'set_light_level',
 5     type: 'GET',
 6     data: { "light_level": $("#light").val() },
 7     success: function(res) {
 8       update_gui(res);
 9     },
10   dataType: "json" });
11 }

Presenter Notes

Web application communication

Websocket

 1 function get_video_frame() {
 2   if (video_socket==null) {
 3     var ws_address;
 4     if (window.location.port != "") {
 5       ws_address = "ws://"+window.location.hostname+":"+window.location.port+"/sample_video_stream";
 6     } else {
 7       ws_address = "ws://"+window.location.hostname+"/sample_video_stream";
 8     }
 9     try {
10       video_socket = new WebSocket(ws_address);
11     } catch(e) {
12       video_socket = new MozWebSocket(ws_address);
13     }
14     video_socket.onopen = function() {
15       video_socket.send('!');
16     };
17     video_socket.onmessage = function(packed_msg) {
18       jpeg_frame.src = "data:image/jpeg;base64,"+packed_msg.data;
19       setTimeout(get_video_frame, 35);
20     };
21   } else {
22     video_socket.send('!');
23   }
24 }

Presenter Notes

Web app. & entreprise web

courtesy of Francoise Koenig-Jost, ESRF

Presenter Notes

Web app. & entreprise web

  • Websockets issue
    • Apache 2.0 does not support websockets
    • a plugin exists, though (not official)
  • Websockets + Reverse Proxy issue

    • Apache cannot deal with websockets when used as a Reverse Proxy
  • Use a dedicated software for Reverse Proxy

    • HAProxy for example
  • Or use another web server

    • nginx for example

Presenter Notes

Demo

Presenter Notes

Conclusion: no technical showstopper

Presenter Notes

Conclusion

  • Sample video is the only performance-critical part
    • at worse, a real streaming server can be used
  • Hardware Objects can be 100% reused

    • faster time-to-market
    • no regression in sensible parts
  • To be continued ?

    • set up a production environment (real web server)
    • solve entreprise network problems
    • final choice on technology stack

Presenter Notes

And... Go !

Presenter Notes

Thanks for your attention! Questions?

Presenter Notes