Mulib/Examples

From Second Life Wiki
Jump to navigation Jump to search
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.

Mulib Examples

These are some short examples to give a flavor of using mulib. You can find all the example code in the examples directory of a mulib checkout.

hello world

The following program will bring up a webserver listening on port 8080 which can respond to a single request, "GET /", with the response "hello, world":

<python># hello_world.py: from mulib import mu

from eventlet import api, httpd

class HelloWorld(mu.Resource):

   def handle_get(self, req):
       req.write("hello, world\n")


if __name__ == "__main__":

   root = HelloWorld()
   httpd.server(
       api.tcp_listener(('0.0.0.0', 8080)),
       mu.SiteMap(root))</python>

CGI

You can treat this resource as a CGI, by writing a second, wrapper, file that refers to it:

<python># hello_world.cgi:

  1. !/usr/bin/python

from mulib import cgiadapter

cgiadapter.run_as_cgi('hello_world', 'HelloWorld')</python>

Configure your web server to execute hello_world.cgi, and you should be able to interact with it just like the standalone version.

stacked

Stacked is a pure REST server, and you can use it to traverse native python objects like dicts. You invoke these special capabilities of Stacked by placing a python dict or list in the resource hierarchy instead of a mu.Resource, in this case at the root.

<python>from mulib import mu

from eventlet import api, httpd

root = {:'hello, world\n',

       'other':"hello, other\n"}

httpd.server(api.tcp_listener(('0.0.0.0', 8080)), mu.SiteMap(root))</python>

You can then access this dictionary as a REST resource, e.g.

 > curl http://localhost:8080/     
 hello, world
 > curl http://localhost:8080/other
 hello, other
 > curl -X PUT -d "the new data" http://localhost:8080/third
 > curl http://localhost:8080/third
 the new data

Mu/stacked can do content negotiation:

 > curl -X PUT -H "Content-type: application/json" -d '{"hi": "there"}' http://localhost:8080/fourth
 > curl http://localhost:8080/fourth/hi
 there
 > curl -H "Accept: application/json" http://localhost:8080/fourth
 {'hi': 'there'}

Note: This means that anyone who has access to your stacked web service can modify the data in your process! In the future we might have a 'read-only' implementation.

Chat Server

EvilChuck wrote a nifty toy chat server that we will partially reproduce here at his permission.

Through stacked, and coros, we can tie a ChatMessage instance to the /listen url:

<python> from mulib import mu, stacked, resources from eventlet import api, httpd, coros, util

util.wrap_socket_with_coroutine_socket()

chat_listener = coros.event()

class ChatMessage(mu.Resource):

   """A Rsource to handle receiving chat messages"""
   def handle_post(self, request):
       """POST to send chat messages
       expects nick and message as POST arguments"""
       nick = request.get_arg('nick')
       message = request.get_arg('message').strip()
       if message:
           # Send the chat message to all who are listening
           chat_listener.send("%s: %s" % (nick, message))
           # Reset the listener so that it can receive more messages 
           chat_listener.reset()
       request.write()

root = {

       'chat' : resources.File('chat.html'),   # /chat -> Load chat.html
       'listen' : chat_listener,               # /listen -> Wait for new msgs 
       'message' : ChatMessage(),              # /message -> Send a message

}

  1. Start the server

httpd.server(

   api.tcp_listener(('0.0.0.0', 5000)),
   mu.SiteMap(root), max_http_version="HTTP/1.0"

) </python>

And with some fancy html which is served up through the resources.File we get:

<html>
  <head>
    <link rel="stylesheet" href="http://yui.yahooapis.com/2.4.1/build/reset-fonts-grids/reset-fonts-grids.css" type="text/css"> 
    <style>
      #hd, #bd, #ft { border: 1px solid #808080;}
      #hd h1 { margin-left: 5px; font-size: 120%; }
      #bd { min-height: 350px; }
      body { position: relative; }
      .bd { text-align: left; }
      input { width: 100%; }
    </style>
  </head>
  <body>
  <div id="doc" class="yui-t7"> 
    <div id="hd"><h1>Web Chat</h1></div> 
    <div id="bd"> 
      <div class="yui-g"> 
        <div id="chat_text"></div>
      </div> 
    </div>
    <div id="ft">
      <input type="text" maxlength="256" id="chat_message"/>
    </div> 
  </body>
  <script src="http://yui.yahooapis.com/2.4.1/build/yahoo/yahoo-min.js"></script> 
  <script src="http://yui.yahooapis.com/2.4.1/build/event/event-min.js" ></script>
  <script src="http://yui.yahooapis.com/2.4.1/build/dom/dom-min.js"></script>
  <script src="http://yui.yahooapis.com/2.4.1/build/connection/connection-min.js"></script>
  <script type="text/javascript">
    YAHOO.util.Event.onDOMReady(function () {
      // Set up a random nickname for the user
      var nick = 'User-' + Math.round(Math.random()*10000);
      var handleReturn = function (type, args, obj) {
        // Handler to run when the Enter key is pressed
        var el = document.getElementById("chat_message");
        if (el.value) {
          // Send the message to the server
          var postData = "nick="+escape(nick)+"&message="+escape(el.value);
          YAHOO.util.Connect.asyncRequest('POST','/message', {
            success : function(o) {
              el.value = '';
              },
          }, postData);
        }
      };
      var listen = function () {
        // Listens for incoming messages
        YAHOO.util.Connect.asyncRequest('GET', '/listen', {
          success: function (o) {
            if (o.status == 200) {
              var el = document.getElementById("chat_text");
              el.innerHTML += o.responseText + '<BR/>';
              listen();
            }
            else if (o.status == 202) {
              // 202 is returned when the connection has timed out
              listen();
            }
          }
        });
      };
      // Register the key listener to listen for the Enter key
      var keyListener = new YAHOO.util.KeyListener(
          document, {keys: 13}, handleReturn);
      keyListener.enable();
      // Start listening for incoming messages
      listen();
    });
  </script>
</html>

To test it out, put both files in the same directory, launch chat.py, and browse to http://localhost:5000/chat