B \]@,@sDdZddlZddlmZGdddejZGdddZdd ZdS) aA class supporting chat-style (command/response) protocols. This class adds support for 'chat' style protocols - where one side sends a 'command', and the other sends a response (examples would be the common internet protocols - smtp, nntp, ftp, etc..). The handle_read() method looks at the input stream for the current 'terminator' (usually '\r\n' for single-line responses, '\r\n.\r\n' for multi-line output), calling self.found_terminator() on its receipt. for example: Say you build an async nntp client using this class. At the start of the connection, you'll have self.terminator set to '\r\n', in order to process the single-line greeting. Just before issuing a 'LIST' command you'll set it to '\r\n.\r\n'. The output of the LIST command will be accumulated (using your own 'collect_incoming_data' method) up to the terminator, and then control will be returned to you - by calling your self.found_terminator() method. N)dequec@seZdZdZdZdZdZdZd(ddZdd Z d d Z d d Z ddZ ddZ ddZddZddZddZddZddZddZd d!Zd"d#Zd$d%Zd&d'ZdS)) async_chatzThis is an abstract class. You must derive from this class, and add the two methods collect_incoming_data() and found_terminator()irzlatin-1NcCs(d|_g|_t|_tj|||dS)N) ac_in_bufferincomingr producer_fifoasyncore dispatcher__init__)selfsockmapr$/usr/local/lib/python3.7/asynchat.pyr Cszasync_chat.__init__cCs tddS)Nzmust be implemented in subclass)NotImplementedError)r datarrrcollect_incoming_dataQsz async_chat.collect_incoming_datacCs|j|dS)N)rappend)r rrrr_collect_incoming_dataTsz!async_chat._collect_incoming_datacCsd|j}|jdd=|S)Nr)joinr)r drrr _get_dataWs  zasync_chat._get_datacCs tddS)Nzmust be implemented in subclass)r)r rrrfound_terminator\szasync_chat.found_terminatorcCsBt|tr|jrt||j}nt|tr8|dkr8td||_dS)zdSet the input delimiter. Can be a fixed string of any length, an integer, or None. rz-the number of received bytes must be positiveN) isinstancestr use_encodingbytesencodingint ValueError terminator)r Ztermrrrset_terminator_s zasync_chat.set_terminatorcCs|jS)N)r )r rrrget_terminatorjszasync_chat.get_terminatorc Csy||j}Wn<tk r$dStk rL}z |dSd}~XYnXt|trj|jrjtt|j }|j ||_ xV|j rt |j }| }|s| |j d|_ qzt|tr|}||kr| |j d|_ |j||_n2| |j d||j |d|_ d|_|qzt |}|j |}|dkrr|dkrT| |j d||j ||d|_ |qzt|j |}|r||kr| |j d| |j | d|_ Pqz| |j d|_ qzWdS)Nrr)recvac_in_buffer_sizeBlockingIOErrorOSError handle_errorrrrrrrlenr"rrr rfindfind_prefix_at_end)r rwhyZlbr nZterminator_lenindexrrr handle_readrsR               zasync_chat.handle_readcCs |dS)N) initiate_send)r rrr handle_writeszasync_chat.handle_writecCs |dS)N)close)r rrr handle_closeszasync_chat.handle_closecCs|t|tttfstdt||j}t||krdx>tdt||D]}|j ||||qBWn |j || dS)Nz#data argument must be byte-ish (%r)r) rr bytearray memoryview TypeErrortypeac_out_buffer_sizer)rangerrr0)r rZsabsirrrpushs   zasync_chat.pushcCs|j||dS)N)rrr0)r producerrrrpush_with_producers zasync_chat.push_with_producercCsdS)z4predicate for inclusion in the readable for select()r)r rrrreadableszasync_chat.readablecCs|jp |j S)z4predicate for inclusion in the writable for select())r connected)r rrrwritableszasync_chat.writablecCs|jddS)zAautomatically close this channel once the outgoing queue is emptyN)rr)r rrrclose_when_doneszasync_chat.close_when_donecCsx|jr|jr|jd}|s>|jd=|dkr>|dS|j}y|d|}Wn8tk r|}|r~|j|n|jd=wYnXt|tr|j rt ||j }y| |}Wnt k r|dSX|r|t|ks|t|kr ||d|jd<n|jd=dSWdS)Nr)rr@r3r8r6more appendleftrrrrrsendr'r(r))r firstZobsrnum_sentrrrr0s8  zasync_chat.initiate_sendcCs d|_|jdd=|jdS)Nr)rrrclear)r rrrdiscard_bufferss zasync_chat.discard_buffers)NN)__name__ __module__ __qualname____doc__r%r8rrr rrrrr!r"r/r1r3r;r=r?rArBr0rIrrrrr4s,  H (rc@seZdZdddZddZdS)simple_producercCs||_||_dS)N)r buffer_size)r rrPrrrr szsimple_producer.__init__cCsJt|j|jkr6|jd|j}|j|jd|_|S|j}d|_|SdS)Nr)r)rrP)r resultrrrrCszsimple_producer.moreN)rO)rJrKrLr rCrrrrrNs rNcCs4t|d}x"|r.||d|s.|d8}qW|S)Nr>)r)endswith)ZhaystackZneedlelrrrr+/s  r+)rMr collectionsrr rrNr+rrrr/s  \