Commits

Ginés Martínez Sánchez committed 0f517b3 Draft

developing http server

  • Participants
  • Parent commits 4f3ed5b

Comments (0)

Files changed (2)

File ginsfsm/c_sock.py

 
 
 def ac_send_data(self, event):
-    self._mt_send_data(event.data)
+    """ Write in the output data buffer and flush it right now.
+    """
+    self._write_soon(event.data)
+    self._transmit_ready_event_done = False
+    self._send_some()
+
+
+def ac_write_output_data(self, event):
+    """ Write in the output data buffer.
+        Equivalent to waitress' write_soon().
+    """
+    self._write_soon(event.data)
+
+
+def ac_flush_output_data(self, event):
+    """ Flush the output data buffer.
+        Equivalent to waitress' send_some().
+    """
+    self._transmit_ready_event_done = False
+    self._send_some()
+
 
 GSOCK_FSM = {
     'event_list': (
         'EV_CONNECT:top input',
         'EV_DROP:top input',
-        'EV_SEND_DATA: top input',
         'EV_CONNECTED: top output',
         'EV_DISCONNECTED: top output',
         'EV_RX_DATA: top output',
+        'EV_SEND_DATA: top input',
+        'EV_WRITE_OUTPUT_DATA: top input',
+        'EV_FLUSH_OUTPUT_DATA: top input',
         'EV_TRANSMIT_READY: top output'
     ),
     'state_list': ('ST_IDLE',),
     'machine': {
         'ST_IDLE':
         (
-            ('EV_CONNECT',      ac_connect,     None),
-            ('EV_DROP',         ac_drop,        None),
-            ('EV_SEND_DATA',    ac_send_data,   None),
+            ('EV_CONNECT',              ac_connect,             None),
+            ('EV_DROP',                 ac_drop,                None),
+            ('EV_SEND_DATA',            ac_send_data,           None),
+            ('EV_WRITE_OUTPUT_DATA',    ac_write_output_data,   None),
+            ('EV_FLUSH_OUTPUT_DATA',    ac_flush_output_data,   None),
         ),
     }
 }
     'host': [str, '', 0, None, "server or client host (ip or name)"],
     'port': [int, 0, 0, None, "server or client port"],
     'tx_buffer_size': [int, 4096, 0, None, ""],
-    'connected_event_name': [str, 'EV_CONNECTED', 0, None, ""],
-    'disconnected_event_name': [str, 'EV_DISCONNECTED', 0, None, ""],
-    'transmit_ready_event_name': [str, 'EV_TRANSMIT_READY', 0, None, ""],
+    'connected_event_name': [str, 'EV_CONNECTED', 0, None,
+        "Must be empty if you don't want receive this event"],
+    'disconnected_event_name': [str, 'EV_DISCONNECTED', 0, None,
+        "Must be empty if you don't want receive this event"],
+    'transmit_ready_event_name': [str, 'EV_TRANSMIT_READY', 0, None,
+        "Must be empty if you don't want receive this event"],
     'rx_data_event_name': [str, 'EV_RX_DATA', 0, None, ""],
     '_socket_map': [None, {}, 0, None, "Set by gaplic. Dict {fd:Gobj}"],
     '_impl_poll': [None, None, 0, None, "Set by gaplic. epoll implementation"],
 
 
     *Input-Events:*
-        * :attr:`'EV_SEND_DATA'`: transmit ``event.data``.
+        * :attr:`'EV_SEND_DATA'`:
 
-          Mandatory attributes of the received :term:`event`:
+          Write data in the output data buffer and flush it right now.
 
-          * ``data``: data to send.
+          Equivalent to EV_WRITE_OUTPUT_DATA and EV_FLUSH_OUTPUT_DATA together.
 
-          **TODO** Right now I use
-          OverflowableBuffer and ReadOnlyFileBasedBuffer to send data.
-          Normalize the output data buffer.
+          Event attributes:
+
+            * ``data``: data to send.
+
+        * :attr:`'EV_WRITE_OUTPUT_DATA'`:
+
+          Write data in the output data buffer.
+
+          Event attributes:
+
+            * ``data``: data to send.
+
+        * :attr:`'EV_FLUSH_OUTPUT_DATA'`:
+
+          Flush the output buffer data.
+
+
 
     *Output-Events:*
         * :attr:`'EV_CONNECTED'`: socket connected.
             * ``sockname``: the socket’s own address.
 
         * :attr:`'EV_DISCONNECTED'`: socket disconnected.
+
         * :attr:`'EV_TRANSMIT_READY'`: socket ready to transmit more data.
+
         * :attr:`'EV_RX_DATA'`: data received.
 
           The data is not buffered.
-          As data are read by recv() then are broadcast.
+          As much data are read by recv() as data are broadcast.
 
-          Attributes added to the sent :term:`event`:
+          Event attributes:
 
             * ``data``: Data received from remote address.
     """
         """ Send data.
         :param data: data to send.
         """
-        self.write_soon(data)
-        self._transmit_ready_event_done = False
-        self.send_some()
 
-    def write_soon(self, data):
-        """ Same as mt_send_data. Need it for waitress use.
+    def _write_soon(self, data):
+        """ Write data in the output buffer.
         """
         if data:
             if data.__class__ is ReadOnlyFileBasedBuffer:
             # we dont want to close the channel twice
             return
 
-        something_sent = self.send_some()
+        something_sent = self._send_some()
+        if not self.connected:
+            # can be disconnected after _send_some()
+            return
         if not something_sent:
             if not self._transmit_ready_event_done:
                 self._transmit_ready_event_done = True
                 if self.transmit_ready_event_name is not None:
                     self.broadcast_event(self.transmit_ready_event_name)
 
-    def send_some(self):
-        """ Need it for waitress use.
-        TODO: WARNING! outbufs directly used by c_http_clisrv!!
+    def _send_some(self):
+        """ Send as much output data as possible.
         """
+        sent = False
         try:
-            self._flush_some()
+            sent = self._flush_some()
         except socket.error:
             logging.exception('Socket error')
             self.will_close = True
 
         if self.will_close:
             self.handle_close()
+        return sent
 
     def _flush_some(self):
         # Send as much data as possible to our client

File ginsfsm/protocols/http/server/c_http_server.py

 
     When a new client connects,
     a new :class:`ginsfsm.c_sock.GSock` gobj is created,
-    and this gclass receives the EV_CONNECTED event.
+    receiving the EV_CONNECTED event.
     Then it creates a
     :class:`ginsfsm.protocols.http.server.c_http_clisrv.GHttpCliSrv` gobj
     that will process all the events of the GSock gobj.