# -*- Mode: Python; tab-width: 4 -*- import corosock import coroutine import regex import socket import string class counter: def __init__ (self, value=0): self.value = value def __int__ (self): return self.value def increment (self): self.value = self.value + 1 return self.value def decrement (self): self.value = self.value - 1 return self.value class http_client: def __init__ (self, conn, addr): self.s = corosock.coroutine_socket (conn) self.addr = addr self.buffer = '' self.lines = [] def read_line (self): # could be yet another use for coroutines if self.lines: l = self.lines[0] self.lines = self.lines[1:] return l else: while not self.lines: buffer = self.s.recv (8192) lines = string.split (buffer, '\r\n') for l in lines[:-1]: self.lines.append (l) self.buffer = lines[-1] return self.read_line() def read_header (self): header = [] while 1: l = self.read_line() if not l: break else: header.append (l) self.header = header return header def send (self, data): olb = lb = len(data) while lb: ns = self.s.send (data) lb = lb - ns return olb # -------------------------------------------------- # split a uri # -------------------------------------------------- # ;?# path_regex = regex.compile ( # path params query fragment '\\([^;?#]*\\)\\(;[^?#]*\\)?\\(\\?[^#]*\)?\(#.*\)?' ) def split_uri (self, uri): if self.path_regex.match (uri) != len(uri): raise ValueError, "Broken URI" else: return map (lambda i,r=self.path_regex: r.group(i), range(1,5)) def unpack_get_vars (self, query): vars = {} for var in string.split (query[1:], '&'): name, value = string.split (var, '=') vars[name] = value return vars session_counter = counter() sessions = {} def handle_request (self): request = self.header[0] method, uri, version = string.split (request) [path, params, query, fragment] = self.split_uri (uri) parts = string.split (path, '/') header = ( 'HTTP/1.0 200 OK\r\n' 'Content-Type: text/html\r\n' 'Connection: close\r\n' '\r\n' ) if query: self.s.send (header) vars = self.unpack_get_vars (query) if vars.has_key ('login'): # create a new session name = vars['login'] sid = self.session_counter.increment() c = coroutine.new (session_loop, (name, sid, self)) corosock.schedule (c) self.sessions[sid] = c elif vars.has_key ('session'): sid = int(vars['session']) print 'existing session', self.sessions[sid] self.vars = vars # resume an existing session corosock.schedule (self.sessions[sid], self) else: self.s.send ('

strange

query=%s' % repr(query)) self.s.close() else: # present login self.s.send (header) self.send ( '\r\n' 'Stateful HTTP Server\r\n' '
\r\n' '

Hello

\r\n' '\r\n' '\r\n' '
\r\n' ) # send data self.s.close() def session_loop (name, sid, client): try: import blackjack game = blackjack.game() # deal first two cards game.next (force=1) result = game.next (force=1) game_counter = counter() client.s.send ( '

Welcome To The Machine, %s

\r\n' % name + '
\r\n' ' \r\n' % sid + ' \r\n' ' \r\n' '
\r\n' '

dealer: %s

\r\n' % (repr(game.cards(game.dhand))) + '

player: %s

\r\n' % (repr(game.cards(game.phand))) + ((result and '

result: %s

\r\n' % repr(result)) or '') + '

winnings: %s

\r\n' % (game.winnings) + '\r\n' ) client.s.close() while 1: # fetch the next hit [if there ever is one] client = coroutine.main (None) if client.vars.has_key ('deal'): game_counter.increment() game.next (force=1) result = game.next (force=1) elif client.vars.has_key ('hit'): result = game.next (1) else: result = game.next (0) if result is not None: [phand, dhand] = game.last_hand else: phand, dhand = game.phand, game.dhand client.s.send ( '

Game #%d

' % game_counter + '

Player: %s

\r\n' % name ) if result is None: client.s.send ( '
\r\n' ' \r\n' % sid + ' \r\n' ' \r\n' '
\r\n' ) else: client.s.send ( '
\r\n' ' \r\n' % sid + ' \r\n' ' \r\n' ) client.send ( '

dealer: %s

\r\n' % (repr(game.cards(dhand))) + '

player: %s

\r\n' % (repr(game.cards(phand))) + ((result and '

result: %s

\r\n' % repr(result)) or '') + '

winnings: %s

\r\n' % (game.winnings) + '\r\n' ) client.s.close() except: import traceback traceback.print_exc() def spawn_client (conn, addr): try: print 'spawn_client (%s)' % repr(addr) h = http_client (conn, addr) h.read_header() h.handle_request() coroutine.main (None) except: import traceback traceback.print_exc() def serve(): try: s = corosock.coroutine_socket() s.create_socket (socket.AF_INET, socket.SOCK_STREAM) s.set_reuse_addr() s.bind (('', 7777)) s.listen (128) while 1: print 'accept loop, just before accept()' conn, addr = s.accept() print 'incoming connection from', addr c = coroutine.new (spawn_client, (conn, addr)) corosock.schedule (c, None) except: import traceback traceback.print_exc() if __name__ == '__main__': try: c = coroutine.new (serve, ()) corosock.schedule (c) corosock.event_loop (30.0) except: import traceback traceback.print_exc()