3 \@,@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|_tjj|||dS)N) ac_in_bufferincomingr producer_fifoasyncore dispatcher__init__)selfZsockmapr /usr/lib64/python3.6/asynchat.pyr Cszasync_chat.__init__cCs tddS)Nzmust be implemented in subclass)NotImplementedError)r datar r rcollect_incoming_dataQsz async_chat.collect_incoming_datacCs|jj|dS)N)rappend)r rr r r_collect_incoming_dataTsz!async_chat._collect_incoming_datacCsdj|j}|jdd=|S)Nr)joinr)r dr r r _get_dataWs  zasync_chat._get_datacCs tddS)Nzmust be implemented in subclass)r)r r r rfound_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 Ztermr r rset_terminator_s zasync_chat.set_terminatorcCs|jS)N)r)r r r rget_terminatorjszasync_chat.get_terminatorcCsy|j|j}Wn:tk r$dStk rJ}z |jdSd}~XnXt|trh|jrhtt|j }|j ||_ xV|j rt |j }|j }|s|j |j d|_ qxt|tr|}||kr|j |j d|_ |j||_n2|j |j d||j |d|_ d|_|jqxt |}|j j|}|dkrp|dkrR|j |j d||j ||d|_ |jqxt|j |}|r||kr|j |j d| |j | d|_ Pqx|j |j d|_ qxWdS)Nrr)Zrecvac_in_buffer_sizeBlockingIOErrorOSError handle_errorrrrrrrlenr!rrrrfindfind_prefix_at_end)r rZwhyZlbrnZterminator_lenindexr r r handle_readrsR               zasync_chat.handle_readcCs |jdS)N) initiate_send)r r r r handle_writeszasync_chat.handle_writecCs |jdS)N)close)r r r r handle_closeszasync_chat.handle_closecCs|t|tttfstdt||j}t||krdx>tdt||D]}|j j ||||qBWn |j j ||j dS)Nz#data argument must be byte-ish (%r)r) rr bytearray memoryview TypeErrortypeac_out_buffer_sizer(rangerrr.)r rZsabsir r rpushs   zasync_chat.pushcCs|jj||jdS)N)rrr.)r Zproducerr r rpush_with_producers zasync_chat.push_with_producercCsdS)z4predicate for inclusion in the readable for select()r"r )r r r rreadableszasync_chat.readablecCs|jp |j S)z4predicate for inclusion in the writable for select())r connected)r r r rwritableszasync_chat.writablecCs|jjddS)zAautomatically close this channel once the outgoing queue is emptyN)rr)r r r rclose_when_doneszasync_chat.close_when_donecCsx|jo|jr|jd}|s<|jd=|dkr<|jdS|j}y|d|}Wn8tk r|j}|r||jj|n|jd=wYnXt|tr|j rt ||j }y|j |}Wnt k r|jdSX|r|t|ks|t|kr||d|jd<n|jd=dSWdS)Nr)rr<r1r6r4more appendleftrrrrrsendr&r'r()r firstZobsrZnum_sentr r rr.s8  zasync_chat.initiate_sendcCs d|_|jdd=|jjdS)Nr)rrrclear)r r r rdiscard_bufferss zasync_chat.discard_buffers)NN)__name__ __module__ __qualname____doc__r$r6rrr rrrrr r!r-r/r1r9r:r;r=r>r.rDr r r rr4s,  H (rc@seZdZdddZddZdS)simple_producercCs||_||_dS)N)r buffer_size)r rrKr r rr szsimple_producer.__init__cCsJt|j|jkr6|jd|j}|j|jd|_|S|j}d|_|SdS)Nr)r(rrK)r resultr r rr?szsimple_producer.moreN)rJ)rErFrGr r?r r r rrIs rIcCs6t|d}x$|r0|j|d| r0|d8}qW|S)Nr")r(endswith)ZhaystackZneedlelr r rr*/s  r*)rHr collectionsrr rrIr*r r r r/s  \