class ExternalRequestStage(object):

    def __init__(self, server):
class ExternalRequestStage(asyncore.dispatcher):
    """ Listens for external connections from clients and creates an ExternalChannel upon accepting."""

    def __init__(self, server, hostname, external_port):
        self.logger = logging.getLogger('{}'.format(self.__class__.__name__))
        self.logger.debug('__init__')

        # socket stuff
        asyncore.dispatcher.__init__(self)
        self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
        self.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.bind((hostname, int(external_port)))
        self.listen(5)

        # protected properties
        self._server = server
        self._hostname = hostname
        self._external_port = external_port
        self._channels = []

        self.logger.debug('__init__.  Binding to {}:{}'.format(hostname, external_port))


    def handle_accept(self):
        self.logger.debug('handle_accept')
        if self._server.is_accepting_external_requests:
            sock, client_address = self.accept()
            external_channel = ExternalChannel(server=self._server, sock=sock)
            self._channels.append(external_channel)

            self.logger.debug('handle_accept.  accepting connection from: {}'.format(client_address))


    def handle_close(self):
        self.logger.debug('handle_close')
        for channel in self._channels:
            channel.close_when_done()
        self.close()

        self.logger.debug('handle_close.  channels and self closed')

    def process(self):
        self.logger.debug('process')
        for external_channel in self._channels:
            external_channel.process()

    def _immediate_shutdown(self):
        self.logger.debug('_immediate_shutdown')
        self.handle_close()

        pass

@@ -1836,17 +1836,1797 @@
 ()%0A%0A
-        pass
+class ExternalChannel(asynchat.async_chat):%0A    %22%22%22 Channel that handles communication with with client.%22%22%22%0A    def __init__(self, server=None, sock=None):%0A        self.logger = logging.getLogger('%7B%7D'.format(self.__class__.__name__))%0A        self.logger.debug('__init__')%0A%0A        asynchat.async_chat.__init__(self, sock)%0A        self._server = server%0A        self._read_buffer = list()%0A        self._request_queue = list()%0A%0A%0A        self.set_terminator(self._server.terminator)%0A%0A    def collect_incoming_data(self, data):%0A        self.logger.debug('collect_incoming_data.  collected data: %7B%7D'.format(data))%0A        self._read_buffer.append(data)%0A%0A    def found_terminator(self):%0A        request = json.loads(''.join(self._read_buffer))%0A        self._handle_request(request)%0A%0A        self.logger.debug('found_terminator.  request: %7B%7D'.format(request))%0A%0A    def _send_message(self, message):%0A        self.push(util.pack_message(message, self._server._terminator))%0A%0A    def _handle_request(self, request):%0A        self.logger.debug('_handle_request.')%0A        request%5B'timestamp'%5D = util.current_time()%0A        request%5B'key'%5D = util.get_hash(request%5B'key'%5D)%0A        external_request = ExternalRequest(request=request, server=self._server)%0A        self._request_queue.append(external_request)%0A    def handle_error(self):%0A        pass%0A%0A    def process(self):%0A        self.logger.info('process')%0A        if not self._request_queue:%0A            self.handle_close()%0A%0A        for external_request in self._request_queue:%0A            external_request.process()%0A%0A        for external_request in self._request_queue:%0A            if external_request.completed:%0A                self._send_message(external_request._reply)%0A                self._request_queue.pop(0)%0A            else:%0A                break%0A
 %0A

Add ExternalChannel