"asynchat" --- Asynchroniczna obsługa gniazda komend/odpowiedzi.
****************************************************************

**Source code:** Lib/asynchat.py

Niezalecane od wersji 3.6: "asynchat" will be removed in Python 3.12
(see **PEP 594** for details). Please use "asyncio" instead.

======================================================================

Informacja:

  This module exists for backwards compatibility only.  For new code
  we recommend using "asyncio".

Ten moduł buduje na infrastrukturze modułu "asyncore", upraszczając
klientów i serwery asynchroniczne i czyniąc łatwiejszym obsługę
protokołów których elementy są zakańczane przez zadane ciągi znaków,
lub są zmiennej długości. Moduł "asynchat" określa abstrakcyjne
uogólnienie "async_chat" które możesz dostosować tworząc własne
podrzędne uogólnienie, dostarczając wypełnień sposobów postępowania
"collect_incoming_data()" i "found_terminator()". Używa tej samej
asynchronicznej pętli co moduł "asyncore", i dwóch rodzajów kanałów,
- "asyncore.dispatcher" i "asynchat.async_chat", mogą być dowolnie być
mieszane w mapie kanałów. Typowo kanał serwera "asyncore.dispatcher"
generuje nowe obiekty kanałów "asynchat.async_chat" gdy otrzymuje
wchodzące zapytania o połączenie.

class asynchat.async_chat

   To uogólnienie jest abstrakcyjnym  uogólnieniem podrzędnym względem
   uogólnienia "asyncore.dispatcher". Aby praktycznie użyć kodu musisz
   dostosować podrzędne uogólnienie względem uogólnienia "async_chat",
   dostarczając sensownego wypełnienia sposobu postępowania
   "collect_incoming_data()" i sposobu postępowania
   "found_terminator()". Sposoby postępowania uogólnienia
   "asyncore.dispatcher" mogą być używane, chociaż nie wszystkie mają
   sens w kontekście wiadomość/odpowiedź.

   Like "asyncore.dispatcher", "async_chat" defines a set of events
   that are generated by an analysis of socket conditions after a
   "select()" call. Once the polling loop has been started the
   "async_chat" object's methods are called by the event-processing
   framework with no action on the part of the programmer.

   Dwie właściwości uogólnienia mogą być modyfikowane, aby poprawić
   wydajność, lub nawet aby możliwie oszczędzać pamięć.

   ac_in_buffer_size

      Rozmiar przestrzeni wymiany wejściowej asynchronicznej
      (domyślnie "4096").

   ac_out_buffer_size

      Rozmiar przestrzeni wymiany wyjściowej asynchronicznej
      (domyślnie "4096").

   Unlike "asyncore.dispatcher", "async_chat" allows you to define a
   FIFO (first-in, first-out) queue of *producers*. A producer need
   have only one method, "more()", which should return data to be
   transmitted on the channel. The producer indicates exhaustion
   (*i.e.* that it contains no more data) by having its "more()"
   method return the empty bytes object. At this point the
   "async_chat" object removes the producer from the queue and starts
   using the next producer, if any. When the producer queue is empty
   the "handle_write()" method does nothing. You use the channel
   object's "set_terminator()" method to describe how to recognize the
   end of, or an important breakpoint in, an incoming transmission
   from the remote endpoint.

   Aby zbudować funkcjonujące podrzędne uogólnienia względem
   uogólnienia "async_chat", twoje sposoby postępowania wprowadzania
   "collect_incoming_data()" i "found_terminator()" muszą obsługiwać
   dane które kanał otrzymuje asynchronicznie. Sposoby postępowania są
   opisane poniżej.

async_chat.close_when_done()

   Pushes a "None" on to the producer queue. When this producer is
   popped off the queue it causes the channel to be closed.

async_chat.collect_incoming_data(data)

   Wywoływany z *danymi* przechowując określoną ilość otrzymanych
   danych. Domyślny sposób postępowania, który musi zostać
   przesłonięty, zgłasza wyjątek "NotImplementedError".

async_chat.discard_buffers()

   In emergencies this method will discard any data held in the input
   and/or output buffers and the producer queue.

async_chat.found_terminator()

   Wywoływana gdy przychodzący strumień danych odpowiada warunkowi
   zakończenia ustawionemu przez sposób postępowania
   "set_terminator()". Domyślny sposób postępowania, który musi być
   przesłonięty, zgłasza wyjątek "NotImplementedError". Dane wejściowe
   z przestrzeni wymiany powinny być dostępne przez właściwość
   przykładu.

async_chat.get_terminator()

   Zwraca obecne zakończenie dla kanału.

async_chat.push(data)

   Pushes data on to the channel's queue to ensure its transmission.
   This is all you need to do to have the channel write the data out
   to the network, although it is possible to use your own producers
   in more complex schemes to implement encryption and chunking, for
   example.

async_chat.push_with_producer(producer)

   Takes a producer object and adds it to the producer queue
   associated with the channel.  When all currently pushed producers
   have been exhausted the channel will consume this producer's data
   by calling its "more()" method and send the data to the remote
   endpoint.

async_chat.set_terminator(term)

   Ustawia warunek zakończenia aby był rozpoznany przez kanał. "term"
   może być dowolną z trzech typów wartości, odpowiadających trzem
   różnym sposobom obsługi przychodzących danych protokołu.

   +-------------+-----------------------------------------------+
   | term - z    | Opis                                          |
   | ang. -      |                                               |
   | termin      |                                               |
   |=============|===============================================|
   | *ciąg       | Wywoła sposób postępowania                    |
   | znaków*     | "found_terminator()" gdy ciąg znaków zostanie |
   |             | znaleziony w strumieniu wejściowym            |
   +-------------+-----------------------------------------------+
   | *integer* - | Wywoła "found_terminator()" gdy wskazana      |
   | z ang. -    | liczba znaków zostanie odebrana               |
   | *liczba     |                                               |
   | całkowita*  |                                               |
   +-------------+-----------------------------------------------+
   | "None" - z  | Kanał nadal zbiera dane w pętli nieskończonej |
   | ang. -      |                                               |
   | "Żaden"     |                                               |
   +-------------+-----------------------------------------------+

   Zauważ że dowolne dane następujące po terminatorze będą dostępne
   dla przeczytania przez kanał po tym jak sposób postępowania
   "found_terminator()" zostanie wywołany.


Przykład asynchat
=================

Następujący częściowy przykład pokazuje jak zapytania HTTP mogą być
wczytane za pomocą "async_chat". Serwer sieci może tworzyć obiekt
"http_request_handler" dla każdego przychodzącego połączenia
klienckiego. Zauważ że początkowo zakończenie kanału jest ustalone aby
odpowiadało pustej linii na końcu nagłówka HTTP, i flaga wskazująca że
nagłówki są wczytywane.

Gdy już nagłówki zostaną wczytane, jeśli zapytanie jest typu POST
(wskazując na to że dalsze dane są obecne w strumieniu wejściowym)
wtedy nagłówek "Content-Length:" jest używany aby ustawić numeryczny
terminator do wczytania właściwej ilości danych z kanału.

Metoda "handle_request()" jest wywoływane gdy już całe istotne wejście
zostało pobrane, po ustawieniu terminatora kanału na "None" - z ang. -
"Żaden" aby upewnić się że jakiekolwiek nadmiarowe dane przesyłane
przez klienta sieci są ignorowane.

   import asynchat

   class http_request_handler(asynchat.async_chat):

       def __init__(self, sock, addr, sessions, log):
           asynchat.async_chat.__init__(self, sock=sock)
           self.addr = addr
           self.sessions = sessions
           self.ibuffer = []
           self.obuffer = b""
           self.set_terminator(b"\r\n\r\n")
           self.reading_headers = True
           self.handling = False
           self.cgi_data = None
           self.log = log

       def collect_incoming_data(self, data):
           """Buffer the data"""
           self.ibuffer.append(data)

       def found_terminator(self):
           if self.reading_headers:
               self.reading_headers = False
               self.parse_headers(b"".join(self.ibuffer))
               self.ibuffer = []
               if self.op.upper() == b"POST":
                   clen = self.headers.getheader("content-length")
                   self.set_terminator(int(clen))
               else:
                   self.handling = True
                   self.set_terminator(None)
                   self.handle_request()
           elif not self.handling:
               self.set_terminator(None)  # browsers sometimes over-send
               self.cgi_data = parse(self.headers, b"".join(self.ibuffer))
               self.handling = True
               self.ibuffer = []
               self.handle_request()
