-
Notifications
You must be signed in to change notification settings - Fork 18
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
26 changed files
with
902 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
import os | ||
import os.path | ||
import mimetypes | ||
import traceback | ||
import random | ||
import time | ||
import cgi | ||
|
||
class Message(object): | ||
def __init__(self, timestamp, user, message): | ||
self.timestamp = timestamp | ||
self.user = user | ||
self.message = message | ||
|
||
class ChatApp(object): | ||
def __init__(self, files_path): | ||
self.file_server = FileServer(files_path) | ||
self.messages = [] | ||
|
||
def get_messages_since(self, timestamp): | ||
"""Retrieve any messages received since the given timestamp.""" | ||
x = [] | ||
for m in self.messages: | ||
if m.timestamp > timestamp: | ||
x.append(m) | ||
|
||
return x | ||
|
||
def format_response(self, new_messages, timestamp): | ||
x = [] | ||
for m in new_messages: | ||
x.append("""\ | ||
<message> | ||
<author>%s</author> | ||
<text>%s</text> | ||
</message> | ||
""" % (m.user, m.message)) | ||
|
||
if x: # new messages received? | ||
# yes | ||
status = 1 | ||
else: | ||
status = 2 # no new messages | ||
|
||
xml = """ | ||
<?xml version="1.0"?> | ||
<response> | ||
<status>%d</status> | ||
<time>%f</time> | ||
%s | ||
</response> | ||
""" % (status, timestamp, "".join(x)) | ||
|
||
return xml | ||
|
||
def __call__(self, environ, start_response): | ||
url = environ['PATH_INFO'] | ||
if url == '/get_messages': | ||
# last_time | ||
form = cgi.FieldStorage(fp=environ['wsgi.input'], environ=environ) | ||
last_time = float(form['last_time'].value) | ||
|
||
new_messages = self.get_messages_since(last_time) | ||
xml = self.format_response(new_messages, time.time()) | ||
|
||
# done; return whatever we've got. | ||
start_response("200 OK", [('Content-type', 'text/html')]) | ||
|
||
print xml | ||
return [xml] | ||
elif url == '/post_message': | ||
form = cgi.FieldStorage(fp=environ['wsgi.input'], environ=environ) | ||
|
||
# retrieve submitted data | ||
last_time = float(form['last_time'].value) | ||
author = form['user'].value | ||
message = form['message'].value | ||
|
||
# create and add new message: | ||
timestamp = time.time() | ||
m = Message(timestamp, author, message) | ||
self.messages.append(m) | ||
|
||
# return any new messages: | ||
new_messages = self.get_messages_since(last_time) | ||
xml = self.format_response(new_messages, timestamp) | ||
|
||
# done; return whatever we've got. | ||
start_response("200 OK", [('Content-type', 'text/html')]) | ||
|
||
print xml | ||
return [xml] | ||
|
||
# by default, just return a file | ||
return self.file_server(environ, start_response) | ||
|
||
class FileServer(object): | ||
def __init__(self,path): | ||
self.path = os.path.abspath(path) | ||
|
||
def __call__(self, environ, start_response): | ||
url = environ['PATH_INFO'] | ||
|
||
print 'url:' + url | ||
if url.endswith('/'): | ||
url += 'index.html' | ||
|
||
fullpath = self.path + url | ||
fullpath = os.path.abspath(fullpath) | ||
assert fullpath.startswith(self.path) | ||
|
||
extension=mimetypes.guess_type(fullpath) | ||
extension=extension[0] | ||
|
||
if extension is None: | ||
extension = 'text/plain' | ||
|
||
status = '200 OK' | ||
headers = [('Content-type', extension )] | ||
|
||
try: | ||
fp = open(fullpath) | ||
contents = fp.read() | ||
start_response(status, headers) | ||
return [contents] | ||
except: | ||
status = '404 Not Found' | ||
headers = [('Content-type', 'text/html')] | ||
start_response(status, headers) | ||
return ['404 Not Found'] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import sys | ||
from webserve import Server | ||
|
||
port = sys.argv[1] | ||
port = int(port) | ||
|
||
from apps import ChatApp | ||
chat_app = ChatApp('./html') | ||
|
||
Server(port, chat_app).serve_forever() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
<!-- chat server, from http://www.sitepoint.com/article/ajax-jquery/ --> | ||
|
||
<head> | ||
|
||
<style type="text/css"> | ||
#messagewindow { | ||
height: 250px; | ||
border: 1px solid; | ||
padding: 5px; | ||
overflow: auto; | ||
} | ||
#wrapper { | ||
margin: auto; | ||
width: 438px; | ||
} | ||
</style> | ||
|
||
<script src="jquery-1.3.2.min.js"></script> | ||
|
||
<script type="text/javascript"> | ||
|
||
$(document).ready(function() { | ||
timestamp = 0; | ||
|
||
function add_messages(xml) { | ||
// retrieve 'status' from the XML; if nothing changed, exit. | ||
if($("status", xml).text() == "2") return; | ||
|
||
// update timestamp value from XML | ||
timestamp = $("time", xml).text(); | ||
|
||
// for each 'message' block in the XML, retrieve author & content, then | ||
// post. | ||
|
||
$("message", xml).each( function(id) { | ||
message = $("message", xml).get(id); | ||
|
||
author = $("author", message).text(); | ||
content = $("text", message).text(); | ||
|
||
$("#messagewindow").prepend("<b>" + author + "</b>:" + content | ||
+ "<br>"); | ||
}); | ||
}; | ||
|
||
// when the 'submit' button is pushed on the chatform, | ||
$("form#chatform").submit(function() { | ||
|
||
// send the message data to the URL 'post_message' | ||
$.post("post_message", | ||
{ message : $("#message").val(), | ||
user : $("#author").val(), | ||
last_time : timestamp, | ||
}, | ||
// apply 'add_messages' to update page with returned data | ||
function(xml) { | ||
add_messages(xml) | ||
} | ||
); | ||
|
||
// blank out the 'message' field in the form | ||
$("#message").val(""); | ||
|
||
return false; | ||
}); | ||
|
||
// | ||
// execute below on load: | ||
// | ||
|
||
// blank out the 'loading' message | ||
$("#loading").remove(); | ||
|
||
// get the current set of messages with timestamp 0 | ||
$.post("get_messages", | ||
{ last_time : timestamp }, | ||
function(xml) { add_messages(xml) } | ||
); | ||
|
||
}); | ||
|
||
</script> | ||
</head> | ||
|
||
<body> | ||
|
||
<div id="wrapper"> | ||
<p id="messagewindow"><span id="loading">Loading...</span></p> | ||
<form id="chatform"> | ||
|
||
Name: <input type="text" id="author" /> | ||
Message: <input type="text" id="message" /> | ||
|
||
<input type="submit" value="ok" /><br /> | ||
|
||
</form> | ||
</div> | ||
|
||
</body> |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
import socket | ||
from cStringIO import StringIO | ||
import urlparse | ||
|
||
class StartResponse(object): | ||
def __call__(self, status, headers): | ||
self.status = status | ||
self.headers = headers | ||
|
||
class Server(object): | ||
def __init__(self, port, wsgi_app): | ||
self.port = port | ||
self.wsgi_app = wsgi_app | ||
|
||
def request_is_complete(self, data): | ||
""" | ||
Evaluate data -- is this a complete (GET or POST) request? | ||
""" | ||
if '\r\n\r\n' not in data: | ||
return False | ||
|
||
head, rest = data.split('\r\n\r\n', 1) | ||
request_line, head = head.split('\r\n', 1) | ||
reqtype, url, protocol = request_line.split(' ') | ||
|
||
parsed_url = urlparse.urlparse(url) | ||
path = parsed_url.path | ||
|
||
# process headers | ||
headers = head.splitlines() | ||
headers = [ x.split(': ', 1) for x in headers ] | ||
|
||
if reqtype != 'POST': | ||
contentsize = 0 | ||
else: | ||
contentsize = None | ||
for k, v in headers: | ||
if k.lower() == 'content-length': | ||
contentsize = int(v) | ||
|
||
if len(rest) == contentsize: | ||
return True | ||
|
||
return False | ||
|
||
def parse_request(self, data): | ||
if '\r\n\r\n' not in data: | ||
return False | ||
|
||
head, rest = data.split('\r\n\r\n', 1) | ||
request_line, head = head.split('\r\n', 1) | ||
request_type, url, protocol = request_line.split(' ') | ||
|
||
parsed_url = urlparse.urlparse(url) | ||
path = parsed_url.path | ||
query = parsed_url.query | ||
|
||
# process headers | ||
headers = head.splitlines() | ||
headers = [ x.split(': ', 1) for x in headers ] | ||
|
||
environ = {} | ||
environ['REQUEST_METHOD'] = request_type | ||
environ['SCRIPT_NAME'] = '' | ||
environ['PATH_INFO'] = path | ||
environ['SERVER_PROTOCOL'] = protocol | ||
environ['QUERY_STRING'] = query | ||
environ['wsgi.input'] = StringIO(rest) | ||
|
||
start_response = StartResponse() | ||
|
||
data = list(self.wsgi_app(environ, start_response)) | ||
data = "".join(data) | ||
|
||
status = start_response.status | ||
headers = start_response.headers | ||
|
||
headers = "\r\n".join([ ": ".join(x) for x in headers ]) | ||
|
||
return "HTTP/1.0 %s\r\n%s\r\n\r\n%s" % (status, headers, data) | ||
|
||
def handle_connection(self, sockobj, data_so_far=None): | ||
if data_so_far is None: # initialize | ||
data_so_far = '' | ||
|
||
try: | ||
data = sockobj.recv(4096) | ||
except socket.error: | ||
return False, data_so_far | ||
|
||
data_so_far += data | ||
if self.request_is_complete(data_so_far): # complete request? | ||
response = self.parse_request(data_so_far) | ||
try: | ||
sockobj.sendall(response) | ||
sockobj.close() | ||
except socket.error: | ||
pass | ||
|
||
return True, None | ||
|
||
# not done yet; keep gathering information | ||
return False, data_so_far | ||
|
||
def serve_forever(self): | ||
print "binding '%s', port %d" % ('', self.port) | ||
sock = socket.socket() | ||
sock.bind( ('', self.port) ) | ||
sock.listen(5) | ||
|
||
while 1: | ||
client_sock, client_addr = sock.accept() | ||
print '----' | ||
print 'connection:', client_addr | ||
|
||
close_flag, data = self.handle_connection(client_sock) | ||
while not close_flag: | ||
close_flag, data = self.handle_connection(client_sock, data) | ||
client_sock.close() | ||
|
||
print 'done with', client_addr |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
<!-- basic jquery; CSS-style selectors --> | ||
|
||
<head> | ||
<script src='jquery-1.3.2.min.js'></script> | ||
</head> | ||
|
||
<body> | ||
|
||
<div class='foo'> | ||
Pre-existing text. | ||
|
||
<div class='parks'> | ||
foo bar baz | ||
</div> | ||
|
||
</div> | ||
|
||
<script type='text/javascript'> | ||
|
||
$("div.foo").append("Hello World!"); | ||
$("div.foo").css("color","red"); | ||
$("div.parks").css("color","blue"); | ||
|
||
</script> | ||
|
||
|
||
</body> |
Oops, something went wrong.