<s> import re <EOL> import traceback <EOL> from gevent . pywsgi import WSGIServer <EOL> from gevent . queue import Channel <EOL> from spinoff . actor import Actor <EOL> from spinoff . actor . events import Events , Error <EOL> from spinoff . actor . exceptions import Unhandled <EOL> from spinoff . util . pattern_matching import ANY <EOL> from werkzeug import BaseRequest <EOL> class HttpServer ( Actor ) : <EOL> def pre_start ( self , address , responders , default_content_type = '<STR_LIT>' ) : <EOL> self . responders = responders <EOL> self . default_content_type = default_content_type <EOL> self . server = WSGIServer ( address , self . handle_wsgi_request ) <EOL> self . server . start ( ) <EOL> def post_stop ( self ) : <EOL> self . server . stop ( ) <EOL> def handle_wsgi_request ( self , env , start_response ) : <EOL> ch = Channel ( ) <EOL> req = Request ( ch , env , start_response , content_type = self . default_content_type ) <EOL> self << ( '<STR_LIT>' , req ) <EOL> return response_stream ( ch ) <EOL> def receive ( self , msg ) : <EOL> if ( '<STR_LIT>' , ANY ) == msg : <EOL> _ , req = msg <EOL> try : <EOL> responder = self . get_responder ( req . env [ '<STR_LIT>' ] ) <EOL> if responder : <EOL> responder , args , kwargs = responder <EOL> self . spawn ( RequestHandler . using ( req , responder , args , kwargs ) ) <EOL> else : <EOL> req . start_response ( '<STR_LIT>' , [ ( '<STR_LIT:Content-Type>' , '<STR_LIT>' ) ] ) <EOL> req . write ( '<STR_LIT>' ) <EOL> req . write ( '<STR_LIT>' ) <EOL> req . close ( ) <EOL> except : <EOL> _send_500 ( req ) <EOL> raise <EOL> elif '<STR_LIT>' == msg : <EOL> self . reply ( self . server . address ) <EOL> else : <EOL> raise Unhandled <EOL> def get_responder ( self , path ) : <EOL> for pattern , responder in self . responders : <EOL> m = re . compile ( pattern ) . match ( path ) <EOL> if m : <EOL> args = m . groups ( ) <EOL> kwargs = m . groupdict ( ) <EOL> return responder , args if not kwargs else ( ) , kwargs <EOL> class RequestHandler ( Actor ) : <EOL> def run ( self , req , responder , args , kwargs ) : <EOL> try : <EOL> self . responder = responder = self . spawn ( responder . using ( req , * args , ** kwargs ) ) <EOL> self . error = None <EOL> try : <EOL> Events . subscribe ( Error , self . check_error ) <EOL> responder . join ( ) <EOL> if not req . closed : <EOL> if self . error : <EOL> _send_500 ( req , extra = '<STR_LIT>' % ( '<STR_LIT>' . join ( traceback . format_exception ( type ( self . error . exc ) , self . error . exc , self . error . tb ) ) , ) ) <EOL> req . close ( ) <EOL> finally : <EOL> Events . unsubscribe ( Error , self . check_error ) <EOL> except : <EOL> _send_500 ( req ) <EOL> raise <EOL> def check_error ( self , error ) : <EOL> if error . actor == self . responder : <EOL> self . error = error <EOL> class _BREAK ( object ) : <EOL> def __repr__ ( self ) : <EOL> return '<STR_LIT>' <EOL> _BREAK = _BREAK ( ) <EOL> def response_stream ( ch ) : <EOL> while True : <EOL> val = ch . get ( ) <EOL> if val is _BREAK : <EOL> break <EOL> yield val <EOL> class Request ( BaseRequest ) : <EOL> def __init__ ( self , ch , env , start_response , content_type ) : <EOL> self . ch = ch <EOL> self . env = env <EOL> self . _response_started = False <EOL> self . _start_response = start_response <EOL> self . content_type = content_type <EOL> self . closed = False <EOL> BaseRequest . __init__ ( self , env ) <EOL> def set_status ( self , status ) : <EOL> self . start_response ( status , [ ( '<STR_LIT:Content-Type>' , self . content_type ) ] ) <EOL> def start_response ( self , * args ) : <EOL> self . _response_started = True <EOL> ret = self . _start_response ( * args ) <EOL> self . start_response = self . _start_response <EOL> return ret <EOL> def write ( self , data ) : <EOL> if not self . _response_started : <EOL> self . _start_response ( '<STR_LIT>' , [ ( '<STR_LIT:Content-Type>' , self . content_type ) ] ) <EOL> self . ch . put ( data ) <EOL> def writeln ( self , data ) : <EOL> self . write ( data + b'<STR_LIT:\n>' ) <EOL> def close ( self ) : <EOL> if not self . _response_started : <EOL> self . _start_response ( '<STR_LIT>' , [ ( '<STR_LIT:Content-Type>' , self . content_type ) ] ) <EOL> self . closed = True <EOL> self . ch . put ( _BREAK ) <EOL> def _send_500 ( req , extra = None ) : <EOL> req . start_response ( '<STR_LIT>' , [ ( '<STR_LIT:Content-Type>' , '<STR_LIT>' ) ] ) <EOL> req . write ( '<STR_LIT>' ) <EOL> req . write ( '<STR_LIT>' ) <EOL> if extra is not None : <EOL> req . write ( extra ) <EOL> req . close ( ) </s>
