Difference between revisions of "Mulib/Examples"
Which Linden (talk | contribs) (→stacked: clarifying how to use stacked) |
Chaser Zaks (talk | contribs) |
||
(9 intermediate revisions by 2 users not shown) | |||
Line 1: | Line 1: | ||
= Mulib Examples = | = Mulib Examples = | ||
These are some short examples to give a flavor of using [[mulib]]. | 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 == | == hello world == | ||
Line 7: | Line 7: | ||
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": | 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": | ||
<syntaxhighlight lang="python"># hello_world.py: | |||
from mulib import mu | |||
from eventlet import api, httpd | |||
class HelloWorld(mu.Resource): | |||
def handle_get(self, req): | def handle_get(self, req): | ||
req.write("hello, world\n") | req.write("hello, world\n") | ||
if __name__ == "__main__": | |||
root = HelloWorld() | |||
httpd.server( | |||
api.tcp_listener(('0.0.0.0', 8080)), | |||
mu.SiteMap(root))</syntaxhighlight> | |||
=== CGI === | |||
You can treat this resource as a [http://en.wikipedia.org/wiki/Common_Gateway_Interface CGI], by writing a second, wrapper, file that refers to it: | |||
<syntaxhighlight lang="python"># hello_world.cgi: | |||
#!/usr/bin/python | |||
from mulib import cgiadapter | |||
cgiadapter.run_as_cgi('hello_world', 'HelloWorld')</syntaxhighlight> | |||
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 == | ||
Line 26: | Line 39: | ||
Stacked is a pure REST server, and you can use it to traverse native python objects like <code>dicts</code>. 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. | Stacked is a pure REST server, and you can use it to traverse native python objects like <code>dicts</code>. 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. | ||
< | <syntaxhighlight lang="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))</syntaxhighlight> | |||
You can then access this dictionary as a REST resource, e.g. | You can then access this dictionary as a REST resource, e.g. | ||
Line 59: | Line 70: | ||
'''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. | '''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 == | |||
[http://www.evilchuck.com/ EvilChuck] wrote a nifty [http://www.evilchuck.com/2008/02/toy-chat-server-with-eventlet-and-mulib.html toy chat server] that we will partially reproduce here at his permission. | |||
Through stacked, and coros, we can tie a <code>ChatMessage</code> instance to the ''/listen'' url: | |||
<syntaxhighlight lang="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 Resource 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 | |||
} | |||
# Start the server | |||
httpd.server( | |||
api.tcp_listener(('0.0.0.0', 5000)), | |||
mu.SiteMap(root), max_http_version="HTTP/1.0" | |||
) | |||
</syntaxhighlight> | |||
And with some fancy html which is served up through the <code>resources.File</code> we get: | |||
<pre> | |||
<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> | |||
</pre> | |||
To test it out, put both files in the same directory, launch chat.py, and browse to http://localhost:5000/chat |
Latest revision as of 07:39, 27 June 2017
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":
# 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))
CGI
You can treat this resource as a CGI, by writing a second, wrapper, file that refers to it:
# hello_world.cgi:
#!/usr/bin/python
from mulib import cgiadapter
cgiadapter.run_as_cgi('hello_world', 'HelloWorld')
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.
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))
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:
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 Resource 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
}
# Start the server
httpd.server(
api.tcp_listener(('0.0.0.0', 5000)),
mu.SiteMap(root), max_http_version="HTTP/1.0"
)
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